Index: inc/core/class.dc.blog.php
===================================================================
--- inc/core/class.dc.blog.php	(revision 1052)
+++ inc/core/class.dc.blog.php	(revision 970)
@@ -194,85 +194,40 @@
 	public function triggerComment($id,$del=false)
 	{
-		$this->triggerComments($id,$del);
-	}
-	
-	/**
-	Updates comments and trackbacks counters in post table. Should be called
-	every time comments or trackbacks are added, removed or changed there status.
-	
-	@param	ids		<b>mixed</b>		Comment(s) ID(s)
-	@param	del		<b>boolean</b>		If comment is delete, set this to true
-	*/
-	public function triggerComments($ids,$del=false)
-	{
-		$co_ids = dcUtils::cleanIds($ids);
-		
-		# a) Retrieve posts affected by comments edition
-		$strReq = 
-			'SELECT post_id, comment_trackback '.
-			'FROM '.$this->prefix.'comment '.
-			'WHERE comment_id'.$this->con->in($co_ids).
-			'GROUP BY post_id,comment_trackback';
+		$id = (integer) $id;
+		
+		$strReq = 'SELECT post_id, comment_trackback '.
+				'FROM '.$this->prefix.'comment '.
+				'WHERE comment_id = '.$id.' ';
 		
 		$rs = $this->con->select($strReq);
 		
-		$a_ids = $a_tbs = array();
-		while ($rs->fetch()) {
-			$a_ids[] = (integer) $rs->post_id;
-			$a_tbs[] = (integer) $rs->comment_trackback;
-		}
-		
-		# b) Count comments of each posts previously retrieved
-		# Note that this does not return posts without comment
-		$strReq = 
-			'SELECT post_id, COUNT(post_id) AS nb_comment,comment_trackback '.
-			'FROM '.$this->prefix.'comment '.
-			'WHERE post_id'.$this->con->in($a_ids).
-			'AND comment_status = 1 ';
+		$post_id = $rs->post_id;
+		$tb = (boolean) $rs->comment_trackback;
+		
+		$strReq = 'SELECT COUNT(post_id) '.
+				'FROM '.$this->prefix.'comment '.
+				'WHERE post_id = '.(integer) $post_id.' '.
+				'AND comment_trackback = '.(integer) $tb.' '.
+				'AND comment_status = 1 ';
 		
 		if ($del) {
-			$strReq .= 
-				'AND comment_id NOT'.$this->con->in($co_ids);
-		}
-		
-		$strReq .= 
-			'GROUP BY post_id,comment_trackback';
+			$strReq .= 'AND comment_id <> '.$id.' ';
+		}
 		
 		$rs = $this->con->select($strReq);
 		
-		$b_ids = $b_tbs = $b_nbs = array();
-		while ($rs->fetch()) {
-			$b_ids[] = (integer) $rs->post_id;
-			$b_tbs[] = (integer) $rs->comment_trackback;
-			$b_nbs[] = (integer) $rs->nb_comment;
-		}
-		
-		# c) Update comments numbers on posts
-		# This compare previous requests to update also posts without comment
 		$cur = $this->con->openCursor($this->prefix.'post');
 		
-		foreach($a_ids as $a_key => $a_id)
-		{
-			$nb_comment = $nb_trackback = 0;
-			foreach($b_ids as $b_key => $b_id)
-			{
-				if ($a_id != $b_id || $a_tbs[$a_key] != $b_tbs[$b_key]) {
-					continue;
-				}
-				
-				if ($b_tbs[$b_key]) {
-					$nb_trackback = $b_nbs[$b_key];
-				} else {
-					$nb_comment = $b_nbs[$b_key];
-				}
-			}
-			
-			if ($a_tbs[$a_key]) {
-				$cur->nb_trackback = $nb_trackback;
-			} else {
-				$cur->nb_comment = $nb_comment;
-			}
-			$cur->update('WHERE post_id = '.$a_id);
-		}
+		if ($rs->isEmpty()) {
+			return;
+		}
+		
+		if ($tb) {
+			$cur->nb_trackback = (integer) $rs->f(0);
+		} else {
+			$cur->nb_comment = (integer) $rs->f(0);
+		}
+		
+		$cur->update('WHERE post_id = '.(integer) $post_id);
 	}
 	//@}
