Просмотр исходного кода

MVC structure. Some sections working.

Iñigo Valentin 7 лет назад
Родитель
Сommit
cd3bf2607e
100 измененных файлов с 5586 добавлено и 48 удалено
  1. 2 2
      .gitignore
  2. 126 0
      site-public/application/Controller.php
  3. 8 0
      site-public/application/config/auth.php
  4. 75 0
      site-public/application/config/config.php
  5. 33 0
      site-public/application/config/url.php
  6. 237 0
      site-public/application/entity/Activity.php
  7. 82 0
      site-public/application/entity/Activity_Comment.php
  8. 61 0
      site-public/application/entity/Activity_Image.php
  9. 89 0
      site-public/application/entity/Activity_Itinerary.php
  10. 84 0
      site-public/application/entity/Album.php
  11. 35 0
      site-public/application/entity/Entity.php
  12. 165 0
      site-public/application/entity/Festival.php
  13. 79 0
      site-public/application/entity/Festival_Day.php
  14. 119 0
      site-public/application/entity/Festival_Event.php
  15. 81 0
      site-public/application/entity/Festival_Offer.php
  16. 55 0
      site-public/application/entity/People.php
  17. 136 0
      site-public/application/entity/Photo.php
  18. 82 0
      site-public/application/entity/Photo_Comment.php
  19. 74 0
      site-public/application/entity/Place.php
  20. 118 0
      site-public/application/entity/Post.php
  21. 82 0
      site-public/application/entity/Post_Comment.php
  22. 61 0
      site-public/application/entity/Post_Image.php
  23. 74 0
      site-public/application/entity/Route.php
  24. 113 0
      site-public/application/entity/Route_Point.php
  25. 100 0
      site-public/application/entity/Sponsor.php
  26. 64 0
      site-public/application/page/Activities_Page.php
  27. 50 0
      site-public/application/page/Activity_Page.php
  28. 36 0
      site-public/application/page/Album_Page.php
  29. 44 0
      site-public/application/page/Blog_Page.php
  30. 102 0
      site-public/application/page/Festivals_Page.php
  31. 43 0
      site-public/application/page/Gallery_Page.php
  32. 31 0
      site-public/application/page/Help_Page.php
  33. 81 0
      site-public/application/page/Home_Page.php
  34. 104 0
      site-public/application/page/Page.php
  35. 33 0
      site-public/application/page/Photo_Page.php
  36. 45 0
      site-public/application/page/Post_Page.php
  37. 31 0
      site-public/application/page/Us_Page.php
  38. 189 0
      site-public/application/template/activities.php
  39. 185 0
      site-public/application/template/activity_future.php
  40. 75 0
      site-public/application/template/activity_past.php
  41. 69 0
      site-public/application/template/album.php
  42. 110 0
      site-public/application/template/blog.php
  43. 212 0
      site-public/application/template/festivals_active.php
  44. 81 0
      site-public/application/template/festivals_inactive.php
  45. 70 0
      site-public/application/template/gallery.php
  46. 198 0
      site-public/application/template/help.php
  47. 63 0
      site-public/application/template/include/footer.php
  48. 23 0
      site-public/application/template/include/header.php
  49. 42 0
      site-public/application/template/photo.php
  50. 128 0
      site-public/application/template/post.php
  51. 83 0
      site-public/application/template/string/lang_en.php
  52. 46 0
      site-public/application/template/string/lang_es.php
  53. 83 0
      site-public/application/template/string/lang_eu.php
  54. 79 0
      site-public/application/template/us.php
  55. 38 0
      site-public/application/util/db.php
  56. 117 0
      site-public/application/util/net.php
  57. 239 0
      site-public/application/util/text.php
  58. 87 0
      site-public/public/.htaccess
  59. 1 6
      site-public/public/css/actividades.css
  60. 0 0
      site-public/public/css/app.css
  61. 0 0
      site-public/public/css/ayuda.css
  62. 28 0
      site-public/public/css/blog.css
  63. 0 0
      site-public/public/css/galeria.css
  64. 105 0
      site-public/public/css/gallery.css
  65. 16 11
      site-public/public/css/index.css
  66. 9 23
      site-public/public/css/lablanca.css
  67. 0 0
      site-public/public/css/m/actividades.css
  68. 0 0
      site-public/public/css/m/ayuda.css
  69. 0 0
      site-public/public/css/m/blog.css
  70. 78 0
      site-public/public/css/m/galeria.css
  71. 0 5
      site-public/public/css/m/index.css
  72. 1 1
      site-public/public/css/m/lablanca.css
  73. 0 0
      site-public/public/css/m/nosotros.css
  74. 0 0
      site-public/public/css/nosotros.css
  75. 289 0
      site-public/public/css/ui.css
  76. 0 0
      site-public/public/fonts/FreeSans.ttf
  77. 0 0
      site-public/public/fonts/FreeSansBold.ttf
  78. 0 0
      site-public/public/fonts/FreeSansBoldOblique.ttf
  79. 0 0
      site-public/public/fonts/FreeSansOblique.ttf
  80. 0 0
      site-public/public/fonts/Vera.ttf
  81. 0 0
      site-public/public/fonts/VeraBI.ttf
  82. 0 0
      site-public/public/fonts/VeraBd.ttf
  83. 0 0
      site-public/public/fonts/VeraIt.ttf
  84. 0 0
      site-public/public/fonts/VeraMoBI.ttf
  85. 0 0
      site-public/public/fonts/VeraMoBd.ttf
  86. 0 0
      site-public/public/fonts/VeraMoIt.ttf
  87. 0 0
      site-public/public/fonts/VeraMono.ttf
  88. 0 0
      site-public/public/fonts/VeraSe.ttf
  89. 0 0
      site-public/public/fonts/VeraSeBd.ttf
  90. 0 0
      site-public/public/fonts/texgyreadventor-bold.otf
  91. 0 0
      site-public/public/fonts/texgyreadventor-bolditalic.otf
  92. 0 0
      site-public/public/fonts/texgyreadventor-italic.otf
  93. 0 0
      site-public/public/fonts/texgyreadventor-regular.otf
  94. 1 0
      site-public/public/img/content/.gitignore
  95. 1 0
      site-public/public/img/content/activities/.gitignore
  96. 1 0
      site-public/public/img/content/activities/x100/.gitignore
  97. 1 0
      site-public/public/img/content/activities/x200/.gitignore
  98. 1 0
      site-public/public/img/content/activities/x300/.gitignore
  99. 1 0
      site-public/public/img/content/activities/x400/.gitignore
  100. 1 0
      site-public/public/img/content/activities/x500/.gitignore

+ 2 - 2
.gitignore

@@ -31,8 +31,8 @@ sql/*__PRIVATE.sql
 sql/*__PRE.sql
 
 #Passwords file
-www/.ht*
-www-admin/.ht*
+site-public/application/config/auth.php_*
+site-private/.ht*
 
 #Photos and unnecessary images
 www/img/actividades/script

+ 126 - 0
site-public/application/Controller.php

@@ -0,0 +1,126 @@
+<?php
+
+    require_once(__DIR__ . "/config/config.php");
+    require_once($path["util"] . "db.php");
+    require_once($path["util"] . "text.php");
+    require_once($path["util"] . "net.php");
+
+
+    /**
+     * Application controller.
+     *
+     * Handles every request, creating the required models and selecting the
+     * view.
+     */
+    class Controller {
+
+        /**
+         * Constructor.
+         *
+         * Handles every request, creating the required models and selecting the
+         * view.
+         */
+        public function __construct($params){
+
+            global $path;
+            global $base_url;
+            global $url_l10n;
+            global $static;
+            global $static_url;
+            global $base_dir;
+            global $data;
+            $page;
+
+            $db = start_db();
+
+            // Parse parameters, get lang and build the route.
+            $pars = [];
+            foreach($params as $p){
+                if (strlen($p) > 0){
+                    array_push($pars, $p);
+                }
+            }
+            $route = [];
+            if (sizeof($pars) > 0 && preg_match("/^[a-zA-Z]{2}$/", $pars[0])){
+                $lang = $pars[0];
+                array_splice($pars, 0, 1);
+                // Override global to include language in URL
+                $base_url = get_protocol() . $_SERVER["HTTP_HOST"] . "/" . $lang;
+            }
+            else{
+                $lang = select_language($db);
+            }
+            if (isset($url_l10n[$lang])){
+                $url = $url_l10n[$lang];
+            }
+            else{
+                $url = $url_l10n["es"];
+            }
+            foreach($pars as $p){
+                array_push($route, $p);
+            }
+
+            // Select the model to load.
+            if (sizeof($route) == 0){
+                require_once($path["page"] . "Home_Page.php");
+                $page = new Home_Page($db, $lang);
+            }
+            else{
+                if (strtolower($route[0]) == $url["help"]){
+                    require_once($path["page"] . "Help_Page.php");
+                    $page = new Help_Page($db, $lang);
+                }
+                if (strtolower($route[0]) == $url["activities"]){
+                    if (sizeof($route) > 1){
+                        require_once($path["page"] . "Activity_Page.php");
+                        $page = new Activity_Page($db, $lang, $route[1]);
+                    }
+                    else{
+                        require_once($path["page"] . "Activities_Page.php");
+                        $page = new Activities_Page($db, $lang);
+                    }
+                }
+                if (strtolower($route[0]) == $url["blog"]){//$url->blog){
+                    if (sizeof($route) > 1){
+                        require_once($path["page"] . "Post_Page.php");
+                        $page = new Post_Page($db, $lang, $route[1]);
+                    }
+                    else{
+                        require_once($path["page"] . "Blog_Page.php");
+                        $page = new Blog_Page($db, $lang);
+                    }
+                }
+                if (strtolower($route[0]) == $url["us"]){
+                    require_once($path["page"] . "Us_Page.php");
+                    $page = new Us_Page($db, $lang);
+                }
+                if (strtolower($route[0]) == $url["gallery"]){
+                    if (sizeof($route) > 1){
+                        require_once($path["page"] . "Album_Page.php");
+                        $page = new Album_Page($db, $lang, $route[1]);
+                    }
+                    else{
+                        require_once($path["page"] . "Gallery_Page.php");
+                        $page = new Gallery_Page($db, $lang);
+                    }
+                }
+                if (strtolower($route[0]) == $url["festivals"]){
+                    // TODO: Manage year and subsections
+                    require_once($path["page"] . "Festivals_Page.php");
+                    $page = new Festivals_Page($db, $lang);
+                }
+            }
+
+            // Load the view, or set an error code.
+            if (!isset($page)){
+                http_response_code(404);
+                // TODO: Set up error page
+                require_once($path["page"] . "Home_Page.php");
+                $page = new Home_Page($db, $lang);
+                //require_once($path["page"] . "Error_Page.php");
+                //$page = new Error_Page($db, $lang);
+            }
+            require_once($page->template);
+        }
+    }
+?>

+ 8 - 0
site-public/application/config/auth.php

@@ -0,0 +1,8 @@
+<?php
+    $auth = [
+        "host" => "localhost",
+        "name" => "gm",
+        "user" => "gm",
+        "pass" => "XXX"
+    ];
+?>

+ 75 - 0
site-public/application/config/config.php

@@ -0,0 +1,75 @@
+<?php
+
+    require_once(__DIR__ . "/auth.php");
+    require_once(__DIR__ . "/../util/net.php");
+
+    /**
+     * Server base url, including protocol, without language indicator.
+     * It may be overwritten by the controller to add the language.
+     */
+    $base_url = get_protocol() . $_SERVER["HTTP_HOST"];
+    $static_url = get_protocol() . $_SERVER["HTTP_HOST"];
+
+    /**
+     * Page urls, different languages.
+     */
+    $url_l10n = [
+        "es" => [
+            "help" => "ayuda",
+            "activities" => "actividades",
+            "blog" => "blog",
+            "us" => "nosotros",
+            "gallery" => "galeria",
+            "festivals" => "fiestas"
+        ],
+        "en" => [
+            "help" => "help",
+            "activities" => "activities",
+            "blog" => "blog",
+            "us" => "us",
+            "gallery" => "gallery",
+            "festivals" => "festivals"
+        ],
+        "eu" => [
+            "help" => "laguntza",
+            "activities" => "aktibitateak",
+            "blog" => "blog",
+            "us" => "gu",
+            "gallery" => "argaskinak",
+            "festivals" => "jaiak"
+        ]
+    ];
+
+    /**
+     * Static url, absolute, language independant.
+     */
+    $static = [
+        "layout" => $static_url . "/img/layout/",
+        "content" => $static_url . "/img/content/",
+        "fonts" => $static_url . "/fonts/",
+        "css" => $static_url . "/css/",
+        "script" => $static_url . "/script/",
+    ];
+
+    /**
+     * Server document root.
+     */
+    $base_dir = $_SERVER["DOCUMENT_ROOT"];
+
+    /**
+     * Paths within the server.
+     */
+    $path = [
+        "application" => $base_dir . "/../application/",
+        "controller" => $base_dir . "/../application/Controller.php",
+        "entity" => $base_dir . "/../application/entity/",
+        "page" => $base_dir . "/../application/page/",
+        "util" => $base_dir . "/../application/util/",
+        "template" => $base_dir . "/../application/template/",
+        "include" => $base_dir . "/../application/template/include/",
+        "string" => $base_dir . "/../application/template/string/"
+    ];
+
+    require_once(__DIR__ . "/data.php");
+
+?>

+ 33 - 0
site-public/application/config/url.php

@@ -0,0 +1,33 @@
+<?php
+
+    /**
+     * Page urls, different languages.
+     */
+    $url = [
+        "es" = [
+            "help" => "ayuda",
+            "activities" => "actividades",
+            "blog" => "blog",
+            "us" => "nosotros",
+            "gallery" => "galeria",
+            "festivals" => "fiestas"
+        ];
+        "en" = [
+            "help" => "help",
+            "activities" => "activities",
+            "blog" => "blog",
+            "us" => "us",
+            "gallery" => "gallery",
+            "festivals" => "festivals"
+        ];
+        "eu" = [
+            "help" => "laguntza",
+            "activities" => "aktibitateak",
+            "blog" => "blog",
+            "us" => "gu",
+            "gallery" => "argaskinak",
+            "festivals" => "jaiak"
+        ];
+    ];
+
+?>

+ 237 - 0
site-public/application/entity/Activity.php

@@ -0,0 +1,237 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "Activity_Comment.php");
+    require_once($path["entity"] . "Activity_Image.php");
+    require_once($path["entity"] . "Activity_Itinerary.php");
+
+    /**
+     * Activity.
+     *
+     * Represents an object from the table 'activity'.
+     */
+    class Activity extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Permalink for linking the entity (relative).
+         */
+        public $permalink;
+
+        /**
+         * Date of the activity.
+         */
+        public $date;
+
+        /**
+         * City the activity takes place in.
+         */
+        public $city;
+
+        /**
+         * Title in the selected language.
+         */
+        public $title;
+
+        /**
+         * Description in the defined language.
+         */
+        public $text;
+
+        /**
+         * Description for when it's in the pase in the defined language.
+         */
+        public $after;
+
+        /**
+         * Price of the activity.
+         */
+        public $price;
+
+        /**
+         * Indicates if an inscription is required.
+         */
+        public $inscription;
+
+        /**
+         * People inscribed to the activity. Undefined if {@see $inscription}
+         * is false.
+         */
+        public $people;
+
+        /**
+         * Maximum number of people that can inscribe. Undefined if
+         * {@see $inscription} is false.
+         */
+        public $max_people;
+
+        /**
+         * Indicates if the activity must be visible.
+         */
+        public $visible;
+
+        /**
+         * Posting datetime.
+         */
+        public $dtime;
+
+        /**
+         * Photo {@see Album} of the activity.
+         */
+        public $album;
+
+        /**
+         * Array with the {@see Activity_Image}.
+         */
+        public $image = [];
+
+        /**
+         * Array with the tags.
+         */
+        public $tag = [];
+
+        /**
+         * Array with the {@see Activity_Comment}.
+         */
+        public $comment = [];
+
+        /**
+         * Array with the {@see Activity_Itinerary} items.
+         */
+        public $itinerary = [];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier or permalink.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, $lang);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  permalink, " .
+              "  date, " .
+              "  city, " .
+              "  title_" . $this->lang . " AS title, " .
+              "  text_" . $this->lang . " AS text, " .
+              "  after_" . $this->lang . " AS after, " .
+              "  price, " .
+              "  inscription, " .
+              "  people, " .
+              "  max_people, " .
+              "  visible, " .
+              "  dtime, " .
+              "  album " .
+              "FROM activity " .
+              "WHERE " .
+              "  visible = 1 AND " .
+              "  ( " .
+              "    id = '$id' OR " .
+              "    permalink = '$id' " .
+              "  );";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->permalink = $r["permalink"];
+                $this->title = $r["title"];
+                $this->text = $r["text"];
+                $this->date = $r["date"];
+                $this->city = $r["city"];
+                if (!is_null($r["after"])){
+                    $this->after = $r["after"];
+                }
+                if ($r["inscription"] == 1){
+                    $this->inscription = true;
+                    $this->people = $r["people"];
+                    $this->max_people = $r["max_people"];
+                }
+                else{
+                    $this->inscription = false;
+                }
+                if ($r["visible"] == 1){
+                    $this->visible = true;
+                }
+                else{
+                    $this->visible = false;
+                }
+                $this->price = $r["price"];
+                $this->dtime = $r["dtime"];
+                // TODO
+                //if (!is_null($r["album"])){
+                //    $this->after = New Album($this->db, $this->lang, $r["album"]);
+                //}
+            }
+            $s_image =
+              "SELECT id " .
+              "FROM activity_image " .
+              "WHERE activity = " . $this->id . " " .
+              "ORDER BY idx; ";
+            $q_image = mysqli_query($this->db, $s_image);
+            while($r_image = mysqli_fetch_array($q_image)){
+                array_push($this->image, new Activity_Image($this->db, $r_image["id"]));
+            }
+            $s_tag =
+              "SELECT tag " .
+              "FROM activity_tag " .
+              "WHERE activity = " . $this->id . ";";
+            $q_tag = mysqli_query($this->db, $s_tag);
+            while($r_tag = mysqli_fetch_array($q_tag)){
+                array_push($this->tag, $r_tag["tag"]);
+            }
+            $s_comment =
+              "SELECT id " .
+              "FROM activity_comment " .
+              "WHERE " .
+              "  activity = " . $this->id . " AND " .
+              "  approved = 1;";
+            $q_comment = mysqli_query($this->db, $s_comment);
+            while($r_tag = mysqli_fetch_array($q_comment)){
+                array_push($this->comment, new Activity_Comment($this->db, $r_comment["id"]));
+            }
+            $s_itinerary =
+              "SELECT id " .
+              "FROM activity_itinerary " .
+              "WHERE " .
+              "  activity = " . $this->id . ";";
+            $q_itinerary = mysqli_query($this->db, $s_itinerary);
+            while($r_itinerary = mysqli_fetch_array($q_itinerary)){
+                array_push($this->itinerary, new Activity_Itinerary($this->db, $this->lang, $r_itinerary["id"]));
+            }
+        }
+
+        /**
+         * Checks if an activity is in the future.
+         *
+         * If the activity takes place during the current day, it's still
+         * considered in the future.
+         *
+         * @return true if future, false if past.
+         */
+        public function is_future(){
+            return (time() - 60 * 60 * 24 < $this->date);
+        }
+
+        /**
+         * Checks if an activity is in the past.
+         *
+         * If the activity takes place during the current day, it's still
+         * considered in the future.
+         *
+         * @return true if past, false if future.
+         */
+        public function is_past(){
+            return !$this->is_future();
+        }
+    }
+?>

