Version compatible with Piwik 2.1
authorRadek Czajka <radekczajka@nowoczesnapolska.org.pl>
Wed, 5 Mar 2014 09:34:24 +0000 (10:34 +0100)
committerRadek Czajka <radekczajka@nowoczesnapolska.org.pl>
Wed, 5 Mar 2014 10:19:53 +0000 (11:19 +0100)
Removed the additionalsuperusers setting, Piwik handles those natively now.
Added custom login image.

Auth.php
CASLogin.php
CHANGELOG
Controller.php
README
plugin.json [new file with mode: 0644]
templates/header.tpl [deleted file]
templates/login.tpl [deleted file]
templates/login.twig [new file with mode: 0644]

index f1a6e2b..e9714d1 100644 (file)
--- a/Auth.php
+++ b/Auth.php
@@ -6,15 +6,25 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id:$
  * 
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id:$
  * 
- * @package Piwik_CASLogin
+ * @category Piwik_Plugins
+ * @package CASLogin
  */
 
  */
 
+namespace Piwik\Plugins\CASLogin;
+
+use Piwik\AuthResult;
+use Piwik\Common;
+use Piwik\Config;
+use Piwik\Db;
+use Piwik\Piwik;
+use Piwik\Plugins\UsersManager\API;
+
 /**
  * Class that implements an authentication mechanism via CAS (Central Authentication Services)
  *
  * @package Piwik_CASLogin
  */
 /**
  * Class that implements an authentication mechanism via CAS (Central Authentication Services)
  *
  * @package Piwik_CASLogin
  */
-class Piwik_CASLogin_Auth implements Piwik_Auth
+class Auth implements \Piwik\Auth
 {
        protected $login = null;
        protected $token_auth = null;
 {
        protected $login = null;
        protected $token_auth = null;
@@ -24,16 +34,11 @@ class Piwik_CASLogin_Auth implements Piwik_Auth
                return 'CASLogin';
        }
 
                return 'CASLogin';
        }
 