@@ -1268,29 +1223,25 @@
 	public function updPostStatus($id,$status)
 	{
-		$this->updPostsStatus($id,$status);
-	}
-	
-	/**
-	Updates posts status.
-	
-	@param	ids		<b>mixed</b>		Post(s) ID(s)
-	@param	status	<b>integer</b>		Post status
-	*/
-	public function updPostsStatus($ids,$status)
-	{
 		if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
 			throw new Exception(__('You are not allowed to change this entry status'));
 		}
 		
-		$posts_ids = dcUtils::cleanIds($ids);
+		$id = (integer) $id;
 		$status = (integer) $status;
-		
-		$strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
-				"AND post_id ".$this->con->in($posts_ids);
 		
 		#If user can only publish, we need to check the post's owner
 		if (!$this->core->auth->check('contentadmin',$this->id))
 		{
-			$strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
+			$strReq = 'SELECT post_id '.
+					'FROM '.$this->prefix.'post '.
+					'WHERE post_id = '.$id.' '.
+					"AND blog_id = '".$this->con->escape($this->id)."' ".
+					"AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
+			
+			$rs = $this->con->select($strReq);
+			
+			if ($rs->isEmpty()) {
+				throw new Exception(__('You are not allowed to change this entry status'));
+			}
 		}
 		
@@ -1300,26 +1251,12 @@
 		$cur->post_upddt = date('Y-m-d H:i:s');
 		
-		$cur->update($strReq);
+		$cur->update(
+			'WHERE post_id = '.$id.' '.
+			"AND blog_id = '".$this->con->escape($this->id)."' "
+			);
 		$this->triggerBlog();
 	}
 	
-	/**
-	Updates post selection.
-	
-	@param	id		<b>integer</b>		Post ID
-	@param	selected	<b>integer</b>		Is selected post
-	*/
 	public function updPostSelected($id,$selected)
-	{
-		$this->updPostsSelected($id,$selected);
-	}
-	
-	/**
-	Updates posts selection.
-	
-	@param	ids		<b>mixed</b>		Post(s) ID(s)
-	@param	selected	<b>integer</b>		Is selected post(s)
-	*/
-	public function updPostsSelected($ids,$selected)
 	{
 		if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
@@ -1327,14 +1264,21 @@
 		}
 		
-		$posts_ids = dcUtils::cleanIds($ids);
+		$id = (integer) $id;
 		$selected = (boolean) $selected;
-		
-		$strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
-				"AND post_id ".$this->con->in($posts_ids);
 		
 		# If user is only usage, we need to check the post's owner
 		if (!$this->core->auth->check('contentadmin',$this->id))
 		{
-			$strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
+			$strReq = 'SELECT post_id '.
+					'FROM '.$this->prefix.'post '.
+					'WHERE post_id = '.$id.' '.
+					"AND blog_id = '".$this->con->escape($this->id)."' ".
+					"AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
+			
+			$rs = $this->con->select($strReq);
+			
+			if ($rs->isEmpty()) {
+				throw new Exception(__('You are not allowed to mark this entry as selected'));
+			}
 		}
 		
@@ -1344,74 +1288,6 @@
 		$cur->post_upddt = date('Y-m-d H:i:s');
 		