+ 82 - 0
site-public/application/entity/Activity_Comment.php

@@ -0,0 +1,82 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Activity_Comment.
+     *
+     * Represents an object from the table 'activity_comment'.
+     */
+    class Activity_Comment extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Identifier of the activity the comment belongs to.
+         */
+        public $activity;
+
+        /**
+         * The content in the defined language.
+         */
+        public $text;
+
+        /**
+         * Posting datetime.
+         */
+        public $dtime;
+
+        /**
+         * Uername.
+         */
+        public $username;
+
+        /**
+         * Language of the comment (unreliable).
+         */
+        public $lang;
+
+        /**
+         * Approved indicator.
+         */
+        public $approved;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param id Identifier.
+         */
+        public function __construct($db, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  activity, " .
+              "  text, " .
+              "  dtime, " .
+              "  username, " .
+              "  lang, " .
+              "  approved " .
+              "FROM activity_comment " .
+              "WHERE id = '$id';";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->activity = $r["activity"];
+                $this->text = $r["text"];
+                $this->dtime = $r["dtime"];
+                $this->username = $r["username"];
+                $this->lang = $r["lang"];
+                $this->approved = $r["approved"];
+            }
+        }
+    }
+?>

+ 61 - 0
site-public/application/entity/Activity_Image.php

@@ -0,0 +1,61 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Activity_Image.
+     *
+     * Represents an object from the table 'activity_image'.
+     */
+    class Activity_Image extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Identifier of the activity the image belongs to.
+         */
+        public $activity;
+
+        /**
+         * Filename.
+         */
+        public $image;
+
+        /**
+         * Order.
+         */
+        public $idx;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param id Identifier.
+         */
+        public function __construct($db, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  activity, " .
+              "  image, " .
+              "  idx " .
+              "FROM activity_image " .
+              "WHERE id = '$id';";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->activity = $r["activity"];
+                $this->image = $r["image"];
+                $this->idx = $r["idx"];
+            }
+        }
+    }
+?>

+ 89 - 0
site-public/application/entity/Activity_Itinerary.php

@@ -0,0 +1,89 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "Route.php");
+    require_once($path["entity"] . "Place.php");
+
+    /**
+     * Activity_Itinerary.
+     *
+     * Represents an object from the table 'activity_itinerary'.
+     */
+    class Activity_Itinerary extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Short name of the itinerary item.
+         */
+        public $name;
+
+        /**
+         * Description of the itinerary entry.
+         */
+        public $description;
+
+        /**
+         * Start time of the item.
+         */
+        public $start;
+
+        /**
+         * End time of the item. It may not be defined.
+         */
+        public $end;
+
+        /**
+         * Place of the item.
+         */
+        public $place;
+
+        /**
+         * Route the itinerary will travel during the item. It may be undefined.
+         */
+        public $route;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, $lang);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  name_$lang AS name, " .
+              "  description_$lang AS description, " .
+              "  start, " .
+              "  end, " .
+              "  place, " .
+              "  route " .
+              "FROM activity_itinerary " .
+              "WHERE id = $id;";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->name = $r["name"];
+                $this->description = $r["description"];
+                $this->start = $r["start"];
+                if (!is_null($r["end"])){
+                    $this->end = $r["end"];
+                }
+                $this->place = new Place($this->db, $this->lang, $r["place"]);
+                if (!is_null($r["route"])){
+                    $this->route = new Route($this->db, $r["route"]);
+                }
+            }
+        }
+    }
+?>

+ 84 - 0
site-public/application/entity/Album.php

@@ -0,0 +1,84 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "Photo.php");
+
+    /**
+     * Album.
+     *
+     * Represents an object from the table 'album'.
+     */
+    class Album extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Permalink for linking the entity (relative).
+         */
+        public $permalink;
+
+        /**
+         * Title in the selected language. It may be not set.
+         */
+        public $title;
+
+        /**
+         * The content in the defined language. It may be not set.
+         */
+        public $description;
+
+        /**
+         * Array with every {@see Photo} in the album.
+         */
+        public $photo = [];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier or permalink.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, $lang);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  file, " .
+              "  permalink, " .
+              "  title_" . $this->lang . " AS title, " .
+              "  description_" . $this->lang . " AS description " .
+              "FROM album " .
+              "WHERE " .
+              "  id = '$id' OR " .
+              "  permalink = '$id';";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->permalink = $r["permalink"];
+                if (!is_null($r["title"])){
+                    $this->title = $r["title"];
+                }
+                if (!is_null($r["description"])){
+                    $this->description = $r["description"];
+                }
+            }
+            $s_photo =
+              "SELECT id " .
+              "FROM photo_album " .
+              "WHERE " .
+              "  album = " . $this->id . ";";
+            $q_photo = mysqli_query($this->db, $s_photo);
+            while($r_photo = mysqli_fetch_array($q_photo)){
+                array_push($this->photo, new Photo($this->db, $this->lang, $r_photo["id"]));
+            }
+        }
+    }
+?>

+ 35 - 0
site-public/application/entity/Entity.php

@@ -0,0 +1,35 @@
+<?php
+
+    /**
+     * Entity superclass.
+     *
+     * Every other entity must inherit from this one. It represents a database
+     * entity.
+     */
+    abstract class Entity{
+
+        /**
+         * Database connection.
+         */
+        public $db;
+
+        /**
+         * The language of the class's text fields (lowercase, two-letter
+         * language code).
+         */
+        public $lang;
+
+        /**
+         * Constructor.
+         *
+         * Sets the database conection and the language.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang){
+            $this->db = $db;
+            $this->lang = $lang;
+        }
+    }
+?>

+ 165 - 0
site-public/application/entity/Festival.php

@@ -0,0 +1,165 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "Festival_Day.php");
+    require_once($path["entity"] . "Festival_Offer.php");
+    require_once($path["entity"] . "Festival_Event.php");
+
+    /**
+     * Festival.
+     *
+     * Represents an object from the table 'festival'.
+     */
+    class Festival extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Year of the festivals.
+         */
+        public $year;
+
+        /**
+         * Short text.
+         */
+        public $text;
+
+        /**
+         * Description of the festivals.
+         */
+        public $description;
+
+        /**
+         * Filename of the festivals banner.
+         */
+        public $image;
+
+        /**
+         * Array of {@see Festival_Day}.
+         */
+        public $day = [];
+
+        /**
+         * Array of {@see Festival_Offer}.
+         */
+        public $offer = [];
+
+        /**
+         * Array of {@see Festival_Event}.
+         */
+        public $event = [
+            "internal" => [],
+            "public" => []
+        ];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param year Year or identifier.
+         */
+        public function __construct($db, $lang, $year){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  year, " .
+              "  text_$lang AS text, " .
+              "  description_$lang AS description, " .
+              "  img AS image " .
+              "FROM festival " .
+              "WHERE " .
+              "  id = $id OR " .
+              "  year = $id;";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->internal = $r["year"];
+                $this->text = $r["text"];
+                $this->description = $r["description"];
+                if (!is_null($r["image"])){
+                    $this->image = $r["image"];
+                }
+            }
+            $s_day =
+              "SELECT id " .
+              "FROM festival_day " .
+              "WHERE year(date) = " . $this->year . " " .
+              "ORDER BY date; ";
+            $q_day = mysqli_query($this->db, $s_day);
+            while($r_day = mysqli_fetch_array($q_day)){
+                array_push($this->day, new Festival_Day($this->db, $this->lang, $r_day["id"]));
+            }
+            $s_offer =
+              "SELECT id " .
+              "FROM festival_offer " .
+              "WHERE year = " . $this->year . " " .
+              "ORDER BY days; ";
+            $q_offer = mysqli_query($this->db, $s_offer);
+            while($r_day = mysqli_fetch_array($q_offer)){
+                array_push($this->offer, new Festival_Offer($this->db, $this->lang, $r_offer["id"]));
+            }
+            // TODO Check
+            $s_g_day =
+              "SELECT DISTINCT " .
+              "  date(start) AS date, " .
+              "  day(start) AS day, " .
+              "FROM festival_event " .
+              "WHERE " .
+              "  gm = 0 AND " .
+              "  year(start) = " . $this->year . " " .
+              "ORDER BY date;";
+            $q_g_day = mysqli_query($this->db, $s_g_day);
+            $events = [];
+            while($r_g_day = mysqli_fetch_array($q_g_day)){
+                $events->$r_g_day["day"] = [];
+                $s_event =
+                  "SELECT id " .
+                  "FROM festival_event " .
+                  "WHERE " .
+                  "  gm = 0 AND " .
+                  "  date(date_add(start, INTERVAL -4 HOUR)) = '" . $r_g_day["date"] . "' " .
+                  "ORDER BY start;";
+                $q_event = mysqli_query($this->db, $s_event);
+                while($r_event = mysqli_fetch_array($q_event)){
+                    array_push($events->$r_g_day["day"], new Festival_Event($this->db, $this->lang, $r_event["id"]));
+                }
+            }
+            array_push($this->event->public, $events);
+            $s_g_day =
+              "SELECT DISTINCT " .
+              "  date(start) AS date, " .
+              "  day(start) AS day, " .
+              "FROM festival_event " .
+              "WHERE " .
+              "  gm = 1 AND " .
+              "  year(start) = " . $this->year . " " .
+              "ORDER BY date;";
+            $q_g_day = mysqli_query($this->db, $s_g_day);
+            $events = [];
+            while($r_g_day = mysqli_fetch_array($q_g_day)){
+                $events->$r_g_day["day"] = [];
+                $s_event =
+                  "SELECT id " .
+                  "FROM festival_event " .
+                  "WHERE " .
+                  "  gm = 1 AND " .
+                  "  date(date_add(start, INTERVAL -4 HOUR)) = '" . $r_g_day["date"] . "' " .
+                  "ORDER BY start;";
+                $q_event = mysqli_query($this->db, $s_event);
+                while($r_event = mysqli_fetch_array($q_event)){
+                    array_push($events->$r_g_day["day"], new Festival_Event($this->db, $this->lang, $r_event["id"]));
+                }
+            }
+            array_push($this->event->internal, $events);
+        }
+    }
+?>

+ 79 - 0
site-public/application/entity/Festival_Day.php

@@ -0,0 +1,79 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Festival_Day.
+     *
+     * Represents an object from the table 'festival_day'.
+     */
+    class Festival_Day extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Date of the day.
+         */
+        public $date;
+
+        /**
+         * Day name.
+         */
+        public $name;
+
+        /**
+         * Prices of the day.
+         */
+        public $price = [
+            "public" => null,
+            "member" => null
+        ];
+
+        /**
+         * Number of people inscribed for the day.
+         */
+        public $people;
+
+        /**
+         * Maximum number of people that can inscribe.
+         */
+        public $max_people;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  name_$lang AS name, " .
+              "  price, " .
+              "  price_public, " .
+              "  people, " .
+              "  max_people " .
+              "FROM festival_day " .
+              "WHERE id = $id;";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->name = $r["name"];
+                $this->price->member = $r["price"];
+                $this->price->public = $r["price_public"];
+                $this->people = $r["people"];
+                $this->max_people = $r["max_people"];
+            }
+        }
+    }
+?>

+ 119 - 0
site-public/application/entity/Festival_Event.php

@@ -0,0 +1,119 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "Route.php");
+    require_once($path["entity"] . "Place.php");
+    require_once($path["entity"] . "People.php");
+
+    /**
+     * Festival_Event.
+     *
+     * Represents an object from the table 'festival_event'.
+     */
+    class Festival_Event extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Indicates if the event is internal or an official event.
+         */
+        public $internal;
+
+        /**
+         * Event name.
+         */
+        public $title;
+
+        /**
+         * Description of the event.
+         */
+        public $description;
+
+        /**
+         * {@see People} hosting or organizing the event.
+         */
+        public $host;
+
+        /**
+         * {@see People} sponsoring the event.
+         */
+        public $sponsor;
+
+        /**
+         * Start time of the item.
+         */
+        public $start;
+
+        /**
+         * End time of the item. It may not be defined.
+         */
+        public $end;
+
+        /**
+         * Place of the item.
+         */
+        public $place;
+
+        /**
+         * Route the itinerary will travel during the item. It may be undefined.
+         */
+        public $route;
+
+        /**
+         * Interest of the event. Arbitrary.
+         */
+        public $interest;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  gm AS internal, " .
+              "  title_$lang AS title, " .
+              "  description_$lang AS description, " .
+              "  start, " .
+              "  end, " .
+              "  place, " .
+              "  route " .
+              "FROM festival_event " .
+              "WHERE id = $id;";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->internal = $r["internal"];
+                $this->title = $r["title"];
+                $this->description = $r["description"];
+                $this->start = $r["start"];
+                if (!is_null($r["end"])){
+                    $this->end = $r["end"];
+                }
+                $this->place = new Place($this->db, $this->lang, $r["place"]);
+                if (!is_null($r["route"])){
+                    $this->route = new Route($this->db, $this->lang, $r["route"]);
+                }
+                if (!is_null($r["host"])){
+                    $this->host = new People($this->db, $this->lang, $r["host"]);
+                }
+                if (!is_null($r["sponsor"])){
+                    $this->host = new Sponsor($this->db, $this->lang, $r["sponsor"]);
+                }
+                $this->interest = $r["interest"];
+            }
+        }
+    }
+?>

+ 81 - 0
site-public/application/entity/Festival_Offer.php

@@ -0,0 +1,81 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Festival_Offer.
+     *
+     * Represents an object from the table 'festival_offer'.
+     */
+    class Festival_Offer extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Year the offer applies on.
+         */
+        public $year;
+
+        /**
+         * Offer name.
+         */
+        public $name;
+
+        /**
+         * Offer description.
+         */
+        public $description;
+
+        /**
+         * Prices of the offer.
+         */
+        public $price = [
+            "public" => null,
+            "member" => null
+        ];
+
+        /**
+         * Number of days included in the offer.
+         */
+        public $days;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  year, " .
+              "  name_$lang AS name, " .
+              "  description_$lang AS description, " .
+              "  price, " .
+              "  price_public, " .
+              "  days " .
+              "FROM festival_offer " .
+              "WHERE id = $id;";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->year = $r["year"];
+                $this->name = $r["name"];
+                $this->description = $r["description"];
+                $this->price->member = $r["price"];
+                $this->price->public = $r["price_public"];
+                $this->days = $r["days"];
+            }
+        }
+    }
+?>

+ 55 - 0
site-public/application/entity/People.php

@@ -0,0 +1,55 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * People.
+     *
+     * Represents an object from the table 'people'.
+     */
+    class People extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Name of the sponsor.
+         */
+        public $name;
+
+        /**
+         * Person url.
+         */
+        public $link;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, $lang);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  name_$lang AS name, " .
+              "  link " .
+              "FROM people " .
+              "WHERE id = '$id';";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->name = $r["name"];
+                $this->link = $r["link"];
+            }
+        }
+    }
+?>

+ 136 - 0
site-public/application/entity/Photo.php