+       public function initSession($login, $md5Password, $rememberMe) {}
+
        public function authenticate()
        {
                $user = '';
        public function authenticate()
        {
                $user = '';
-               $rootLogin = Zend_Registry::get('config')->superuser->login;
-
-               $additionalSuperUsers = array();
-               $oAdditionalSuperUsers = Zend_Registry::get('config')->caslogin->additionalsuperusers;
-               if(is_object($oAdditionalSuperUsers)) {
-                       $additionalSuperUsers = $oAdditionalSuperUsers->toArray();
-               }
 
                require_once PIWIK_INCLUDE_PATH . '/plugins/CASLogin/CAS/CAS.php';
 
 
                require_once PIWIK_INCLUDE_PATH . '/plugins/CASLogin/CAS/CAS.php';
 
@@ -47,25 +52,25 @@ class Piwik_CASLogin_Auth implements Piwik_Auth
                // phpCAS::client() would fail.
                global $PHPCAS_CLIENT;
                if(!is_object($PHPCAS_CLIENT)) {
                // phpCAS::client() would fail.
                global $PHPCAS_CLIENT;
                if(!is_object($PHPCAS_CLIENT)) {
-                       phpCAS::client(
-                               constant( Zend_Registry::get('config')->caslogin->protocol ),
-                               Zend_Registry::get('config')->caslogin->host,
-                               (integer) Zend_Registry::get('config')->caslogin->port,
+                       \phpCAS::client(
+                               constant( Config::getInstance()->caslogin['protocol'] ),
+                               Config::getInstance()->caslogin['host'],
+                               (integer) Config::getInstance()->caslogin['port'],
                 '',
                 false
                        );
                }
 
                // no SSL validation for the CAS server
                 '',
                 false
                        );
                }
 
                // no SSL validation for the CAS server
-               phpCAS::setNoCasServerValidation();
+               \phpCAS::setNoCasServerValidation();
 
                // Handle single signout requests from CAS server
 
                // Handle single signout requests from CAS server
-               phpCAS::handleLogoutRequests();
+               \phpCAS::handleLogoutRequests();
 
                // force CAS authentication only if it has been requested by action argument
                $action = Piwik::getAction();
                
 
                // force CAS authentication only if it has been requested by action argument
                $action = Piwik::getAction();
                
-               $auth = phpCAS::checkAuthentication();
+               $auth = \phpCAS::checkAuthentication();
                if(!$auth) {
                        if($action == 'redirectToCAS') {
                                phpCAS::forceAuthentication();
                if(!$auth) {
                        if($action == 'redirectToCAS') {
                                phpCAS::forceAuthentication();
@@ -77,7 +82,7 @@ class Piwik_CASLogin_Auth implements Piwik_Auth
                        } elseif($action == 'redirectToCAS') {
                                phpCAS::forceAuthentication();
                        } else {
                        } elseif($action == 'redirectToCAS') {
                                phpCAS::forceAuthentication();
                        } else {
-                               return new Piwik_Auth_Result( Piwik_Auth_Result::FAILURE, $user, NULL );
+                               return new AuthResult( AuthResult::FAILURE, $user, NULL );
                        }
                }
 
                        }
                }
 
@@ -86,7 +91,7 @@ class Piwik_CASLogin_Auth implements Piwik_Auth
                // dependable on a specific installation. CAS|piwik hackers can do some magic
                // here with SAML attributes etc.
                /*
                // dependable on a specific installation. CAS|piwik hackers can do some magic
                // here with SAML attributes etc.
                /*
-               foreach (phpCAS::getAttributes() as $key => $value) {
+               foreach (\phpCAS::getAttributes() as $key => $value) {
                        // syslog(LOG_DEBUG, "attribute: $key - ". print_r($value, true));
                }
                 */
                        // syslog(LOG_DEBUG, "attribute: $key - ". print_r($value, true));
                }
                 */
@@ -96,31 +101,32 @@ class Piwik_CASLogin_Auth implements Piwik_Auth
                }
 
                if($user) {
                }
 
                if($user) {
-                       if($user == $rootLogin || in_array($user, $additionalSuperUsers)) {
-                               // Root / Admin login
-                               return new Piwik_Auth_Result(Piwik_Auth_Result::SUCCESS_SUPERUSER_AUTH_CODE, $user, NULL );
-                       }
-
-                       $login = Zend_Registry::get('db')->fetchOne(
-                                       'SELECT login FROM '.Piwik_Common::prefixTable('user').' WHERE login = ?',
+                       $db_user = Db::fetchRow('SELECT login, superuser_access FROM '.Common::prefixTable('user').' WHERE login = ?',
                                        array($user)
                        );
                                        array($user)
                        );
-                       if($login === false) {
+                       if($db_user === null) {
                                // ***User Autocreate***
                                // We can either add the authenticated but not-yet-authorized user to the piwik users
                                // database, or ignore that.
                                // TODO: make this a config option
                                // ***User Autocreate***
                                // We can either add the authenticated but not-yet-authorized user to the piwik users
                                // database, or ignore that.
                                // TODO: make this a config option
-                               // $this->_populateDb($user);
+                               $this->_populateDb($user);
                                $login = $user;
                                $login = $user;
+                               $superuser = false;
+                       }
+                       else {
+                               $login = $db_user['login'];
+                               $superuser = $db_user['superuser_access'];
                        }
                        }
-
                        if($login == $user)
                        {
                        if($login == $user)
                        {
-                               return new Piwik_Auth_Result(Piwik_Auth_Result::SUCCESS, $login, NULL );
+                               if ($superuser)
+                                       $code = AuthResult::SUCCESS_SUPERUSER_AUTH_CODE;
+                               else $code = AuthResult::SUCCESS; 
+                               return new AuthResult($code, $login, NULL );
                        }
                }
 
                        }
                }
 
-               return new Piwik_Auth_Result( Piwik_Auth_Result::FAILURE, $user, NULL );
+               return new AuthResult( AuthResult::FAILURE, $user, NULL );
        }
 
        public function setLogin($login)
        }
 
        public function setLogin($login)