-		$cur->update($strReq);
-		$this->triggerBlog();
-	}
-	
-	/**
-	Updates post category. <var>$cat_id</var> can be null.
-	
-	@param	id		<b>integer</b>		Post ID
-	@param	cat_id	<b>integer</b>		Category ID
-	*/
-	public function updPostCategory($id,$cat_id)
-	{
-		$this->updPostsCategory($id,$cat_id);
-	}
-	
-	/**
-	Updates posts category. <var>$cat_id</var> can be null.
-	
-	@param	ids		<b>mixed</b>		Post(s) ID(s)
-	@param	cat_id	<b>integer</b>		Category ID
-	*/
-	public function updPostsCategory($ids,$cat_id)
-	{
-		if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
-			throw new Exception(__('You are not allowed to change this entry category'));
-		}
-		
-		$posts_ids = dcUtils::cleanIds($ids);
-		$cat_id = (integer) $cat_id;
-		
-		$strReq = "WHERE blog_id = '".$this->con->escape($this->id)."' ".
-				"AND post_id ".$this->con->in($posts_ids);
-		
-		# If user is only usage, we need to check the post's owner
-		if (!$this->core->auth->check('contentadmin',$this->id))
-		{
-			$strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
-		}
-		
-		$cur = $this->con->openCursor($this->prefix.'post');
-		
-		$cur->cat_id = ($cat_id ? $cat_id : null);
-		$cur->post_upddt = date('Y-m-d H:i:s');
-		
-		$cur->update($strReq);
-		$this->triggerBlog();
-	}
-	
-	/**
-	Updates posts category. <var>$new_cat_id</var> can be null.
-	
-	@param	old_cat_id	<b>integer</b>		Old category ID
-	@param	new_cat_id	<b>integer</b>		New category ID
-	*/
-	public function changePostsCategory($old_cat_id,$new_cat_id)
-	{
-		if (!$this->core->auth->check('contentadmin,categories',$this->id)) {
-			throw new Exception(__('You are not allowed to change entries category'));
-		}
-		
-		$old_cat_id = (integer) $old_cat_id;
-		$new_cat_id = (integer) $new_cat_id;
-		
-		$cur = $this->con->openCursor($this->prefix.'post');
-		
-		$cur->cat_id = ($new_cat_id ? $new_cat_id : null);
-		$cur->post_upddt = date('Y-m-d H:i:s');
-		
 		$cur->update(
-			'WHERE cat_id = '.$old_cat_id.' '.
+			'WHERE post_id = '.$id.' '.
 			"AND blog_id = '".$this->con->escape($this->id)."' "
 		);
@@ -1420,4 +1296,47 @@
 	
 	/**
+	Updates post category. <var>$cat_id</var> can be null.
+	
+	@param	id		<b>integer</b>		Post ID
+	@param	cat_id	<b>integer</b>		Category ID
+	*/
+	public function updPostCategory($id,$cat_id)
+	{
+		if (!$this->core->auth->check('usage,contentadmin',$this->id)) {
+			throw new Exception(__('You are not allowed to change this entry category'));
+		}
+		
+		$id = (integer) $id;
+		$cat_id = (integer) $cat_id;
+		
+		# If user is only usage, we need to check the post's owner
+		if (!$this->core->auth->check('contentadmin',$this->id))
+		{
+			$strReq = 'SELECT post_id '.
+					'FROM '.$this->prefix.'post '.
+					'WHERE post_id = '.$id.' '.
+					"AND blog_id = '".$this->con->escape($this->id)."' ".
+					"AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
+			
+			$rs = $this->con->select($strReq);
+			
+			if ($rs->isEmpty()) {
+				throw new Exception(__('You are not allowed to change this entry category'));
+			}
+		}
+		
+		$cur = $this->con->openCursor($this->prefix.'post');
+		
+		$cur->cat_id = ($cat_id ? $cat_id : null);
+		$cur->post_upddt = date('Y-m-d H:i:s');
+		
+		$cur->update(
+			'WHERE post_id = '.$id.' '.
+			"AND blog_id = '".$this->con->escape($this->id)."' "
+		);
+		$this->triggerBlog();
+	}
+	
+	/**
 	Deletes a post.
 	
@@ -1425,14 +1344,4 @@
 	*/
 	public function delPost($id)
-	{
-		$this->delPosts($id);
-	}
-	
-	/**
-	Deletes multiple posts.
-	
-	@param	ids		<b>mixed</b>		Post(s) ID(s)
-	*/
-	public function delPosts($ids)
 	{
 		if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
@@ -1440,19 +1349,30 @@
 		}
 		
-		$posts_ids = dcUtils::cleanIds($ids);
-		
-		if (empty($posts_ids)) {
+		$id = (integer) $id;
+		
+		if (empty($id)) {
 			throw new Exception(__('No such entry ID'));
 		}
-		
-		$strReq = 'DELETE FROM '.$this->prefix.'post '.
-				"WHERE blog_id = '".$this->con->escape($this->id)."' ".
-				"AND post_id ".$this->con->in($posts_ids);
 		
 		#If user can only delete, we need to check the post's owner
 		if (!$this->core->auth->check('contentadmin',$this->id))
 		{
-			$strReq .= "AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
-		}
+			$strReq = 'SELECT post_id '.
+					'FROM '.$this->prefix.'post '.
+					'WHERE post_id = '.$id.' '.
+					"AND blog_id = '".$this->con->escape($this->id)."' ".
+					"AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
+			
+			$rs = $this->con->select($strReq);
+			
+			if ($rs->isEmpty()) {
+				throw new Exception(__('You are not allowed to delete this entry'));
+			}
+		}
+		
+		
+		$strReq = 'DELETE FROM '.$this->prefix.'post '.
+				'WHERE post_id = '.$id.' '.
+				"AND blog_id = '".$this->con->escape($this->id)."' ";
 		
 		$this->con->execute($strReq);
@@ -1926,6 +1846,5 @@
 		
 		if (isset($params['comment_ip'])) {
-			$comment_ip = $this->con->escape(str_replace('*','%',$params['comment_ip']));
-			$strReq .= "AND comment_ip LIKE '".$comment_ip."' ";
+			$strReq .= "AND comment_ip = '".$this->con->escape($params['comment_ip'])."' ";
 		}
 		
@@ -2100,60 +2019,11 @@
 	public function updCommentStatus($id,$status)
 	{
-		$this->updCommentsStatus($id,$status);
-	}
-	
-	/**
-	Updates comments status.
-	
-	@param	ids		<b>mixed</b>		Comment(s) ID(s)
-	@param	status	<b>integer</b>		Comment status
-	*/
-	public function updCommentsStatus($ids,$status)
-	{
 		if (!$this->core->auth->check('publish,contentadmin',$this->id)) {
 			throw new Exception(__("You are not allowed to change this comment's status"));
 		}
 		
-		$co_ids = dcUtils::cleanIds($ids);
-		$status = (integer) $status;
-		
-		$strReq = 
-			'UPDATE '.$this->prefix.'comment tc ';
-		
-		# mySQL uses "JOIN" synthax
-		if ($this->con->driver() == 'mysql') {
-			$strReq .= 
-				'JOIN '.$this->prefix.'post tp ON tc.post_id = tp.post_id ';
-		}
-		
-		$strReq .= 
-			'SET comment_status = '.$status.' ';
-		
-		# pgSQL uses "FROM" synthax
-		if ($this->con->driver() != 'mysql') {
-			$strReq .= 
-				'FROM '.$this->prefix.'post tp ';
-		}
-		
-		$strReq .=
-			"WHERE blog_id = '".$this->con->escape($this->id)."' ".
-			'AND comment_id'.$this->con->in($co_ids);
-		
-		# add pgSQL "WHERE" clause
-		if ($this->con->driver() != 'mysql') {
-			$strReq .= 
-				'AND tc.post_id = tp.post_id ';
-		}
-		
-		#If user is only usage, we need to check the post's owner
-		if (!$this->core->auth->check('contentadmin',$this->id))
-		{
-			$strReq .= 
-				"AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
-		}
-		
-		$this->con->execute($strReq);
-		$this->triggerComments($co_ids);
-		$this->triggerBlog();
+		$cur = $this->con->openCursor($this->prefix.'comment');
+		$cur->comment_status = (integer) $status;
+		$this->updComment($id,$cur);
 	}
 	
@@ -2164,14 +2034,4 @@
 	*/
 	public function delComment($id)
-	{
-		$this->delComments($id);
-	}
-	
-	/**
-	Delete comments
-	
-	@param	ids		<b>mixed</b>		Comment(s) ID(s)
-	*/
-	public function delComments($ids)
 	{
 		if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
@@ -2179,73 +2039,31 @@
 		}
 		
-		$co_ids = dcUtils::cleanIds($ids);
-		
-		if (empty($ids)) {
+		$id = (integer) $id;
+		
+		if (empty($id)) {
 			throw new Exception(__('No such comment ID'));
 		}
-		
-		# mySQL uses "INNER JOIN" synthax
-		if ($this->con->driver() == 'mysql') {
-			$strReq = 
-				'DELETE FROM tc '.
-				'USING '.$this->prefix.'comment tc '.
-				'INNER JOIN '.$this->prefix.'post tp ';
-		}
-		# pgSQL uses nothing special
-		else {
-			$strReq = 
-				'DELETE FROM '.$this->prefix.'comment tc '.
-				'USING '.$this->prefix.'post tp ';
-		}
-		
-		$strReq .= 
-			'WHERE tc.post_id = tp.post_id '.
-			"AND tp.blog_id = '".$this->con->escape($this->id)."' ".
-			'AND comment_id'.$this->con->in($co_ids);
 		
 		#If user can only delete, we need to check the post's owner
 		if (!$this->core->auth->check('contentadmin',$this->id))
 		{
-			$strReq .= 
-				"AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
-		}
-		
-		$this->con->execute($strReq);
-		$this->triggerComments($co_ids,true);
-		$this->triggerBlog();
-	}
-
-	public function delJunkComments()
-	{
-		if (!$this->core->auth->check('delete,contentadmin',$this->id)) {
-			throw new Exception(__('You are not allowed to delete comments'));
-		}
-		
-		# mySQL uses "INNER JOIN" synthax
-		if ($this->con->driver() == 'mysql') {
-			$strReq = 
-				'DELETE FROM tc '.
-				'USING '.$this->prefix.'comment tc '.
-				'INNER JOIN '.$this->prefix.'post tp ';
-		}
-		# pgSQL uses nothing special
-		else {
-			$strReq = 
-				'DELETE FROM '.$this->prefix.'comment tc '.
-				'USING '.$this->prefix.'post tp ';
-		}
-		
-		$strReq .= 
-			'WHERE tc.post_id = tp.post_id '.
-			"AND tp.blog_id = '".$this->con->escape($this->id)."' ".
-			'AND comment_status = -2';
-		
-		#If user can only delete, we need to check the post's owner
-		if (!$this->core->auth->check('contentadmin',$this->id))
-		{
-			$strReq .= 
-				"AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
-		}
-		
+			$strReq = 'SELECT P.post_id '.
+					'FROM '.$this->prefix.'post P, '.$this->prefix.'comment C '.
+					'WHERE P.post_id = C.post_id '.
+					"AND P.blog_id = '".$this->con->escape($this->id)."' ".
+					'AND comment_id = '.$id.' '.
+					"AND user_id = '".$this->con->escape($this->core->auth->userID())."' ";
+			
+			$rs = $this->con->select($strReq);
+			
+			if ($rs->isEmpty()) {
+				throw new Exception(__('You are not allowed to delete this comment'));
+			}
+		}
+		
+		$strReq = 'DELETE FROM '.$this->prefix.'comment '.
+				'WHERE comment_id = '.$id.' ';
+		
+		$this->triggerComment($id,true);
 		$this->con->execute($strReq);
 		$this->triggerBlog();
Index: inc/core/class.dc.core.php
===================================================================
--- inc/core/class.dc.core.php	(revision 706)
+++ inc/core/class.dc.core.php	(revision 1056)
@@ -39,4 +39,5 @@
 	public $rest;		///< <b>dcRestServer</b>	dcRestServer object
 	public $log;		///< <b>dcLog</b>			dcLog object
+	public $tpl;		///< <b>Twig_Environment</b>	Twig_Environment object
 	
 	private $versions = null;
@@ -95,4 +96,6 @@
 		$this->addFormater('xhtml', create_function('$s','return $s;'));
 		$this->addFormater('wiki', array($this,'wikiTransform'));
+		
+		$this->loadTemplateEnvironment();
 	}
 	