@@ -0,0 +1,136 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "Photo_Comment.php");
+    require_once($path["entity"] . "Place.php");
+
+    /**
+     * Photo.
+     *
+     * Represents an object from the table 'photo'.
+     */
+    class Photo extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Filename.
+         */
+        public $file;
+
+        /**
+         * Permalink for linking the entity (relative).
+         */
+        public $permalink;
+
+        /**
+         * Title in the selected language. It may be not set.
+         */
+        public $title;
+
+        /**
+         * The content in the defined language. It may be not set.
+         */
+        public $description;
+
+        /**
+         * Time the photo was taken.
+         */
+        public $dtime;
+
+        /**
+         * Time the photo was taken.
+         */
+        public $uploaded;
+
+        /**
+         * {@see Place} the photo was taken in. It may be unknown.
+         */
+        public $place;
+
+        /**
+         * Indicates if the photo has been approven and can be shown.
+         */
+        public $approved;
+
+        /**
+         * Username of the uploader or sender.
+         */
+        public $username;
+
+        /**
+         * Array with the {@see Post_Comment}.
+         */
+        public $comment = [];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier or permalink.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, $lang);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  file, " .
+              "  permalink, " .
+              "  title_" . $this->lang . " AS title, " .
+              "  description_" . $this->lang . " AS description, " .
+              "  dtime, " .
+              "  uploaded, " .
+              "  place, " .
+              "  approved, " .
+              "  username " .
+              "FROM photo " .
+              "WHERE " .
+              "  approved = 1 AND " .
+              "  ( " .
+              "    id = '$id' OR " .
+              "    permalink = '$id' " .
+              "  );";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->file = $r["file"];
+                $this->permalink = $r["permalink"];
+                if (!is_null($r["title"])){
+                    $this->title = $r["title"];
+                }
+                if (!is_null($r["description"])){
+                    $this->description = $r["description"];
+                }
+                if (!is_null($r["dtime"])){
+                    $this->dtime = $r["dtime"];
+                }
+                $this->uploaded = $r["uploaded"];
+                if (!is_null($r["place"])){
+                    $this->place = New Place($this->db, $this->lang, $r["place"]);
+                }
+                $this->approved = $r["approved"];
+                if (!is_null($r["username"])){
+                    $this->username = $r["username"];
+                }
+            }
+            $s_comment =
+              "SELECT id " .
+              "FROM photo_comment " .
+              "WHERE " .
+              "  photo = " . $this->id . " AND " .
+              "  approved = 1;";
+            $q_comment = mysqli_query($this->db, $s_comment);
+            while($r_comment = mysqli_fetch_array($q_comment)){
+                array_push($this->comment, new Photo_Comment($this->db, $r_comment["id"]));
+            }
+        }
+    }
+?>

+ 82 - 0
site-public/application/entity/Photo_Comment.php

@@ -0,0 +1,82 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Photo_Comment.
+     *
+     * Represents an object from the table 'photo_comment'.
+     */
+    class Photo_Comment extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Identifier of the photo the comment belongs to.
+         */
+        public $photo;
+
+        /**
+         * The content in the defined language.
+         */
+        public $text;
+
+        /**
+         * Posting datetime.
+         */
+        public $dtime;
+
+        /**
+         * Uername.
+         */
+        public $username;
+
+        /**
+         * Language of the comment (unreliable).
+         */
+        public $lang;
+
+        /**
+         * Approved indicator.
+         */
+        public $approved;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param id Identifier.
+         */
+        public function __construct($db, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  photo, " .
+              "  text, " .
+              "  dtime, " .
+              "  username, " .
+              "  lang, " .
+              "  approved " .
+              "FROM photo_comment " .
+              "WHERE id = '$id';";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->photo = $r["photo"];
+                $this->text = $r["text"];
+                $this->dtime = $r["dtime"];
+                $this->username = $r["username"];
+                $this->lang = $r["lang"];
+                $this->approved = $r["approved"];
+            }
+        }
+    }
+?>

+ 74 - 0
site-public/application/entity/Place.php

@@ -0,0 +1,74 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Place.
+     *
+     * Represents an object from the table 'sponsor'.
+     */
+    class Place extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Name of the place.
+         */
+        public $name;
+
+        /**
+         * Place address.
+         */
+        public $address;
+
+        /**
+         * Postal code.
+         */
+        public $cp;
+
+        /**
+         * Geographical location.
+         */
+        public $location = [
+            "lat" => null,
+            "lon" => null
+        ];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, $lang);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  name_$lang AS name, " .
+              "  address_$lang AS address, " .
+              "  cp, " .
+              "  lat, " .
+              "  lon " .
+              "FROM place " .
+              "WHERE id = $id;";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->name = $r["name"];
+                $this->address = $r["address"];
+                $this->cp = $r["cp"];
+                $this->location["lat"] = $r["lat"];
+                $this->location["lon"] = $r["lon"];
+            }
+        }
+    }
+?>

+ 118 - 0
site-public/application/entity/Post.php

@@ -0,0 +1,118 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "Post_Comment.php");
+    require_once($path["entity"] . "Post_Image.php");
+
+    /**
+     * Post.
+     *
+     * Represents an object from the table 'post'.
+     */
+    class Post extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Permalink for linking the entity (relative).
+         */
+        public $permalink;
+
+        /**
+         * Title in the selected language.
+         */
+        public $title;
+
+        /**
+         * The content in the defined language.
+         */
+        public $text;
+
+        /**
+         * Posting datetime.
+         */
+        public $dtime;
+
+        /**
+         * Array with the {@see Post_Image}.
+         */
+        public $image = [];
+
+        /**
+         * Array with the tags.
+         */
+        public $tag = [];
+
+        /**
+         * Array with the {@see Post_Comment}.
+         */
+        public $comment = [];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier or permalink.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, $lang);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  permalink, " .
+              "  title_" . $this->lang . " AS title, " .
+              "  text_" . $this->lang . " AS text, " .
+              "  dtime " .
+              "FROM post " .
+              "WHERE " .
+              "  visible = 1 AND " .
+              "  ( " .
+              "    id = '$id' OR " .
+              "    permalink = '$id' " .
+              "  );";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->permalink = $r["permalink"];
+                $this->title = $r["title"];
+                $this->text = $r["text"];
+                $this->dtime = $r["dtime"];
+            }
+            $s_image =
+              "SELECT id " .
+              "FROM post_image " .
+              "WHERE post = " . $this->id . " " .
+              "ORDER BY idx; ";
+            $q_image = mysqli_query($this->db, $s_image);
+            while($r_image = mysqli_fetch_array($q_image)){
+                array_push($this->image, new Post_Image($this->db, $r_image["id"]));
+            }
+            $s_tag =
+              "SELECT tag " .
+              "FROM post_tag " .
+              "WHERE post = " . $this->id . ";";
+            $q_tag = mysqli_query($this->db, $s_tag);
+            while($r_tag = mysqli_fetch_array($q_tag)){
+                array_push($this->tag, $r_tag["tag"]);
+            }
+            $s_comment =
+              "SELECT id " .
+              "FROM post_comment " .
+              "WHERE " .
+              "  post = " . $this->id . " AND " .
+              "  approved = 1;";
+            $q_comment = mysqli_query($this->db, $s_comment);
+            while($r_comment = mysqli_fetch_array($q_comment)){
+                array_push($this->comment, new Post_Comment($this->db, $r_comment["id"]));
+            }
+        }
+    }
+?>

+ 82 - 0
site-public/application/entity/Post_Comment.php

@@ -0,0 +1,82 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Post_Comment.
+     *
+     * Represents an object from the table 'post_comment'.
+     */
+    class Post_Comment extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Identifier of the post the comment belongs to.
+         */
+        public $post;
+
+        /**
+         * The content in the defined language.
+         */
+        public $text;
+
+        /**
+         * Posting datetime.
+         */
+        public $dtime;
+
+        /**
+         * Uername.
+         */
+        public $username;
+
+        /**
+         * Language of the comment (unreliable).
+         */
+        public $lang;
+
+        /**
+         * Approved indicator.
+         */
+        public $approved;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param id Identifier.
+         */
+        public function __construct($db, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  post, " .
+              "  text, " .
+              "  dtime, " .
+              "  username, " .
+              "  lang, " .
+              "  approved " .
+              "FROM post_comment " .
+              "WHERE id = '$id';";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->post = $r["post"];
+                $this->text = $r["text"];
+                $this->dtime = $r["dtime"];
+                $this->username = $r["username"];
+                $this->lang = $r["lang"];
+                $this->approved = $r["approved"];
+            }
+        }
+    }
+?>

+ 61 - 0
site-public/application/entity/Post_Image.php

@@ -0,0 +1,61 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Post_Image.
+     *
+     * Represents an object from the table 'post_image'.
+     */
+    class Post_Image extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Identifier of the post the image belongs to.
+         */
+        public $post;
+
+        /**
+         * Filename.
+         */
+        public $image;
+
+        /**
+         * Order.
+         */
+        public $idx;
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param id Identifier.
+         */
+        public function __construct($db, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  post, " .
+              "  image, " .
+              "  idx " .
+              "FROM post_image " .
+              "WHERE id = '$id';";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->post = $r["post"];
+                $this->image = $r["image"];
+                $this->idx = $r["idx"];
+            }
+        }
+    }
+?>

+ 74 - 0
site-public/application/entity/Route.php

@@ -0,0 +1,74 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+    require_once($path["entity"] . "Route_Point.php");
+
+    /**
+     * Route.
+     *
+     * Represents an object from the table 'route'.
+     */
+    class Route extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Name of the route. Keyword with no actual value.
+         */
+        public $name;
+
+        /**
+         * Duration of the route.
+         */
+        public $mins;
+
+        /**
+         * Default zoom level. Arbitrary. 14 is OK for urban routes.
+         */
+        public $zoom;
+
+        /**
+         * Aproximate center of the route. Used to center map.
+         */
+        public $center = [
+            "lat" => null,
+            "lon" => null
+        ];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param id Identifier.
+         */
+        public function __construct($db, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  name, " .
+              "  mins, " .
+              "  c_lat, " .
+              "  c_lon, " .
+              "  zoom " .
+              "FROM route " .
+              "WHERE id = $id;";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->name = $r["name"];
+                $this->mins = $r["mins"];
+                $this->zoom = $r["zoom"];
+                $this->center["lat"] = $r["c_lat"];
+                $this->center["lon"] = $r["c_lon"];
+            }
+        }
+    }
+?>

+ 113 - 0
site-public/application/entity/Route_Point.php

@@ -0,0 +1,113 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Route_Point.
+     *
+     * Represents an object from the table 'route_point'.
+     */
+    class Route_Point extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Reference of the route it belongs to.
+         */
+        public $route;
+
+        /**
+         * Numberic order of this on the route .
+         */
+        public $part;
+
+        /**
+         * Minutes it takes to cmplete this.
+         */
+        public $mins;
+
+        /**
+         * Indicates if the segment must be visible.
+         */
+        public $visible;
+
+        /**
+         * Starting point.
+         */
+        public $start = [
+            "lat" => null,
+            "lon" => null
+        ];
+
+        /**
+         * End point.
+         */
+        public $end = [
+            "lat" => null,
+            "lon" => null
+        ];
+
+        /**
+         * Sorted array of {@see Route_Point}.
+         */
+        public $point = [];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param id Identifier.
+         */
+        public function __construct($db, $id){
+            parent::__construct($db, null);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  route, " .
+              "  part, " .
+              "  lat_o, " .
+              "  lon_o, " .
+              "  lat_d, " .
+              "  lon_d, " .
+              "  mins, " .
+              "  visible " .
+              "FROM route_point " .
+              "WHERE id = $id;";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->route = $r["route"];
+                $this->part = $r["part"];
+                $this->mins = $r["mins"];
+                if ($r["visible"] == 1){
+                   $this->visible = true;
+                }
+                else{
+                    $this->visible = false;
+                }
+                $this->start->lat = $r["lat_o"];
+                $this->start->lon = $r["lon_o"];
+                $this->end->lat = $r["lat_d"];
+                $this->end->lon = $r["lon_d"];
+                $s_point =
+                  "SELECT id " .
+                  "FROM route_point " .
+                  "WHERE " .
+                  "  route = " . $this->id . " AND " .
+                  "  visible = 1 " .
+                  "ORDER BY part;";
+                $q_point = mysqli_query($this->db, $s_point);
+                while($r_point = mysqli_fetch_array($q_point)){
+                    array_push($this->point, new Route_Point($this->db, $r_point["id"]));
+                }
+            }
+        }
+    }
+?>

+ 100 - 0
site-public/application/entity/Sponsor.php

@@ -0,0 +1,100 @@
+<?php
+
+    require_once($path["entity"] . "Entity.php");
+
+    /**
+     * Sponsor.
+     *
+     * Represents an object from the table 'sponsor'.
+     */
+    class Sponsor extends Entity{
+
+        /**
+         * Identifier.
+         */
+        public $id;
+
+        /**
+         * Name of the sponsor.
+         */
+        public $name;
+
+        /**
+         * Short text describing the sponsor.
+         */
+        public $text;
+
+        /**
+         * Sponsor logo.
+         */
+        public $image;
+
+        /**
+         * Sponsor url.
+         */
+        public $link;
+
+        /**
+         * Indicates if the sponsor has a phisical location.
+         */
+        public $local;
+
+        /**
+         * Address, if any.
+         */
+        public $address;
+
+        /**
+         * Geographical location, if any.
+         */
+        public $location = [
+            "lat" => null,
+            "lon" => null
+        ];
+
+        /**
+         * Constructor.
+         *
+         * Searches the database and retrieves the information about the
+         * entity, populating it and it's items.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Identifier.
+         */
+        public function __construct($db, $lang, $id){
+            parent::__construct($db, $lang);
+            $s =
+              "SELECT " .
+              "  id, " .
+              "  name_$lang AS name, " .
+              "  text_$lang AS text, " .
+              "  image, " .
+              "  link, " .
+              "  local, " .
+              "  address_$lang AS address, " .
+              "  lat, " .
+              "  lon " .
+              "FROM sponsor " .
+              "WHERE id = '$id';";
+            $q = mysqli_query($this->db, $s);
+            if (mysqli_num_rows($q) > 0){
+                $r = mysqli_fetch_array($q);
+                $this->id = $r["id"];
+                $this->name = $r["name"];
+                $this->text = $r["text"];
+                $this->image = $r["image"];
+                $this->link = $r["link"];
+                if ($r["local"] == 1){
+                    $this->local = true;
+                    $this->address = $r["address"];
+                    $this->location["lat"] = $r["lat"];
+                    $this->location["lon"] = $r["lon"];
+                }
+                else{
+                    $this->local = false;
+                }
+            }
+        }
+    }
+?>

+ 64 - 0
site-public/application/page/Activities_Page.php

@@ -0,0 +1,64 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Activity.php");
+
+    /**
+     * Activities page model.
+     */
+    class Activities_Page extends Page{
+
+        /**
+         * List of {@see Activity} in the future, sorted with the closest one
+         * first.
+         */
+        public $future = [];
+
+        /**
+         * List of {@see Activity} in the past, sorted with the closest one
+         * first.
+         */
+        public $past = [];
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang){
+            global $path;
+            global $base_url;
+            global $data;
+            parent::__construct($db, $lang);
+            $this->template = $path["template"] . "activities.php";
+            $s_future =
+              "SELECT id " .
+              "FROM activity " .
+              "WHERE " .
+              "  visible = 1 AND " .
+              "  date > now() " .
+              "ORDER BY date;";
+            $q_future = mysqli_query($this->db, $s_future);
+            while($r_future = mysqli_fetch_array($q_future)){
+                array_push($this->future, new Activity($this->db, $this->lang, $r_future["id"]));
+            }
+            $s_past =
+              "SELECT id " .
+              "FROM activity " .
+              "WHERE " .
+              "  visible = 1 AND " .
+              "  date < now() " .
+              "ORDER BY date DESC;";
+            $q_past = mysqli_query($this->db, $s_past);
+            while($r_past = mysqli_fetch_array($q_past)){
+                array_push($this->past, new Activity($this->db, $this->lang, $r_past["id"]));
+            }
+            $this->title = $this->string["section_activities"] . " - " . $data["name"];
+            $this->description = $this->string["section_activities"] . " - " . $data["name"];
+            $this->canonical = $base_url . "/actividades/";
+        }
+    }
+?>

+ 50 - 0
site-public/application/page/Activity_Page.php

@@ -0,0 +1,50 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Activity.php");
+
+
+    /**
+     * Activity page model.
+     */
+    class Activity_Page extends Page{
+
+        /**
+         * The selected {@see Activity}.
+         */
+        public $activity;
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Activity id or permalink.
+         */
+        public function __construct($db, $lang, $id){
+            global $path;
+            global $base_url;
+            global $static;
+            global $data;
+            parent:: __construct($db, $lang);
+            $this->activity = new Activity($this->db, $this->lang, $id);
+            if ($this->activity->is_past()){
+                $this->template = $path["template"] . "activity_past.php";
+            }
+            else{
+                $this->template = $path["template"] . "activity_future.php";
+            }
+            $this->title = $this->activity->title . " - " . $data["name"];
+            $this->description = $this->activity->title . " - " . $data["name"];
+            if (sizeof($this->activity->image) > 0){
+                $this->icon = $static["content"] . "activity/" . $this->activity->image[0]->image;
+            }
+            else{
+                $this->icon = $static["layout"] . "logo/logo.svg";
+            }
+            $this->canonical = $base_url . "/actividades/" . $this->activity->permalink . "/";
+        }
+    }
+?>

+ 36 - 0
site-public/application/page/Album_Page.php