@@ -142,9 +148,9 @@ class Piwik_CASLogin_Auth implements Piwik_Auth
                $result = null;
                $dummy = md5('abcd1234');
                if ($this->_helper_userExists($user)) {
                $result = null;
                $dummy = md5('abcd1234');
                if ($this->_helper_userExists($user)) {
-                       $this->_helper_updateUser($user, $dummy, '', 'alias');
+                       $this->_helper_updateUser($user, $dummy, '', $user);
                } else {
                } else {
-                       $this->_helper_addUser($user, $dummy, '', 'alias');
+                       $this->_helper_addUser($user, $dummy, '', $user);
                }
        }
 
                }
        }
 
@@ -156,19 +162,17 @@ class Piwik_CASLogin_Auth implements Piwik_Auth
        ///// Warning - these methods are of course under Piwik's license.
        private function _helper_userExists($name)
        {
        ///// Warning - these methods are of course under Piwik's license.
        private function _helper_userExists($name)
        {
-               $count = Zend_Registry::get('db')->fetchOne("SELECT count(*)
-                                                                       FROM ".Piwik_Common::prefixTable("user"). "
+               $count = Db::fetchOne("SELECT count(*)
+                                                                       FROM ".Common::prefixTable("user"). "
                                                                        WHERE login = ?", $name);
                return $count > 0;
        }
 
        private function _helper_updateUser( $userLogin, $password = false, $email = false, $alias = false ) 
        {
                                                                        WHERE login = ?", $name);
                return $count > 0;
        }
 
        private function _helper_updateUser( $userLogin, $password = false, $email = false, $alias = false ) 
        {
-               $token_auth = Piwik_UsersManager_API::getTokenAuth($userLogin, $password);
-
-               $db = Zend_Registry::get('db');
+               $token_auth = API::getTokenAuth($userLogin, $password);
 
 
-               $db->update( Piwik_Common::prefixTable("user"),
+               Db::get()->update( Common::prefixTable("user"),
                                        array(
                                                'password' => $password,
                                                'alias' => $alias,
                                        array(
                                                'password' => $password,
                                                'alias' => $alias,
@@ -181,11 +185,9 @@ class Piwik_CASLogin_Auth implements Piwik_Auth
 
        private function _helper_addUser( $userLogin, $password, $email, $alias = false )
        {               
 
        private function _helper_addUser( $userLogin, $password, $email, $alias = false )
        {               
-               $token_auth = Piwik_UsersManager_API::getTokenAuth($userLogin, $password);
-
-               $db = Zend_Registry::get('db');
+               $token_auth = API::getTokenAuth($userLogin, $password);
 
 
-               $db->insert( Piwik_Common::prefixTable("user"), array(
+               Db::get()->insert( Common::prefixTable("user"), array(
                                                                        'login' => $userLogin,
                                                                        'password' => $password,
                                                                        'alias' => $alias,
                                                                        'login' => $userLogin,
                                                                        'password' => $password,
                                                                        'alias' => $alias,
index 69c8524..e8df58e 100644 (file)
@@ -9,9 +9,13 @@
  * @package Piwik_CASLogin
  */
 
  * @package Piwik_CASLogin
  */
 
+namespace Piwik\Plugins\CASLogin;
+
+use Piwik\Piwik;
+
 require PIWIK_INCLUDE_PATH . '/plugins/CASLogin/Auth.php';
 
 require PIWIK_INCLUDE_PATH . '/plugins/CASLogin/Auth.php';
 
-class Piwik_CASLogin extends Piwik_Plugin
+class CASLogin extends \Piwik\Plugin
 {
        public function getInformation()
        {
 {
        public function getInformation()
        {
@@ -20,23 +24,23 @@ class Piwik_CASLogin extends Piwik_Plugin
                        'description' => 'CAS Login plugin. It uses JA-SIG Central Authentication Services to authenticate users and grant them access to piwik.',
                        'author' => 'OW',
                         'homepage' => 'http://dev.piwik.org/trac/ticket/598/',
                        'description' => 'CAS Login plugin. It uses JA-SIG Central Authentication Services to authenticate users and grant them access to piwik.',
                        'author' => 'OW',
                         'homepage' => 'http://dev.piwik.org/trac/ticket/598/',
-                        'version' => '0.6',
+                        'version' => '0.7',
                );
        }
 
        function getListHooksRegistered()
        {
                $hooks = array(
                );
        }
 
        function getListHooksRegistered()
        {
                $hooks = array(
-                       'FrontController.initAuthenticationObject'      => 'initAuthenticationObject',
+                       'Request.initAuthenticationObject'      => 'initAuthenticationObject',
                        );
                return $hooks;
        }
 
                        );
                return $hooks;
        }
 
-       function initAuthenticationObject($notification)
+       function initAuthenticationObject()
        {
         set_include_path(get_include_path() . PATH_SEPARATOR . PIWIK_INCLUDE_PATH . '/plugins/CASLogin/CAS');
         require_once('CAS/CAS.php');
        {
         set_include_path(get_include_path() . PATH_SEPARATOR . PIWIK_INCLUDE_PATH . '/plugins/CASLogin/CAS');
         require_once('CAS/CAS.php');
-               $auth = new Piwik_CASLogin_Auth();
-               Zend_Registry::set('auth', $auth);
+               $auth = new Auth();
+               \Piwik\Registry::set('auth', $auth);
        }
 }
        }
 }
index 0660e77..a01801d 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,9 @@
 == Changelog ==
 == Changelog ==
+0.7
+ * Compatible with Piwik 2.1
+ * Removed the "additional root logins" option (Piwik handles multiple superusers natively now)
+ * Added custom CAS login image
+
 0.6.3
  * Bugfix: Added $this->setBasicVariablesView($view) to Controller.php to fix missing variables issue 
    after upgrading to Piwik 1.6
 0.6.3
  * Bugfix: Added $this->setBasicVariablesView($view) to Controller.php to fix missing variables issue 
    after upgrading to Piwik 1.6
index 4a8db55..a90f39f 100644 (file)
@@ -6,16 +6,23 @@
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id: Controller.php 943 2009-03-01 23:36:36Z matt $
  *
  * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
  * @version $Id: Controller.php 943 2009-03-01 23:36:36Z matt $
  *
- * @package Piwik_CASLogin
+ * @category Piwik_Plugins
+ * @package CASLogin
  */
 
  */
 
-require PIWIK_INCLUDE_PATH . '/plugins/UsersManager/API.php';
-require PIWIK_INCLUDE_PATH . '/core/View.php';
+namespace Piwik\Plugins\CASLogin;
+
+use Piwik\Config;
+use Piwik\Nonce;
+use Piwik\Piwik;
+use Piwik\Plugins\UsersManager\API;
+use Piwik\Url;
+use Piwik\View;
 
 /**
 
 /**
- * @package Piwik_CASLogin
+ * @package CASLogin
  */
  */
-class Piwik_CASLogin_Controller extends Piwik_Controller
+class Controller extends \Piwik\Plugin\Controller
 {
        public function index()
        {
 {
        public function index()
        {
@@ -33,15 +40,15 @@ class Piwik_CASLogin_Controller extends Piwik_Controller
                 $this->setBasicVariablesView($view);
                 $view->linkTitle = Piwik::getRandomTitle();
 
                 $this->setBasicVariablesView($view);
                 $view->linkTitle = Piwik::getRandomTitle();
 
-               $enableFramedLogins = Zend_Registry::get('config')->General->enable_framed_logins;
+               $enableFramedLogins = Config::getInstance()->General['enable_framed_pages'];
                $view->enableFramedLogins = $enableFramedLogins;
                if(!$enableFramedLogins)
                {
                        $view->setXFrameOptions('sameorigin');
                }
                $view->enableFramedLogins = $enableFramedLogins;
                if(!$enableFramedLogins)
                {
                        $view->setXFrameOptions('sameorigin');
                }
-               $view->forceSslLogin = Zend_Registry::get('config')->General->force_ssl_login;
+               $view->forceSslLogin = Config::getInstance()->General['force_ssl'];
                // crsf token: don't trust the submitted value; generate/fetch it from session data
                // crsf token: don't trust the submitted value; generate/fetch it from session data
-               $view->nonce = Piwik_Nonce::getNonce('Piwik_Login.login');
+               $view->nonce = Nonce::getNonce('Piwik_Login.login');
        }
     
        /**
        }
     
        /**
@@ -53,9 +60,11 @@ class Piwik_CASLogin_Controller extends Piwik_Controller
         */
        function login($messageNoAccess = null)
        {
         */
        function login($messageNoAccess = null)
        {
-               $view = Piwik_View::factory('login');
+               $view = new View('@CASLogin/login');
                $view->AccessErrorString = $messageNoAccess;
                $view->linkTitle = Piwik::getRandomTitle();
                $view->AccessErrorString = $messageNoAccess;
                $view->linkTitle = Piwik::getRandomTitle();
+               $config = Config::getInstance()->caslogin;
+               $view->loginImage = isset($config['loginimage']) ? $config['loginimage'] : '';
                $view->subTemplate = 'genericForm.tpl';
                $this->configureView($view);
                echo $view->render();
                $view->subTemplate = 'genericForm.tpl';
                $this->configureView($view);
                echo $view->render();
@@ -88,6 +97,6 @@ class Piwik_CASLogin_Controller extends Piwik_Controller
        
        public function logout()
        {
        
        public function logout()
        {
-        phpCAS::logoutWithUrl(Piwik_Url::getCurrentUrlWithoutQueryString() );
+        \phpCAS::logoutWithUrl(Url::getCurrentUrlWithoutQueryString() );
        }
 }
        }
 }
diff --git a/README b/README
index 0479817..0c82c89 100644 (file)
--- a/README
+++ b/README
@@ -12,13 +12,10 @@ piwik itself.
 To make this work, first you need to make sure that the user that logs in
 also exists in piwik user tables and has some rights to view or edit sites.
 
 To make this work, first you need to make sure that the user that logs in
 also exists in piwik user tables and has some rights to view or edit sites.
 
-The superuser login value in piwik itself should also correspond to a proper
-user in CAS.
-
 So a way to make this work in *new* piwik installations is:
 
 So a way to make this work in *new* piwik installations is:
 
- * In main piwik configuration, set the "login" in [superuser] section to
-   correspond to an actual CAS user.
+ * Make sure a superuser exists with login corresponding to
+   an actual CAS user.
  * Enable the CASLogin plugin (see "Installation" below).
  * Log in as the superuser. Go to Settings -> Users. Add a username (just
    the actual username is needed, other data can be left empty). And for that
  * Enable the CASLogin plugin (see "Installation" below).
  * Log in as the superuser. Go to Settings -> Users. Add a username (just
    the actual username is needed, other data can be left empty). And for that
@@ -47,17 +44,10 @@ Option "protocol" is one of CAS_VERSION_1_0, CAS_VERSION_2_0 or SAML_VERSION_1_1
 
 == Additional Options ==
 
 
 == Additional Options ==
 
-By default, only the user defined in piwik configuration (config/config.ini.php) in
-the [superuser] section is regarded as a superuser / root administrator.
-
-However, with the CAS Login scheme, you might need to add additional accounts as
-superusers, each one of them logging in as normal with their own password.
-
-If you'd like to do that, add these accounts in section [caslogin] as follows:
+You can add a custom image on login page by setting it in [caslogin] section:
 
 {{{
 
 {{{
-additionalsuperusers[] = uid1
-additionalsuperusers[] = uid2
+loginimage = 'url-of-image'
 }}}
 
 
 }}}
 
 
diff --git a/plugin.json b/plugin.json
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/templates/header.tpl b/templates/header.tpl
deleted file mode 100644 (file)
index 1a8a499..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
-<head>
-       <title>Piwik &rsaquo; Login</title>
-       <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-       <link rel="shortcut icon" href="plugins/CoreHome/templates/images/favicon.ico" />
-
-       <link rel="stylesheet" type="text/css" href="plugins/CASLogin/templates/login.css" media="screen" />
-       {postEvent name="template_css_import"}
-       
-       {literal}
-       <script type="text/javascript">
-               function focusit() {
-                       var formLogin = document.getElementById('form_login');
-                       if(formLogin)
-                       {
-                               formLogin.focus();
-                       }
-               }
-               window.onload = focusit;
-       </script>
-       {/literal}
-       <script type="text/javascript" src="libs/jquery/jquery.js"></script>
-       {postEvent name="template_js_import"}
-</head>
-
-<body class="login">
-<!-- shamelessly taken from wordpress 2.5 - thank you guys!!! -->
-
-<div id="logo">
-       <a href="http://piwik.org" title="{$linkTitle}"><span class="h1"><span style="color: rgb(245, 223, 114);">P</span><span style="color: rgb(241, 175, 108);">i</span><span style="color: rgb(241, 117, 117);">w</span><span style="color: rgb(155, 106, 58);">i</span><span style="color: rgb(107, 50, 11);">k</span> <span class="description"># {'General_OpenSourceWebAnalytics'|translate}</span></span></a>
-</div>
diff --git a/templates/login.tpl b/templates/login.tpl
deleted file mode 100644 (file)
index 3fe269a..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{include file="Login/templates/header.tpl"}
-
-<div id="login">
-
-{if $AccessErrorString}
-<div id="login_error"><strong>{'General_Error'|translate}</strong>: {$AccessErrorString}<br /></div>
-{/if}
-
-<div id="loginbox">
-    <div id="loginlink">
-               <a href="index.php?module=CASLogin&amp;action=redirectToCAS">{'Login_LogIn'|translate}</a>
-    </div>
-</div>
-
-</div>
-
-</body>
-</html>
diff --git a/templates/login.twig b/templates/login.twig
new file mode 100644 (file)
index 0000000..95d93ac
--- /dev/null
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>{% if isCustomLogo == false %}Piwik &rsaquo; {% endif %}{{ 'Login_LogIn'|translate }}</title>
+
+    <link rel="shortcut icon" href="plugins/CoreHome/images/favicon.ico"/>
+    {% autoescape false %}
+    {{ includeAssets({"type": "css"}) }}
+    {% endautoescape %}
+    <link rel="stylesheet" type="text/css" href="plugins/Login/stylesheets/login.css"/>
+    <meta name="description" content="{{ 'General_OpenSourceWebAnalytics'|translate }}"/>
+    {% if 'General_LayoutDirection'|translate =='rtl' %}
+        <link rel="stylesheet" type="text/css" href="plugins/Zeitgeist/stylesheets/rtl.css"/>
+    {% endif %}
+</head>
+<body id="loginPage">
+
+    {% include "_iframeBuster.twig" %}
+
+    <div id="logo">
+        {% if isCustomLogo == false %}
+            <a href="http://piwik.org" title="{{ linkTitle }}">
+        {% endif %}
+        {% if hasSVGLogo %}
+            <img src='{{ logoSVG }}' title="{{ linkTitle }}" alt="Piwik" class="ie-hide"/>
+            <!--[if lt IE 9]>
+        {% endif %}
+        <img src='{{ logoLarge }}' title="{{ linkTitle }}" alt="Piwik" />
+        {% if hasSVGLogo %}<![endif]-->{% endif %}
+
+        {% if isCustomLogo %}
+            {% set poweredByPiwik %}
+            <i><a href="http://piwik.org/" target="_blank">{{ linkTitle }}</a></i>
+            {% endset %}
+        {% endif %}
+
+        {% if isCustomLogo == false %}
+            </a>
+            <div class="description">
+                <a href="http://piwik.org" title="{{ linkTitle }}">{{ linkTitle }}</a>
+                <div class="arrow"></div>
+            </div>
+        {% endif %}
+    </div>
+
+    <section class="loginSection">
+
+<div id="loginbox">
+    <div id="loginlink" style="text-align:center;">
+               {{ 'Login_LogIn'|translate }}<br/><br/>
+                <a href="index.php?module=CASLogin&amp;action=redirectToCAS"><img src="{{ loginImage }}" alt="{{ 'Login_LogIn'|translate }}" style="max-width:50%;"></a>
+    </div>
+</div>
+
+
+            </div>
+    </section>
+</body>
+</html>