From 92e805609fe9c4306542a0c9fde30606aec6fca4 Mon Sep 17 00:00:00 2001 From: Vincent Zanotti Date: Fri, 18 Jan 2008 01:25:15 +0100 Subject: [PATCH] Adds two iGoogle gadgets (one for directory queries, the other for the latest events). Signed-off-by: Vincent Zanotti --- ChangeLog | 4 ++ htdocs/css/igoogle.css | 97 +++++++++++++++++++++++++++++++++++++ htdocs/javascript/igoogle.js | 37 ++++++++++++++ htdocs/xorg.php | 3 +- include/userset.inc.php | 42 ++++++++++++++++ modules/gadgets.php | 92 +++++++++++++++++++++++++++++++++++ modules/gadgets/gadgets.inc.php | 60 +++++++++++++++++++++++ templates/gadgets/ig-events.tpl | 51 +++++++++++++++++++ templates/gadgets/ig-events.xml.tpl | 35 +++++++++++++ templates/gadgets/ig-login.tpl | 34 +++++++++++++ templates/gadgets/ig-minifiche.tpl | 82 +++++++++++++++++++++++++++++++ templates/gadgets/ig-search.tpl | 56 +++++++++++++++++++++ templates/gadgets/ig-search.xml.tpl | 35 +++++++++++++ templates/gadgets/ig-skin.tpl | 41 ++++++++++++++++ 14 files changed, 668 insertions(+), 1 deletion(-) create mode 100644 htdocs/css/igoogle.css create mode 100644 htdocs/javascript/igoogle.js create mode 100644 modules/gadgets.php create mode 100644 modules/gadgets/gadgets.inc.php create mode 100644 templates/gadgets/ig-events.tpl create mode 100644 templates/gadgets/ig-events.xml.tpl create mode 100644 templates/gadgets/ig-login.tpl create mode 100644 templates/gadgets/ig-minifiche.tpl create mode 100644 templates/gadgets/ig-search.tpl create mode 100644 templates/gadgets/ig-search.xml.tpl create mode 100644 templates/gadgets/ig-skin.tpl diff --git a/ChangeLog b/ChangeLog index 9ea2e70..78aa29a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,9 @@ New: * Core: - New PlProfiler tool -FRU + * Goodies: + - iGoogle gadgets for latest events and directory search -VZA + Bug/Wish: * Emails: @@ -1152,6 +1155,7 @@ ACRONYMS: * SHK: Jeremy Lainé (Sharky) * VP : Vincent Palatin * XdX: Alexandre Hô (XandreX) + * VZA: Vincent Zanotti (vinZ2) ================================================================================ vim:et:ts=4:sw=4:tw=80:enc=utf-8: diff --git a/htdocs/css/igoogle.css b/htdocs/css/igoogle.css new file mode 100644 index 0000000..4fe8ada --- /dev/null +++ b/htdocs/css/igoogle.css @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2003-2008 Polytechnique.org * + * http://opensource.polytechnique.org/ * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + ***************************************************************************/ + +body { + font-family: "Arial", sans-serif; + font-size: small; + color: #000000; + background: #ffffff; + background-position: center; + margin: 0.2em 0em; +} + +a:link, a:visited, a:active, a:hover { color: #003399; background: none; } +img { vertical-align: middle; } +a img { border: 0px; } +td { vertical-align: top; } +div.more { font-size: x-small; text-align: right; } + +/* Events */ +div.events ul { margin: 0; padding: 0 0.2em 0 1em; } +div.events ul li { margin: 0.5em 0.2em; padding: 0; } +li.unread { font-weight: bold; } + +/* Search gadget: frame */ +div.welcome { + text-align: center; +} + +div.search { + text-align: center; + margin-top: 1em; +} + +div.error { + color: red; + font-weight: bold; +} + +/* Search gadget: result page */ +div.contact-list div.contact { + width: 100%; + text-align: left; + border-top: 1px solid #003399; + background: #F4D09C; + color: inherit; +} + +div.grayed { + color: #444444; + font-style: italic; +} + +div.grayed div.contact { + background: #eee; +} + +div.contact div.nom { + font-weight: bold; + float: left; +} + +div.contact div.autre { + text-align: right; + float: right; +} + +div.contact div.long { + width: 100%; + clear: both; + background: white; + color: inherit; + padding-top: 1px; + padding-bottom: 1px; +} + +div.long table { width: 100%; } +div.long td.lt { width: 35%; } +div.long td.rt { width: 65%; } + +/* vim: set et ts=4 sts=4 sw=4: */ diff --git a/htdocs/javascript/igoogle.js b/htdocs/javascript/igoogle.js new file mode 100644 index 0000000..abea945 --- /dev/null +++ b/htdocs/javascript/igoogle.js @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2003-2008 Polytechnique.org * + * http://opensource.polytechnique.org/ * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + ***************************************************************************/ + +function igOnLoadHandler() +{ + if (typeof(_IG_AdjustIFrameHeight) != 'undefined') { + _IG_AdjustIFrameHeight(); + } +} + +function markEventAsRead(event_id) +{ + _toggle(_gel("mark-read-" + event_id)); + _gel("evt-" + event_id).setAttribute("class", "read"); + _gel("link-" + event_id).setAttribute("href", "events/unread/" + event_id); + Ajax.update_html(null, "events/read/" + event_id); + return false; +} + +// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: diff --git a/htdocs/xorg.php b/htdocs/xorg.php index 72026ca..f0faa4e 100644 --- a/htdocs/xorg.php +++ b/htdocs/xorg.php @@ -27,7 +27,8 @@ if (!($path = Env::v('n')) || ($path{0} < 'A' || $path{0} > 'Z')) { $platal = new Platal('auth', 'banana', 'carnet', 'email', 'events', 'geoloc', 'lists', 'marketing', 'payment', 'platal', 'profile', 'register', 'search', 'stats', 'admin', - 'newsletter', 'axletter', 'bandeau', 'survey'); + 'newsletter', 'axletter', 'bandeau', 'survey', + 'gadgets'); $platal->run(); exit; diff --git a/include/userset.inc.php b/include/userset.inc.php index 0da93ad..382baa3 100644 --- a/include/userset.inc.php +++ b/include/userset.inc.php @@ -374,5 +374,47 @@ class GeolocView implements PlView } } +class GadgetView implements PlView +{ + public function __construct(PlSet &$set, $data, array $params) + { + $this->set =& $set; + } + + public function fields() + { + return "u.user_id AS id, + u.*, a.alias AS forlife," . + (S::logged() ? "q.profile_mobile AS mobile, " : "IF(q.profile_mobile_pub = 'public', q.profile_mobile, NULL) as mobile, ") . + "u.perms != 'pending' AS inscrit, + u.perms != 'pending' AS wasinscrit, + u.deces != 0 AS dcd, u.deces, + FIND_IN_SET('femme', u.flags) AS sexe, + adr.city, gp.a2, gp.pays AS countrytxt, gr.name AS region" . + (S::logged() ? ", c.contact AS contact" : ''); + } + + public function joins() + { + return "LEFT JOIN adresses AS adr ON (u.user_id = adr.uid AND FIND_IN_SET('active', adr.statut)".(S::logged() ? "" : " AND adr.pub = 'public'").") + LEFT JOIN geoloc_pays AS gp ON (adr.country = gp.a2) + LEFT JOIN geoloc_region AS gr ON (adr.country = gr.a2 AND adr.region = gr.region)" . + (S::logged() ? + "LEFT JOIN contacts AS c On (c.contact = u.user_id AND c.uid = " . S::v('uid') . ")" + : ""); + } + + public function apply(PlatalPage &$page) + { + $page->assign_by_ref('set', + $this->set->get($this->fields(), $this->joins(), null, null, null, 5, 0)); + } + + public function args() + { + return null; + } +} + // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: ?> diff --git a/modules/gadgets.php b/modules/gadgets.php new file mode 100644 index 0000000..0a90079 --- /dev/null +++ b/modules/gadgets.php @@ -0,0 +1,92 @@ + $this->make_hook('ig_events_xml', AUTH_PUBLIC, 'user', NO_HTTPS), + 'gadgets/ig-events' => $this->make_hook('ig_events', AUTH_PUBLIC), + 'gadgets/ig-search.xml' => $this->make_hook('ig_search_xml', AUTH_PUBLIC, 'user', NO_HTTPS), + 'gadgets/ig-search' => $this->make_hook('ig_search', AUTH_PUBLIC), + ); + } + + function handler_ig_events_xml(&$page) { + require_once 'gadgets/gadgets.inc.php'; + init_igoogle_xml('gadgets/ig-events.xml.tpl'); + } + + function handler_ig_events(&$page) { + require_once 'gadgets/gadgets.inc.php'; + init_igoogle_html('gadgets/ig-events.tpl', AUTH_COOKIE); + + $events = XDB::iterator( + 'SELECT SQL_CALC_FOUND_ROWS + e.id, e.titre, UNIX_TIMESTAMP(e.creation_date) AS creation_date, + IF(u.nom_usage = "", u.nom, u.nom_usage) AS nom, u.prenom, u.promo, + ev.user_id IS NULL AS nonlu + FROM evenements AS e + INNER JOIN auth_user_md5 AS u ON e.user_id = u.user_id + LEFT JOIN evenements_vus AS ev ON (e.id = ev.evt_id AND ev.user_id = {?}) + WHERE FIND_IN_SET("valide", e.flags) AND peremption >= NOW() + AND (e.promo_min = 0 || e.promo_min <= {?}) + AND (e.promo_max = 0 || e.promo_max >= {?}) + ORDER BY e.creation_date DESC + LIMIT {?}', + S::i('uid'), S::i('promo'), S::i('promo'), 5); + $page->assign('events', $events); + $page->assign('event_count', XDB::query("SELECT FOUND_ROWS()")->fetchOneCell()); + } + + function handler_ig_search_xml(&$page) { + require_once 'gadgets/gadgets.inc.php'; + init_igoogle_xml('gadgets/ig-search.xml.tpl'); + } + + function handler_ig_search(&$page) + { + if (Env::has('quick') && Env::s('quick') != '') { + require_once 'userset.inc.php'; + $view = new SearchSet(true); + $view->addMod('gadget', 'Gadget', true); + $view->apply(null, $page); + + $nb_tot = $view->count(); + $page->assign('result_count', $nb_tot); + + if (!S::logged() && $nb_tot > $globals->search->public_max) { + $page->assign('error', 'Votre recherche a généré trop de résultats pour un affichage public.'); + } elseif ($nb_tot > $globals->search->private_max) { + $page->assign('error', 'Recherche trop générale.'); + } elseif (empty($nb_tot)) { + $page->assign('error', 'Il n\'existe personne correspondant à ces critères dans la base !'); + } + } + + require_once 'gadgets/gadgets.inc.php'; + init_igoogle_html('gadgets/ig-search.tpl', AUTH_PUBLIC); + } +} + +// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: +?> diff --git a/modules/gadgets/gadgets.inc.php b/modules/gadgets/gadgets.inc.php new file mode 100644 index 0000000..613c2df --- /dev/null +++ b/modules/gadgets/gadgets.inc.php @@ -0,0 +1,60 @@ +changeTpl($template, NO_SKIN); + + header('Content-Type: application/xml; charset=utf-8'); +} + +function init_igoogle_html($template, $auth = AUTH_PUBLIC) +{ + global $page; + $page->changeTpl('gadgets/ig-skin.tpl', NO_SKIN); + $page->register_modifier('escape_html', 'escape_html'); + $page->default_modifiers = Array('@escape_html'); + header('Accept-Charset: utf-8'); + + // Adds external JavaScript libraries provided by iGoogle to the page. + if (Env::has('libs')) { + $libs = split(',', Env::s('libs')); + foreach ($libs as $lib) { + if (preg_match('@^[a-z0-9/._-]+$@i', $lib) && !preg_match('@([.][.])|([.]/)|(//)@', $lib)) { + $page->append('gadget_js', 'https://www.google.com/ig/f/' . $lib); + } + } + } + + // Redirects the user to the login pagin if required. + if ($auth > S::v('auth', AUTH_PUBLIC)) { + $page->assign('gadget_tpl', 'gadgets/ig-login.tpl'); + return false; + } + + $page->assign('gadget_tpl', $template); + return true; +} + +// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: +?> diff --git a/templates/gadgets/ig-events.tpl b/templates/gadgets/ig-events.tpl new file mode 100644 index 0000000..b6ab0c6 --- /dev/null +++ b/templates/gadgets/ig-events.tpl @@ -0,0 +1,51 @@ +{**************************************************************************} +{* *} +{* Copyright (C) 2003-2008 Polytechnique.org *} +{* http://opensource.polytechnique.org/ *} +{* *} +{* This program is free software; you can redistribute it and/or modify *} +{* it under the terms of the GNU General Public License as published by *} +{* the Free Software Foundation; either version 2 of the License, or *} +{* (at your option) any later version. *} +{* *} +{* This program is distributed in the hope that it will be useful, *} +{* but WITHOUT ANY WARRANTY; without even the implied warranty of *} +{* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *} +{* GNU General Public License for more details. *} +{* *} +{* You should have received a copy of the GNU General Public License *} +{* along with this program; if not, write to the Free Software *} +{* Foundation, Inc., *} +{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *} +{* *} +{**************************************************************************} + +
+ +
+ + +{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *} diff --git a/templates/gadgets/ig-events.xml.tpl b/templates/gadgets/ig-events.xml.tpl new file mode 100644 index 0000000..f077f08 --- /dev/null +++ b/templates/gadgets/ig-events.xml.tpl @@ -0,0 +1,35 @@ +{**************************************************************************} +{* *} +{* Copyright (C) 2003-2008 Polytechnique.org *} +{* http://opensource.polytechnique.org/ *} +{* *} +{* This program is free software; you can redistribute it and/or modify *} +{* it under the terms of the GNU General Public License as published by *} +{* the Free Software Foundation; either version 2 of the License, or *} +{* (at your option) any later version. *} +{* *} +{* This program is distributed in the hope that it will be useful, *} +{* but WITHOUT ANY WARRANTY; without even the implied warranty of *} +{* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *} +{* GNU General Public License for more details. *} +{* *} +{* You should have received a copy of the GNU General Public License *} +{* along with this program; if not, write to the Free Software *} +{* Foundation, Inc., *} +{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *} +{* *} +{**************************************************************************} + + + + + + + + + + +{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *} diff --git a/templates/gadgets/ig-login.tpl b/templates/gadgets/ig-login.tpl new file mode 100644 index 0000000..6a0d9d7 --- /dev/null +++ b/templates/gadgets/ig-login.tpl @@ -0,0 +1,34 @@ +{**************************************************************************} +{* *} +{* Copyright (C) 2003-2008 Polytechnique.org *} +{* http://opensource.polytechnique.org/ *} +{* *} +{* This program is free software; you can redistribute it and/or modify *} +{* it under the terms of the GNU General Public License as published by *} +{* the Free Software Foundation; either version 2 of the License, or *} +{* (at your option) any later version. *} +{* *} +{* This program is distributed in the hope that it will be useful, *} +{* but WITHOUT ANY WARRANTY; without even the implied warranty of *} +{* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *} +{* GNU General Public License for more details. *} +{* *} +{* You should have received a copy of the GNU General Public License *} +{* along with this program; if not, write to the Free Software *} +{* Foundation, Inc., *} +{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *} +{* *} +{**************************************************************************} + +
+
+ Polytechnique.org +
+ + +{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *} diff --git a/templates/gadgets/ig-minifiche.tpl b/templates/gadgets/ig-minifiche.tpl new file mode 100644 index 0000000..b04a21d --- /dev/null +++ b/templates/gadgets/ig-minifiche.tpl @@ -0,0 +1,82 @@ +{**************************************************************************} +{* *} +{* Copyright (C) 2003-2008 Polytechnique.org *} +{* http://opensource.polytechnique.org/ *} +{* *} +{* This program is free software; you can redistribute it and/or modify *} +{* it under the terms of the GNU General Public License as published by *} +{* the Free Software Foundation; either version 2 of the License, or *} +{* (at your option) any later version. *} +{* *} +{* This program is distributed in the hope that it will be useful, *} +{* but WITHOUT ANY WARRANTY; without even the implied warranty of *} +{* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *} +{* GNU General Public License for more details. *} +{* *} +{* You should have received a copy of the GNU General Public License *} +{* along with this program; if not, write to the Free Software *} +{* Foundation, Inc., *} +{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *} +{* *} +{**************************************************************************} + +{if !$c.inscrit || $c.dcd}
{/if} +
+ +
+ {if $c.iso3166} + {$c.nat}  + {/if} + (X {$c.promo}) + {if $c.dcd}décédé{if $c.sexe}e{/if} le {$c.deces|date_format}{/if} + {if $smarty.session.auth ge AUTH_COOKIE} + {if !$c.wasinscrit && !$c.dcd} + {if $show_action eq ajouter} + {* + *}{icon name=add title="Ajouter à la liste de mes surveillances"} + {else} + {* + *}{icon name=cross title="Retirer de la liste de mes surveillances"} + {/if} + {elseif $c.wasinscrit && !$c.dcd} + {* + *}{icon name=vcard title="Afficher la carte de visite"} + {if $show_action eq ajouter} + {* + *}{icon name=add title="Ajouter à mes contacts"} + {else} + {* + *}{icon name=cross title="Retirer de mes contacts"} + {/if} + {/if} + {/if} +
+
+ {if $c.wasinscrit} + {if $c.mobile || $c.countrytxt || $c.city} + + {if $c.countrytxt || $c.city} + + + + + {/if} + {if $c.mobile && !$c.dcd} + + + + + {/if} +
Géographie:{$c.city}{if $c.city && $c.countrytxt}, {/if}{$c.countrytxt}
Mobile:{$c.mobile}
+ {/if} + {/if} +
+
+{if !$c.inscrit || $c.dcd}
{/if} + +{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *} diff --git a/templates/gadgets/ig-search.tpl b/templates/gadgets/ig-search.tpl new file mode 100644 index 0000000..67fdd83 --- /dev/null +++ b/templates/gadgets/ig-search.tpl @@ -0,0 +1,56 @@ +{**************************************************************************} +{* *} +{* Copyright (C) 2003-2008 Polytechnique.org *} +{* http://opensource.polytechnique.org/ *} +{* *} +{* This program is free software; you can redistribute it and/or modify *} +{* it under the terms of the GNU General Public License as published by *} +{* the Free Software Foundation; either version 2 of the License, or *} +{* (at your option) any later version. *} +{* *} +{* This program is distributed in the hope that it will be useful, *} +{* but WITHOUT ANY WARRANTY; without even the implied warranty of *} +{* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *} +{* GNU General Public License for more details. *} +{* *} +{* You should have received a copy of the GNU General Public License *} +{* along with this program; if not, write to the Free Software *} +{* Foundation, Inc., *} +{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *} +{* *} +{**************************************************************************} + +{if $error} +
{$error}
+{elseif $set} +
+{iterate from=$set item=res} + {if $res.contact} + {include file="gadgets/ig-minifiche.tpl" c=$res show_action="retirer"} + {else} + {include file="gadgets/ig-minifiche.tpl" c=$res show_action="ajouter"} + {/if} +{/iterate} +
+ +{else} +
+ Logo Polytechnique.org +
+{/if} + + + +{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *} diff --git a/templates/gadgets/ig-search.xml.tpl b/templates/gadgets/ig-search.xml.tpl new file mode 100644 index 0000000..ae4eae4 --- /dev/null +++ b/templates/gadgets/ig-search.xml.tpl @@ -0,0 +1,35 @@ +{**************************************************************************} +{* *} +{* Copyright (C) 2003-2008 Polytechnique.org *} +{* http://opensource.polytechnique.org/ *} +{* *} +{* This program is free software; you can redistribute it and/or modify *} +{* it under the terms of the GNU General Public License as published by *} +{* the Free Software Foundation; either version 2 of the License, or *} +{* (at your option) any later version. *} +{* *} +{* This program is distributed in the hope that it will be useful, *} +{* but WITHOUT ANY WARRANTY; without even the implied warranty of *} +{* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *} +{* GNU General Public License for more details. *} +{* *} +{* You should have received a copy of the GNU General Public License *} +{* along with this program; if not, write to the Free Software *} +{* Foundation, Inc., *} +{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *} +{* *} +{**************************************************************************} + + + + + + + + + + +{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *} diff --git a/templates/gadgets/ig-skin.tpl b/templates/gadgets/ig-skin.tpl new file mode 100644 index 0000000..050c14c --- /dev/null +++ b/templates/gadgets/ig-skin.tpl @@ -0,0 +1,41 @@ +{**************************************************************************} +{* *} +{* Copyright (C) 2003-2008 Polytechnique.org *} +{* http://opensource.polytechnique.org/ *} +{* *} +{* This program is free software; you can redistribute it and/or modify *} +{* it under the terms of the GNU General Public License as published by *} +{* the Free Software Foundation; either version 2 of the License, or *} +{* (at your option) any later version. *} +{* *} +{* This program is distributed in the hope that it will be useful, *} +{* but WITHOUT ANY WARRANTY; without even the implied warranty of *} +{* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *} +{* GNU General Public License for more details. *} +{* *} +{* You should have received a copy of the GNU General Public License *} +{* along with this program; if not, write to the Free Software *} +{* Foundation, Inc., *} +{* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *} +{* *} +{**************************************************************************} + +{include file="skin/common.doctype.tpl"} + + + + + + + + {foreach from=$gadget_js item=js} + + {/foreach} + + + +{if $gadget_tpl}{include file=$gadget_tpl}{/if} + + + +{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *} -- 2.1.4