@@ -0,0 +1,36 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Album.php");
+
+    /**
+     * Album page model.
+     */
+    class Album_Page extends Page{
+
+        /**
+         * Selected {@see Album}.
+         */
+        public $album;
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang, $id){
+            global $path;
+            global $base_url;
+            global $data;
+            parent::__construct($db, $lang);
+            $this->template = $path["template"] . "album.php";
+            $this->album, new Album($this->db, $this->lang, $id));
+            $this->title = $this->album->title . " - " . $data["name"];
+            $this->description = $this->album->title . " - " . $data["name"];
+            $this->canonical = $base_url . "/galeria/" . $this->album->permalink;
+        }
+    }
+?>

+ 44 - 0
site-public/application/page/Blog_Page.php

@@ -0,0 +1,44 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Post.php");
+
+    /**
+     * Blog page model.
+     */
+    class Blog_Page extends Page{
+
+        /**
+         * List of {@see Post}.
+         */
+        public $post = [];
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang){
+            global $path;
+            global $base_url;
+            global $data;
+            parent::__construct($db, $lang);
+            $this->template = $path["template"] . "blog.php";
+            $s =
+              "SELECT id " .
+              "FROM post " .
+              "WHERE visible = 1 " .
+              "ORDER BY dtime DESC;";
+            $q = mysqli_query($this->db, $s);
+            while($r = mysqli_fetch_array($q)){
+                array_push($this->post, new Post($this->db, $this->lang, $r["id"]));
+            }
+            $this->title = $this->string["section_blog"] . " - " . $data["name"];
+            $this->description = $this->string["section_blog"] . " - " . $data["name"];
+            $this->canonical = $base_url . "/blog/";
+        }
+    }
+?>

+ 102 - 0
site-public/application/page/Festivals_Page.php

@@ -0,0 +1,102 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Festival.php");
+
+    /**
+     * Festivals page model.
+     */
+    class Festivals_Page extends Page{
+
+        /**
+         * The selected {@see Festival}.
+         * If a year has been specified, and it exists, it will be defined.
+         * If no year is specified, and the setting for the festival is active,
+         * it will have the one of the current year.
+         * In any other case, it will be null.
+         */
+        public $festival;
+
+        /**
+         * Previous years with festivals.
+         */
+        public $previous = [];
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param $year Year of the festivals.
+         */
+        public function __construct($db, $lang, $year = null){
+            global $path;
+            global $base_url;
+            global $url;
+            global $data;
+            parent::__construct($db, $lang);
+            if (is_set($year)){
+                $s_festival =
+                  "SELECT 1 " .
+                  "FROM festival " .
+                  "WHERE " .
+                  "  year = $year;";
+                $q_festival = mysqli_query($this->db, $s_festival);
+                if (mysqli_num_rows($q_festival) > 0){
+                    $this->festival = new Festival($this->db, $this->lang, $year);
+                    $this->template = $path["template"] . "festivals_active.php";
+                    $this->title = str_replace('#', $year, $this->string['lablanca_title']) . " - " . $data["name"];
+                    $this->description = str_replace('#', $year, $this->string['lablanca_title']) . " - " . $data["name"];
+                    $this->canonical = $base_url . "/" . $url->festivals . "/" . $year;
+                }
+                else{
+                    $this->template = $path["template"] . "festivals_inactive.php";
+                    $this->title = $this->string['lablanca_no_title'] . " - " . $data["name"];
+                    $this->description = $this->string['lablanca_no_title'] . " - " . $data["name"];
+                    $this->canonical = $base_url . "/" . $url->festivals . "/";
+                }
+            }
+            else{
+                $s_setting =
+                  "SELECT value " .
+                  "FROM settings " .
+                  "WHERE " .
+                  "  value = 1 AND " .
+                  "  name = 'festivals';";
+                $q_setting = mysqli_query($this->db, $s_setting);
+                if (mysqli_num_rows($q_setting) > 0){
+                    $s_festival =
+                      "SELECT 1 " .
+                      "FROM festival " .
+                      "WHERE " .
+                      "  year = " . date("Y") . ";";
+                    $q_festival = mysqli_query($this->db, $s_festival);
+                    if (mysqli_num_rows($q_festival) > 0){
+                        $this->festival = new Festival($this->db, $this->lang, date("Y"));
+                        $this->template = $path["template"] . "festivals_active.php";
+                        $this->title = str_replace('#', date("Y"), $this->string['lablanca_title']) . " - " . $data["name"];
+                        $this->description = str_replace('#', date("Y"), $this->string['lablanca_title']) . " - " . $data["name"];
+                        $this->canonical = $base_url . "/" . $url->festivals . "/" . date("Y");
+                    }
+                    else{
+                        $this->template = $path["template"] . "festivals_inactive.php";
+                        $this->title = $this->string['lablanca_no_title'] . " - " . $data["name"];
+                        $this->description = $this->string['lablanca_no_title'] . " - " . $data["name"];
+                        $this->canonical = $base_url . "/" . $url->festivals . "/";
+                    }
+                }
+            }
+            $s_previous =
+              "SELECT year " .
+              "FROM festival " .
+              "WHERE str_to_date(concat(year, '-08-10'), '%Y-%m-%d') < now() " .
+              "ORDER BY year DESC;";
+            $q_previous = mysqli_query($this->db, $s_previous);
+            while($r_previous = mysqli_fetch_array($q_previous)){
+                array_push($this->previous, $r_previous["year"]);
+            }
+        }
+    }
+?>

+ 43 - 0
site-public/application/page/Gallery_Page.php

@@ -0,0 +1,43 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Album.php");
+
+    /**
+     * Gallery page model.
+     */
+    class Gallery_Page extends Page{
+
+        /**
+         * List of {@see Album}.
+         */
+        public $album = [];
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang){
+            global $path;
+            global $base_url;
+            global $data;
+            parent::__construct($db, $lang);
+            $this->template = $path["template"] . "album.php";
+            $s =
+              "SELECT id " .
+              "FROM album " .
+              "ORDER BY dtime DESC;";
+            $q = mysqli_query($this->db, $s);
+            while($r = mysqli_fetch_array($q)){
+                array_push($this->album, new Album($this->db, $this->lang, $r["id"]));
+            }
+            $this->title = $this->string["section_gallery"] . " - " . $data["name"];
+            $this->description = $this->string["section_galery"] . " - " . $data["name"];
+            $this->canonical = $base_url . "/galeria/";
+        }
+    }
+?>

+ 31 - 0
site-public/application/page/Help_Page.php

@@ -0,0 +1,31 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+
+
+    /**
+     * Help page model.
+     */
+    class Help_Page extends Page{
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang){
+            global $path;
+            global $base_url;
+            global $static;
+            global $data;
+            parent:: __construct($db, $lang);
+            $this->view = $path["view"] . "help.php";
+            $this->title = $this->string["section_help"] . " - " . $data["name"];
+            $this->description = $this->string["section_help"] . " - " . $data["name"];
+            $this->canonical = $base_url . "/" . $url->help . "/"";
+        }
+    }
+?>

+ 81 - 0
site-public/application/page/Home_Page.php

@@ -0,0 +1,81 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Post.php");
+    require_once($path["entity"] . "Activity.php");
+
+    /**
+     * Home page model.
+     */
+    class Home_Page extends Page{
+
+        /**
+         * List of the last 3 {@see Post}.
+         */
+        public $post = [];
+
+        /**
+         * List of {@see Activity} in the future, sorted with the closest one
+         * first.
+         */
+        public $future = [];
+
+        /**
+         * List of {@see Activity} in the past, sorted with the closest one
+         * first. Limited to 3.
+         */
+        public $past = [];
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang){
+            global $path;
+            global $base_url;
+            global $data;
+            parent::__construct($db, $lang);
+            $this->template = $path["template"] . "home.php";
+            $s =
+              "SELECT id " .
+              "FROM post " .
+              "WHERE visible = 1 " .
+              "ORDER BY dtime DESC " .
+              "LIMIT 3;";
+            $q = mysqli_query($this->db, $s);
+            while($r = mysqli_fetch_array($q)){
+                array_push($this->post, new Post($this->db, $this->lang, $r["id"]));
+            }
+            $s_future =
+              "SELECT id " .
+              "FROM activity " .
+              "WHERE " .
+              "  visible = 1 AND " .
+              "  date > now() " .
+              "ORDER BY date;";
+            $q_future = mysqli_query($this->db, $s_future);
+            while($r_future = mysqli_fetch_array($q_future)){
+                array_push($this->future, new Activity($this->db, $this->lang, $r_future["id"]));
+            }
+            $s_past =
+              "SELECT id " .
+              "FROM activity " .
+              "WHERE " .
+              "  visible = 1 AND " .
+              "  date < now() " .
+              "ORDER BY date DESC " .
+              "LIMIT 3;";
+            $q_past = mysqli_query($this->db, $s_past);
+            while($r_past = mysqli_fetch_array($q_past)){
+                array_push($this->past, new Activity($this->db, $this->lang, $r_past["id"]));
+            }
+            $this->title = $data["name"];
+            $this->description = $data["description"];
+            $this->canonical = $base_url . "/";
+        }
+    }
+?>

+ 104 - 0
site-public/application/page/Page.php

@@ -0,0 +1,104 @@
+<?php
+
+    require_once($path["entity"] . "Sponsor.php");
+
+    /**
+     * Page superclass.
+     *
+     * Every visitable page type must inherit from this one.
+     */
+    abstract class Page{
+
+        /**
+         * Database connection.
+         */
+        public $db;
+
+        /**
+         * Template associated with the page.
+         */
+        public $template;
+
+        /**
+         * Language the page will be served on (lowercase, two-letter
+         * language code).
+         */
+        public $lang;
+
+        /**
+         * Title of the page, in the defined language.
+         */
+        public $title;
+
+        /**
+         * Site name.
+         */
+        public $name;
+
+        /**
+         * Page description, in the defined language.
+         */
+        public $description;
+
+        /**
+         * Path to the site favicon.
+         */
+        public $favicon;
+
+        /**
+         * Path to the page icon or main image.
+         */
+        public $icon;
+
+        /**
+         * Canonical URL.
+         */
+        public $canonical;
+
+        /**
+         * Author URL.
+         */
+        public $author;
+
+        /**
+         * String array for the layout texts
+         */
+        public $string;
+
+        /**
+         * List of {@see Sponsor}.
+         */
+        public $sponsor = [];
+
+
+        /**
+         * Constructor.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang){
+            global $static;
+            global $base_url;
+            global $path;
+            global $data;
+            $this->db = $db;
+            $this->lang = $lang;
+            require_once($path["string"] . "lang_" . $lang . ".php");
+            $this->string = $string;
+            $this->favicon = $static["layout"] . "logo/logo.svg";
+            $this->icon = $static["layout"] . "logo/logo.svg";
+            $this->name = $data["name"];
+            $this->author = $data["name"];
+            $s_sponsor =
+              "SELECT id " .
+              "FROM sponsor " .
+              "WHERE ammount > 0 " .
+              "ORDER BY ammount DESC;";
+            $q_sponsor = mysqli_query($this->db, $s_sponsor);
+            while($r_sponsor = mysqli_fetch_array($q_sponsor)){
+                array_push($this->sponsor, new Sponsor($this->db, $this->lang, $r_sponsor["id"]));
+            }
+        }
+    }
+?>

+ 33 - 0
site-public/application/page/Photo_Page.php

@@ -0,0 +1,33 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Photo.php");
+
+    /**
+     * Photo page model.
+     */
+    class Photo_Page extends Page{
+
+        /**
+         * Selected {@see Photo}.
+         */
+        public $photo;
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang, $id){
+            global $path;
+            global $base_url;
+            global $data;
+            parent::__construct($db, $lang);
+            $this->template = $path["template"] . "photo.php";
+            $this->photo = new Photo($this->db, $this->lang, $r["id"]));
+        }
+    }
+?>

+ 45 - 0
site-public/application/page/Post_Page.php

@@ -0,0 +1,45 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+    require_once($path["entity"] . "Post.php");
+
+
+    /**
+     * Post page model.
+     */
+    class Post_Page extends Page{
+
+        /**
+         * The selected {@see Post}.
+         */
+        public $post;
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         * @param id Post id or permalink.
+         */
+        public function __construct($db, $lang, $id){
+            global $path;
+            global $base_url;
+            global $static;
+            global $data;
+            parent:: __construct($db, $lang);
+            $this->template = $path["template"] . "post.php";
+            $this->post = new Post($this->db, $this->lang, $id);
+            $this->title = $this->post->title . " - " . $data["name"];
+            $this->description = $this->post->title . " - " . $data["name"];
+            if (sizeof($this->post->image) > 0){
+                $this->icon = $static["content"] . "blog/" . $this->post->image[0]->image;
+            }
+            else{
+                $this->icon = $static["layout"] . "logo/logo.svg";
+            }
+            $this->canonical = $base_url . "/blog/" . $this->post->permalink . "/";
+        }
+    }
+?>

+ 31 - 0
site-public/application/page/Us_Page.php

@@ -0,0 +1,31 @@
+<?php
+
+    require_once($path["page"] . "Page.php");
+
+
+    /**
+     * Us page model.
+     */
+    class Us_Page extends Page{
+
+        /**
+         * Constructor.
+         *
+         * Retrieves the data and initializes the variables.
+         *
+         * @param db Connection to the database.
+         * @param lang Lowercase, two-letter language code.
+         */
+        public function __construct($db, $lang){
+            global $path;
+            global $base_url;
+            global $static;
+            global $data;
+            parent:: __construct($db, $lang);
+            $this->view = $path["view"] . "us.php";
+            $this->title = $this->string["section_us"] . " - " . $data["name"];
+            $this->description = $this->string["section_us"] . " - " . $data["name"];
+            $this->canonical = $base_url . "/" . $url->us . "/"";
+        }
+    }
+?>

+ 189 - 0
site-public/application/template/activities.php