@@ -118,4 +121,39 @@
 	}
 	
+	/**
+	Create template environment (Twig_Environment instance)
+	
+	default-templates path must be added from admin|public/prepend.php with:
+	$core->tpl->getLoader()->addPath('PATH_TO/default-templates');
+	Selected theme path must be added with:
+	$core->tpl->getLoader()->prependPath('PATH_TO/MY_THEME');
+	*/
+	protected function loadTemplateEnvironment()
+	{
+		# If cache dir is writable, use it.
+		$cache_dir = dirname(DC_TPL_CACHE.'/twtpl');
+		if (!is_dir($cache_dir)) {
+			try {
+				files::makeDir($cache_dir);
+			} catch (Exception $e) {
+				$cache_dir = false;
+			}
+		}
+		
+		$this->tpl = new Twig_Environment(
+			new Twig_Loader_Filesystem(dirname(__FILE__).'/../swf'),
+			array(
+				'auto_reload' => true,
+				'autoescape' => 'html',
+				'base_template_class' => 'Twig_Template',
+				'cache' => $cache_dir, 
+				'charset' => 'UTF-8',
+				'debug' => DC_DEBUG,
+				'optimizations' => -1,
+				'strict_variables' => 0 //DC_DEBUG // Please fix undefined variables!
+			)
+		);
+		$this->tpl->addExtension(new dcFormExtension($this));
+	}
 	
 	/// @name Blog init methods