@@ -0,0 +1,189 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>activity.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["script"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["script"]?>activity.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+<?php
+            if (sizeof($page->future) > 0){
+?>
+                <section id='future_list'>
+                    <h3>
+                        <?=$page->string["activities_upcoming"]?>
+                    </h3>
+<?php
+                    foreach($page->future as $activity) {
+?>
+                        <article>
+                            <h4>
+                                <a href='<?=$base_url?>/actividades/<?=$activity->permalink?>'><?=$activity->title?></a>
+                            </h4>
+<?php
+                            if (sizeof($activity->image) > 0){
+?>
+                                <a href='<?=$base_url?>/actividades/<?=$activity->permalink?>'>
+                                    <img alt='<?=$activity->title?>' title='<?=$activity->title?>' src='<?=$static["content"]?>activity/<?=$activity->image[0]->image?>' srcset='<?=srcset("activity/" . $activity->image[0]->image)?>'/>
+                                </a>
+<?php
+                            } // if (sizeof($activity->image) > 0)
+?>
+                            <div class='activity_details'>
+                                <span class='date'>
+                                    <?=format_date($activity->date, $page->lang, false)?>
+                                </span>
+                                <span class='city'>
+                                    <?=$activity->city?>
+                                </span>
+                                <span class='price'>
+<?php
+                                    if ($activity->price == 0){
+?>
+                                        <?=$page->string["price_free"]?>
+<?php
+                                    }
+                                    else{
+?>
+                                    <?=$activity->price?>€
+<?php
+                                    }
+?>
+                                </span>
+                            </div>
+                            <p>
+                                <?=cut_text($activity->text, 800, $page->string['keep_reading'], $base_url . "/actividades/" . $actividades->permalink)?>
+                            </p>
+                            <div class='activity_footer'>
+                                <div class='activity_footer_tags'>
+<?php
+                                    $tags = "";
+                                    foreach($activity->tag as $tag) {
+                                        $tags = $tags . $tag . ", ";
+                                    }
+                                    substr($tags, 0, strlen($tags) - 2);
+?>
+                                    <?=$tags?>
+                                </div>
+                                <div class='activity_footer_comments'>
+<?php
+                                    $comment = "";
+                                    if (sizeof($post->comment) == 1){
+                                        $comments = $page->string["comment_1"];
+                                    }
+                                    else if (sizeof($post->comment) == 0){
+                                        $comments = $page->string["comment_0"];
+                                    }
+                                    else{
+                                        $comments = str_replace("#", sizeof($activity->comment), $page->string["comment_n"]);
+                                    }
+?>
+                                    <?=$comments?>
+                                </div>
+                            </div>
+
+                        </article>
+<?php
+                    } // foreach($page->future as $activity)
+?>
+                </section>
+<?php
+            } // if (sizeof($page->future) > 0)
+?>
+            <section id='past_list'>
+                <h3>
+                    <?=$page->string["activities_past"]?>
+                </h3>
+<?php
+                foreach($page->past as $activity) {
+?>
+                    <article>
+                        <h4>
+                            <a href='<?=$base_url?>/actividades/<?=$activity->permalink?>'><?=$activity->title?></a>
+                        </h4>
+<?php
+                        if (strlen($activity->image) > 0){
+?>
+                            <a href='<?=$base_url?>/actividades/<?=$activity->permalink?>'>
+                                <img alt='<?=$activity->title?>' title='<?=$activity->title?>' src='<?=$static["content"]?>activity/<?=$activity->image[0]->image?>' srcset='<?=srcset("activity/" . $activity->image[0]->image)?>'/>
+                            </a>
+<?php
+                        } // if (strlen($activity->image) > 0)
+?>
+                        <div class='activity_details'>
+                            <span class='date'>
+                                <?=format_date($activity->date, $page->lang, false)?>
+                            </span>
+                            <span class='city'>
+                                <?=$activity->city?>
+                            </span>
+                        </div>
+                        <div class='activity_footer'>
+                            <div class='activity_footer_tags'>
+<?php
+                                $tags = "";
+                                foreach($activity->tag as $tag) {
+                                    $tags = $tags . $tag . ", ";
+                                }
+                                substr($tags, 0, strlen($tags) - 2);
+?>
+                                <?=$tags?>
+                            </div>
+                            <div class='activity_footer_comments'>
+<?php
+                                $comment = "";
+                                if (strlen($activity->comment) == 1){
+                                    $comments = $page->string["comments_1"];
+                                }
+                                else if (strlen($activity->comment) == 0){
+                                    $comments = $page->string["comments_0"];
+                                }
+                                else{
+                                    $comments = str_replace("#", sizeof($activity->comment), $page->string["comments_n"]);
+                                }
+?>
+                                <?=$comments?>
+                            </div>
+                        </div>
+
+                    </article>
+<?php
+                } // foreach($page->past as $activity)
+?>
+            </section>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 185 - 0
site-public/application/template/activity_future.php

@@ -0,0 +1,185 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>activity.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["script"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["script"]?>activity.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+            <section id='activity_future'>
+                <h3>
+                    <?=$page->activity['title']?> - <?=format_date($page->activity['date'], $page->lang, false)?>
+                </h3>
+                <article>
+<?php
+                    if (strlen($page->activity->image) > 0){
+?>
+                        <img id='main_image' alt='<?=$page->activity->title?>' title='<?=$page->activity->title?>' src='<?=$static["content"]?>activity/<?=$page->activity->image[0]->image?>' srcset='<?=srcset("activity/" . $page->activity->image[0]->image)?>'/>
+<?php
+                    }
+?>
+                    <p>
+                        <?=$page->activity->text?>
+                    </p>
+                    <table id='activity_details'>
+                        <tr>
+                            <td class='field_name'>
+                                <?=$page->string["activities_city"]?>
+                            </td>
+                            <td>
+                                <?=$page->activity->city?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='field_name'>
+                                <?=$page->string["city"]?>
+                            </td>
+                            <td>
+<?php
+                                if ($page->activity->price == 0){
+?>
+                                    <?=$page->string["price_free"]?>
+<?php
+                                }
+                                else{
+?>
+                                    <?=$page->activity->price?>€
+<?php
+                                }
+?>
+                            </td>
+                        </tr>
+<?php
+                            if ($page->activity->price == 0){
+?>
+                                <tr>
+                                    <td class='field_name'>
+                                        <?=$page->string["activities_inscription"]?>
+                                    </td>
+                                    <td>
+<?php
+                                        if ($page->activity->inscription){
+?>
+                                            <?=$page->string["yes"]?>
+<?php
+                                        }
+                                        else{
+?>
+                                            <?=$page->string["no"]?>
+<?php
+                                        }
+?>
+                                    </td>
+                                </tr>
+<?php
+                            }
+                            if ($page->activity->inscription && $page->activity->max_people > 0){
+?>
+                                <tr>
+                                    <td class='field_name'>
+                                        <?=$page->string["activities_maxpeople"]?>
+                                    </td>
+                                    <td>
+                                        <?=$page->activity->max_people?>
+                                    </td>
+                                </tr>
+<?php
+                            }
+?>
+                    </table>
+<?php
+                    if (sizeof($page->activity->itinerary) > 0){
+?>
+                        <table id='activity_itinerary'>
+                            <tr>
+                                <th>
+                                    <?=$page->string["activities_when"]?>
+                                </th>
+                                <th>
+                                    <?=$page->string["activities_what"]?>
+                                </th>
+                            </tr>
+<?php
+                            foreach ($page->activity->itinerary as $itin){
+?>
+                                <tr>
+                                    <td>
+<?php
+                                        if (is_set($itin->end)){
+?>
+                                            <?=date("H:i", $itin->start)?> - <?=date("H:i", $itin->end)?>
+<?php
+                                        }
+                                        else{
+?>
+                                            <?=date("H:i", $itin->start)?>
+<?php
+                                        }
+?>
+                                    </td>
+                                    <td>
+                                        <h5>
+                                            <?=$itin->name?>
+                                        </h5>
+                                        <p>
+                                            <?=$itin->description?>
+                                        </p>
+                                        <span class='place'>
+                                            <?=$itin->place->name?>
+<?php
+                                            if ($itin->place->name != $itin->place->address){
+?>
+                                                <span class='address'>
+                                                    <?=$itin->place->address?>
+                                                </span>
+<?php
+                                            }
+?>
+                                        </span>
+                                    </td>
+                                </tr>
+<?php
+                            }
+?>
+                        </table>
+<?php
+                    }
+?>
+                </article>
+            </section>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 75 - 0
site-public/application/template/activity_past.php

@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>activity.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["script"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["script"]?>activity.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+            <section id='activity_past'>
+                <h3>
+                    <?=$page->activity->title?> - <?=format_date($page->activity->date, $page->lang, false)?>
+                </h3>
+                <article>
+<?php
+                    if (sizeof($page->activity->image) > 0){
+?>
+                        <img id='main_image' alt='<?=$page->activity->title?>' title='<?=$page->activity->title?>' src='<?=$static["content"]?>activity/<?=$page->activity->image[0]->image?>' srcset='<?=srcset("activity/" . $page->activity->image[0]->image)?>'/>
+<?php
+                    }
+?>
+                    <p>
+                        <h5 class='italic'>
+                            <?=$page->string["city"]?>
+                        </h5>
+<?php
+                        if (isset($page->activity->after)){
+?>
+                            <?=$page->activity->after?>
+<?php
+                        }
+                        else{
+?>
+                            <?=$page->activity->text?>
+<?php
+                        }
+?>
+                    </p>
+                </article>
+            </section>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 69 - 0
site-public/application/template/album.php

@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>gallery.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["js"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["js"]?>gallery.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+            <section id='album'>
+                <h3>
+                    <?=$page->album->title?>
+                </h3>
+                <article>
+<?php
+                    foreach($page->album->photo as $photo) {
+?>
+                        <img class='pointer' onClick="showPhotoByPath('<?=$photo->file?>');" src='<?=$static["content"]?>gallery/<?=$photo->image?>' srcset='<?=srcset("gallery/" . $photo->image)?>'/>
+<?php
+                        if (is_set($photo->title)){
+?>
+                            <h5>
+                                <?=$photo->title?>
+                            </h5>
+<?php
+                        }
+                    }
+?>
+                </article>
+            </section>
+        </main>
+        <div id='screen_cover' onClick='closeViewer();'>
+        </div>
+        <section id='photo_viewer'>
+        </section>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 110 - 0
site-public/application/template/blog.php

@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>blog.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["script"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["script"]?>blog.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+<?php
+            // TODO: Worth it?
+            //include $path["inc"] . "blog-left.php";
+?>
+            <section id='post_list'>
+                <h3>
+                    <?=$page->title?>
+                </h3>
+<?php
+                foreach($page->post as $post) {
+?>
+                    <article>
+                        <h4>
+                            <a href='<?=$base_url?>/blog/<?=$post->permalink?>'><?=$post->title?></a>
+                        </h4>
+<?php
+                        if (sizeof($post->image) > 0){
+?>
+                            <a href='<?=$base_url?>/blog/<?=$post->permalink?>'>
+                                <img alt='<?=$post->title?>' title='<?=$post->title?>' src='<?=$static["content"]?>blog/<?=$post->image[0]->image?>' srcset='<?=srcset("blog/" . $post->image[0]->image)?>'/>
+                            </a>
+<?php
+                        } // if (strlen($post->image) > 0)
+?>
+                        <p>
+                            <?=cut_text($post->text, 100, $page->string["keep_reading"], $base_url . "/blog/" . $post->permalink)?>
+                        </p>
+                        <div class='post_details'>
+                            <div class='post_details_date'>
+                                <?=format_date($post->dtime, $page->lang, false)?>
+                            </div>
+                            <div class='post_details_tags'>
+<?php
+                                $tags = "";
+                                foreach($post->tag as $tag) {
+                                    $tags = $tags . $tag . ", ";
+                                }
+                                substr($tags, 0, strlen($tags) - 2);
+?>
+                                <?=$tags?>
+                            </div>
+                            <div class='post_details_comments'>
+<?php
+                                $comment = "";
+                                if (sizeof($post->comment) == 1){
+                                    $comments = $page->string["comment_1"];
+                                }
+                                else if (sizeof($post->comment) == 0){
+                                    $comments = $page->string["comment_0"];
+                                }
+                                else{
+                                    $comments = str_replace("#", sizeof($post->comment), $page->string["comment_n"]);
+                                }
+?>
+                                <?=$comments?>
+                            </div>
+                        </div>
+                    </article>
+<?php
+                } // foreach($array as $item)
+?>
+            </section>
+<?php
+            // TODO: Worth it?
+            //include $path["inc"] . "blog-right.php";
+?>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 212 - 0
site-public/application/template/festivals_active.php

@@ -0,0 +1,212 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>festivals.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["js"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["js"]?>festivals.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+            <section id='festivals_active'>
+                <h3>
+                    <?=str_replace('#', $page->festival->year, $page->string["festival_title_year"])?>
+                </h3>
+                <article>
+<?php
+                    if (is_set($page->festival->image)){
+?>
+                        <img alt='<?=$page->festival->year?>' title='<?=$page->festival->year?>' src='<?=$static["content"]?>festivals/<?=$page->festival->image?>' srcset='<?=srcset("festivals/" . $page->festival->image)?>'/>
+<?php
+                    }
+?>
+                    <p>
+                        <?=$page->festival->year?>
+                    </p>
+                </article>
+            </section>
+            <section id='festival_schedule'>
+                <h3>
+                    <?=$page->string["festival_schedule"]?>
+                </h3>
+<?php
+                foreach ($page->festival->event->internal as $day){
+?>
+                    <h4 onClick='expandDay(<?=$day?>);' class='pointer'>
+                        <img class='slid' src='<?=$static["layout"]?>/control/slid-right.png' id='slid_day_<?=$day?>'/>
+<?php
+                        $s_day = $day;
+                        if ($day == "25"){
+                            $s_day = format_festival_date(date("Y") . "-07-" . $day);
+                        }
+                        else{
+                            $s_day = format_festival_date(date("Y") . "-08-" . $day);
+                        }
+?>
+                        <?=$s_day?>
+                        <table>
+<?php
+                            foreach ($day as $event){
+?>
+                                <tr>
+                                    <td>
+                                        <span class='time'>
+                                            <?=$event->start?>
+                                        </span>
+                                    </td>
+                                    <td class='timeline'>
+                                        <img class='timeline_dot' alt=' ' src='<?=$static["layout"]?>/control/schedule-point.png'/>
+                                    </td>
+                                    <td>
+                                        <span class='title'>
+                                            <?=$event->title?>
+                                        </span>
+<?php
+                                        if (strlen($event->description) > 0 && $event->description != $event->title){
+?>
+                                            <div class='description'>
+                                                <?=$event->description?>
+                                            </div>
+<?php
+                                        }
+?>
+                                        <div class='location'>
+                                            <!-- TODO: Implement OSM routes -->
+                                            <a target='_blank' href='https://www.openstreetmap.org/#map=16/<?=$event->place->location->lat?>/<?=$event->place->location->lon?>'>
+                                                <img alt=' ' src=''<?=$static["layout"]?>/control/pinpoint.png'/>
+<?php
+                                                //If name and address are the same, show only name
+                                                if ($event->place->name == $event->place->address){
+?>
+                                                    <?=$event->place->name?>
+<?php
+                                                }
+                                                else{
+?>
+                                                    <?=$event->place->name?>
+                                                    <span class='address italic'>
+                                                        - <?=$event->place->name?>
+                                                    </span>
+<?php
+                                                }
+?>
+                                            </a>
+                                        </div>
+                                    </td>
+                                </tr>
+<?php
+                            } // foreach ($day as $event)
+?>
+                        </table>
+
+                    </h4>
+<?php
+                } // foreach ($page->festival->event->internal as $day)
+?>
+            </section>
+            <section id='festival_prices'>
+                <h3>
+                    <?=$page->string["festival_prices"]?>
+                </h3>
+                <article id='festival_prices_days'>
+                    <table>
+                        <!-- TODO: Members/public -->
+<?php
+                        foreach ($page->festival->day as $day){
+?>
+                            <tr>
+                                <td>
+                                    <?=format_festival_date($day->date)?>
+                                </td>
+                                <td class='price'>
+                                    <?=$day->price?> &euro;
+                                </td>
+                            </tr>
+<?php
+                        }
+?>
+                    </table>
+                </article>
+                <article id='festival_prices_offers'>
+                    <table>
+                        <!-- TODO: Members/public -->
+<?php
+                        foreach ($page->festival->offer as $offer){
+?>
+                            <tr>
+                                <td>
+                                    <?=$offer->name?>
+                                    <p>
+                                        <?=$offer->description?>
+                                    </p>
+                                </td>
+                                <td class='price'>
+                                    <?=$offer->price?> &euro;
+                                </td>
+                            </tr>
+<?php
+                        }
+?>
+                    </table>
+                </article>
+            </section>
+<?php
+            if (strlen($page->previous) > 0){
+?>
+                <section id='festival_previous'>
+                    <h3>
+<!--                         <?=$page->string["festival_past"]?> -->
+                    </h3>
+                    <article>
+                        <ul>
+<?php
+                            foreach ($page->previous as $y){
+?>
+                                <li>
+                                    <a href='<?=$base_url?>/<?=$url->festivals?>/<?=$y?>'>
+                                        <?=$y?>
+                                    </a>
+                                </li>
+<?php
+                            }
+?>
+                        </ul>
+                    </article>
+                </section>
+<?php
+            }
+?>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 81 - 0
site-public/application/template/festivals_inactive.php

@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>festivals.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["js"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["js"]?>festivals.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+            <section id='festivals_inactive'>
+                <h3>
+                    <?=$page->string["festival_inactive"]?>
+                </h3>
+                <article>
+                    <?=$page->string["festival_inactive_header"]?>
+                </article>
+                <article>
+                    <?=$page->string["festival_inactive_description"]?>
+                </article>
+            </section>
+<?php
+            if (strlen($page->previous) > 0){
+?>
+                <section id='festival_previous'>
+                    <h3>
+                        <?=$page->string["festival_past"]?>
+                    </h3>
+                    <article>
+                        <ul>
+<?php
+                            foreach ($page->previous as $y){
+?>
+                                <li>
+                                    <a href='<?=$base_url?>/<?=$url->festivals?>/<?=$y?>'>
+                                        <?=$y?>
+                                    </a>
+                                </li>
+<?php
+                            }
+?>
+                        </ul>
+                    </article>
+                </section>
+<?php
+            }
+?>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 70 - 0
site-public/application/template/gallery.php

@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>gallery.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["js"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["js"]?>gallery.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+            <section id='album_list'>
+                <h3>
+                    <?=$page->title?>
+                </h3>
+<?php
+                foreach($page->album as $album) {
+?>
+                    <article>
+                        <h4>
+                            <a href='<?=$base_url?>/galeria/<?=$album->permalink?>'><?=album->title?></a>
+                        </h4>
+<?php
+                        for($i = 0; $i < 4; $i ++) {
+                            $r = mt_rand (0, strlen($album->photo) - 1);
+?>
+                            <a href='<?=$base_url?>/galeria/<?=$album->permalink?>'>
+                                <img alt=' <?=$album->photo[$r]->title?>' title=' <?=$album->photo[$r]->title?>' src='<?=$static["content"]?>gallery/<?=$album->photo[$r]->image?>' srcset='<?=srcset("gallery/" . $album->photo[$r]->image)?>'/>
+                            </a>
+<?php
+                        }
+?>
+                    </article>
+<?php
+                } // foreach($page->album as $album)
+?>
+            </section>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 198 - 0
site-public/application/template/help.php

@@ -0,0 +1,198 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>help.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["js"]?>ui.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+            <section id='shortcout'>
+                <h3>
+                    <?=$page->string["help_shortcouts"]?>
+                </h3>
+                <article>
+                    <ul>
+                        <li>
+                            <a href="#association">
+                                <?=$page->string["help_contact_title"]?>
+                            </a>
+                        </li>
+                        <li>
+                            <a href="#license">
+                                <?=$page->string["help_license_title"]?>
+                            </a>
+                        </li>
+                        <li>
+                            <a href="#privacy">
+                                <?=$page->string["help_privacy_title"]?>
+                            </a>
+                        </li>
+                        <li>
+                            <a href="#cookie">
+                                <?=$page->string["help_cookie_title"]?>
+                            </a>
+                        </li>
+                        <li>
+                            <a href="#ad">
+                                <?=$page->string["help_ad_title"]?>
+                            </a>
+                        </li>
+                    </ul>
+                </article>
+            </section>
+            <section id='association'>
+                <h3 class='section_title'><?=$page->string["help_shortcouts"]?></h3>
+                <article>
+                    <table>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_register"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->registry->number?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_date_constitution"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->registry->constitution_value?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_date_inscription"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->registry->registry_date?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_city"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->registry->city?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_territory"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->registry->county?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_country"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->registry->country?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_clasification"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->registry->type?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_objectives"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->registry->target?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_phone"]?>
+                            </td>
+                            <td class='value'>
+                                <?=$data->contact->phone?>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class='name'>
+                                <?=$page->string["help_contact_email"]?>
+                            </td>
+                            <td class='value'>
+                                <a target='_blank' href='mailto:<?=$data->contact->mail?>'>
+                                    <?=$data->contact->mail?>
+                                </a>
+                            </td>
+                        </tr>
+                    </table>
+                </article>
+            </section>
+            <section id='license'>
+                <h3>
+                    <?=$page->string["help_license_title"]?>
+                </h3>
+                <article>
+                    <?=$page->string["help_license"]?>
+                </article>
+            </section>
+            <section id='privacy'>
+                <h3>
+                    <?=$page->string["help_privacy_title"]?>
+                </h3>
+                <article>
+                    <?=$page->string["help_privacy"]?>
+                </article>
+            </section>
+            <section id='cookie'>
+                <h3>
+                    <?=$page->string["help_cookie_title"]?>
+                </h3>
+                <article>
+                    <?=$page->string["help_cookie"]?>
+                </article>
+            </section>
+            <section id='ad'>
+                <h3>
+                    <?=$page->string["help_ad_title"]?>
+                </h3>
+                <article>
+                    <?=$page->string["help_ad"]?>
+                </article>
+            </section>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 63 - 0
site-public/application/template/include/footer.php

@@ -0,0 +1,63 @@
+<footer>
+    <div id='footer_social'>
+        <span id='footer_follow' class='desktop'>
+            <?=$page->string["follow_us"]?>
+        </span>
+        <br/>
+        <a title='Facebook' target='_blank' href='<?=$data["social"]["facebook"]?>'>
+            <img src='<?=$static["layout"]?>/social/facebook.gif' alt='Facebook'/>
+        </a>
+        <a title='Twitter' target='_blank' href='<?=$data["social"]["twitter"]?>'>
+            <img src='<?=$static["layout"]?>/social/twitter.gif' alt='Twitter'/>
+        </a>
+        <a title='Youtube' target='_blank' href='<?=$data["social"]["youtube"]?>'>
+            <img src='<?=$static["layout"]?>/social/youtube.gif' alt='Youtube'/>
+        </a>
+        <a title='Instagram' target='_blank' href='<?=$data["social"]["instagram"]?>'>
+            <img src='<?=$static["layout"]?>/social/instagram.gif' alt='Instagram'/>
+        </a>
+        <br/>
+        <span id='footer_info' class='desktop'>
+            <?=$data["registry"]["name"]?>
+            <br/>
+            <?=$page->string["registry_number"]?>: <?=$data["registry"]["number"]?>
+        </span>
+    </div>
+    <div id='footer_sponsors'>
+        <span class='desktop'>
+            <?=$page->string["sponsors"]?>
+        </span>
+        <br class='desktop'/>
+<?php
+        foreach ($page->sponsor as $sponsor){
+?>
+            <a target='_blank' href='<?=$sponsor->link?>'>
+                <img src='<?=$static["content"]?>/sponsor/<?=$sponsor->image?>' srcset='<?=srcset("sponsor/" . $sponsor->image)?>'/>
+            </a>
+<?php
+        }
+?>
+    </div>
+    <div id='footer_util'>
+        <a href='<?=$base_url?>/ayuda/'>
+            <?=$page->string["section_help"]?>
+        </a>
+        &nbsp;&nbsp;-&nbsp;&nbsp;
+        <a href='<?=$base_url?>/ayuda/#section_privacy'>
+            <?=$page->string["section_privacy"]?>
+        </a>
+        <br/>
+        <br class='mobile'/>
+        <img class='lang' alt='Espanol' src='/img/lang/es.gif' onClick='changeLanguage("es", "<?=$base_url?>");'/>
+        <img class='lang' alt='English' src='/img/lang/en.gif' onClick='changeLanguage("en", "<?=$base_url?>");'/>
+        <img class='lang' alt='Euskara' src='/img/lang/eu.gif' onClick='changeLanguage("eu", "<?=$base_url?>");'/>
+        <br class='desktop'/>
+        <a title='Google Play' href='<?=$data["app"]["android"]?>'>
+            <img class='app' alt='<?=$page->string["app_android"]?>' src='/img/app/android.gif' />
+        </a>
+        <br class='desktop'/>
+        <a title='App Store' href='<?=$data["app"]["ios"]?>'>
+            <img class='app' alt='<?=$page->string["app_ios"]?>' src='/img/app/ios.gif' />
+        </a>
+    </div>
+</footer>

+ 23 - 0
site-public/application/template/include/header.php

@@ -0,0 +1,23 @@
+<?php global $static?>
+<header>
+    <img src='<?=$static["layout"]?>/logo/logo.png'/>
+    <a href='<?=$base_url?>/'>
+        <?=$page->string["section_home"]?>
+    </a>
+    <a href='<?=$base_url?>/fiestas/'>
+        <?=$page->string["section_festivals"]?>
+    </a>
+    <a href='<?=$base_url?>/actividades/'>
+        <?=$page->string["section_activities"]?>
+    </a>
+    <a href='<?=$base_url?>/blog/'>
+        <?=$page->string["section_blog"]?>
+    </a>
+    <a href='<?=$base_url?>/nosotros/'>
+        <?=$page->string["section_us"]?>
+    </a>
+    <a href='<?=$base_url?>/galeria/'>
+        <?=$page->string["section_gallery"]?>
+    </a>
+</header>
+

+ 42 - 0
site-public/application/template/photo.php

@@ -0,0 +1,42 @@
+<h3>
+<?php
+    if (is_set($page->photo->title)){
+?>
+        <?=$page->photo->title?>
+<?php
+    }
+?>
+    <div id='viewer_close_container'>
+        <img id='viewer_close' class='pointer' alt=' ' src='<?=$static["layout"]?>/control/close.png' onClick='closeViewer();'/>
+    </div>
+</h3>
+<article>
+    <div class='arrow'>
+        <img id='viewer_arrow_left' class='viewer_arrow pointer' alt=' ' src='<?=$static["layout"]?>/control/slid-left.png' onClick='scrollPhoto(-1);'/>
+    </div>
+    <div id='photo_view'>
+        <img alt=' <?=$page->photo->title?>' title=' <?=$page->photo->title?>' src='<?=$static["content"]?>gallery/<?=$page->photo->image?>' srcset='<?=srcset("gallery/" . $page->photo->image)?>'/>
+<?php
+        if (is_set($page->photo->description)){
+?>
+            <p>
+                <?=$page->photo->description?>
+            </p>
+<?php
+        }
+        if (is_set($page->photo->username)){
+?>
+            <span id='photo_user' class='italic'>
+                <?=$page->string["photo_user"]?><?=$page->photo->username?>
+            </span>
+<?php
+        }
+?>
+        <span id='photo_date' class='italic'>
+            <?=format_date($page->photo->uploaded, $lang)?>
+        </span>
+    </div>
+    <div class='arrow'>
+        <img id='viewer_arrow_right' class='viewer_arrow pointer' alt=' ' src='<?=$static["layout"]?>/control/slid-left.png' onClick='scrollPhoto(1);'/>
+    </div>
+</article>

+ 128 - 0
site-public/application/template/post.php

@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>blog.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["script"]?>ui.js'></script>
+        <script type='text/javascript' src='<?=$static["script"]?>blog.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+<?php
+            // TODO: Worth it?
+            //include $path["inc"] . "blog-left.php";
+?>
+            <section id='post'>
+                <h3>
+                    <?=$page->post->title?>
+                </h3>
+                <article>
+<?php
+                    if (sizeof($page->post->image) > 0){
+?>
+                        <img id='main_image' alt='<?=$page->post->title?>' title='<?=$page->post->title?>' src='<?=$static["content"]?>blog/<?=$page->post->image[0]->image?>' srcset='<?=srcset("blog/" . $page->post->image[0]->image)?>'/>
+<?php
+                    }
+?>
+                    <p>
+                        <?=$page->post->text?>
+                    </p>
+                    <div id='details'>
+                        <div class='post_details_date'>
+                            <?=format_date($page->post->dtime, $page->lang, false)?>
+                        </div>
+                        <div class='post_details_tags'>
+<?php
+                            $tags = "";
+                            foreach($page->post->tag as $tag) {
+                                $tags = $tags . $tag . ", ";
+                            }
+                            substr($tags, 0, strlen($tags) - 2);
+?>
+                            <?=$tags?>
+                        </div>
+                    </div>
+                    <div id='comments'>
+<?php
+                        $comment = "";
+                        if (sizeof($page->post->comment) == 1){
+                            $comments =  $page->string["comment_1"];
+                        }
+                        else if (sizeof($page->post->comment) == 0){
+                            $comments = $page->string["comment_0"];
+                        }
+                        else{
+                            $comments =  str_replace("#", sizeof($page->post->comment), $page->string["comment_n"]);
+                        }
+?>
+                        <?=$comments?>
+<?php
+                        foreach ($page->post->comment as $comment){
+?>
+                            <div id='comment_<?=$comment->id?>' class='comment'>
+                                <span class='comment_user'>
+<!--                                     <?=$comment->username?> -->
+                                </span>
+                                <span class='comment_date date'>
+                                    <?=format_date($comment->dtime, $page->lang)?>
+                                </span>
+                                <p class='comment_text'>
+                                    <?=$comment->text?>
+                                </p>
+                            </div>
+<?php
+                        }
+?>
+                    </div>
+                    <div class='comment' id='comment_new'>
+                        <form id='comment_form' method='post' action='/' onsubmit='event.preventDefault();postComment($id, "<?=$page->lang?>");'>
+                            <textarea id='new_comment_text' name='text' maxlength='1800' onChange='dissmiss_comment_error();' onKeyDown='dissmiss_comment_error();' placeholder='<?=$page->string["comment_form_text"]?>'>
+                            </textarea>
+                            <input type='hidden' name='id' value='<?=$page->post->id?>'/>
+                            <br/>
+                            <div id='identification_form'>
+                                <input id='new_comment_user' name='user' maxlength='50' type='text' placeholder='<?$page->string["comment_form_name"]?>' onChange='dissmiss_comment_error();' onKeyDown='dissmiss_comment_error();'/>
+                            <input type='submit' value='<?=$page->string["comment_form_send"]?>'/>
+                            </div>
+                        </form>
+                    </div>
+                </article>
+            </section>
+<?php
+            // TODO: Worth it?
+            //include $path["inc"] . "blog-right.php";
+?>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

Разница между файлами не показана из-за своего большого размера
+ 83 - 0
site-public/application/template/string/lang_en.php


Разница между файлами не показана из-за своего большого размера
+ 46 - 0
site-public/application/template/string/lang_es.php


Разница между файлами не показана из-за своего большого размера
+ 83 - 0
site-public/application/template/string/lang_eu.php


+ 79 - 0
site-public/application/template/us.php

@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html lang='<?=$page->lang?>'>
+    <head>
+        <meta content='text/html; charset=utf-8' http-equiv='content-type'/>
+        <meta charset='utf-8'/>
+        <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1'/>
+        <title><?=$page->title?></title>
+        <link rel='shortcut icon' href='<?=$page->favicon?>'/>
+        <!-- CSS files -->
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>ui.css'/>
+        <link rel='stylesheet' type='text/css' href='<?=$static["css"]?>us.css'/>
+        <!-- Script files -->
+        <script type='text/javascript' src='<?=$static["js"]?>ui.js'></script>
+        <!-- Meta tags -->
+        <link rel='canonical' href='<?=$page->canonical?>'/>
+        <link rel='author' href='<?=$page->author?>'/>
+        <link rel='publisher' href='<?=$page->author?>'/>
+        <meta name='description' content='<?=$page->description?>'/>
+        <meta property='og:title' content='<?=$page->title?>'/>
+        <meta property='og:url' content='<?=$page->canonical?>'/>
+        <meta property='og:description' content='<?=$page->description?>'/>
+        <meta property='og:image' content='<?=$page->icon?>'/>
+        <meta property='og:site_name' content='<?=$page->name?>'/>
+        <meta property='og:type' content='website'/>
+        <meta property='og:locale' content='<?=$page->lang?>'/>
+        <meta name='twitter:card' content='summary'/>
+        <meta name='twitter:title' content='<?=$page->title?>'/>
+        <meta name='twitter:description' content='<?=$page->description?>'/>
+        <meta name='twitter:image' content='<?=$page->icon?>'/>
+        <meta name='twitter:url' content='<?=$page->canonical?>'/>
+        <meta name='robots' content='index follow'/>
+    </head>
+    <body>
+<?php
+        include $path["include"] . "header.php";
+?>
+        <main>
+            <section id='association'>
+                <h3>
+                    <?=$page->string["us_association"]?>
+                </h3>
+                <article>
+                    <img src="<?=$static["layout"]?>/us/logo.png" alt=" "/>
+                    <?=$page->string["us_association_content"]?>
+                </div>
+            </section>
+            <section id='cuadrilla'>
+                <h3>
+                    <?=$page->string["us_cuadrilla"]?>
+                </h3>
+                <article>
+                    <img src="<?=$static["layout"]?>/us/margolo.png" alt=" "/>
+                    <?=$page->string["us_cuadrilla_content"]?>
+                </div>
+            </section>
+            <section id='activities'>
+                <h3>
+                    <?=$page->string["us_activities"]?>
+                </h3>
+                <article>
+                    <img src="<?=$static["layout"]?>/us/activities.png" alt=" "/>
+                    <?=$page->string["us_activities_content"]?>
+                </div>
+            </section>
+            <section id='transparency'>
+                <h3>
+                    <?=$page->string["us_transparency"]?>
+                </h3>
+                <article>
+                    <img src="<?=$static["layout"]?>/us/transparency.png" alt=" "/>
+                    <?=$page->string["us_transparency_content"]?>
+                </div>
+            </section>
+        </main>
+<?php
+        include $path["include"] . "footer.php";
+?>
+    </body>
+</html>

+ 38 - 0
site-public/application/util/db.php

@@ -0,0 +1,38 @@
+<?php
+
+    /**
+     * Creates a database connection using the data in the config files.
+     * 
+     * @param mode 'ro' for read-only, 'rw' for (limited) write privileges.
+     * @return MySQL_connection or -1 on error or wrong mode.
+     */
+    function start_db($mode = 'ro'){
+        global $auth;
+        $db;
+        //Connect to to database
+        if ($mode == 'ro')
+            $db = mysqli_connect($auth["host"], $auth["user"], $auth["pass"], $auth["name"]);
+        else if ($mode == 'rw'){
+            $db = mysqli_connect($auth["host"], $auth["user-rw"], $auth["pass-rw"], $auth["name"]);
+        }
+        else{
+            return -1;
+        }
+
+        // Check connection
+        if (mysqli_connect_errno()){
+            error_log("Failed to connect to database: " . mysqli_connect_error());
+            return -1;
+        }
+
+        //Set encoding options
+        mysqli_set_charset($db, 'utf-8');
+        header('Content-Type: text/html; charset=utf8');
+        mysqli_query($db, 'SET NAMES utf8;');
+
+        //Return the db connection
+        return $db;
+    }
+
+?>
+

+ 117 - 0
site-public/application/util/net.php

@@ -0,0 +1,117 @@
+<?php
+
+
+    /**
+     * Finds out the protocol the user is connecting to the site with.
+     *
+     * @return "http://" or "https://".
+     */
+    function get_protocol(){
+        if (isset($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on" || $_SERVER["HTTPS"] == 1) || isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && $_SERVER["HTTP_X_FORWARDED_PROTO"] == "https") {
+            $protocol = "https://";
+        }
+        else {
+            $protocol = "http://";
+        }
+        return $protocol;
+    }
+
+
+    /**
+     * Finds out the IP address of the client.
+     * 
+     * @return Client IP address.
+     */
+    function get_ip(){
+        $client  = @$_SERVER["HTTP_CLIENT_IP"];
+        $forward = @$_SERVER["HTTP_X_FORWARDED_FOR"];
+        $remote  = $_SERVER["REMOTE_ADDR"];
+        if(filter_var($client, FILTER_VALIDATE_IP)){
+            $ip = $client;
+        }
+        elseif(filter_var($forward, FILTER_VALIDATE_IP)){
+            $ip = $forward;
+        }
+        else{
+            $ip = $remote;
+        }
+        return $ip;
+    }
+
+
+    /**
+     * Registers the page viewed by the user. If it is first page shown in his
+     * visit, it also registers the visit. 
+     * 
+     * @param db Connection to the database.
+     * @param section Site section being visited.
+     * @param id ID of the entry being visited.
+     */
+    function stats($db, $section, $id){
+
+        // Get client data
+        $ip = get_ip();
+        $browser_data = get_browser(null, true);
+        $os = $browser_data["platform"];
+        $browser = $browser_data["browser"];
+        $uagent = $browser_data["browser_name_pattern"];
+
+        //If bot, do nothing
+        $bot_kw = Array();
+        $bot_kw[0] = "bot";
+        $bot_kw[1] = "spider";
+        $bot_kw[2] = "crawl";
+        $bot_kw[3] = ".com";
+        $bot_kw[4] = ".ru";
+        $bot_kw[5] = "baidu";
+        $bot_kw[6] = "survey";
+        $bot_kw[7] = "scan";
+        $bot_kw[8] = "feed";
+        $bot_kw[9] = "bing";
+        $bot_kw[10] = "yahoo";
+        $bot_kw[11] = "engine";
+        $bot_kw[12] = "preview";
+        $bot_kw[13] = "checker";
+        $bot_kw[14] = "catalog";
+        $bot_kw[15] = "accelerator";
+        $bot_kw[16] = "python";
+        $bot_kw[14] = "qt";
+        $bot_kw[15] = "webdav";
+        $bot_kw[16] = "http";
+        $bot_kw[17] = "url";
+        $bot_kw[18] = "fake";
+        $bot_kw[19] = "library";
+        $bot_kw[20] = "commerce";
+        $bot_kw[21] = "htmlbot";
+        $bot_kw[22] = "fetch";
+        $bot_kw[23] = "googleb";
+        $bot_kw[24] = "facebook";
+        $bot_kw[25] = "whatsapp";
+        $bot_kw[26] = "pinterest";
+        $bot_kw[27] = "scrapy";
+        $bot_kw[28] = "libwww";
+        $bot_kw[29] = "java standard library";
+        $bot_kw[30] = "default browser";
+        $bot_kw[31] = "twingly recon";
+        $bot_kw[32] = "siteexplorer";
+        $bot_kw[33] = "yandex";
+        $bot_kw[34] = "wotbox";
+        $bot_kw[35] = "apache synapse";
+        $bot_kw[36] = "catexplorador";
+        $bot_kw[37] = "internet archive";
+        if (in_array(strtolower($uagent), $bot_kw)){
+            return;
+        }
+
+        //Look for a visit with the same IP in the last 30 mins.
+        $q = mysqli_query($db, "SELECT stat_visit.id AS visitid FROM stat_view, stat_visit WHERE visit = stat_visit.id AND stat_view.dtime > DATE_SUB(now(), INTERVAL 30 MINUTE) AND ip = '$ip' AND uagent = '$uagent';");
+        if (mysqli_num_rows($q) == 0){
+            mysqli_query($db, "INSERT INTO stat_visit (ip, uagent, os, browser) VALUES ('$ip', '$uagent', '$os', '$browser');");
+            $q = mysqli_query($db, "SELECT stat_visit.id AS visitid FROM stat_visit WHERE ip = '$ip' AND uagent = '$uagent' ORDER BY stat_visit.id DESC LIMIT 1;");
+        }
+        $r = mysqli_fetch_array($q);
+        $visit = $r['visitid'];
+        mysqli_query($db, "INSERT INTO stat_view (visit, section, entry) VALUES ($visit, '$section', '$id');");
+    }
+
+?>

+ 239 - 0
site-public/application/util/text.php

@@ -0,0 +1,239 @@
+<?php
+
+
+    /**
+     * Selects the language the page will be displayed on.
+     * 
+     * First, it tries to read the language cookie in the client. If none is
+     * set, get the browser language preference list. If none is provided or
+     * they are not supported, it will use the default language.
+     * 
+     * @param db Connection to the database.
+     * @return Lowercase, two-letter language code.
+     */
+    function select_language($db){
+
+        // Get available languages from db
+        $available_languages = array();
+        // TODO: FIX
+        array_push($available_languages, "es");
+        array_push($available_languages, "en");
+        array_push($available_languages, "eu");
+        //$q_lang = mysqli_query($db, "SELECT code FROM lang WHERE active = 1;");
+        //while ($r_lang = mysqli_fetch_array($q_lang)){
+        //    array_push($available_languages, $r_lang["code"]);
+        //}
+
+        // Is there a language cookie installed on the client?.
+        header("Cache-control: private");
+        if (isSet($_COOKIE["lang"])){
+            $lang = $_COOKIE["lang"];
+            if (in_array($lang, $available_languages)){
+                return $lang;
+            }
+        }
+
+        // If no cookie, select from client browser preferences.
+        $lang = prefered_language($available_languages, $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
+        if (in_array($lang, $available_languages)){
+            return $lang;
+        }
+
+        // If no method was succesfull, default language
+        $lang = $available_languages[0];
+        return $lang;
+    }
+
+
+    /**
+     * Parses the language prefrences of the client broser, comparing them to
+     * the languages offered by the site and selects the prefered one among
+     * the ones supported.
+     * 
+     * @param available_languages List of lowercase, two-letter language codes
+     *                            allowed by the site.
+     * @param http_accept_language Raw header with info about client language
+     *                             preferences.
+     * @return Lowercase, two-letter code of the prefered available language.
+     */
+    function prefered_language(array $available_languages, $http_accept_language) {
+
+        $available_languages = array_flip($available_languages);
+
+        $langs = array();
+        preg_match_all("~([\w-]+)(?:[^,\d]+([\d.]+))?~", strtolower($http_accept_language), $matches, PREG_SET_ORDER);
+        foreach($matches as $match) {
+
+            list($a, $b) = explode("-", $match[1]) + array("", "");
+            $value = isset($match[2]) ? (float) $match[2] : 1.0;
+
+            if(isset($available_languages[$match[1]])) {
+                $langs[$match[1]] = $value;
+                continue;
+            }
+
+            if(isset($available_languages[$a])) {
+                $langs[$a] = $value - 0.1;
+            }
+
+        }
+        if (sizeof($langs) > 0){
+            arsort($langs);
+            //return $langs[0];
+            array_values($langs)[0];
+        }
+        else{
+            return 'en';
+        }
+    }
+
+
+    /**
+     * Turns a date string into a human readable string on the specified
+     * language. Only works for spanish, basque and english.
+     * 
+     * @param str_date Date string ('yyyy-mm-dd' or 'yyyy-mm-dd HH:MM:SS')
+     * @param lang Language code (es, en, eu).
+     * @param time Boolean to append the time at the end (by default, it does)
+     * @return Formatted date string.
+     */
+    function format_date($str_date, $lang, $time = true){
+        $date = strtotime($str_date);
+        $year = date("o", $date);
+        $month = date("n", $date);
+        $month --;
+        $day = date("j", $date);
+        $wday = date("N", $date);
+        $wday --;
+        $hour = date("H", $date);
+        $minute = date("i", $date);
+        switch ($lang){
+            case "en":
+                $week = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
+                $months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
+                if ($time){
+                    $str = "$week[$wday], $months[$month] $day, $year at $hour:$minute";
+                }
+                else{
+                    $str = "$week[$wday], $months[$month] $day, $year";
+                }
+                break;
+            case "eu":
+                $week = ["astelehena", "asteartea", "asteazkena", "osteguna", "ostirala", "larumbata", "igandea"];
+                $months = ["urtarrilaren", "otsailaren", "martxoaren", "apirilaren", "maiatzaren", "ekainaren", "uztailaren", "abuztuaren", "irailaren", "urriaren", "azaroaren", "abenduaren"];
+                if ($time){
+                    $str = $year . "ko $months[$month] $day" . "an, $week[$wday], $hour:$minute";
+                }
+                else{
+                    $str = $year . "ko $months[$month] $day" . "an, $week[$wday]";
+                }
+                break;
+            default:
+                $week = ["Lunes", "Martes", "Mi&eacute;rcoles", "Jueves", "Viernes", "S&aacute;bado", "Domingo"];
+                $months = ["enero", " febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"];
+                if ($time){
+                    $str = "$week[$wday] $day de $months[$month] de $year a las $hour:$minute";
+                }
+                else{
+                    $str = "$week[$wday] $day de $months[$month] de $year";
+                }
+        }
+        return $str;
+    }
+
+
+    /**
+     * Retrieves a text fragment from the database.
+     * 
+     * @param model An initialized data model.
+     * @param id Text identifier.
+     * @returns The text.
+     */
+    function text($model, $id){
+        global $path;
+        $q = mysqli_query($model->db, "SELECT text, file FROM text WHERE id = '$id' AND lang = '" . $model->lang . "';");
+        $r = mysqli_fetch_array($q);
+        if (strlen($r["file"]) > 0){
+            return file_get_contents($path["string"] . $r["file"]);
+        }
+        else{
+            return $r["text"];
+        }
+    }
+
+
+    /**
+     * This function closes all the opened HTML tags in a given string.
+     * 
+     * @param html The string with HTML tags.
+     * @return HTML with closed tags.
+     */
+    function close_tags($html) {
+        $result = [];
+        preg_match_all("#<(?!meta|img|br|hr|input\b)\b([a-z]+)(?: .*)?(?<![/|/ ])>#iU", $html, $result);
+        $openedtags = $result[1];
+        preg_match_all("#</([a-z]+)>#iU", $html, $result);
+        $closedtags = $result[1];
+        $len_opened = count($openedtags);
+        if (count($closedtags) == $len_opened) {
+            return $html;
+        }
+        $openedtags = array_reverse($openedtags);
+        for ($i=0; $i < $len_opened; $i++) {
+            if (!in_array($openedtags[$i], $closedtags)) {
+                $html .= "</".$openedtags[$i].">";
+            } else {
+                unset($closedtags[array_search($openedtags[$i], $closedtags)]);
+            }
+        }
+        return $html;
+    }
+
+
+    /**
+     * Text shortener. Given a string, it trims in the proximity of the
+     * desired string, up to the next white character. If indicated, it will
+     * append a link to the full text.
+     * 
+     * @param text The text to shorten.
+     * @param length The desired length.
+     * @param link_text Text for the link. Optional.
+     * @param link URI of the link.
+     * @return Shortened text.
+     */
+     function cut_text($text, $length, $link_text = "", $link = ""){
+        if (strlen($text) < $length){
+            return $text;
+        }
+        $cut = substr($text, 0, strpos($text, " ", $length));
+        $cut = close_tags($cut);
+        if (strlen($cut) == 0){
+            $cut = $text;
+        }
+        if (strlen($text) != strlen($cut) && strlen($link) > 0 && strlen($link_text) > 0){
+            $cut = $cut . "... <a href='$link'>$link_text</a>";
+        }
+        return $cut;
+    }
+
+    /**
+     * Creates the srcset attribute for content images.
+     * Creates 9 different resolutions, from 100px to 900px.
+     * 
+     * @param file Path to the file, relative to $path["img"]["content"]).
+     * @return srcset atttribute content.
+     */
+    function srcset($file){
+        global $static;
+        $srcset = "";
+        $dir = dirname($file);
+        $name = basename($file);
+        foreach (range(1, 9) as $d) {
+            $srcset = $srcset . $static["content"] . $dir . "/x" . $d . "00/" . $name . " " . $d . "00px, ";
+        }
+        $srcset = rtrim($srcset, ", ");
+        return $srcset;
+    }
+
+?>
+

+ 87 - 0
site-public/public/.htaccess

@@ -0,0 +1,87 @@
+Options -MultiViews
+
+
+#
+# REWRITES
+#
+# Used to: Force https.
+#
+<IfModule mod_rewrite.c>
+	# Force https
+	RewriteCond %{HTTPS} !=on
+	RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
+</ifModule>
+
+
+#
+# FALLBACKRESOURCE
+#
+# Used to: all pages to index.php
+#
+FallbackResource /index.php
+
+
+#
+# EXPIRES
+#
+# Used to: control the cache times of the different files on the server.
+#
+<IfModule mod_expires.c>
+        ExpiresActive on
+        ExpiresDefault "access plus 2 days"
+        ExpiresByType application/javascript "access plus 6 days"
+        ExpiresByType image/x-ico "access plus 12 days"
+        ExpiresByType image/jpg "access plus 12 days"
+        ExpiresByType image/jpeg "access plus 12 days"
+        ExpiresByType image/gif "access plus 12 days"
+        ExpiresByType image/png "access plus 12 days"
+        ExpiresByType video/mkv "access plus 12 days"
+        ExpiresByType text/css "access plus 6 days"
+        ExpiresByType text/plain "access plus 6 days"
+</IfModule>
+
+
+#
+# HEADERS
+#
+# Used to: control the cache times of the different files on the client.
+#
+<ifModule mod_headers.c>
+	<filesMatch "\.(ico|jpe?g|png|gif|swf|svg)$">
+		Header set Cache-Control "max-age=86400, public, must-revalidate"
+	</filesMatch>
+	<filesMatch "\.(css)$">
+		Header set Cache-Control "max-age=86400, public, must-revalidate"
+	</filesMatch>
+	<filesMatch "\.(js)$">
+		Header set Cache-Control "max-age=86400, private, must-revalidate"
+	</filesMatch>
+	<filesMatch "\.(x?html?|php)$">
+		Header set Cache-Control "max-age=86400, private, must-revalidate"
+	</filesMatch>
+</ifModule>
+
+AddType image/svg+xml svg svgz
+<ifModule mod_deflate.c>
+	AddOutputFilterByType DEFLATE text/html text/xml text/css text/plain
+	AddOutputFilterByType DEFLATE image/x-icon
+	AddOutputFilterByType DEFLATE image/svg+xml application/xhtml+xml application/xml
+	AddOutputFilterByType DEFLATE application/rdf+xml application/rss+xml application/atom+xml
+	AddOutputFilterByType DEFLATE text/javascript application/javascript application/x-javascript application/json
+	AddOutputFilterByType DEFLATE application/x-font-ttf application/x-font-otf
+	AddOutputFilterByType DEFLATE font/truetype font/opentype
+</ifModule>
+
+
+#
+# ERROR
+#
+# Used to: redirect to nice error pages.
+#
+ErrorDocument 400 /error.php
+ErrorDocument 401 /error.php
+ErrorDocument 403 /error.php
+ErrorDocument 404 /error.php
+ErrorDocument 500 /error.php
+
+

+ 1 - 6
www/css/actividades.css → site-public/public/css/actividades.css

@@ -37,6 +37,7 @@ div.list_year{
 ul.activity_list{
     margin-top:        0em;
     margin-bottom:    0em;
+    /*     display:        none; */
     max-height:        0em;
     overflow-y:        hidden;
     transition:    max-height 0.6s ease-in-out;
@@ -131,12 +132,6 @@ div#activity_itinerary table#activity_itinerary td span.address, p.description{
     font-size:    80%;
 }
 
-div#activity_itinerary table#activity_itinerary td span.route_start{
-    opacity: 0.7;
-    font-size: 90%;
-    font-style: italic;
-}
-
 
 /* /actividades/index.php */
 

+ 0 - 0
www/css/app.css → site-public/public/css/app.css


+ 0 - 0
www/css/ayuda.css → site-public/public/css/ayuda.css


+ 28 - 0
site-public/public/css/blog.css

@@ -0,0 +1,28 @@
+/* Blog main page. */
+section#post_list article img{
+    max-width: 7em;
+    max-height: 5em;
+    margin-right: 1em;
+    display: inline-block;
+    vertical-align: top;
+}
+section#post_list article p{
+    display: inline-block;
+    vertical-align: top;
+}
+section#post_list article div.post_details > div{
+    display: inline-block;
+    vertical-align: top;
+    font-size: 90%;
+}
+section#post_list article div.post_details div.post_details_date{
+    width: 40%;
+}
+section#post_list article div.post_details div.post_details_tags{
+    width: 40%;
+}
+section#post_list article div.post_details div.post_details_comments{
+    width: 20%;
+}
+
+/* Single post page. */

+ 0 - 0
www/css/galeria.css → site-public/public/css/galeria.css


+ 105 - 0
site-public/public/css/gallery.css

@@ -0,0 +1,105 @@
+/* Gallery page. */
+section#album_list{
+    text-align: center;
+}
+
+section#album_list h3{
+    text-align: left;
+}
+
+section#album_list article{
+    display: inline-block;
+    vertical-align: top;
+    text-align: center;
+    margin: 1em;
+    width: 20em;
+}
+
+section#album_list article img{
+    display: inline-block;
+    width: 4em;
+    margin: 1em;
+    border: 0.2em solid black;
+
+}
+
+/* Album page. */
+section#album{
+    text-align: center;
+}
+section#album h3{
+    text-align: left;
+}
+section#album img{
+    max-height: 7em;
+    max-width: 7em;
+    margin: 1em;
+}
+
+/* Photo viewer. */
+div#screen_cover{
+    position: fixed;
+    top: 0;
+    left: 0;
+    background-color: black;
+    display: none;
+    width: 100%;
+    height: 100%;
+    opacity: 0;
+    transition: all .9s ease-in-out;
+    z-index: 1000;
+}
+section#photo_viewer{
+    position: fixed;
+    display: none;
+    top: 1em;
+    left: 4em;
+    right: 4em;
+    bottom: 1em;
+    opacity: 0;
+    transition: all .6s ease-in-out;
+    z-index: 1001;
+    min-height: 10em;
+}
+@media screen and max-width: 800px{
+    div#photo_viewer{
+        top: 2%;
+        left: 2%;
+        right: 2%;
+        bottom: 2%;
+    }
+}
+section#photo_viewer h3 div#viewer_close_container{
+    height: 1.5em;
+    float: right;
+    margin-top: -0.3em;
+    margin-right: -0.4em;
+}
+section#photo_viewer article{
+    text-align: center;
+}
+section#photo_viewer article div{
+    display: inline-block;
+    vertical-align: middle;
+    margin: 0;
+}
+section#photo_viewer article div.arrow{
+    width: 15%;
+    padding: 0.5em;
+}
+section#photo_viewer article div#photo_view{
+    width: 65%;
+    padding: 0.1em;
+}
+section#photo_viewer article div#photo_view img{
+    display: block;
+    background: #000000;
+    border: 0.1em solid #000000;
+    border-radius: 0.5em;
+}
+
+section#photo_viewer article div#photo_view p{
+    margin: 0.2em;
+    padding: 0;
+    text-align: left;
+}

+ 16 - 11
www/css/index.css → site-public/public/css/index.css

@@ -1,6 +1,6 @@
 div#festivals div#festivals_summary img{
     display: inline-block;
-    max-width: 35%;
+    max-width: 40%;
     max-height: 15em;
     vertical-align: top;
     border: 0.1em solid black;
@@ -173,7 +173,6 @@ div#upcoming_details table td{
 }
 
 /* Us section */
-
 div#us p{
     display:    inline-block;
     vertical-align:    top;
@@ -263,11 +262,13 @@ table#table_photos td{
 }
 
 table#table_photos img{
-    max-width: 90%;
-    max-height: 10em;
-    border: 0.1em solid #112244;
-    box-shadow: 0 0 0.8em #004488;
-    border-radius: 0.8em;
+    max-width:        90%;
+    max-height:        10em;
+    border:            0.1em solid #112244;
+
+/*     border:            0.1em solid #333333; */
+/*     box-shadow:        0 0 0.8em #000000; */
+/*     border-radius:    0.2em */
 }
 
 div#latest_activities{
@@ -292,10 +293,14 @@ table.latest_activity td.latest_activity_image{
 }
 
 div#latest_activities img{
-    max-height: 10em;
-    max-width: 13em;
-    margin: 0.5em 1em 0.5em 0.5em;
-    border: 0.1em solid #112244;
+/*     max-width:        40%; */
+    max-height:        10em;
+    margin:            0.5em 1em 0.5em 0.5em;
+    border:            0.1em solid #112244;
+
+/*     border:            0.15em solid #333333; */
+/*     border-radius:    0.2em; */
+/*     box-shadow:        0 0 0.5em #111111; */
 }
 
 div.activity_text{

+ 9 - 23
www/css/lablanca.css → site-public/public/css/lablanca.css

@@ -21,11 +21,11 @@ div#content_table div.content_tr div.content_td{
 }
 
 div#content_table div.content_tr div#content_td_schedule{