Index: inc/core/class.dc.twig.page.php
===================================================================
--- inc/core/class.dc.twig.page.php	(revision 1014)
+++ inc/core/class.dc.twig.page.php	(revision 1014)
@@ -0,0 +1,65 @@
+<?php
+
+// common to public and admin sides @see inc/admin/prepend.php
+class dcTwigPage extends Twig_Environment
+{
+	protected $core;
+	protected $context = null;
+	
+	public function __construct($default_tpl_dir,$cache_dir,$context,$core)
+	{
+		$this->core =& $core;
+		
+		# Twig Loader
+		$loader = new Twig_Loader_Filesystem($this->checkDefaultTemplateDir($default_tpl_dir));
+		
+		# Twig Environment options
+		$options = array(
+			'auto_reload' => true,
+			'base_template_class' => 'Twig_Template',
+			'cache' => $this->setCacheDir($cache_dir),
+			'charset' => 'UTF-8',
+			'debug' => DC_DEBUG,
+			'optimizations' => -1
+		);
+		
+		# Twig Environment
+		parent::__construct($loader,$options);
+		
+		# Add context helper (public vs admin)
+		if ($context instanceof Twig_ExtensionInterface) {
+			$this->context = $context;
+			$this->addExtension($context);
+		}
+		
+		# Add form helper
+		$this->addExtension(new dcFormExtension($core));
+		
+		$this->clearCacheFiles();
+	}
+	
+	protected function checkDefaultTemplateDir($dir)
+	{
+		$dir = path::real($dir,false);
+		
+		return is_dir($dir) ? $dir : false;
+	}
+	
+	protected function setCacheDir($dir)
+	{
+		try {
+			$dir = path::real($dir,false);
+			files::makeDir($dir,true);
+			return $dir;
+		}
+		catch(Exception $e) { }
+		
+		return false;
+	}
+	
+	public function getContext()
+	{
+		return $this->context;
+	}
+}
+?>
Index: inc/core/class.dc.utils.php
===================================================================
--- inc/core/class.dc.utils.php	(revision 1030)
+++ inc/core/class.dc.utils.php	(revision 270)
@@ -49,29 +49,4 @@
 		return $user_id;
 	}
-	
-	/**
-	Cleanup a list of IDs
-	
-	@param	ids			<b>mixed</b>	ID(s)
-	@return	<b>array</b>
-	*/
-	public static function cleanIds($ids)
-	{
-		$clean_ids = array();
-		
-		if (!is_array($ids)) {
-			$ids = array($ids);
-		}
-		
-		foreach($ids as $id)
-		{
-			$id = abs((integer) $id);
-			
-			if (!empty($id)) {
-				$clean_ids[] = $id;
-			}
-		}
-		return $clean_ids;
-	}
 }
 