-    width:        50%;
+    width:        60%;
 }
 
 div#content_table div.content_tr div#content_td_prices{
-    width:        50%;
+    width:        40%;
 }
 
 div#content_table div.content_tr div#content_td_prices div#prices{
@@ -72,22 +72,11 @@ div#festivals_image_top_container div#festivals_image_container img#festivals_im
     max-height:        20em;
 }
 
-/* programa.php */
 div#schedule{
-    display: inline-block;
-    vertical-align: top;
-    margin-top: 2em;
-    margin-right: 1em;
-    text-align: center
-    width: 100%;
-}
-
-div#schedule div.button{
-    margin: 1em 0.5em 1em 0.5em;
-    padding: 0.5em;
-    display: inline-block;
-    vertical-align: top;
-    width: 40%;
+    display:        inline-block;
+    vertical-align:    top;
+    margin-top:        2em;
+    margin-right:    1em;
 }
 
 div.day_title h4{
@@ -154,18 +143,15 @@ table.schedule div.location{
     margin-left:        2em;
 }
 
-table.schedule div.location span.route_start{
-    opacity: 0.7;
-    font-size: 90%;
-    font-style: italic;
+table.schedule div.location img{
+    max-height:        1.3em;
+    vertical-align:    middle;
 }
 
 table.schedule div.location span.address{
     font-style:    italic;
 }
 
-
-/* fiestas.php */
 div#prices{
     display:        inline-block;
     vertical-align:    top;

+ 0 - 0
www/css/m/actividades.css → site-public/public/css/m/actividades.css


+ 0 - 0
www/css/m/ayuda.css → site-public/public/css/m/ayuda.css


+ 0 - 0
www/css/m/blog.css → site-public/public/css/m/blog.css


+ 78 - 0
site-public/public/css/m/galeria.css

@@ -0,0 +1,78 @@
+div#photo_viewer{
+    top: 2%;
+    left: 2%;
+    right: 2%;
+    bottom: 2%;
+}
+
+/* /galeria/load_photo.php */
+
+div#photo_viewer div#viewer_table{
+    display: block;
+}
+
+div#photo_viewer div#viewer_table div.viewer_row{
+    display: block;
+}
+
+div#photo_viewer div#viewer_table div.viewer_row div.viewer_cell{
+    display: block;
+}
+
+div#photo_viewer div#viewer_table div.viewer_row div#cell_image{
+    text-align: center;
+    position: initial;
+    bottom: initial;
+    top: initial;
+    left: initial;
+    right: initial;
+    height: 50%;
+    
+}
+
+div#photo_viewer div#viewer_table div.viewer_row div#cell_details{
+    width: 100%;
+    height: 40%;
+    overflow-y: auto;
+}
+
+div#photo_viewer_image_container{
+    height: 100%;
+    padding-top: 0;
+}
+
+img#photo_viewer_image{
+    max-height: 95%;
+}
+
+div#photo_viewer div#viewer_controls{
+    height: 8%;
+    bottom: 5%;
+}
+
+div#photo_viewer div#viewer_controls img#viewer_close{
+    float: right;
+    margin-right: 10%;
+    margin-left: -10%;
+    max-height: 3em;
+    max-width: 3em;
+}
+
+div#photo_viewer_details{
+    position: initial;
+    top: initial;
+    bottom: initial;
+    right: initial;
+    left: initial;
+    overflow-y: auto;
+}
+
+div#file_box span#select_mobile{
+    font-weight: bold;
+    font-size: 130%;
+}
+
+div#cell_comments{
+    width: initial !important;
+    margin: 0 1em 0.5em 1em;
+}

+ 0 - 5
www/css/m/index.css → site-public/public/css/m/index.css

@@ -65,8 +65,3 @@ div#content_table div.content_row div#cell_posts div.section{
 div#content_table div.content_row div#cell_photos div.section{
     margin-left:    0;
 }
-
-div#latest_activities img{
-    max-width: 10em;
-}
-

+ 1 - 1
www/css/m/lablanca.css → site-public/public/css/m/lablanca.css

@@ -4,6 +4,7 @@ div#content_table{
 
 div#content_table div.content_tr{
     display:    inline;
+    
 }
 
 div#content_table div.content_tr div.content_td{
@@ -35,4 +36,3 @@ div#schedule{
 div#prices{
     display:        block;
 }
-

+ 0 - 0
www/css/m/nosotros.css → site-public/public/css/m/nosotros.css


+ 0 - 0
www/css/nosotros.css → site-public/public/css/nosotros.css


+ 289 - 0
site-public/public/css/ui.css

@@ -0,0 +1,289 @@
+/* Glogal font. */
+@font-face{
+    font-family: font;
+    src: url('/font/FreeSans.ttf')
+}
+
+/* Mobile or desktop specifics. */
+.mobile{
+    display: none;
+}
+@media screen and max-width: 800px{
+    .desktop{
+        display: none;
+    }
+}
+
+/* Common elements across the page. */
+a, .fake_a{
+    color: #4c9ed9;
+    text-decoration: none;
+    transition: all .2s ease-in-out;
+}
+a:hover, .fake_a:hover{
+    color: #347;
+    text-shadow: 0 0 0.4em #265885;
+    text-decoration: underline;
+}
+input[type="text"], input[type="number"], input[type="date"]{
+    border-radius: 0.3em;
+    height: 1.5em;
+    border: 0.2em solid #0078ff;
+    color: #002255;
+    background-color: #ccddff;
+    margin: 0.1em;
+}
+input[type="button"], input[type="submit"], select{
+    border-radius: 0.3em;
+    height: 2em;
+    border: 0.2em solid #0078ff;
+    font-weight: bold;
+    color: #ffffff;
+    background-color: #124567;
+    cursor: pointer;
+    margin: 0.1em;
+    letter-spacing: 0.1em;
+}
+textarea{
+    border-radius: 0.3em;
+    min-height: 2em;
+    max-height: 15em;
+    border: 0.2em solid #0078ff;
+    color: #002255;
+    background-color: #ccddff;
+    resize: vertical;
+    margin: 0.1em;
+}
+li{
+    list-style-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAG0lEQVQImWNgIBqU//+PWwKGcUoQVECanVgAAJSsH/KywgEfAAAAAElFTkSuQmCC');
+}
+img.slid{
+    height: 0.9em;
+    width: 0.9em;
+    padding: 0.1em;
+    cursor: pointer;
+    vertical-align: middle;
+    transition: opacity 0.5s ease-in-out;
+}
+
+/* Quick styles for varios elements used widely. */
+.pointer{cursor: pointer;}
+.hidden{display: none;}
+.italic{font-style: italic;}
+.bold{font-weight: bold;}
+.stroke{text-decoration: line-through;}
+.underline{text-decoration: underline;}
+
+
+/* Body */
+body{
+    font-family: font;
+    margin: 0;
+    /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#b5d3e5+0,e5f4ff+10,e5f4ff+90,b5d3e5+100 */
+    background: linear-gradient(to right, #b5d3e5 0%,#e5f4ff 10%,#e5f4ff 90%,#b5d3e5 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b5d3e5', endColorstr='#b5d3e5',GradientType=1 ); /* IE6-9 */
+}
+
+/* Header */
+header{
+    margin: -0.5em auto 2.5em auto;
+    padding: 0.5em 0 0 0;
+    width: 100%;
+    background-color: #0078ff;
+    border-bottom: 0.1em solid #1a4d6a;
+    box-shadow: 0 0 3em #dde;
+    text-align: center;
+}
+header img{
+    display: inline-block;
+    width: 10%;
+    max-width: 5em;
+    margin: 1em;
+    vertical-align: middle;
+    filter: drop-shadow(0 0 0.4em #dde);
+    border-radius: 100%;
+}
+
+header a{
+    display: inline-block;
+    vertical-align: middle;
+    width: calc(((100% - 6em) / 6) - 2em);
+    margin: 0;
+    padding: 0.5em 0.1em;
+    font-size: 110%;
+    color: #ffffff;
+    text-align: center;
+    padding: 0.5em 0;
+    border-top: 0.1em solid #1a4d6a;
+    border-bottom: 0.1em solid #1a4d6a;
+    transition: all .3s ease-in-out;
+    overflow-x: hidden;
+    white-space: nowrap;
+}
+header a:hover{
+    border-top: 0.3em solid #1a4d6a;
+    border-bottom: 0.3em solid #1a4d6a;
+    padding: 0.3em 0.1em;
+    color: #0078ff;
+    background-color: #ffffff;
+    text-shadow: 0 0 0em #ffffff;
+}
+
+/* Footer. */
+footer{
+    width: 100%;
+    display: inline-block;
+    background-color: #0078ff;
+    border-top: 0.1em solid #1a4d6a;
+    margin: 1em 0 0 0;
+    padding: 0;
+    width: 100%;
+    box-shadow: 0 0 2em #dde;
+    text-align: center;
+    color: #ccddff
+}
+
+footer > div{
+    display: inline-block;
+    vertical-align: middle;
+    margin: 0;
+    padding: 1em;
+    text-align: center;
+}
+footer > div#footer_social{
+    width: 22%;
+}
+footer > div#footer_social img{
+    display: inline-block;
+    vertical-align:center;
+    height: 2.2em;
+    margin: 0.12em;
+    transition: all .3s ease-in-out;
+    filter: drop-shadow(0 0 0.2em #ddddee);
+}
+footer > div#footer_social img:hover{
+    filter: drop-shadow(0 0 0.6em #111);
+}
+footer > div#footer_sponsors{
+    width: 55%;
+}
+footer > div#footer_sponsors img{
+    display: inline-block;
+    vertical-align:center;
+    max-height: 3.3em;
+    min-height: 2em;
+    min-width: 3em;
+    max-width: 5em;
+    border: 0.1em solid #111122;
+    border-radius: 0.2em;
+    margin: 0.1em 0.4em 0.1em 0.4em;
+    vertical-align: middle;
+}
+footer > div#footer_util{
+    width: 22%;
+}
+footer > div#footer_util img.lang{
+    height: 1em;
+    margin: 0.5em;
+    border-radius: 0.2em;
+    border: 0.15em solid #003;
+    cursor: pointer;
+    box-shadow: 0 0 0.7em #dde;
+    transition: all .3s ease-in-out;
+}
+footer > div#footer_util img.lang:hover{
+    box-shadow: 0 0 1em #111;
+}
+footer > div#footer_util img.app{
+    height: 2em;
+    border-radius: 0.4em;
+    border: 0.15em solid #003;
+    cursor: pointer;
+    box-shadow: 0 0 0.5em #dde;
+    transition: all .3s ease-in-out;
+}
+footer > div#footer_util img.app:hover{
+    box-shadow: 0 0 0.8em #dde;
+}
+
+/* Basic page structures. */
+main{
+    margin: auto;
+    width: 90%;
+    max-width: 80em;
+    min-width: 60em;
+}
+section{
+    border-left: 0.1em solid #000011;
+    border-right: 0.1em solid #000011;
+    border-bottom: 0.1em solid #000011;
+    border-radius: 1em;
+    padding: 0 0 0.5em 0;
+    background-color: #98c8ff;
+    -webkit-filter: drop-shadow(0 0 0.4em #000011);
+    filter: drop-shadow(0 0 0.4em #000011);
+    -ms-filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=0, OffY=0, Color='#000011')";
+    filter: "progid:DXImageTransform.Microsoft.Dropshadow(OffX=0, OffY=0, Color='#000011')";
+}
+section h3{
+    font-size: 120%;
+    font-style: bold;
+    color: #ffffff;
+    background-color: #0078ff;
+    padding: 0.5em 2em 0.1em 1.5em;
+    border-top-left-radius: 0.7em;
+    border-top-right-radius: 0.7em;
+    border: 0.1em solid #000011;
+    margin: 0;
+}
+article{
+    background-color: #ffffff;
+    padding: 0.2em;
+    margin: 0.4em;
+    border: 0.1em solid #6D6990;
+    border-radius: 0.3em;
+    box-shadow: inset 0 0 0.2em #dde;
+    transition: all .3s ease-in-out;
+}
+article h4{
+    color: #275573;
+    font-weight: bold;
+    font-size: 1.3em;
+    margin: 1em 1em 0.3em 0em;
+}
+article h4 a{
+    color: #275573;
+}
+
+/* Posted omments */
+div.comment{
+    margin: 0.5em 1em 0.5em 1em;
+}
+div.comment span.comment_user{
+    font-weight: bold;
+}
+div.comment span.comment_date{
+    font-style: italic;
+    font-size: 80%;
+}
+div.comment span.comment_date::before {
+    content: " - ";
+    font-size: 80%;
+}
+div.comment p.comment_text{
+    margin: 0.5em 1em 0.5em 0.5em;
+}
+
+/* Comment form */
+div#comment_new{
+    padding: 0.5em 1.5em 0.5em 1.5em;
+}
+div#comment_new textarea{
+    width: 95%;
+}
+div#comment_new input[type='text']{
+    width: 70%;
+}
+div#comment_new input[type='submit']{
+    width: 25%;
+}

+ 0 - 0
www-admin/font/FreeSans.ttf → site-public/public/fonts/FreeSans.ttf


+ 0 - 0
www-admin/font/FreeSansBold.ttf → site-public/public/fonts/FreeSansBold.ttf


+ 0 - 0
www-admin/font/FreeSansBoldOblique.ttf → site-public/public/fonts/FreeSansBoldOblique.ttf


+ 0 - 0
www-admin/font/FreeSansOblique.ttf → site-public/public/fonts/FreeSansOblique.ttf


+ 0 - 0
www-admin/font/Vera.ttf → site-public/public/fonts/Vera.ttf


+ 0 - 0
www-admin/font/VeraBI.ttf → site-public/public/fonts/VeraBI.ttf


+ 0 - 0
www-admin/font/VeraBd.ttf → site-public/public/fonts/VeraBd.ttf


+ 0 - 0
www-admin/font/VeraIt.ttf → site-public/public/fonts/VeraIt.ttf


+ 0 - 0
www-admin/font/VeraMoBI.ttf → site-public/public/fonts/VeraMoBI.ttf


+ 0 - 0
www-admin/font/VeraMoBd.ttf → site-public/public/fonts/VeraMoBd.ttf


+ 0 - 0
www-admin/font/VeraMoIt.ttf → site-public/public/fonts/VeraMoIt.ttf


+ 0 - 0
www-admin/font/VeraMono.ttf → site-public/public/fonts/VeraMono.ttf


+ 0 - 0
www-admin/font/VeraSe.ttf → site-public/public/fonts/VeraSe.ttf


+ 0 - 0
www-admin/font/VeraSeBd.ttf → site-public/public/fonts/VeraSeBd.ttf


+ 0 - 0
www-admin/font/texgyreadventor-bold.otf → site-public/public/fonts/texgyreadventor-bold.otf


+ 0 - 0
www-admin/font/texgyreadventor-bolditalic.otf → site-public/public/fonts/texgyreadventor-bolditalic.otf


+ 0 - 0
www-admin/font/texgyreadventor-italic.otf → site-public/public/fonts/texgyreadventor-italic.otf


+ 0 - 0
www-admin/font/texgyreadventor-regular.otf → site-public/public/fonts/texgyreadventor-regular.otf


+ 1 - 0
site-public/public/img/content/.gitignore

@@ -0,0 +1 @@
+!.gitignore

+ 1 - 0
site-public/public/img/content/activities/.gitignore

@@ -0,0 +1 @@
+!.gitignore

+ 1 - 0
site-public/public/img/content/activities/x100/.gitignore

@@ -0,0 +1 @@
+!.gitignore

+ 1 - 0
site-public/public/img/content/activities/x200/.gitignore

@@ -0,0 +1 @@
+!.gitignore

+ 1 - 0
site-public/public/img/content/activities/x300/.gitignore

@@ -0,0 +1 @@
+!.gitignore

+ 1 - 0
site-public/public/img/content/activities/x400/.gitignore

@@ -0,0 +1 @@
+!.gitignore

+ 1 - 0
site-public/public/img/content/activities/x500/.gitignore

@@ -0,0 +1 @@
+!.gitignore

Некоторые файлы не были показаны из-за большого количества измененных файлов