]> _ Git - cubeextranet.git/commitdiff
wait #3270 @1
authorvincent@cubedesigners.com <vincent@cubedesigners.com@f5622870-0f3c-0410-866d-9cb505b7a8ef>
Wed, 18 Dec 2019 18:14:52 +0000 (18:14 +0000)
committervincent@cubedesigners.com <vincent@cubedesigners.com@f5622870-0f3c-0410-866d-9cb505b7a8ef>
Wed, 18 Dec 2019 18:14:52 +0000 (18:14 +0000)
inc/commons/class.common.ajax.php
inc/ws/Controlleur/class.ws.ajax.php
inc/ws/DAO/class.ws.dao.book.php

index 47fae4be1c18275ea237123031c7630f868f4e5c..18ccee259533177c6dd1fe0e2f198cffd6c3677d 100644 (file)
@@ -583,7 +583,7 @@ Mot de passe : $password";
 
     public static function _formatWsReferenceRef($ref, $type)
     {
-        if ($type == '10doigts') {
+        if ($type === '10doigts') {
             if (stripos($ref, 'ic') === 0) {
                 return 'C' . substr($ref, 2);
             }
index 33442d1ea48c4690e8312816dc380c451aeaca0a..dc1091798e9ee46af2abfa2e334cd4657df6c75f 100644 (file)
@@ -1316,6 +1316,7 @@ class wsAjax extends cubeAjax
     public static function importFluidbookSettings($args, &$x)
     {
         global $core;
+
         $dao = new wsDAOBook($core->con);
 
         new PHPExcel();
@@ -1326,7 +1327,11 @@ class wsAjax extends cubeAjax
         $ignore = wsUrl::getReadonlySettings();
 
         $sheet = $xls->getActiveSheet()->toArray();
+
         $nlines = count($sheet);
+
+        $x->addDebug($nlines);
+
         for ($i = 1; $i < $nlines; $i++) {
             $line = $sheet[$i];
             $id = (int)$line[0];
@@ -1341,7 +1346,14 @@ class wsAjax extends cubeAjax
                 }
                 $settings[$col] = $v;
             }
-            $dao->setSettings($id, $settings);
+          //  $x->addDebug($id.' : '.json_encode($settings));
+
+            try {
+                $dao->setSettings($id, $settings);
+            }catch (Exception $e){
+                $x->addDebug($e->getMessage());
+            }
         }
+        $x->addAlert(__('Paramètres importés'));
     }
 }
\ No newline at end of file
index 5a43a0a20e67e28fd06162140c2e38967a0fc114..4d13e4008d66fa08108b91c5068038eae5dbbded 100644 (file)
 class wsDAOBook extends commonDAO
 {
 
-       public static $pagesOfBookCache = array();
-
-       /**
-        * wsDAOBook::singleton()
-        *
-        * @param mixed $r
-        * @return
-        */
-       protected function singleton($r)
-       {
-               $book = new wsBook();
-               $book->book_id = $r->book_id;
-               $book->cid = $r->cid;
-               $book->nom = $r->nom;
-               $book->lang = $r->lang;
-               $book->theme = $r->theme;
-               $book->proprietaire = $r->proprietaire_nom;
-               $book->proprietaire_id = $r->proprietaire_id;
-               $book->proprietaire_utilisateur = $r->proprietaire_utilisateur;
-               $book->hash = $r->hash;
-               $book->compteur_visites = $r->compteur_visites;
-               $book->status = $r->status;
-               $book->date_status = $r->date_status;
-               $book->date = $r->date;
-               $book->pages = array();
-               $book->chapters = $r->chapters;
-               $book->traductions = $r->traductions;
-               $book->specialLinks = $r->specialLinks;
-               $book->specialRulers = $r->specialRulers;
-               $book->parametres = $r->parametres;
-               $book->extras = $r->extras;
-               $book->numerotation = $r->numerotation;
-               $book->changedate = $r->changedate;
-               $book->compiledate = $r->compiledate;
-               $book->compile1date = $r->compile1date;
-               $book->compilehtml5date = $r->compilehtml5date;
-               $book->facturable = $r->facturable;
-               $book->facturable_id = $r->facturable_id;
-               $book->tache = $r->tache;
-               if (isset($r->projet)) {
-                       $book->projet = $r->projet;
-               }
-               $book->version = $r->version;
-               $book->composition_update = $r->composition_update;
-               $book->dir_references = $r->dir_references;
-               $book->dir_hosting = $r->dir_hosting;
-               $book->dir_macbook_phonegap_ios = $r->dir_macbook_phonegap_ios;
-               $book->dir_phonegap_android = $r->dir_phonegap_android;
-               $book->dir_external = $r->dir_external;
-               $book->demo_counter = $r->demo_counter;
-               $book->exportdatas = $r->exportdatas;
-
-               return $book;
-       }
-
-       protected function cree($r)
-       {
-               $book = new wsBook();
-               $book->book_id = 'new';
-               $book->nom = '';
-               $book->cid = null;
-               $book->lang = 'fr';
-               $book->theme = 1;
-               $book->proprietaire = '';
-               $book->proprietaire_id = 0;
-               $book->hash = '';
-               $book->compteur_visites = 20;
-               $book->status = 0;
-               $book->date_status = TIME;
-               $book->date = TIME;
-               $book->composition_update = TIME;
-               $book->chapters = json_encode(array());
-               $book->parametres = new wsBookParametres();
-               $book->tache = 0;
-               $book->pages = array();
-               $book->version = 2;
-               return $book;
-       }
-
-       protected function getNextId()
-       {
-               $r = $this->con->select('SELECT MAX(book_id) AS book_id FROM books');
-               if ($r->book_id < 10000) {
-                       return 10000;
-               }
-               return $r->book_id + 1;
-       }
-
-       public function saveExportDatas($book_id, $datas)
-       {
-               $c = $this->con->openCursor('books');
-               $c->exportdatas = json_encode($datas);
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function addDemoCount($book_id)
-       {
-
-               $r = $this->con->select('SELECT demo_counter,nom FROM books WHERE book_id=\'' . $book_id . '\'');
-               $m = 20;
-               if ($r->demo_counter > 0 && $r->demo_counter % $m == 0) {
-                       $mail = new cubeMail();
-                       $mail->charset = 'UTF-8';
-                       $mail->from = 'contact@fluidbook.com';
-                       $mail->to = 'tech@fluidbook.com';
-                       $mail->subject = '[Fluidbook Workshop] Fluidbook consulté via l\'url publique';
-                       $mail->body = 'Le fluidbook suivant a été consulté ' . $m . ' fois (et ' . $r->demo_counter . ' au total) via l\'url publique : ' . "\r\n" .
-                               'Fluidbook # ' . $book_id . ' - ' . $r->nom;
-                       $mail->send();
-               }
-
-               $this->con->select('UPDATE books SET demo_counter=demo_counter+1 WHERE book_id=\'' . $book_id . '\'');
-       }
-
-       public function selectByIds($book_ids = array(), $simple = false)
-       {
-               if ($simple) {
-                       $table = 'books';
-               } else {
-                       $table = 'books_vue';
-               }
-
-               $ids = array();
-               foreach ($book_ids as $bid) {
-                       fb($bid);
-                       if (intval($bid) > 0) {
-                               $ids[] = $bid;
-                       }
-               }
-
-               $sql = 'SELECT * FROM ' . $table . ' WHERE book_id IN (' . implode(',', $ids) . ')';
-               $books = $this->factory($this->con->select($sql));
-               $res = array();
-               foreach ($books as $book) {
-                       $res[$book->book_id] = $book;
-               }
-               return $res;
-       }
-
-       public function selectById($book_id = null, $simple = false)
-       {
-               if (is_null($book_id)) {
-                       return $this->cree();
-               }
-               if ($simple) {
-                       $table = 'books';
-               } else {
-                       $table = 'books_vue';
-               }
-               $sql = 'SELECT * FROM ' . $table . ' WHERE book_id=\'' . $this->con->escape($book_id) . '\' LIMIT 1';
-               $r = $this->con->select($sql);
-               return $this->singleton($r);
-       }
-
-       public function selectByCid($cid = null, $simple = false)
-       {
-               if ($simple) {
-                       $table = 'books';
-               } else {
-                       $table = 'books_vue';
-               }
-
-               $sql = 'SELECT * FROM ' . $table . ' WHERE cid LIKE BINARY \'' . $this->con->escape($cid) . '\' LIMIT 1';
-               $r = $this->con->select($sql);
-               return $this->singleton($r);
-       }
-
-       public function selectLuceneToDo()
-       {
-               $sql = 'SELECT * FROM books_vue WHERE lucene_time<composition_update AND version=2 ORDER BY book_id ASC LIMIT 1';
-               $r = $this->con->select($sql);
-               return $this->factory($r);
-       }
-
-       public function selectLuceneTimeNotSet()
-       {
-               $sql = 'SELECT * FROM books_vue WHERE lucene_time=0 AND version=2';
-               $r = $this->con->select($sql);
-               return $this->factory($r);
-       }
-
-       /**
-        * wsDAOBook::sauve()
-        *
-        * @param mixed $createur
-        * @param mixed $data
-        * @return
-        */
-       public function sauve($createur, $data)
-       {
-               $c = $this->con->openCursor('books');
-               if (isset($data['nom'])) {
-                       $c->nom = $data['nom'];
-               }
-               if (isset($data['lang'])) {
-                       $c->lang = $data['lang'];
-               }
-               if (isset($data['theme'])) {
-                       $c->theme = $data['theme'];
-               }
-               if (isset($data['proprietaire'])) {
-                       $c->proprietaire = $data['proprietaire'];
-               }
-
-               if ($data['book_id'] == 'new' || $data['book_id'] == '') {
-                       $c->date = TIME;
-                       $c->hash = md5(rand(0, 123456789365469));
-                       $c->compteur_visites = 20;
-                       $c->parametres = serialize(new wsParametres());
-                       $c->changedate = TIME;
-                       $book_id = $c->book_id = $this->getNextId();
-
-                       $c->insert();
-               } else {
-                       $c->changedate = TIME;
-                       $book_id = $data['book_id'];
-                       $c->update('WHERE book_id=\'' . $this->con->escape($data['book_id']) . '\'');
-               }
-
-               if (isset(self::$pagesOfBookCache[$book_id])) {
-                       unset(self::$pagesOfBookCache[$book_id]);
-               }
-
-               return $this->selectById($book_id);
-       }
-
-       public function duplicate($book_id, $createur, $nom = null, $pages = false, $complete = false)
-       {
-               $r = $this->con->select('SELECT * FROM books_vue WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-
-               $old_id = $book_id;
-
-
-               $parametres = unserialize($r->parametres);
-               $parametres->setParent($this);
-               if (null === $nom) {
-                       $nom = $parametres->title;
-               }
-               $parametres->title = $nom;
-
-               if (!$complete) {
-                       $parametres->pdfReplace = '';
-               }
-
-               $c = $this->con->openCursor('books');
-               $c->proprietaire = $createur;
-               $c->date = TIME;
-               $c->hash = md5(rand(0, 1234567893));
-               $c->cid = $this->generateCID();
-               $c->compteur_visites = 20;
-               $c->status = -1;
-               $c->date_status = TIME;
-               $c->lang = $r->lang;
-               $c->parametres = serialize($parametres);
-               $c->nom = $nom;
-               $c->theme = $r->theme;
-               $c->changedate = TIME;
-               $c->compiledate = 0;
-               $c->version = 2;
-               $c->traductions = $r->traductions;
-               $c->specialLinks = $r->specialLinks;
-               $c->specialRulers = $r->specialRulers;
-               $c->composition_update = TIME;
-               $book_id = $c->book_id = $this->getNextId();
-               if ($pages) {
-                       $c->numerotation = $r->numerotation;
-                       $c->chapters = $r->chapters;
-                       $this->con->execute('INSERT INTO book_pages SELECT ' . $book_id . ' AS book_id,book_page,document_id,document_page FROM book_pages WHERE book_id=' . $old_id);
-               }
-               if ($complete) {
-                       $c->numerotation = $r->numerotation;
-                       $c->chapters = $r->chapters;
-               }
-               $c->insert();
-
-               $this->saveCompositionVersion($book_id);
-
-               return $this->selectById($book_id);
-       }
-
-       public function creeEmpty($createur, $lang, $nom)
-       {
-               $c = $this->con->openCursor('books');
-
-               $parametres = new wsBookParametres($this);
-               $parametres->title = $nom;
-
-               $c->proprietaire = $createur;
-               $c->cid = $this->generateCID();
-               $c->nom = $nom;
-               $c->date = TIME;
-               $c->hash = md5(rand(0, 1234567893));
-               $c->compteur_visites = 20;
-               $c->status = -1;
-               $c->date_status = TIME;
-               $c->parametres = serialize($parametres);
-
-               $c->theme = 1;
-               $c->lang = $lang;
-               $c->changedate = TIME;
-               $c->compiledate = 0;
-               $c->version = 2;
-               $c->composition_update = TIME;
-               $book_id = $c->book_id = $this->getNextId();
-               $c->insert();
-               return $this->selectById($book_id);
-       }
-
-       public function supprime($book_id)
-       {
-               $this->con->execute('DELETE FROM book_pages_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-               $this->con->execute('DELETE FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-               return $this->con->execute('DELETE FROM books WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function count($limitedToUserRights = false)
-       {
-               $filters = $this->makeWhereFromFiltres();
-               if ($filters == '1=1') {
-                       $table = 'books';
-               } else {
-                       $table = 'books_vue';
-               }
-
-               $where = '(' . $filters . ')';
-               $where .= $this->limitToUserRights($limitedToUserRights);
-               $r = $this->con->select('SELECT COUNT(*) AS nb FROM ' . $table . ' WHERE ' . $where);
-               return $r->nb;
-       }
-
-       public function getPagesOfBookAt($book_id, $time)
-       {
-               $r = $this->con->select('SELECT * FROM book_pages_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\' ORDER BY `update` ASC');
-               if (!$r->count()) {
-                       return $this->getPagesOfBook($book_id);
-               }
-               if ($r->count() == 1) {
-                       $pages = unserialize($r->composition);
-                       if (null === $pages || !count($pages)) {
-                               return $this->getPagesOfBook($book_id);
-                       }
-                       return $pages;
-               }
-
-               $pages = null;
-               while ($r->fetch()) {
-                       if ($r->update > $time) {
-
-                               if (is_null($pages)) {
-                                       return $this->getPagesOfBook($book_id);
-                               }
-                               $res = unserialize($pages);
-                               if (null === $res || !count($res)) {
-                                       return $this->getPagesOfBook($book_id);
-                               }
-                               return $res;
-                       }
-                       if (!count(unserialize($r->composition))) {
-                               continue;
-                       }
-                       $pages = $r->composition;
-               }
-
-               $res = unserialize($pages);
-               if (null === $res || !count($res)) {
-                       return $this->getPagesOfBook($book_id);
-               }
-               return $res;
-       }
-
-       public function getDocumentsToUpdate($book_id)
-       {
-               $res = array();
-               $r = $this->con->select('SELECT DISTINCT d.document_id FROM book_pages b,documents d WHERE b.book_id=\'' . $this->con->escape($book_id) . '\' AND d.version=1 AND b.document_id=d.document_id');
-               while ($r->fetch()) {
-                       $res[] = $r->document_id;
-               }
-               return $res;
-       }
-
-       public function getPagesOfBook($book_id, $conversion = true, $force = false)
-       {
-               if ($force || !isset(self::$pagesOfBookCache[$book_id])) {
-                       $pages = array();
-
-                       $sql = 'SELECT b.*,d.numberSections AS num,d.conversionInfos AS conversion,d.pages AS doc_pages,d.version AS version FROM book_pages b JOIN documents d ON d.document_id=b.document_id WHERE b.book_id=\'' . $this->con->escape($book_id) . '\' ORDER BY book_page';
-
-                       $r = $this->con->select($sql);
-                       while ($r->fetch()) {
-                               $n = explode(',', $r->num);
-
-                               if (isset($n[$r->document_page - 1])) {
-                                       $num = $n[$r->document_page - 1];
-                               } else {
-                                       $num = '';
-                               }
-                               $pages[$r->book_page] = array('document_id' => $r->document_id,
-                                       'document_page' => $r->document_page,
-                                       'version' => $r->version,
-                                       'defaultNum' => $num,
-                                       'nb_pages' => $r->doc_pages
-                               );
-
-                               if ($conversion) {
-                                       if ($r->conversion != '') {
-                                               $c = unserialize($r->conversion);
-                                               $c = $c->pages[$r->document_page];
-                                       }
-                                       $qp = array('resolution', 'method', 'quality', 'objects');
-                                       foreach ($qp as $p) {
-                                               if (isset($c) && isset($c->$p)) {
-                                                       $pages[$r->book_page][$p] = $c->$p;
-                                               }
-                                       }
-                               }
-                       }
-                       if (!count($pages)) {
-                               return [];
-                       }
-
-                       self::$pagesOfBookCache[$book_id] = $pages;
-               }
-               return self::$pagesOfBookCache[$book_id];
-       }
-
-       public function appendDocument($book_id, $document_id)
-       {
-               $r = $this->con->select('SELECT MAX(book_page) AS book_page FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-               $lastPage = is_null($r->book_page) ? 0 : $r->book_page;
-               $this->insertDocument($book_id, $lastPage, $document_id);
-       }
-
-       public function removePage($book_id, $book_page)
-       {
-               // Supprime la page
-               $this->con->execute('DELETE FROM book_pages WHERE book_page=\'' . $this->con->escape($book_page) . '\' AND book_id=\'' . $this->con->escape($book_id) . '\'');
-               // Décale les pages suivantes vers le haut
-               $this->decalePages($book_id, $book_page, -1);
-       }
-
-       public function insertPage($book_id, $after_page, $document_id, $document_page)
-       {
-               // Décale les pages vers le bas
-               $this->decalePages($book_id, $after_page, 1);
-               // Insère la page
-               $c = $this->con->openCursor('book_pages');
-               $c->book_id = $book_id;
-               $c->book_page = $after_page + 1;
-               $c->document_id = $document_id;
-               $c->document_page = $document_page;
-               $c->insert();
-       }
-
-       public function insertDocument($book_id, $after_page, $document_id)
-       {
-               // Obtiens le book
-               $book = $this->selectById($book_id);
-               $num = explode(',', $book->numerotation);
-               // Obtiens le nombre de pages
-               $r = $this->con->select('SELECT pages,numberSections FROM documents WHERE document_id=\'' . $this->con->escape($document_id) . '\'');
-               // Décale les pages vers le bas
-               if ($after_page > 0) {
-                       $this->decalePages($book_id, $after_page, $r->pages);
-               }
-               // Insère les pages
-               $c = $this->con->openCursor('book_pages');
-               $c->book_id = $book_id;
-               $c->document_id = $document_id;
-               for ($i = 1; $i <= $r->pages; $i++) {
-                       $c->document_page = $i;
-                       $c->book_page = $after_page + $i;
-                       $c->insert();
-               }
-               // Mets à jour la liste des numéros des pages
-               $before = array_slice($num, 0, $after_page);
-               $after = array_slice($num, $after_page, count($num) - $after_page);
-
-               $newnum = $r->numberSections;
-               if (trim($newnum, ',') == '') {
-                       // If no number detected, we create a numeric list from 1
-                       $between = range(1, $r->pages);
-               } else {
-                       // Else, we use numbers detected at conversion
-                       $between = explode(',', $r->numberSections);
-               }
-               $num = array_merge($before, $between, $after);
-               // Mets à jour la numerotation de la publication
-               $c = $this->con->openCursor('books');
-               $c->numerotation = implode(',', $num);
-               $c->composition_update = TIME;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-
-               $this->saveCompositionVersion($book_id);
-       }
-
-       protected function decalePages($book_id, $after_page, $decalage)
-       {
-               $decalage = ($decalage >= 0) ? '+' . $decalage : $decalage;
-               $this->con->execute('UPDATE book_pages SET book_page=book_page' . $decalage . ' WHERE book_page>' . $this->con->escape($after_page) . ' AND book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function getListe($orderby = null, $sens = null, $limit = null, $limitedToUserRights = false)
-       {
-               if (!is_null($this->q)) {
-                       $where = '(';
-                       if ($this->search_id) {
-                               $where .= ' book_id=\'' . $this->con->escape($this->q) . '\' OR ';
-                       }
-
-                       if (!cubeMath::is_int($this->q)) {
-                               $where .= 'nom LIKE \'%' . $this->con->escape($this->q) . '%\'';
-                               $daoClient = new commonDAOClient($this->con);
-                               $where .= ' OR proprietaire_id IN(' . $daoClient->querySearchByName($this->q) . ') OR ';
-                       }
-                       $limit = null;
-                       $where .= '1=2)';
-               } else {
-                       $where = '(' . $this->makeWhereFromFiltres() . ')';
-               }
-               $where .= $this->limitToUserRights($limitedToUserRights);
-
-               $orderby = is_null($orderby) ? 'book_id' : $orderby;
-               $sens = is_null($sens) ? 'DESC' : $sens;
-               $limit = is_null($limit) ? '' : $this->con->limit($limit);
-
-               $sql = 'SELECT * FROM books_vue WHERE ' . $where . ' ORDER BY ' . $orderby . ' ' . $sens . ' ' . $limit;
-               $r = $this->con->select($sql);
-               return $this->factory($r);
-       }
-
-       protected function limitToUserRights($utilisateur)
-       {
-               if ($utilisateur) {
-                       if (wsDroits::admin()) {
-                               return '';
-                       }
-                       return ' AND proprietaire IN (' . $utilisateur->ws_rights . ')';
-               }
-               return '';
-       }
-
-       protected function makeWhereFromFiltres()
-       {
-               if (!is_null($this->filtres)) {
-                       $w = array('1=1');
-                       if (commonFiltre::test('admin_book', $this->filtres)) {
-                               $w[] = 'super_admin IN (' . implode(',', array_keys($this->filtres['admin_book'])) . ')';
-                       }
-                       if (commonFiltre::test('status_book', $this->filtres)) {
-                               $w[] = 'status IN(' . implode(',', array_keys($this->filtres['status_book'])) . ')';
-                       }
-                       if (commonFiltre::test('revendeur_book', $this->filtres)) {
-                               $v = array_keys($this->filtres['revendeur_book']);
-                               $values = array();
-                               foreach ($v as $r) {
-                                       $values[] = $this->con->escape($r);
-                               }
-
-
-                               $w[] = 'facturable IN(\'' . implode('\',\'', $values) . '\')';
-                       }
-                       return implode(' AND ', $w);
-               } else {
-                       return '1=1';
-               }
-       }
-
-       public function setChapters($book_id, $json)
-       {
-               $chapters = json_decode($json, true);
-               $res = array();
-
-               foreach ($chapters as $c) {
-                       $c['label'] = trim($c['label']);
-                       $n = (string)$c['page'];
-                       $c['label'] = trim(preg_replace('|\s+' . $n . '$|iu', '', $c['label']));
-                       $res[] = $c;
-               }
-
-               $json_chapters = json_encode($res);
-
-               $c = $this->con->openCursor('books');
-               $c->chapters = $json_chapters;
-               $c->changedate = TIME;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-
-               if ($json_chapters && $json_chapters != '[]') {
-                       if (count($res) == 1) {
-                               if ($res[0]['label'] == '' && $res[0]['page'] == '') {
-                                       return;
-                               }
-                       }
-                       $c = $this->con->openCursor('books_chapters_versions');
-                       $c->book_id = $book_id;
-                       $c->chapters = $json_chapters;
-                       $c->time = TIME;
-                       $c->insert();
-               }
-       }
-
-       public function setSpecialLinksAndRulers($book_id, $links, $rulers)
-       {
-               $c1 = $this->con->openCursor('special_links_versions');
-               $c = $this->con->openCursor('books');
-
-               if (is_string($links)) {
-                       $links = json_encode(json_decode($links, false));
-               }
-               if (is_string($rulers)) {
-                       $rulers = json_encode(json_decode($rulers, false));
-               }
-
-
-               $links = wsLinks::encryptLinks(json_decode($links));
-
-
-               if (is_array($links)) {
-                       $links = json_encode($links);
-               }
-               if (is_array($rulers)) {
-                       $rulers = json_encode($rulers);
-               }
-
-               $c1->links = $c->specialLinks = $links;
-               $c1->rulers = $c->specialRulers = $rulers;
-               $c1->update = $c->changedate = TIME;
-               $c1->book_id = $book_id;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-               try {
-                       $c1->insert();
-               } catch (Exception $e) {
-                       try {
-                               $c1->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\' AND `update`=' . TIME);
-                       } catch (Exception $e) {
-
-                       }
-               }
-       }
-
-       public function setTheme($book_id, $theme)
-       {
-               $c = $this->con->openCursor('books');
-               $c->theme = $theme;
-               $c->changedate = TIME;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function setStatus($book_id, $status)
-       {
-               $c = $this->con->openCursor('books');
-               if ($status < 2) {
-                       $c->tache = 0;
-               }
-               $c->status = $status;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-               return $this->selectById($book_id);
-       }
-
-       public function setChaptersFromOldFluidbook($book_id)
-       {
-               $book = $this->selectById($book_id);
-               $n = explode(',', $book->numerotation);
-
-               $xml = simplexml_load_file('https://ws.fluidbook.com/books/' . $book_id . '/data/links.xml');
-               $res = array();
-               $chapters = $xml->xpath('//chapters');
-               foreach ($chapters as $ch) {
-                       $c = array();
-                       $c['label'] = (string)$ch->txt;
-
-                       $p = intval((string)$ch->page);
-                       if ($p <= 0) {
-                               continue;
-                       }
-                       $c['page'] = $n[$p];
-                       $c['level'] = intval((string)$ch->level);
-                       $res[] = $c;
-               }
-
-               $c = $this->con->openCursor('books');
-               $c->chapters = json_encode($res);
-               $c->changedate = TIME;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function saveCompositionVersion($book_id, $time = null)
-       {
-               $time = is_null($time) ? TIME : $time;
-
-               $pages = $this->getPagesOfBook($book_id, true, true);
-
-               $c = $this->con->openCursor('book_pages_versions');
-               $c->update = $time;
-               $c->book_id = $book_id;
-               $c->composition = serialize($pages);
-               $c->insert();
-       }
-
-       public function setLang($book_id, $base, $traductions)
-       {
-               // Cleanup user translations
-               $traductions = json_decode($traductions, true);
-               foreach ($traductions as $k => $v) {
-                       $traductions[$k] = $v;
-               }
-
-               $daoLang = new wsDAOLang($this->con);
-               $lang = $daoLang->selectById($base);
-               // Cleanup base translations
-               $baseTraductions = $lang->traductions;
-               foreach ($baseTraductions as $k => $v) {
-                       $baseTraductions[$k] = $v;
-               }
-               // Then compare them. If there is no differences, we don't save translations in the book
-               if ($traductions == $baseTraductions) {
-                       $t = '';
-               } else {
-                       $t = json_encode($traductions);
-               }
-
-               $c = $this->con->openCursor('books');
-               $c->lang = $base;
-               $c->traductions = $t;
-               $c->changedate = TIME;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function setSettings($book_id, $settings)
-       {
-               $book = $this->selectById($book_id);
-               $parametres = $book->parametres;
-               $new = $settings;
-               foreach ($new as $k => $v) {
-                       if ($k == '_empty_') {
-                               continue;
-                       }
-                       $parametres->$k = $v;
-               }
-
-               $ip = array();
-               if (isset($parametres->stats_exclude_ip) && trim($parametres->stats_exclude_ip) != '') {
-                       $list = $parametres->stats_exclude_ip;
-                       $list = str_replace("\r", "\n", $list);
-                       $e = explode("\n", $list);
-                       foreach ($e as $i) {
-                               $i = trim($i);
-                               if ($i == '') {
-                                       continue;
-                               }
-                               $long = ip2long($i);
-                               if ($long !== false) {
-                                       $ip[] = $long;
-                               }
-                       }
-               }
-
-               $file = '/home/stats/www/exclude/' . $book_id;
-
-               if (count($ip)) {
-                       file_put_contents($file, implode(',', $ip));
-                       chmod($file, 0777);
-                       chown($file, 'stats');
-               } else if (file_exists($file)) {
-                       unlink($file);
-               }
-
-               $c = $this->con->openCursor('books');
-               $c->nom = $parametres->title;
-               $c->parametres = serialize($parametres);
-               $c->changedate = TIME;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function setProprietaire($book_id, $proprietaire_id)
-       {
-               $c = $this->con->openCursor('books');
-               $c->proprietaire = $proprietaire_id;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function setTache($book_id, $tache)
-       {
-               $c = $this->con->openCursor('books');
-               $c->tache = $tache;
-               $c->status = 2;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function setVersion($book_id, $version)
-       {
-               $c = $this->con->openCursor('books');
-               $c->version = $version;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function touch($book_id)
-       {
-               $c = $this->con->openCursor('books');
-               $c->changedate = TIME;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function touchCompile($book_id, $version = 'all')
-       {
-               $c = $this->con->openCursor('books');
-               if ($version == '2') {
-                       $c->compiledate = TIME;
-               } elseif ($version == '1') {
-                       $c->compile1date = TIME;
-               } elseif ($version == 'html5') {
-                       $c->compilehtml5date = TIME;
-               } else {
-                       $c->compiledate = TIME;
-                       $c->compile1date = TIME;
-                       $c->compilehtml5date = TIME;
-               }
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function isUpToDate($book, $version)
-       {
-               $version = (string)$version;
-               if ($version == '2') {
-                       if (!file_exists(WS_BOOKS . '/final/' . $book->book_id)) {
-                               return false;
-                       }
-                       if ($book->compiledate < $book->changedate) {
-                               return false;
-                       }
-               } else if ($version == '1') {
-                       // V1
-                       if (!file_exists(WS_BOOKS . '/finalv1/' . $book->book_id . '/index.swf')) {
-                               return false;
-                       }
-                       if ($book->compile1date < $book->changedate) {
-                               return false;
-                       }
-               } else if ($version == 'html5') {
-                       return false;
-                       // HTML5
-                       $checks = array($book->changedate, cubeFiles::filemtimeRecursive(WS_BOOKS . '/working/' . $book->book_id), cubeFiles::filemtimeRecursive(WS_COMPILE_ASSETS . '/_html5'), cubeFiles::filemtimeRecursive(ROOT . '/inc/ws/Util/html5'));
-                       foreach ($checks as $check) {
-                               if ($check > $book->compilehtml5date) {
-                                       return false;
-                               }
-                       }
-               }
-               return true;
-       }
-
-       public function setComposition($book_id, $pages)
-       {
-               $numerotation = array();
-               $nb_pages = 0;
-               foreach ($pages as $p) {
-                       $numerotation[] = $p->virtual;
-                       $nb_pages++;
-               }
-
-               $book = $this->selectById($book_id);
-               $parametres = $book->parametres;
-               $parametres->pages = $nb_pages;
-
-               $c = $this->con->openCursor('books');
-               $c->parametres = serialize($parametres);
-               $c->numerotation = implode(',', $numerotation);
-               $c->changedate = TIME;
-
-               // Check if composition need to be updated
-               $r = $this->con->select('SELECT * FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-               $tab = array();
-               $now = array();
-               $ref = array();
-               while ($r->fetch()) {
-                       $ref[$r->book_page] = array((int)$r->document_id, (int)$r->document_page);
-               }
-               $i = 1;
-               foreach ($pages as $p) {
-                       $now[$i] = array((int)$p->document_id, (int)$p->document_page);
-                       $i++;
-               }
-               if ($now != $ref) {
-                       $this->con->execute('DELETE FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-
-                       $c1 = $this->con->openCursor('book_pages');
-                       $c1->book_id = $book_id;
-                       $i = 1;
-                       foreach ($pages as $p) {
-                               $c1->document_id = $p->document_id;
-                               $c1->document_page = $p->document_page;
-                               $c1->book_page = $i;
-                               $c1->insert();
-                               $i++;
-                       }
-                       $c->composition_update = TIME;
-                       $this->saveCompositionVersion($book_id);
-               }
-
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function setInstallDir($book_id, $dir, $server)
-       {
-               $col = 'dir_' . $server;
-
-               $c = $this->con->openCursor('books');
-               $c->$col = $dir;
-               $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
-       }
-
-       public function makeTextsIndexes($book, $pages, &$index, &$textes, $simple = false)
-       {
-               global $core;
-               $prefix = '';
-               if ($book->parametres->textExtraction == 'poppler') {
-                       $prefix = 'p';
-               } else if ($book->parametres->textExtraction == 'fluidbook') {
-                       $prefix = 'f';
-               }
-
-               $dir = WS_BOOKS . '/index/' . $book->book_id;
-               if ($book->parametres->ignoreSearchSeparators != '') {
-                       $dir .= '/' . sha1($book->parametres->ignoreSearchSeparators);
-               }
-               if (!file_exists($dir)) {
-                       mkdir($dir, 0777, true);
-               }
-
-               if ($simple) {
-                       $ifilec = $dir . '/' . $prefix . 'sindex.json';
-               } else {
-                       $ifilec = $dir . '/' . $prefix . 'index.json';
-               }
-               $tfilec = $dir . '/' . $prefix . 'textes.json';
-
-               if (CubeIT_Util_Gzip::file_exists($ifilec) && CubeIT_Util_Gzip::file_exists($tfilec) && (min(CubeIT_Util_Gzip::filemtime($ifilec), CubeIT_Util_Gzip::filemtime($tfilec)) >= max($book->composition_update, filemtime(__FILE__), filemtime(WS_TOOLS . '/fwstk/out/artifacts/fwstk_jar/fwstk.jar')))) {
-                       $index = CubeIT_Util_Gzip::file_get_contents($ifilec);
-                       $textes = CubeIT_Util_Gzip::file_get_contents($tfilec);
-                       return;
-               }
-
-               if ($book->parametres->ignoreSearchSeparators != "") {
-                       $docs = array();
-                       foreach ($pages as $p => $i) {
-                               $docs[] = $i['document_id'];
-                       }
-                       $docs = array_unique($docs);
-
-                       foreach ($docs as $doc) {
-                               $out = wsDocument::getDir($doc);
-
-                               $fwstk = new cubeCommandLine('fwstk.sh');
-                               $fwstk->setPath(CONVERTER_PATH);
-                               $fwstk->setArg('--input ' . $out . '/crop.pdf');
-                               $fwstk->setArg('--extractTexts ' . $out . '%s%d.txt');
-                               $fwstk->setArg('--extractTextsMethod ' . $book->parametres->textExtraction);
-                               $fwstk->setArg('--threads 1');
-                               $fwstk->setArg('--ignoreSeparators ' . $book->parametres->ignoreSearchSeparators);
-                               $fwstk->execute();
-                       }
-               }
-
-               $index = array();
-               $textes = array();
-               foreach ($pages as $book_page => $infos) {
-                       $tfile = wsDocument::getDir($infos['document_id']) . $prefix . 'p' . $infos['document_page'] . '.txt';
-                       $ifile = wsDocument::getDir($infos['document_id']) . $prefix . 'i' . $infos['document_page'] . '.txt';
-
-                       if (!file_exists($tfile) || !file_exists($ifile)) {
-                               $daoDoc = new wsDAODocument($core->con);
-                               $out = wsDocument::getDir($infos['document_id']);
-
-                               $fwstk = new cubeCommandLine('fwstk.sh');
-                               $fwstk->setPath(CONVERTER_PATH);
-                               $fwstk->setArg('--input ' . $out . '/crop.pdf');
-                               $fwstk->setArg('--extractTexts ' . $out . '%s%d.txt');
-                               $fwstk->setArg('--extractTextsMethod ' . $book->parametres->textExtraction);
-                               if ($book->parametres->ignoreSearchSeparators != '') {
-                                       $fwstk->setArg('--ignoreSeparators ' . $book->parametres->ignoreSearchSeparators);
-                               }
-                               $fwstk->setArg('--threads 1');
-                               $fwstk->execute();
-                       }
-
-                       CubeIT_Util_Gzip::compressIfNotCompressed($tfile);
-                       CubeIT_Util_Gzip::compressIfNotCompressed($ifile);
-                       $text = CubeIT_Util_Gzip::file_get_contents($tfile);
-                       $ipage = CubeIT_Util_Gzip::file_get_contents($ifile);
-
-                       if ($simple) {
-                               $this->fillIndexWithWordsSimple($index, $book_page, $ipage);
-                       } else {
-                               $this->fillIndexWithWords($index, $book_page, $ipage);
-                       }
-                       $textes[$book_page] = $text;
-               }
-               ksort($index);
-
-               $textes = json_encode($textes);
-               $index = json_encode($index);
-
-               CubeIT_Util_Gzip::file_put_contents($tfilec, $textes);
-               CubeIT_Util_Gzip::file_put_contents($ifilec, $index);
-       }
-
-       public function makeHighlightIndex($book, $pages)
-       {
-               $jar = WS_TOOLS . '/fwstk/out/artifacts/fwstk_jar/fwstk.jar';
-
-               $daoDoc = new wsDAODocument($this->con);
-               $res = new stdClass();
-               foreach ($pages as $book_page => $infos) {
-                       $fby = wsDocument::getDir($infos['document_id']) . 'html/p' . $infos['document_page'] . '.fby';
-                       // Refresh highlight data if fby file doesn't exists or if fwstk has been updated
-                       $fbymtime = @filemtime($fby);
-                       if (!file_exists($fby) || filemtime($jar) > $fbymtime || filemtime(__FILE__) > $fbymtime) {
-                               $doc = $daoDoc->selectById($infos['document_id']);
-                               $doc->getHighlightTextsData();
-                       }
-
-                       if (file_exists($fby)) {
-                               $words = CubeIT_Util_Json::decode(file_get_contents($fby), CubeIT_Util_Json::TYPE_OBJECT);
-
-                               if (is_array($words)) {
-                                       foreach ($words as $i => $w) {
-                                               $word = $w->word;
-                                               $word = trim($word, "\0");
-                                               if ($word == '') {
-                                                       continue;
-                                               }
-                                               unset($w->word);
-                                               $w->page = $book_page;
-                                               $w->idx = $i;
-                                               if (!isset($res->{$word})) {
-                                                       $res->{$word} = array();
-                                               }
-                                               $res->{$word}[] = $w;
-                                       }
-                               }
-                       }
-               }
-               return $res;
-       }
-
-       protected function _escapeIndex($str)
-       {
-               $todelete = array('\ufffd');
-               foreach ($todelete as $d) {
-                       $str = str_replace($d, '', $str);
-               }
-               return $str;
-       }
-
-       protected function fillIndexWithWordsSimple(&$index, $page, $ipage)
-       {
-               $twords = explode("\n", trim($ipage));
-
-               foreach ($twords as $woadata) {
-                       $w1 = explode(',', trim($woadata));
-                       if (count($w1) <= 1) {
-                               continue;
-                       }
-                       list($woa, $worddata) = $w1;
-                       $e = explode("\t", $worddata, 2);
-                       if (count($e) < 2) {
-                               continue;
-                       }
-                       list($total, $wordslist) = $e;
-
-                       if ($woa == '') {
-                               continue;
-                       }
-
-                       if (!isset($index[$woa])) {
-                               $index[$woa] = array('t' => 0, 'p' => array());
-                       }
-                       $index[$woa]['t'] += $total;
-
-                       $words = explode("\t", $wordslist);
-                       foreach ($words as $word) {
-                               list($wordwa, $count) = explode('$', $word, 2);
-                               if (!isset($index[$woa]['p'][$page])) {
-                                       $index[$woa]['p'][$page] = 0;
-                               }
-                               $index[$woa]['p'][$page] += $count;
-                       }
-               }
-       }
-
-       protected function fillIndexWithWords(&$index, $page, $ipage)
-       {
-               $twords = explode("\n", trim($ipage));
-
-               foreach ($twords as $woadata) {
-                       $w1 = explode(',', trim($woadata));
-                       if (count($w1) <= 1) {
-                               continue;
-                       }
-                       list($woa, $worddata) = $w1;
-                       $e = explode("\t", $worddata, 2);
-                       if (count($e) < 2) {
-                               continue;
-                       }
-                       list($total, $wordslist) = $e;
-
-                       if ($woa == '') {
-                               continue;
-                       }
-
-                       if (!isset($index[$woa])) {
-                               $index[$woa] = array('t' => 0, 'w' => array());
-                       }
-                       $index[$woa]['t'] += $total;
-
-                       $words = explode("\t", $wordslist);
-
-                       foreach ($words as $word) {
-                               list($wordwa, $count) = explode('$', $word, 2);
-                               if (!isset($index[$woa]['w'][$wordwa])) {
-                                       $index[$woa]['w'][$wordwa] = array('t' => 0, 'p' => array());
-                               }
-                               if (!isset($index[$woa]['w'][$wordwa]['p'][$page])) {
-                                       $index[$woa]['w'][$wordwa]['p'][$page] = 0;
-                               }
-                               $index[$woa]['w'][$wordwa]['t'] += $count;
-                               $index[$woa]['w'][$wordwa]['p'][$page] += $count;
-                       }
-               }
-       }
-
-       public function getNumerotationFromDocs($book_id)
-       {
-               $pages = $this->getPagesOfBook($book_id);
-       }
-
-       public function compileTemp($book_id, $version, $dir)
-       {
-               if ($version == 'ha' || $version == 'hi') {
-                       if ($version == 'ha') {
-                               $os = 'android';
-                       } elseif ($version == 'hi') {
-                               $os = 'ios';
-                       }
-                       $packager = new wsPackagerPhonegap($book_id, $dir, false, true, $os);
-                       $packager->makePackage(false);
-               }
-       }
-
-       public function compile($book_id, $version = 'all', $complete = false, $force = false, $dev = false, $book = null, $delete = true)
-       {
-               if (is_null($book_id) || !$book_id) {
-                       return;
-               }
-
-               $v1 = $v2 = $html5 = false;
-
-               if ($version == 'all') {
-                       $v1 = $v2 = $html5 = true;
-               } else if ($version == '1') {
-                       $v1 = true;
-               } else if ($version == '2') {
-                       $v2 = true;
-               } elseif ($version == 'html5') {
-                       $html5 = true;
-               }
-
-               if (null === $book) {
-                       $book = $this->selectById($book_id);
-               }
-               $pages = $this->getPagesOfBook($book_id);
-
-               if (!$force) {
-                       $v1 = $v1 && !$this->isUpToDate($book, 1);
-                       $v2 = $v2 && !$this->isUpToDate($book, 2);
-                       $html5 = $html5 && !$this->isUpToDate($book, 'html5');
-               } else {
-                       $v1 = false;
-                       $html5 = true;
-                       $v2 = true;
-               }
-
-               $res = '';
-               if ($v1) {
-                       fb(time(), 'Compile V1');
-                       $res .= $this->compile1($book_id, $book, $pages);
-                       $this->touchCompile($book_id, '1');
-               }
-               if ($v2) {
-                       fb(time(), 'Compile V2');
-                       $res .= $this->compile3($book_id, $complete, $book, $pages);
-                       $this->touchCompile($book_id, '2');
-               }
-               if ($html5) {
-                       fb(time(), 'Compile HTML5');
-                       $res .= $this->compileHTML5($book_id, $book, $dev, $delete);
-                       $this->touchCompile($book_id, 'html5');
-               }
-               if ($v1 || $v2) {
-                       fb(time(), 'Compile PDF & Widget');
-                       $this->compilePDF($book, $pages);
-                       $this->compileWidget($book, $pages);
-               }
-
-               fb(time(), 'End Compile');
-               return $res;
-       }
-
-       public function compile1($book_id, $book, $pages)
-       {
-               $finalDir = WS_BOOKS . '/finalv1/' . $book_id . '/';
-               $packager = new wsPackagerV1($book_id, $finalDir, false);
-               $packager->makePackage(false);
-       }
-
-       public function compile3($book_id, $complete, $book, $pages)
-       {
-               $res = '';
-
-               $compilerDir = WS_BOOKS . '/datasCompiler/' . $book_id . '/';
-               $finalDir = WS_BOOKS . '/final/' . $book_id . '/';
-
-               $vdir = new CubeIT_Files_VirtualDirectory($finalDir);
-
-               $debug = false;
-
-               $flex = new cubeFlexCompiler('FluidbookDatas', $compilerDir, 'flash.display.Sprite', explode(';', AS3_SOURCES), MXMLC_PATH, 10, 30, 800, 600, $debug);
-               $flexLight = new cubeFlexCompiler('FluidbookDatasLight', $compilerDir, 'flash.display.Sprite', explode(';', AS3_SOURCES), MXMLC_PATH, 10, 30, 800, 600, $debug);
-
-               $filesToCopy = array();
-               $this->compileFlex($book_id, $complete, $compilerDir, $vdir, $filesToCopy, $book, $pages, $flex, $flexLight, $finalDir);
-
-               $res .= $flex->compile() . "\n\n-------------------\n\n";
-               $flexLight->addVariable('datasSize', filesize($compilerDir . '/FluidbookDatas.swf'));
-               $res .= $flexLight->compile();
-
-               $filesToCopy['data/fd.swf'] = $compilerDir . '/FluidbookDatas.swf';
-               $filesToCopy['data/fdl.swf'] = $compilerDir . '/FluidbookDatasLight.swf';
-
-               // Copy of files
-               // Check if dest dir exists
-
-               foreach ($filesToCopy as $local => $source) {
-                       $localPath = $local;
-                       $vdir->copy($source, $localPath);
-               }
-
-               $workingDir = WS_BOOKS . '/working/' . $book_id . '/';
-               $vdir->copyDirectory($workingDir . 'media', 'data');
-               $vdir->sync(true);
-
-               return $res;
-       }
-
-       public function copy($source, $dest)
-       {
-               copy($source, $dest);
-               touch($dest, filemtime($source));
-       }
-
-       public static function getDocumentPage($book_id, $book_page)
-       {
-               global $core;
-               $dao = new wsDAOBook($core->con);
-               $pages = $dao->getPagesOfBook($book_id);
-               return $pages[$book_page];
-       }
-
-       public function compileAir($book_id)
-       {
-               $compilerDir = WS_BOOKS . '/air/' . $book_id . '/compiler';
-               $finalDir = WS_BOOKS . '/air/' . $book_id . '/';
-
-               $book = $this->selectById($book_id);
-               $pages = $this->getPagesOfBook($book_id);
-
-               $src = AS3_FLUIDBOOK_SOURCES . '/_src/';
-               $lib10 = AS3_FLUIDBOOK_SOURCES . '/lib10/';
-               $libs = array(
-                       $src,
-                       $lib10,
-                       AS3_SOURCES,
-                       $src . 'lib/fluidbook3dLibrary.swc',
-                       $src . 'lib/mdm.swc',
-                       $lib10 . 'flash.swc',
-                       $lib10 . 'flex.swc',
-                       $lib10 . 'framework.swc',
-               );
-
-               wsSVN::updateToLastRevision();
-
-               $swf = 'FluidbookAirProjector' . $book_id;
-               $flex = new cubeFlexCompiler($swf, $compilerDir, 'com.fluidbook.player.AIRMain', $libs, '/usr/local/flex/bin/mxmlc', 'air', 45, 800, 600, true);
-
-               $this->compileFlex($book_id, true, $compilerDir, $finalDir, $filesToCopy, $book, $pages, $flex, $flex);
-               $res = $flex->compile();
-
-               $air = new cubeAIRCompiler($swf . '.swf', '/usr/local/flex/bin', $compilerDir, '2.0');
-               $air->setApplicationDatas('com.fluidbook' . $book_id, $book->parametres->title, $book->parametres->title, cubeText::str2URL($book->parametres->title), $book->lang);
-               $air->setInitialWindow($book->parametres->title);
-               $res .= $air->compile();
-
-               return $res;
-       }
-
-       public function compileFlex($book_id, $complete, $compilerDir, $vdir, &$filesToCopy, $book, $pages, $flex, $flexLight)
-       {
-               /* @var $vdir CubeIT_Files_VirtualDirectory */
-
-               cubePHP::neverStop();
-               /* @var $flex cubeFlexCompiler */
-
-               $workingDir = WS_BOOKS . '/working/' . $book_id . '/';
-
-               $res = '';
-
-               $daoDoc = new wsDAODocument($this->con);
-               $firstDoc = $daoDoc->selectById($pages[1]['document_id']);
-               $size = $firstDoc->generalInfos['size'];
-
-               $daoLang = new wsDAOLang($this->con);
-               $lang = $daoLang->selectById($book->lang);
-
-               $langs = $daoLang->selectAll();
-
-               $daoTheme = new wsDAOTheme($this->con);
-               $theme = $daoTheme->getThemeOfBook($book_id, true);
-
-               $daoSignature = new wsDAOSignature($this->con);
-               $signature = $daoSignature->selectById($book->parametres->signature);
-
-               $exportSignature = array('main' => $signature->main,
-                       'mainLink' => $signature->mainLink,
-                       'partner' => $signature->partner,
-                       'partnerLink' => $signature->partnerLink);
-
-               $index = '';
-               $textes = '';
-               $pageLabels = array();
-
-               $hash = $book_id;
-               $hash .= 'kjgl!az4.';
-               $hash .= count($pages);
-               $hash .= round($size[0], 3);
-
-               $hash = sha1($hash);
-
-               $this->makeTextsIndexes($book, $pages, $index, $textes);
-
-               $daoDoc->getLinksAndRulers($book_id, $links, $rulers);
-
-               $audiodescription = array();
-
-               $imagesassets = array();
-               $id = 1;
-               $ignoreLinks = array();
-               foreach ($links as $id => $link) {
-                       $links[$id]['id'] = $id;
-                       $skipCopyAsset = false;
-
-                       if (isset($link['image']) && $link['image']) {
-                               $workingFile = $workingDir . '/' . $link['image'];
-                               $assetId = 'link_datas_i_' . md5($link['image']);
-
-                               if (isset($imagesassets[$assetId])) {
-
-                               } else {
-                                       if (file_exists($workingFile)) {
-                                               if ($link['page'] <= 1) {
-                                                       $flexLight->addBitmap($workingFile, $assetId);
-                                               } else {
-                                                       $flex->addBitmap($workingFile, $assetId);
-                                               }
-                                       }
-                                       $imagesassets[$assetId] = true;
-                               }
-                       }
-
-                       if ($link['type'] == 16 && $book->parametres->linkFilePrefix) {
-                               if (!CubeIT_Util_Url::isDistant($link['to'])) {
-                                       $skipCopyAsset = true;
-                                       $links[$id]['to'] = $book->parametres->linkFilePrefix . $link['to'];
-                               }
-                       }
-
-                       if ($link['type'] == 15) {
-                               if (isset($imagesassets[$id])) {
-                                       continue;
-                               }
-                               if ($link['page'] <= 1) {
-                                       $flexLight->addBitmap($workingDir . '/' . $link['to'], 'link_datas_' . $id);
-                               } else {
-                                       $flex->addBitmap($workingDir . '/' . $link['to'], 'link_datas_' . $id);
-                               }
-                               $imagesassets[$id] = true;
-                       } else if (in_array($link['type'], array(4, 6, 7, 9, 16, 17, 25))) {
-                               if (!$skipCopyAsset) {
-                                       $workingFile = $workingDir . '/' . $link['to'];
-                                       if (file_exists($workingFile)) {
-                                               $filesToCopy['data/' . $link['to']] = $workingFile;
-                                       }
-
-                                       if ($link['type'] == 4) {
-                                               $poster = $link['to'];
-                                               $e = explode('.', $poster);
-                                               array_pop($e);
-                                               array_push($e, 'jpg');
-                                               $poster = implode('.', $e);
-
-                                               $workingFile = $workingDir . '/' . $poster;
-                                               if (file_exists($workingFile)) {
-                                                       $filesToCopy['data/' . $poster] = $workingFile;
-                                               }
-                                       }
-                               }
-                       }
-
-                       if ($link['type'] == 25) {
-                               $audiodescription[$link['page']] = $link['to'];
-                               $ignoreLinks[] = $id;
-                       }
-                       if ($link['type'] == 26) {
-                               $pageLabels[$link['to']] = $link['page'];
-                               $ignoreLinks[] = $id;
-                       }
-               }
-
-               foreach ($ignoreLinks as $ignoreLink) {
-                       unset($links[$ignoreLink]);
-               }
-               $links = array_values($links);
-
-               $externalsOptions = array('ongletsSWF', 'tabs2DSWF', 'externalChapters', 'externalArchives', 'ambientSound');
-               foreach ($externalsOptions as $e) {
-                       if (isset($book->parametres->$e) && $book->parametres->$e != '') {
-                               $f = $workingDir . '/' . $book->parametres->$e;
-                               if (file_exists($f)) {
-                                       $filesToCopy['data/' . $book->parametres->$e] = $f;
-                               }
-                       }
-               }
-
-               $flex->addVariable('audiodescription', $audiodescription, false, true, "JSONObject");
-               $flex->addVariable('pagelabels', $pageLabels, false, true, 'JSONObject');
-               $flex->addVariable('links', $links, false, true, 'JSONObject');
-
-               $flex->addVariable('signature', $exportSignature, false, true, 'JSONObject');
-               $flexLight->addVariable('datas', $book->parametres->toStandardObject(), false, true, 'JSONObject');
-               $flexLight->addVariable('id', $book_id, false, true, 'uint');
-               $flexLight->addVariable('cid', $book->cid, false, true, 'String');
-
-               $traductions = (!count($book->traductions)) ? $lang->traductions : $book->traductions;
-               $allTraductions = array();
-               foreach ($langs as $l) {
-                       $allTraductions[$l->lang_id] = $l->traductions;
-               }
-
-               $flex->addVariable('traductions', $traductions, false, true, 'JSONObject', false);
-               $flex->addVariable('allTraductions', $allTraductions, false, true, 'JSONObject');
-               $flex->addVariable('chapters', $book->chapters, false, true, 'JSONObject');
-               $flex->addVariable('extras', '<extras>' . $book->extras . '</extras>', false, true, 'XML');
-               $flex->addVariable('numerotation', $book->numerotation, false, true, 'String');
-               $flexLight->addVariable('theme', $theme->parametres->toStandardObject(), false, true, 'JSONObject');
-               $flexLight->addVariable('pages', $book->parametres->pages);
-               $flexLight->addVariable('fwidth', round($size[0], 4), false, true, 'Number');
-               $flexLight->addVariable('fheight', round($size[1], 4), false, true, 'Number');
-               $flexLight->addVariable('pagesInDatas', $complete, false, true, 'Boolean');
-               $flex->addVariable('index', $index, false, true, 'JSONObject', false, false);
-               $flex->addVariable('textes', $textes, false, true, 'JSONObject', false, false);
-
-               $rasterized = array();
-               $sizes = array();
-
-               foreach ($pages as $i => $infos) {
-                       $base = wsDocument::getDir($infos['document_id']) . 'p' . $infos['document_page'];
-                       $baset = wsDocument::getDir($infos['document_id']) . 't' . $infos['document_page'];
-                       $swffile = $base . '.swf';
-                       if (file_exists($swffile)) {
-                               clearstatcache(true, $swffile);
-                               $fsize = filesize($swffile);
-                       } else {
-                               $fsize = 0;
-                       }
-
-                       if ($complete) {
-                               $flex->addSWF($swffile, 'page' . $i);
-                       } else {
-                               $filesToCopy['data/p' . $i . '.swf'] = $swffile;
-                               if ($infos['method'] >= wsDocument::BARBARE_PNM) {
-                                       $rasterized[$i] = true;
-                                       $filesToCopy['data/t' . $i . '.swf'] = $baset . '.swf';
-                               } else {
-                                       $rasterized[$i] = false;
-                               }
-                       }
-
-                       $thumb = false;
-                       if ($book->parametres->pdfThumbnails) {
-                               $thumb = wsPDFConvert::getThumbFromPDF($workingDir . '/' . $book->parametres->pdfThumbnails, $i);
-                       }
-                       if (!$thumb) {
-                               $thumb = $base . '.jpg';
-                       }
-
-                       if ($i == 1) {
-                               $flexLight->addBitmap($thumb, 'thumb1');
-                       } else {
-                               $flex->addBitmap($thumb, 'thumb' . $i);
-                       }
-                       $sizes[$i] = $fsize;
-               }
-
-               $flexLight->addVariable('rasterized', $rasterized, false, true, 'JSONObject');
-               $flexLight->addVariable('sizes', $sizes, false, true, 'JSONObject');
-
-               if ($book->parametres->soundTheme != '') {
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/corner-drag.mp3', 'soundDragCorner');
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/corner-release.mp3', 'soundReleaseCorner');
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/page-flip-1.mp3', 'soundPage0');
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/page-flip-2.mp3', 'soundPage1');
-                       $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/cover-flip.mp3', 'soundCover0');
-               }
-               // Theme assets
-               $themeRoot = WS_THEMES . '/' . $theme->theme_id . '/';
-
-               if ($theme->parametres->backgroundImage != '') {
-                       $flexLight->addBitmap($themeRoot . $theme->parametres->backgroundImage, 'background');
-               }
-               if ($theme->parametres->menuImage != '') {
-                       $flex->addBitmap($themeRoot . $theme->parametres->menuImage, 'menu');
-               }
-               if ($theme->parametres->logoLoader != '') {
-                       $flexLight->addBitmap($themeRoot . $theme->parametres->logoLoader, 'logoLoader');
-               }
-               if ($theme->parametres->topBar != '') {
-                       $flexLight->addBitmap($themeRoot . $theme->parametres->topBar, 'topBar');
-               }
-               if ($theme->parametres->logo != '') {
-                       $flex->addBitmap($themeRoot . $theme->parametres->logo, 'logo');
-               }
-               if ($theme->parametres->afterSearch != '') {
-                       $flex->addBitmap($themeRoot . $theme->parametres->afterSearch, 'aftersearch');
-               }
-               if ($theme->parametres->favicon != '') {
-                       $filesToCopy['data/fluidbook.ico'] = $themeRoot . 'fluidbook.ico';
-               }
-
-               // Icons assets
-               $iconsRoot = WS_ICONS . '/' . $theme->parametres->iconSet . '/';
-               foreach (wsIcone::$files as $file) {
-                       $flex->addBitmap($iconsRoot . 'nav-' . $file . '.png', 'nav_' . $file);
-               }
-               // Share icons
-               $iconsRoot = WS_ICONS . '/share/';
-               foreach (wsIcone::$share as $file) {
-                       $flex->addBitmap($iconsRoot . 'share-' . $file . '.png', 'share_' . $file);
-               }
-
-               // Multilang
-               if (trim($book->parametres->multilang) != '') {
-                       $m = str_replace("\r", "\n", trim($book->parametres->multilang));
-                       $langs = explode("\n", $m);
-                       $langNames = array();
-                       $countryNames = array();
-                       $iso = l10n::getISOcodes();
-                       $chars = '()';
-                       $vuFlags = array();
-                       foreach ($langs as $l) {
-                               list($mlang, $flag, $url) = explode(',', trim($l), 3);
-                               if (!isset($vuFlags[$flag])) {
-                                       $flex->addBitmap(cubeMedia::getFlagFile($flag), 'flag_' . $flag);
-                                       $vuFlags[$flag] = true;
-                               }
-                               $ll = explode('-', $mlang);
-                               $n = cubeText::ucfirst($iso[$ll[0]]);
-                               $langNames[$mlang] = $n;
-                               $cn = cubeCountry::getCountryName($flag, $mlang);
-                               $countryNames[$mlang . '_' . $flag] = $cn;
-                               $chars .= $n . $cn;
-                       }
-
-                       $chars = preg_split('/(?<!^)(?!$)/u', $chars);
-                       $chars = array_unique($chars);
-
-                       $flex->addFont(WS_FILES . '/fonts/FluidbookMultilang.ttf', 'MultilangFont', $chars);
-                       $flex->addVariable('langNames', $langNames, false, true, 'JSONObject');
-                       $flex->addVariable('countryNames', $countryNames, false, true, 'JSONObject');
-               }
-               $flexLight->addVariable('lang', $book->lang);
-
-               // Basket
-               if ($book->parametres->basket) {
-                       $formats = array('jpg', 'png', 'jpeg');
-                       $referencesFile = self::getWorkingFile($book->parametres->basketReferences, $book_id, 'commerce');
-
-                       if (file_exists($referencesFile) || CubeIT_Util_Url::isDistant($referencesFile)) {
-                               $ext = CubeIT_Files::getExtension($referencesFile);
-                               if ($ext == 'xml') {
-                                       $xml = simplexml_load_file($referencesFile);
-                                       $i = 0;
-                                       $allref = array();
-                                       foreach ($xml->item as $item) {
-                                               $ref = (string)$item['reference'];
-                                               if (isset($allref[$ref])) {
-                                                       continue;
-                                               }
-                                               $allref[$ref] = true;
-                                               foreach ($formats as $f) {
-                                                       $refimage = $workingDir . 'commerce/' . $ref . '.' . $f;
-                                                       if (file_exists($refimage)) {
-                                                               $flex->addBitmap($refimage, "basket_image_" . $ref);
-                                                               break;
-                                                       }
-                                               }
-                                               $i++;
-                                       }
-                               } elseif ($ext == 'xlsx') {
-                                       $references = wsUtil::excelToArray($referencesFile);
-                                       if ($book->parametres->customLinkClass == 'AtlanticDownloadLink') {
-                                               $references = wsUtil::atlanticReferences($references, 'local/', null, array($vdir, 'copy'));
-                                       }
-                                       $flex->addVariable('basketReferences', $references, false, true, "OrderedObject");
-                               }
-                       }
-                       if (isset($xml)) {
-                               $flex->addVariable('basketReferences', cubeXML::condense($xml->asXML()), false, true, "String");
-                       }
-                       if ($book->parametres->basketPDFBackground != '') {
-                               $flex->addByteArray($workingDir . 'commerce/' . $book->parametres->basketPDFBackground, 'basket_pdf_background');
-                       }
-               }
-               // Fonts
-               if ($theme->parametres->fontKit == 'auto') {
-                       if ($lang->font != 'system') {
-                               $font = FONT_PATH . '/' . $lang->font;
-                               $bfont = FONT_PATH . '/B' . $lang->font;
-                               if (!file_exists($bfont)) {
-                                       $bfont = $font;
-                               }
-
-                               $flex->addFont($bfont, 'BoldFont', $lang->charset);
-                               $flex->addFont($font, 'GeneralFont', $lang->charset);
-                       }
-                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
-                       $flexLight->addFont(FONT_PATH . '/FluidbookLoader.ttf', 'LoaderFont', 'Numerals');
-               } else if ($theme->parametres->fontKit == 'vagrounded') {
-                       $flex->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Bold.otf', 'BoldFont', $lang->charset);
-                       $flex->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Light.otf', 'GeneralFont', $lang->charset);
-                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
-                       $flexLight->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Bold.otf', 'LoaderFont', 'Numerals');
-               } else if ($theme->parametres->fontKit == 'gill') {
-                       $flex->addFont(FONT_PATH . '/gill/gill.ttf', 'BoldFont', $lang->charset);
-                       $flex->addFont(FONT_PATH . '/gill/gill.ttf', 'GeneralFont', $lang->charset);
-                       $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
-                       $flexLight->addFont(FONT_PATH . '/gill/gill.ttf', 'LoaderFont', 'Numerals');
-               }
-
-               $flexLight->addVariable('checksum', $hash, false, true, 'String');
-       }
-
-
-       public static function getWorkingFile($path, $book_id, $dir = "")
-       {
-               if (CubeIT_Util_Url::isDistant($path) || (substr($path, 0, 1) == '/' && file_exists($path))) {
-                       return $path;
-               }
-
-               $workingDir = WS_BOOKS . '/working/' . $book_id . '/';
-               return $workingDir . trim($dir, '/') . '/' . $path;
-       }
-
-       public function compileWidget($book, $pages)
-       {
-               if (!$book->parametres->widget) {
-                       return;
-               }
-
-               global $core;
-
-               $finalDir = WS_BOOKS . '/final/' . $book->book_id . '/widget/';
-               $finalWidget = $finalDir . 'miniFluidbook.swf';
-
-               if (!file_exists($finalDir)) {
-                       mkdir($finalDir, 0777, true);
-               }
-
-               if ($book->parametres->widgetCover) {
-                       $file = 'miniFluidbookCouv.swf';
-               } else {
-                       $file = 'miniFluidbook.swf';
-               }
-               $mini = WS_COMPILE_ASSETS . '/_widget/' . $file;
-
-               $from = max(1, $book->parametres->widgetStart);
-               $to = min($book->parametres->widgetEnd, count($pages));
-
-               $swfcombine = new cubeCommandLine('swfcombine');
-               $swfcombine->setPath(CONVERTER_PATH);
-               $swfcombine->setArg('merge');
-               $swfcombine->setArg('stack1');
-               $swfcombine->setArg('z');
-               $swfcombine->setArg('o', $finalWidget);
-               $swfcombine->setArg(null, $mini);
-
-               $tempimage = array();
-               $tempswf = array();
-               $timg = array();
-
-               for ($i = $from; $i <= $to; $i++) {
-                       $page = $pages[$i];
-
-                       $timg[$i] = $tempimage[$i] = cubeFiles::tempnam();
-                       $tempswf[$i] = cubeFiles::tempnam();
-
-                       $it = new imageTools();
-                       $image = wsDocument::getDir($page['document_id']) . '/html/t150-' . $page['document_page'] . '.jpg';
-
-                       try {
-                               $it->loadImage($image);
-                               $it->resize($book->parametres->widgetSize, 10000);
-                               $it->output('jpeg', $tempimage[$i], 100);
-                       } catch (Exception $e) {
-                               $tempimage[$i] = $image;
-                       }
-                       $jpg2swf = new cubeCommandLine('jpeg2swf');
-                       $jpg2swf->setEnv('PATH', '/bin:/usr/bin:/usr/local/bin');
-                       $jpg2swf->setArg('q', $book->parametres->widgetQuality);
-                       $jpg2swf->setArg('o', $tempswf[$i]);
-                       $jpg2swf->setArg(null, $tempimage[$i]);
-                       $jpg2swf->execute();
-
-                       $swfcombine->setArg(null, $tempswf[$i]);
-               }
-               $swfcombine->execute();
-
-               foreach ($timg as $t) {
-                       if (file_exists($t)) {
-                               unlink($t);
-                       }
-               }
-               foreach ($tempswf as $t) {
-                       unlink($t);
-               }
-       }
-
-       public function compileHTML5($book_id, $book, $dev = false, $delete = true)
-       {
-               $version = $book->parametres->mobileLVersion;
-               if ($dev) {
-                       $version = 'dev';
-               }
-
-               $htmlCompiler = wsHTML5::compilerFactory($book_id, $version, false, 'latest', null, false, false, false, $book);
-               $htmlCompiler->compile($delete);
-       }
-
-       /* public function indexPDF($book, $pages) {
-         $indexPath = WS_BOOKS . '/search/' . $book->book_id;
-
-         Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive());
-
-         if (file_exists($indexPath)) {
-         files::deltree($indexPath);
-         }
-         $index = Zend_Search_Lucene::create($indexPath);
-
-         foreach ($pages as $i => $infos) {
-         $doc = new Zend_Search_Lucene_Document();
-         $doc->addField(Zend_Search_Lucene_Field::Text('url', '#' . $i));
-         $doc->addField(Zend_Search_Lucene_Field::UnStored('contents', file_get_contents(wsDocument::getDir($infos['document_id']) . 'p' . $infos['document_page'] . '.txt')));
-         $index->addDocument($doc);
-         }
-
-         $c = $this->con->openCursor('books');
-         $c->lucene_time = TIME;
-         $c->update('WHERE book_id=' . $book->book_id);
-         } */
-
-       public function compilePDF($book, $pages)
-       {
-               $res = wsUtil::compilePDF($book, $pages);
-
-               $finalPDF = WS_BOOKS . '/final/' . $book->book_id . '/data/' . $book->parametres->pdfName;
-               if ($res) {
-                       $this->copy($res, $finalPDF);
-               }
-       }
-
-       public function generateCID()
-       {
-
-               do {
-                       $res = '';
-                       for ($i = 0; $i < 8; $i++) {
-                               $j = rand(0, 61);
-                               $res .= $this->base62($j);
-                       }
-                       $r = $this->con->select('SELECT book_id FROM books WHERE cid=\'' . $res . '\'');
-                       if ($r->count() == 0) {
-                               return $res;
-                       }
-               } while (true);
-       }
-
-       protected function base62($val)
-       {
-               $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-               $base = strlen($chars);
-               $str = '';
-               do {
-                       $i = $val % $base;
-                       $str = $chars[$i] . $str;
-                       $val = ($val - $i) / $base;
-               } while ($val > 0);
-               return $str;
-       }
+    public static $pagesOfBookCache = array();
+
+    /**
+     * wsDAOBook::singleton()
+     *
+     * @param mixed $r
+     * @return
+     */
+    protected function singleton($r)
+    {
+        $book = new wsBook();
+        $book->book_id = $r->book_id;
+        $book->cid = $r->cid;
+        $book->nom = $r->nom;
+        $book->lang = $r->lang;
+        $book->theme = $r->theme;
+        $book->proprietaire = $r->proprietaire_nom;
+        $book->proprietaire_id = $r->proprietaire_id;
+        $book->proprietaire_utilisateur = $r->proprietaire_utilisateur;
+        $book->hash = $r->hash;
+        $book->compteur_visites = $r->compteur_visites;
+        $book->status = $r->status;
+        $book->date_status = $r->date_status;
+        $book->date = $r->date;
+        $book->pages = array();
+        $book->chapters = $r->chapters;
+        $book->traductions = $r->traductions;
+        $book->specialLinks = $r->specialLinks;
+        $book->specialRulers = $r->specialRulers;
+        $book->parametres = $r->parametres;
+        $book->extras = $r->extras;
+        $book->numerotation = $r->numerotation;
+        $book->changedate = $r->changedate;
+        $book->compiledate = $r->compiledate;
+        $book->compile1date = $r->compile1date;
+        $book->compilehtml5date = $r->compilehtml5date;
+        $book->facturable = $r->facturable;
+        $book->facturable_id = $r->facturable_id;
+        $book->tache = $r->tache;
+        if (isset($r->projet)) {
+            $book->projet = $r->projet;
+        }
+        $book->version = $r->version;
+        $book->composition_update = $r->composition_update;
+        $book->dir_references = $r->dir_references;
+        $book->dir_hosting = $r->dir_hosting;
+        $book->dir_macbook_phonegap_ios = $r->dir_macbook_phonegap_ios;
+        $book->dir_phonegap_android = $r->dir_phonegap_android;
+        $book->dir_external = $r->dir_external;
+        $book->demo_counter = $r->demo_counter;
+        $book->exportdatas = $r->exportdatas;
+
+        return $book;
+    }
+
+    protected function cree($r)
+    {
+        $book = new wsBook();
+        $book->book_id = 'new';
+        $book->nom = '';
+        $book->cid = null;
+        $book->lang = 'fr';
+        $book->theme = 1;
+        $book->proprietaire = '';
+        $book->proprietaire_id = 0;
+        $book->hash = '';
+        $book->compteur_visites = 20;
+        $book->status = 0;
+        $book->date_status = TIME;
+        $book->date = TIME;
+        $book->composition_update = TIME;
+        $book->chapters = json_encode(array());
+        $book->parametres = new wsBookParametres();
+        $book->tache = 0;
+        $book->pages = array();
+        $book->version = 2;
+        return $book;
+    }
+
+    protected function getNextId()
+    {
+        $r = $this->con->select('SELECT MAX(book_id) AS book_id FROM books');
+        if ($r->book_id < 10000) {
+            return 10000;
+        }
+        return $r->book_id + 1;
+    }
+
+    public function saveExportDatas($book_id, $datas)
+    {
+        $c = $this->con->openCursor('books');
+        $c->exportdatas = json_encode($datas);
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function addDemoCount($book_id)
+    {
+
+        $r = $this->con->select('SELECT demo_counter,nom FROM books WHERE book_id=\'' . $book_id . '\'');
+        $m = 20;
+        if ($r->demo_counter > 0 && $r->demo_counter % $m == 0) {
+            $mail = new cubeMail();
+            $mail->charset = 'UTF-8';
+            $mail->from = 'contact@fluidbook.com';
+            $mail->to = 'tech@fluidbook.com';
+            $mail->subject = '[Fluidbook Workshop] Fluidbook consulté via l\'url publique';
+            $mail->body = 'Le fluidbook suivant a été consulté ' . $m . ' fois (et ' . $r->demo_counter . ' au total) via l\'url publique : ' . "\r\n" .
+                'Fluidbook # ' . $book_id . ' - ' . $r->nom;
+            $mail->send();
+        }
+
+        $this->con->select('UPDATE books SET demo_counter=demo_counter+1 WHERE book_id=\'' . $book_id . '\'');
+    }
+
+    public function selectByIds($book_ids = array(), $simple = false)
+    {
+        if ($simple) {
+            $table = 'books';
+        } else {
+            $table = 'books_vue';
+        }
+
+        $ids = array();
+        foreach ($book_ids as $bid) {
+            fb($bid);
+            if (intval($bid) > 0) {
+                $ids[] = $bid;
+            }
+        }
+
+        $sql = 'SELECT * FROM ' . $table . ' WHERE book_id IN (' . implode(',', $ids) . ')';
+        $books = $this->factory($this->con->select($sql));
+        $res = array();
+        foreach ($books as $book) {
+            $res[$book->book_id] = $book;
+        }
+        return $res;
+    }
+
+    public function selectById($book_id = null, $simple = false)
+    {
+        if (is_null($book_id)) {
+            return $this->cree();
+        }
+        if ($simple) {
+            $table = 'books';
+        } else {
+            $table = 'books_vue';
+        }
+        $sql = 'SELECT * FROM ' . $table . ' WHERE book_id=\'' . $this->con->escape($book_id) . '\' LIMIT 1';
+        $r = $this->con->select($sql);
+        return $this->singleton($r);
+    }
+
+    public function selectByCid($cid = null, $simple = false)
+    {
+        if ($simple) {
+            $table = 'books';
+        } else {
+            $table = 'books_vue';
+        }
+
+        $sql = 'SELECT * FROM ' . $table . ' WHERE cid LIKE BINARY \'' . $this->con->escape($cid) . '\' LIMIT 1';
+        $r = $this->con->select($sql);
+        return $this->singleton($r);
+    }
+
+    public function selectLuceneToDo()
+    {
+        $sql = 'SELECT * FROM books_vue WHERE lucene_time<composition_update AND version=2 ORDER BY book_id ASC LIMIT 1';
+        $r = $this->con->select($sql);
+        return $this->factory($r);
+    }
+
+    public function selectLuceneTimeNotSet()
+    {
+        $sql = 'SELECT * FROM books_vue WHERE lucene_time=0 AND version=2';
+        $r = $this->con->select($sql);
+        return $this->factory($r);
+    }
+
+    /**
+     * wsDAOBook::sauve()
+     *
+     * @param mixed $createur
+     * @param mixed $data
+     * @return
+     */
+    public function sauve($createur, $data)
+    {
+        $c = $this->con->openCursor('books');
+        if (isset($data['nom'])) {
+            $c->nom = $data['nom'];
+        }
+        if (isset($data['lang'])) {
+            $c->lang = $data['lang'];
+        }
+        if (isset($data['theme'])) {
+            $c->theme = $data['theme'];
+        }
+        if (isset($data['proprietaire'])) {
+            $c->proprietaire = $data['proprietaire'];
+        }
+
+        if ($data['book_id'] == 'new' || $data['book_id'] == '') {
+            $c->date = TIME;
+            $c->hash = md5(rand(0, 123456789365469));
+            $c->compteur_visites = 20;
+            $c->parametres = serialize(new wsParametres());
+            $c->changedate = TIME;
+            $book_id = $c->book_id = $this->getNextId();
+
+            $c->insert();
+        } else {
+            $c->changedate = TIME;
+            $book_id = $data['book_id'];
+            $c->update('WHERE book_id=\'' . $this->con->escape($data['book_id']) . '\'');
+        }
+
+        if (isset(self::$pagesOfBookCache[$book_id])) {
+            unset(self::$pagesOfBookCache[$book_id]);
+        }
+
+        return $this->selectById($book_id);
+    }
+
+    public function duplicate($book_id, $createur, $nom = null, $pages = false, $complete = false)
+    {
+        $r = $this->con->select('SELECT * FROM books_vue WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+
+        $old_id = $book_id;
+
+
+        $parametres = unserialize($r->parametres);
+        $parametres->setParent($this);
+        if (null === $nom) {
+            $nom = $parametres->title;
+        }
+        $parametres->title = $nom;
+
+        if (!$complete) {
+            $parametres->pdfReplace = '';
+        }
+
+        $c = $this->con->openCursor('books');
+        $c->proprietaire = $createur;
+        $c->date = TIME;
+        $c->hash = md5(rand(0, 1234567893));
+        $c->cid = $this->generateCID();
+        $c->compteur_visites = 20;
+        $c->status = -1;
+        $c->date_status = TIME;
+        $c->lang = $r->lang;
+        $c->parametres = serialize($parametres);
+        $c->nom = $nom;
+        $c->theme = $r->theme;
+        $c->changedate = TIME;
+        $c->compiledate = 0;
+        $c->version = 2;
+        $c->traductions = $r->traductions;
+        $c->specialLinks = $r->specialLinks;
+        $c->specialRulers = $r->specialRulers;
+        $c->composition_update = TIME;
+        $book_id = $c->book_id = $this->getNextId();
+        if ($pages) {
+            $c->numerotation = $r->numerotation;
+            $c->chapters = $r->chapters;
+            $this->con->execute('INSERT INTO book_pages SELECT ' . $book_id . ' AS book_id,book_page,document_id,document_page FROM book_pages WHERE book_id=' . $old_id);
+        }
+        if ($complete) {
+            $c->numerotation = $r->numerotation;
+            $c->chapters = $r->chapters;
+        }
+        $c->insert();
+
+        $this->saveCompositionVersion($book_id);
+
+        return $this->selectById($book_id);
+    }
+
+    public function creeEmpty($createur, $lang, $nom)
+    {
+        $c = $this->con->openCursor('books');
+
+        $parametres = new wsBookParametres($this);
+        $parametres->title = $nom;
+
+        $c->proprietaire = $createur;
+        $c->cid = $this->generateCID();
+        $c->nom = $nom;
+        $c->date = TIME;
+        $c->hash = md5(rand(0, 1234567893));
+        $c->compteur_visites = 20;
+        $c->status = -1;
+        $c->date_status = TIME;
+        $c->parametres = serialize($parametres);
+
+        $c->theme = 1;
+        $c->lang = $lang;
+        $c->changedate = TIME;
+        $c->compiledate = 0;
+        $c->version = 2;
+        $c->composition_update = TIME;
+        $book_id = $c->book_id = $this->getNextId();
+        $c->insert();
+        return $this->selectById($book_id);
+    }
+
+    public function supprime($book_id)
+    {
+        $this->con->execute('DELETE FROM book_pages_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+        $this->con->execute('DELETE FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+        return $this->con->execute('DELETE FROM books WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function count($limitedToUserRights = false)
+    {
+        $filters = $this->makeWhereFromFiltres();
+        if ($filters == '1=1') {
+            $table = 'books';
+        } else {
+            $table = 'books_vue';
+        }
+
+        $where = '(' . $filters . ')';
+        $where .= $this->limitToUserRights($limitedToUserRights);
+        $r = $this->con->select('SELECT COUNT(*) AS nb FROM ' . $table . ' WHERE ' . $where);
+        return $r->nb;
+    }
+
+    public function getPagesOfBookAt($book_id, $time)
+    {
+        $r = $this->con->select('SELECT * FROM book_pages_versions WHERE book_id=\'' . $this->con->escape($book_id) . '\' ORDER BY `update` ASC');
+        if (!$r->count()) {
+            return $this->getPagesOfBook($book_id);
+        }
+        if ($r->count() == 1) {
+            $pages = unserialize($r->composition);
+            if (null === $pages || !count($pages)) {
+                return $this->getPagesOfBook($book_id);
+            }
+            return $pages;
+        }
+
+        $pages = null;
+        while ($r->fetch()) {
+            if ($r->update > $time) {
+
+                if (is_null($pages)) {
+                    return $this->getPagesOfBook($book_id);
+                }
+                $res = unserialize($pages);
+                if (null === $res || !count($res)) {
+                    return $this->getPagesOfBook($book_id);
+                }
+                return $res;
+            }
+            if (!count(unserialize($r->composition))) {
+                continue;
+            }
+            $pages = $r->composition;
+        }
+
+        $res = unserialize($pages);
+        if (null === $res || !count($res)) {
+            return $this->getPagesOfBook($book_id);
+        }
+        return $res;
+    }
+
+    public function getDocumentsToUpdate($book_id)
+    {
+        $res = array();
+        $r = $this->con->select('SELECT DISTINCT d.document_id FROM book_pages b,documents d WHERE b.book_id=\'' . $this->con->escape($book_id) . '\' AND d.version=1 AND b.document_id=d.document_id');
+        while ($r->fetch()) {
+            $res[] = $r->document_id;
+        }
+        return $res;
+    }
+
+    public function getPagesOfBook($book_id, $conversion = true, $force = false)
+    {
+        if ($force || !isset(self::$pagesOfBookCache[$book_id])) {
+            $pages = array();
+
+            $sql = 'SELECT b.*,d.numberSections AS num,d.conversionInfos AS conversion,d.pages AS doc_pages,d.version AS version FROM book_pages b JOIN documents d ON d.document_id=b.document_id WHERE b.book_id=\'' . $this->con->escape($book_id) . '\' ORDER BY book_page';
+
+            $r = $this->con->select($sql);
+            while ($r->fetch()) {
+                $n = explode(',', $r->num);
+
+                if (isset($n[$r->document_page - 1])) {
+                    $num = $n[$r->document_page - 1];
+                } else {
+                    $num = '';
+                }
+                $pages[$r->book_page] = array('document_id' => $r->document_id,
+                    'document_page' => $r->document_page,
+                    'version' => $r->version,
+                    'defaultNum' => $num,
+                    'nb_pages' => $r->doc_pages
+                );
+
+                if ($conversion) {
+                    if ($r->conversion != '') {
+                        $c = unserialize($r->conversion);
+                        $c = $c->pages[$r->document_page];
+                    }
+                    $qp = array('resolution', 'method', 'quality', 'objects');
+                    foreach ($qp as $p) {
+                        if (isset($c) && isset($c->$p)) {
+                            $pages[$r->book_page][$p] = $c->$p;
+                        }
+                    }
+                }
+            }
+            if (!count($pages)) {
+                return [];
+            }
+
+            self::$pagesOfBookCache[$book_id] = $pages;
+        }
+        return self::$pagesOfBookCache[$book_id];
+    }
+
+    public function appendDocument($book_id, $document_id)
+    {
+        $r = $this->con->select('SELECT MAX(book_page) AS book_page FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+        $lastPage = is_null($r->book_page) ? 0 : $r->book_page;
+        $this->insertDocument($book_id, $lastPage, $document_id);
+    }
+
+    public function removePage($book_id, $book_page)
+    {
+        // Supprime la page
+        $this->con->execute('DELETE FROM book_pages WHERE book_page=\'' . $this->con->escape($book_page) . '\' AND book_id=\'' . $this->con->escape($book_id) . '\'');
+        // Décale les pages suivantes vers le haut
+        $this->decalePages($book_id, $book_page, -1);
+    }
+
+    public function insertPage($book_id, $after_page, $document_id, $document_page)
+    {
+        // Décale les pages vers le bas
+        $this->decalePages($book_id, $after_page, 1);
+        // Insère la page
+        $c = $this->con->openCursor('book_pages');
+        $c->book_id = $book_id;
+        $c->book_page = $after_page + 1;
+        $c->document_id = $document_id;
+        $c->document_page = $document_page;
+        $c->insert();
+    }
+
+    public function insertDocument($book_id, $after_page, $document_id)
+    {
+        // Obtiens le book
+        $book = $this->selectById($book_id);
+        $num = explode(',', $book->numerotation);
+        // Obtiens le nombre de pages
+        $r = $this->con->select('SELECT pages,numberSections FROM documents WHERE document_id=\'' . $this->con->escape($document_id) . '\'');
+        // Décale les pages vers le bas
+        if ($after_page > 0) {
+            $this->decalePages($book_id, $after_page, $r->pages);
+        }
+        // Insère les pages
+        $c = $this->con->openCursor('book_pages');
+        $c->book_id = $book_id;
+        $c->document_id = $document_id;
+        for ($i = 1; $i <= $r->pages; $i++) {
+            $c->document_page = $i;
+            $c->book_page = $after_page + $i;
+            $c->insert();
+        }
+        // Mets à jour la liste des numéros des pages
+        $before = array_slice($num, 0, $after_page);
+        $after = array_slice($num, $after_page, count($num) - $after_page);
+
+        $newnum = $r->numberSections;
+        if (trim($newnum, ',') == '') {
+            // If no number detected, we create a numeric list from 1
+            $between = range(1, $r->pages);
+        } else {
+            // Else, we use numbers detected at conversion
+            $between = explode(',', $r->numberSections);
+        }
+        $num = array_merge($before, $between, $after);
+        // Mets à jour la numerotation de la publication
+        $c = $this->con->openCursor('books');
+        $c->numerotation = implode(',', $num);
+        $c->composition_update = TIME;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+
+        $this->saveCompositionVersion($book_id);
+    }
+
+    protected function decalePages($book_id, $after_page, $decalage)
+    {
+        $decalage = ($decalage >= 0) ? '+' . $decalage : $decalage;
+        $this->con->execute('UPDATE book_pages SET book_page=book_page' . $decalage . ' WHERE book_page>' . $this->con->escape($after_page) . ' AND book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function getListe($orderby = null, $sens = null, $limit = null, $limitedToUserRights = false)
+    {
+        if (!is_null($this->q)) {
+            $where = '(';
+            if ($this->search_id) {
+                $where .= ' book_id=\'' . $this->con->escape($this->q) . '\' OR ';
+            }
+
+            if (!cubeMath::is_int($this->q)) {
+                $where .= 'nom LIKE \'%' . $this->con->escape($this->q) . '%\'';
+                $daoClient = new commonDAOClient($this->con);
+                $where .= ' OR proprietaire_id IN(' . $daoClient->querySearchByName($this->q) . ') OR ';
+            }
+            $limit = null;
+            $where .= '1=2)';
+        } else {
+            $where = '(' . $this->makeWhereFromFiltres() . ')';
+        }
+        $where .= $this->limitToUserRights($limitedToUserRights);
+
+        $orderby = is_null($orderby) ? 'book_id' : $orderby;
+        $sens = is_null($sens) ? 'DESC' : $sens;
+        $limit = is_null($limit) ? '' : $this->con->limit($limit);
+
+        $sql = 'SELECT * FROM books_vue WHERE ' . $where . ' ORDER BY ' . $orderby . ' ' . $sens . ' ' . $limit;
+        $r = $this->con->select($sql);
+        return $this->factory($r);
+    }
+
+    protected function limitToUserRights($utilisateur)
+    {
+        if ($utilisateur) {
+            if (wsDroits::admin()) {
+                return '';
+            }
+            return ' AND proprietaire IN (' . $utilisateur->ws_rights . ')';
+        }
+        return '';
+    }
+
+    protected function makeWhereFromFiltres()
+    {
+        if (!is_null($this->filtres)) {
+            $w = array('1=1');
+            if (commonFiltre::test('admin_book', $this->filtres)) {
+                $w[] = 'super_admin IN (' . implode(',', array_keys($this->filtres['admin_book'])) . ')';
+            }
+            if (commonFiltre::test('status_book', $this->filtres)) {
+                $w[] = 'status IN(' . implode(',', array_keys($this->filtres['status_book'])) . ')';
+            }
+            if (commonFiltre::test('revendeur_book', $this->filtres)) {
+                $v = array_keys($this->filtres['revendeur_book']);
+                $values = array();
+                foreach ($v as $r) {
+                    $values[] = $this->con->escape($r);
+                }
+
+
+                $w[] = 'facturable IN(\'' . implode('\',\'', $values) . '\')';
+            }
+            return implode(' AND ', $w);
+        } else {
+            return '1=1';
+        }
+    }
+
+    public function setChapters($book_id, $json)
+    {
+        $chapters = json_decode($json, true);
+        $res = array();
+
+        foreach ($chapters as $c) {
+            $c['label'] = trim($c['label']);
+            $n = (string)$c['page'];
+            $c['label'] = trim(preg_replace('|\s+' . $n . '$|iu', '', $c['label']));
+            $res[] = $c;
+        }
+
+        $json_chapters = json_encode($res);
+
+        $c = $this->con->openCursor('books');
+        $c->chapters = $json_chapters;
+        $c->changedate = TIME;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+
+        if ($json_chapters && $json_chapters != '[]') {
+            if (count($res) == 1) {
+                if ($res[0]['label'] == '' && $res[0]['page'] == '') {
+                    return;
+                }
+            }
+            $c = $this->con->openCursor('books_chapters_versions');
+            $c->book_id = $book_id;
+            $c->chapters = $json_chapters;
+            $c->time = TIME;
+            $c->insert();
+        }
+    }
+
+    public function setSpecialLinksAndRulers($book_id, $links, $rulers)
+    {
+        $c1 = $this->con->openCursor('special_links_versions');
+        $c = $this->con->openCursor('books');
+
+        if (is_string($links)) {
+            $links = json_encode(json_decode($links, false));
+        }
+        if (is_string($rulers)) {
+            $rulers = json_encode(json_decode($rulers, false));
+        }
+
+
+        $links = wsLinks::encryptLinks(json_decode($links));
+
+
+        if (is_array($links)) {
+            $links = json_encode($links);
+        }
+        if (is_array($rulers)) {
+            $rulers = json_encode($rulers);
+        }
+
+        $c1->links = $c->specialLinks = $links;
+        $c1->rulers = $c->specialRulers = $rulers;
+        $c1->update = $c->changedate = TIME;
+        $c1->book_id = $book_id;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+        try {
+            $c1->insert();
+        } catch (Exception $e) {
+            try {
+                $c1->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\' AND `update`=' . TIME);
+            } catch (Exception $e) {
+
+            }
+        }
+    }
+
+    public function setTheme($book_id, $theme)
+    {
+        $c = $this->con->openCursor('books');
+        $c->theme = $theme;
+        $c->changedate = TIME;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function setStatus($book_id, $status)
+    {
+        $c = $this->con->openCursor('books');
+        if ($status < 2) {
+            $c->tache = 0;
+        }
+        $c->status = $status;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+        return $this->selectById($book_id);
+    }
+
+    public function setChaptersFromOldFluidbook($book_id)
+    {
+        $book = $this->selectById($book_id);
+        $n = explode(',', $book->numerotation);
+
+        $xml = simplexml_load_file('https://ws.fluidbook.com/books/' . $book_id . '/data/links.xml');
+        $res = array();
+        $chapters = $xml->xpath('//chapters');
+        foreach ($chapters as $ch) {
+            $c = array();
+            $c['label'] = (string)$ch->txt;
+
+            $p = intval((string)$ch->page);
+            if ($p <= 0) {
+                continue;
+            }
+            $c['page'] = $n[$p];
+            $c['level'] = intval((string)$ch->level);
+            $res[] = $c;
+        }
+
+        $c = $this->con->openCursor('books');
+        $c->chapters = json_encode($res);
+        $c->changedate = TIME;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function saveCompositionVersion($book_id, $time = null)
+    {
+        $time = is_null($time) ? TIME : $time;
+
+        $pages = $this->getPagesOfBook($book_id, true, true);
+
+        $c = $this->con->openCursor('book_pages_versions');
+        $c->update = $time;
+        $c->book_id = $book_id;
+        $c->composition = serialize($pages);
+        $c->insert();
+    }
+
+    public function setLang($book_id, $base, $traductions)
+    {
+        // Cleanup user translations
+        $traductions = json_decode($traductions, true);
+        foreach ($traductions as $k => $v) {
+            $traductions[$k] = $v;
+        }
+
+        $daoLang = new wsDAOLang($this->con);
+        $lang = $daoLang->selectById($base);
+        // Cleanup base translations
+        $baseTraductions = $lang->traductions;
+        foreach ($baseTraductions as $k => $v) {
+            $baseTraductions[$k] = $v;
+        }
+        // Then compare them. If there is no differences, we don't save translations in the book
+        if ($traductions == $baseTraductions) {
+            $t = '';
+        } else {
+            $t = json_encode($traductions);
+        }
+
+        $c = $this->con->openCursor('books');
+        $c->lang = $base;
+        $c->traductions = $t;
+        $c->changedate = TIME;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function setSettings($book_id, $settings)
+    {
+        $book = $this->selectById($book_id);
+        $parametres = $book->parametres;
+        $new = $settings;
+        $root = ['lang', 'proprietaire_id', 'status'];
+        $rootSettings = [];
+        foreach ($new as $k => $v) {
+            if ($k == '_empty_') {
+                continue;
+            }
+            if (in_array($k, $root)) {
+                $rootSettings[$k] = $v;
+            } else {
+                try {
+                    $parametres->$k = $v;
+                } catch (Exception $e) {
+
+                }
+            }
+        }
+
+
+        $ip = array();
+        if (isset($parametres->stats_exclude_ip) && trim($parametres->stats_exclude_ip) != '') {
+            $list = $parametres->stats_exclude_ip;
+            $list = str_replace("\r", "\n", $list);
+            $e = explode("\n", $list);
+            foreach ($e as $i) {
+                $i = trim($i);
+                if ($i == '') {
+                    continue;
+                }
+                $long = ip2long($i);
+                if ($long !== false) {
+                    $ip[] = $long;
+                }
+            }
+        }
+
+        $file = '/home/stats/www/exclude/' . $book_id;
+
+        if (count($ip)) {
+            file_put_contents($file, implode(',', $ip));
+            chmod($file, 0777);
+            chown($file, 'stats');
+        } else if (file_exists($file)) {
+            unlink($file);
+        }
+
+        $c = $this->con->openCursor('books');
+        $c->nom = $parametres->title;
+        $c->parametres = serialize($parametres);
+        $c->changedate = TIME;
+        foreach ($rootSettings as $k => $v) {
+            $c->$k = $v;
+        }
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function setProprietaire($book_id, $proprietaire_id)
+    {
+        $c = $this->con->openCursor('books');
+        $c->proprietaire = $proprietaire_id;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function setTache($book_id, $tache)
+    {
+        $c = $this->con->openCursor('books');
+        $c->tache = $tache;
+        $c->status = 2;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function setVersion($book_id, $version)
+    {
+        $c = $this->con->openCursor('books');
+        $c->version = $version;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function touch($book_id)
+    {
+        $c = $this->con->openCursor('books');
+        $c->changedate = TIME;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function touchCompile($book_id, $version = 'all')
+    {
+        $c = $this->con->openCursor('books');
+        if ($version == '2') {
+            $c->compiledate = TIME;
+        } elseif ($version == '1') {
+            $c->compile1date = TIME;
+        } elseif ($version == 'html5') {
+            $c->compilehtml5date = TIME;
+        } else {
+            $c->compiledate = TIME;
+            $c->compile1date = TIME;
+            $c->compilehtml5date = TIME;
+        }
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function isUpToDate($book, $version)
+    {
+        $version = (string)$version;
+        if ($version == '2') {
+            if (!file_exists(WS_BOOKS . '/final/' . $book->book_id)) {
+                return false;
+            }
+            if ($book->compiledate < $book->changedate) {
+                return false;
+            }
+        } else if ($version == '1') {
+            // V1
+            if (!file_exists(WS_BOOKS . '/finalv1/' . $book->book_id . '/index.swf')) {
+                return false;
+            }
+            if ($book->compile1date < $book->changedate) {
+                return false;
+            }
+        } else if ($version == 'html5') {
+            return false;
+            // HTML5
+            $checks = array($book->changedate, cubeFiles::filemtimeRecursive(WS_BOOKS . '/working/' . $book->book_id), cubeFiles::filemtimeRecursive(WS_COMPILE_ASSETS . '/_html5'), cubeFiles::filemtimeRecursive(ROOT . '/inc/ws/Util/html5'));
+            foreach ($checks as $check) {
+                if ($check > $book->compilehtml5date) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public function setComposition($book_id, $pages)
+    {
+        $numerotation = array();
+        $nb_pages = 0;
+        foreach ($pages as $p) {
+            $numerotation[] = $p->virtual;
+            $nb_pages++;
+        }
+
+        $book = $this->selectById($book_id);
+        $parametres = $book->parametres;
+        $parametres->pages = $nb_pages;
+
+        $c = $this->con->openCursor('books');
+        $c->parametres = serialize($parametres);
+        $c->numerotation = implode(',', $numerotation);
+        $c->changedate = TIME;
+
+        // Check if composition need to be updated
+        $r = $this->con->select('SELECT * FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+        $tab = array();
+        $now = array();
+        $ref = array();
+        while ($r->fetch()) {
+            $ref[$r->book_page] = array((int)$r->document_id, (int)$r->document_page);
+        }
+        $i = 1;
+        foreach ($pages as $p) {
+            $now[$i] = array((int)$p->document_id, (int)$p->document_page);
+            $i++;
+        }
+        if ($now != $ref) {
+            $this->con->execute('DELETE FROM book_pages WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+
+            $c1 = $this->con->openCursor('book_pages');
+            $c1->book_id = $book_id;
+            $i = 1;
+            foreach ($pages as $p) {
+                $c1->document_id = $p->document_id;
+                $c1->document_page = $p->document_page;
+                $c1->book_page = $i;
+                $c1->insert();
+                $i++;
+            }
+            $c->composition_update = TIME;
+            $this->saveCompositionVersion($book_id);
+        }
+
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function setInstallDir($book_id, $dir, $server)
+    {
+        $col = 'dir_' . $server;
+
+        $c = $this->con->openCursor('books');
+        $c->$col = $dir;
+        $c->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\'');
+    }
+
+    public function makeTextsIndexes($book, $pages, &$index, &$textes, $simple = false)
+    {
+        global $core;
+        $prefix = '';
+        if ($book->parametres->textExtraction == 'poppler') {
+            $prefix = 'p';
+        } else if ($book->parametres->textExtraction == 'fluidbook') {
+            $prefix = 'f';
+        }
+
+        $dir = WS_BOOKS . '/index/' . $book->book_id;
+        if ($book->parametres->ignoreSearchSeparators != '') {
+            $dir .= '/' . sha1($book->parametres->ignoreSearchSeparators);
+        }
+        if (!file_exists($dir)) {
+            mkdir($dir, 0777, true);
+        }
+
+        if ($simple) {
+            $ifilec = $dir . '/' . $prefix . 'sindex.json';
+        } else {
+            $ifilec = $dir . '/' . $prefix . 'index.json';
+        }
+        $tfilec = $dir . '/' . $prefix . 'textes.json';
+
+        if (CubeIT_Util_Gzip::file_exists($ifilec) && CubeIT_Util_Gzip::file_exists($tfilec) && (min(CubeIT_Util_Gzip::filemtime($ifilec), CubeIT_Util_Gzip::filemtime($tfilec)) >= max($book->composition_update, filemtime(__FILE__), filemtime(WS_TOOLS . '/fwstk/out/artifacts/fwstk_jar/fwstk.jar')))) {
+            $index = CubeIT_Util_Gzip::file_get_contents($ifilec);
+            $textes = CubeIT_Util_Gzip::file_get_contents($tfilec);
+            return;
+        }
+
+        if ($book->parametres->ignoreSearchSeparators != "") {
+            $docs = array();
+            foreach ($pages as $p => $i) {
+                $docs[] = $i['document_id'];
+            }
+            $docs = array_unique($docs);
+
+            foreach ($docs as $doc) {
+                $out = wsDocument::getDir($doc);
+
+                $fwstk = new cubeCommandLine('fwstk.sh');
+                $fwstk->setPath(CONVERTER_PATH);
+                $fwstk->setArg('--input ' . $out . '/crop.pdf');
+                $fwstk->setArg('--extractTexts ' . $out . '%s%d.txt');
+                $fwstk->setArg('--extractTextsMethod ' . $book->parametres->textExtraction);
+                $fwstk->setArg('--threads 1');
+                $fwstk->setArg('--ignoreSeparators ' . $book->parametres->ignoreSearchSeparators);
+                $fwstk->execute();
+            }
+        }
+
+        $index = array();
+        $textes = array();
+        foreach ($pages as $book_page => $infos) {
+            $tfile = wsDocument::getDir($infos['document_id']) . $prefix . 'p' . $infos['document_page'] . '.txt';
+            $ifile = wsDocument::getDir($infos['document_id']) . $prefix . 'i' . $infos['document_page'] . '.txt';
+
+            if (!file_exists($tfile) || !file_exists($ifile)) {
+                $daoDoc = new wsDAODocument($core->con);
+                $out = wsDocument::getDir($infos['document_id']);
+
+                $fwstk = new cubeCommandLine('fwstk.sh');
+                $fwstk->setPath(CONVERTER_PATH);
+                $fwstk->setArg('--input ' . $out . '/crop.pdf');
+                $fwstk->setArg('--extractTexts ' . $out . '%s%d.txt');
+                $fwstk->setArg('--extractTextsMethod ' . $book->parametres->textExtraction);
+                if ($book->parametres->ignoreSearchSeparators != '') {
+                    $fwstk->setArg('--ignoreSeparators ' . $book->parametres->ignoreSearchSeparators);
+                }
+                $fwstk->setArg('--threads 1');
+                $fwstk->execute();
+            }
+
+            CubeIT_Util_Gzip::compressIfNotCompressed($tfile);
+            CubeIT_Util_Gzip::compressIfNotCompressed($ifile);
+            $text = CubeIT_Util_Gzip::file_get_contents($tfile);
+            $ipage = CubeIT_Util_Gzip::file_get_contents($ifile);
+
+            if ($simple) {
+                $this->fillIndexWithWordsSimple($index, $book_page, $ipage);
+            } else {
+                $this->fillIndexWithWords($index, $book_page, $ipage);
+            }
+            $textes[$book_page] = $text;
+        }
+        ksort($index);
+
+        $textes = json_encode($textes);
+        $index = json_encode($index);
+
+        CubeIT_Util_Gzip::file_put_contents($tfilec, $textes);
+        CubeIT_Util_Gzip::file_put_contents($ifilec, $index);
+    }
+
+    public function makeHighlightIndex($book, $pages)
+    {
+        $jar = WS_TOOLS . '/fwstk/out/artifacts/fwstk_jar/fwstk.jar';
+
+        $daoDoc = new wsDAODocument($this->con);
+        $res = new stdClass();
+        foreach ($pages as $book_page => $infos) {
+            $fby = wsDocument::getDir($infos['document_id']) . 'html/p' . $infos['document_page'] . '.fby';
+            // Refresh highlight data if fby file doesn't exists or if fwstk has been updated
+            $fbymtime = @filemtime($fby);
+            if (!file_exists($fby) || filemtime($jar) > $fbymtime || filemtime(__FILE__) > $fbymtime) {
+                $doc = $daoDoc->selectById($infos['document_id']);
+                $doc->getHighlightTextsData();
+            }
+
+            if (file_exists($fby)) {
+                $words = CubeIT_Util_Json::decode(file_get_contents($fby), CubeIT_Util_Json::TYPE_OBJECT);
+
+                if (is_array($words)) {
+                    foreach ($words as $i => $w) {
+                        $word = $w->word;
+                        $word = trim($word, "\0");
+                        if ($word == '') {
+                            continue;
+                        }
+                        unset($w->word);
+                        $w->page = $book_page;
+                        $w->idx = $i;
+                        if (!isset($res->{$word})) {
+                            $res->{$word} = array();
+                        }
+                        $res->{$word}[] = $w;
+                    }
+                }
+            }
+        }
+        return $res;
+    }
+
+    protected function _escapeIndex($str)
+    {
+        $todelete = array('\ufffd');
+        foreach ($todelete as $d) {
+            $str = str_replace($d, '', $str);
+        }
+        return $str;
+    }
+
+    protected function fillIndexWithWordsSimple(&$index, $page, $ipage)
+    {
+        $twords = explode("\n", trim($ipage));
+
+        foreach ($twords as $woadata) {
+            $w1 = explode(',', trim($woadata));
+            if (count($w1) <= 1) {
+                continue;
+            }
+            list($woa, $worddata) = $w1;
+            $e = explode("\t", $worddata, 2);
+            if (count($e) < 2) {
+                continue;
+            }
+            list($total, $wordslist) = $e;
+
+            if ($woa == '') {
+                continue;
+            }
+
+            if (!isset($index[$woa])) {
+                $index[$woa] = array('t' => 0, 'p' => array());
+            }
+            $index[$woa]['t'] += $total;
+
+            $words = explode("\t", $wordslist);
+            foreach ($words as $word) {
+                list($wordwa, $count) = explode('$', $word, 2);
+                if (!isset($index[$woa]['p'][$page])) {
+                    $index[$woa]['p'][$page] = 0;
+                }
+                $index[$woa]['p'][$page] += $count;
+            }
+        }
+    }
+
+    protected function fillIndexWithWords(&$index, $page, $ipage)
+    {
+        $twords = explode("\n", trim($ipage));
+
+        foreach ($twords as $woadata) {
+            $w1 = explode(',', trim($woadata));
+            if (count($w1) <= 1) {
+                continue;
+            }
+            list($woa, $worddata) = $w1;
+            $e = explode("\t", $worddata, 2);
+            if (count($e) < 2) {
+                continue;
+            }
+            list($total, $wordslist) = $e;
+
+            if ($woa == '') {
+                continue;
+            }
+
+            if (!isset($index[$woa])) {
+                $index[$woa] = array('t' => 0, 'w' => array());
+            }
+            $index[$woa]['t'] += $total;
+
+            $words = explode("\t", $wordslist);
+
+            foreach ($words as $word) {
+                list($wordwa, $count) = explode('$', $word, 2);
+                if (!isset($index[$woa]['w'][$wordwa])) {
+                    $index[$woa]['w'][$wordwa] = array('t' => 0, 'p' => array());
+                }
+                if (!isset($index[$woa]['w'][$wordwa]['p'][$page])) {
+                    $index[$woa]['w'][$wordwa]['p'][$page] = 0;
+                }
+                $index[$woa]['w'][$wordwa]['t'] += $count;
+                $index[$woa]['w'][$wordwa]['p'][$page] += $count;
+            }
+        }
+    }
+
+    public function getNumerotationFromDocs($book_id)
+    {
+        $pages = $this->getPagesOfBook($book_id);
+    }
+
+    public function compileTemp($book_id, $version, $dir)
+    {
+        if ($version == 'ha' || $version == 'hi') {
+            if ($version == 'ha') {
+                $os = 'android';
+            } elseif ($version == 'hi') {
+                $os = 'ios';
+            }
+            $packager = new wsPackagerPhonegap($book_id, $dir, false, true, $os);
+            $packager->makePackage(false);
+        }
+    }
+
+    public function compile($book_id, $version = 'all', $complete = false, $force = false, $dev = false, $book = null, $delete = true)
+    {
+        if (is_null($book_id) || !$book_id) {
+            return;
+        }
+
+        $v1 = $v2 = $html5 = false;
+
+        if ($version == 'all') {
+            $v1 = $v2 = $html5 = true;
+        } else if ($version == '1') {
+            $v1 = true;
+        } else if ($version == '2') {
+            $v2 = true;
+        } elseif ($version == 'html5') {
+            $html5 = true;
+        }
+
+        if (null === $book) {
+            $book = $this->selectById($book_id);
+        }
+        $pages = $this->getPagesOfBook($book_id);
+
+        if (!$force) {
+            $v1 = $v1 && !$this->isUpToDate($book, 1);
+            $v2 = $v2 && !$this->isUpToDate($book, 2);
+            $html5 = $html5 && !$this->isUpToDate($book, 'html5');
+        } else {
+            $v1 = false;
+            $html5 = true;
+            $v2 = true;
+        }
+
+        $res = '';
+        if ($v1) {
+            fb(time(), 'Compile V1');
+            $res .= $this->compile1($book_id, $book, $pages);
+            $this->touchCompile($book_id, '1');
+        }
+        if ($v2) {
+            fb(time(), 'Compile V2');
+            $res .= $this->compile3($book_id, $complete, $book, $pages);
+            $this->touchCompile($book_id, '2');
+        }
+        if ($html5) {
+            fb(time(), 'Compile HTML5');
+            $res .= $this->compileHTML5($book_id, $book, $dev, $delete);
+            $this->touchCompile($book_id, 'html5');
+        }
+        if ($v1 || $v2) {
+            fb(time(), 'Compile PDF & Widget');
+            $this->compilePDF($book, $pages);
+            $this->compileWidget($book, $pages);
+        }
+
+        fb(time(), 'End Compile');
+        return $res;
+    }
+
+    public function compile1($book_id, $book, $pages)
+    {
+        $finalDir = WS_BOOKS . '/finalv1/' . $book_id . '/';
+        $packager = new wsPackagerV1($book_id, $finalDir, false);
+        $packager->makePackage(false);
+    }
+
+    public function compile3($book_id, $complete, $book, $pages)
+    {
+        $res = '';
+
+        $compilerDir = WS_BOOKS . '/datasCompiler/' . $book_id . '/';
+        $finalDir = WS_BOOKS . '/final/' . $book_id . '/';
+
+        $vdir = new CubeIT_Files_VirtualDirectory($finalDir);
+
+        $debug = false;
+
+        $flex = new cubeFlexCompiler('FluidbookDatas', $compilerDir, 'flash.display.Sprite', explode(';', AS3_SOURCES), MXMLC_PATH, 10, 30, 800, 600, $debug);
+        $flexLight = new cubeFlexCompiler('FluidbookDatasLight', $compilerDir, 'flash.display.Sprite', explode(';', AS3_SOURCES), MXMLC_PATH, 10, 30, 800, 600, $debug);
+
+        $filesToCopy = array();
+        $this->compileFlex($book_id, $complete, $compilerDir, $vdir, $filesToCopy, $book, $pages, $flex, $flexLight, $finalDir);
+
+        $res .= $flex->compile() . "\n\n-------------------\n\n";
+        $flexLight->addVariable('datasSize', filesize($compilerDir . '/FluidbookDatas.swf'));
+        $res .= $flexLight->compile();
+
+        $filesToCopy['data/fd.swf'] = $compilerDir . '/FluidbookDatas.swf';
+        $filesToCopy['data/fdl.swf'] = $compilerDir . '/FluidbookDatasLight.swf';
+
+        // Copy of files
+        // Check if dest dir exists
+
+        foreach ($filesToCopy as $local => $source) {
+            $localPath = $local;
+            $vdir->copy($source, $localPath);
+        }
+
+        $workingDir = WS_BOOKS . '/working/' . $book_id . '/';
+        $vdir->copyDirectory($workingDir . 'media', 'data');
+        $vdir->sync(true);
+
+        return $res;
+    }
+
+    public function copy($source, $dest)
+    {
+        copy($source, $dest);
+        touch($dest, filemtime($source));
+    }
+
+    public static function getDocumentPage($book_id, $book_page)
+    {
+        global $core;
+        $dao = new wsDAOBook($core->con);
+        $pages = $dao->getPagesOfBook($book_id);
+        return $pages[$book_page];
+    }
+
+    public function compileAir($book_id)
+    {
+        $compilerDir = WS_BOOKS . '/air/' . $book_id . '/compiler';
+        $finalDir = WS_BOOKS . '/air/' . $book_id . '/';
+
+        $book = $this->selectById($book_id);
+        $pages = $this->getPagesOfBook($book_id);
+
+        $src = AS3_FLUIDBOOK_SOURCES . '/_src/';
+        $lib10 = AS3_FLUIDBOOK_SOURCES . '/lib10/';
+        $libs = array(
+            $src,
+            $lib10,
+            AS3_SOURCES,
+            $src . 'lib/fluidbook3dLibrary.swc',
+            $src . 'lib/mdm.swc',
+            $lib10 . 'flash.swc',
+            $lib10 . 'flex.swc',
+            $lib10 . 'framework.swc',
+        );
+
+        wsSVN::updateToLastRevision();
+
+        $swf = 'FluidbookAirProjector' . $book_id;
+        $flex = new cubeFlexCompiler($swf, $compilerDir, 'com.fluidbook.player.AIRMain', $libs, '/usr/local/flex/bin/mxmlc', 'air', 45, 800, 600, true);
+
+        $this->compileFlex($book_id, true, $compilerDir, $finalDir, $filesToCopy, $book, $pages, $flex, $flex);
+        $res = $flex->compile();
+
+        $air = new cubeAIRCompiler($swf . '.swf', '/usr/local/flex/bin', $compilerDir, '2.0');
+        $air->setApplicationDatas('com.fluidbook' . $book_id, $book->parametres->title, $book->parametres->title, cubeText::str2URL($book->parametres->title), $book->lang);
+        $air->setInitialWindow($book->parametres->title);
+        $res .= $air->compile();
+
+        return $res;
+    }
+
+    public function compileFlex($book_id, $complete, $compilerDir, $vdir, &$filesToCopy, $book, $pages, $flex, $flexLight)
+    {
+        /* @var $vdir CubeIT_Files_VirtualDirectory */
+
+        cubePHP::neverStop();
+        /* @var $flex cubeFlexCompiler */
+
+        $workingDir = WS_BOOKS . '/working/' . $book_id . '/';
+
+        $res = '';
+
+        $daoDoc = new wsDAODocument($this->con);
+        $firstDoc = $daoDoc->selectById($pages[1]['document_id']);
+        $size = $firstDoc->generalInfos['size'];
+
+        $daoLang = new wsDAOLang($this->con);
+        $lang = $daoLang->selectById($book->lang);
+
+        $langs = $daoLang->selectAll();
+
+        $daoTheme = new wsDAOTheme($this->con);
+        $theme = $daoTheme->getThemeOfBook($book_id, true);
+
+        $daoSignature = new wsDAOSignature($this->con);
+        $signature = $daoSignature->selectById($book->parametres->signature);
+
+        $exportSignature = array('main' => $signature->main,
+            'mainLink' => $signature->mainLink,
+            'partner' => $signature->partner,
+            'partnerLink' => $signature->partnerLink);
+
+        $index = '';
+        $textes = '';
+        $pageLabels = array();
+
+        $hash = $book_id;
+        $hash .= 'kjgl!az4.';
+        $hash .= count($pages);
+        $hash .= round($size[0], 3);
+
+        $hash = sha1($hash);
+
+        $this->makeTextsIndexes($book, $pages, $index, $textes);
+
+        $daoDoc->getLinksAndRulers($book_id, $links, $rulers);
+
+        $audiodescription = array();
+
+        $imagesassets = array();
+        $id = 1;
+        $ignoreLinks = array();
+        foreach ($links as $id => $link) {
+            $links[$id]['id'] = $id;
+            $skipCopyAsset = false;
+
+            if (isset($link['image']) && $link['image']) {
+                $workingFile = $workingDir . '/' . $link['image'];
+                $assetId = 'link_datas_i_' . md5($link['image']);
+
+                if (isset($imagesassets[$assetId])) {
+
+                } else {
+                    if (file_exists($workingFile)) {
+                        if ($link['page'] <= 1) {
+                            $flexLight->addBitmap($workingFile, $assetId);
+                        } else {
+                            $flex->addBitmap($workingFile, $assetId);
+                        }
+                    }
+                    $imagesassets[$assetId] = true;
+                }
+            }
+
+            if ($link['type'] == 16 && $book->parametres->linkFilePrefix) {
+                if (!CubeIT_Util_Url::isDistant($link['to'])) {
+                    $skipCopyAsset = true;
+                    $links[$id]['to'] = $book->parametres->linkFilePrefix . $link['to'];
+                }
+            }
+
+            if ($link['type'] == 15) {
+                if (isset($imagesassets[$id])) {
+                    continue;
+                }
+                if ($link['page'] <= 1) {
+                    $flexLight->addBitmap($workingDir . '/' . $link['to'], 'link_datas_' . $id);
+                } else {
+                    $flex->addBitmap($workingDir . '/' . $link['to'], 'link_datas_' . $id);
+                }
+                $imagesassets[$id] = true;
+            } else if (in_array($link['type'], array(4, 6, 7, 9, 16, 17, 25))) {
+                if (!$skipCopyAsset) {
+                    $workingFile = $workingDir . '/' . $link['to'];
+                    if (file_exists($workingFile)) {
+                        $filesToCopy['data/' . $link['to']] = $workingFile;
+                    }
+
+                    if ($link['type'] == 4) {
+                        $poster = $link['to'];
+                        $e = explode('.', $poster);
+                        array_pop($e);
+                        array_push($e, 'jpg');
+                        $poster = implode('.', $e);
+
+                        $workingFile = $workingDir . '/' . $poster;
+                        if (file_exists($workingFile)) {
+                            $filesToCopy['data/' . $poster] = $workingFile;
+                        }
+                    }
+                }
+            }
+
+            if ($link['type'] == 25) {
+                $audiodescription[$link['page']] = $link['to'];
+                $ignoreLinks[] = $id;
+            }
+            if ($link['type'] == 26) {
+                $pageLabels[$link['to']] = $link['page'];
+                $ignoreLinks[] = $id;
+            }
+        }
+
+        foreach ($ignoreLinks as $ignoreLink) {
+            unset($links[$ignoreLink]);
+        }
+        $links = array_values($links);
+
+        $externalsOptions = array('ongletsSWF', 'tabs2DSWF', 'externalChapters', 'externalArchives', 'ambientSound');
+        foreach ($externalsOptions as $e) {
+            if (isset($book->parametres->$e) && $book->parametres->$e != '') {
+                $f = $workingDir . '/' . $book->parametres->$e;
+                if (file_exists($f)) {
+                    $filesToCopy['data/' . $book->parametres->$e] = $f;
+                }
+            }
+        }
+
+        $flex->addVariable('audiodescription', $audiodescription, false, true, "JSONObject");
+        $flex->addVariable('pagelabels', $pageLabels, false, true, 'JSONObject');
+        $flex->addVariable('links', $links, false, true, 'JSONObject');
+
+        $flex->addVariable('signature', $exportSignature, false, true, 'JSONObject');
+        $flexLight->addVariable('datas', $book->parametres->toStandardObject(), false, true, 'JSONObject');
+        $flexLight->addVariable('id', $book_id, false, true, 'uint');
+        $flexLight->addVariable('cid', $book->cid, false, true, 'String');
+
+        $traductions = (!count($book->traductions)) ? $lang->traductions : $book->traductions;
+        $allTraductions = array();
+        foreach ($langs as $l) {
+            $allTraductions[$l->lang_id] = $l->traductions;
+        }
+
+        $flex->addVariable('traductions', $traductions, false, true, 'JSONObject', false);
+        $flex->addVariable('allTraductions', $allTraductions, false, true, 'JSONObject');
+        $flex->addVariable('chapters', $book->chapters, false, true, 'JSONObject');
+        $flex->addVariable('extras', '<extras>' . $book->extras . '</extras>', false, true, 'XML');
+        $flex->addVariable('numerotation', $book->numerotation, false, true, 'String');
+        $flexLight->addVariable('theme', $theme->parametres->toStandardObject(), false, true, 'JSONObject');
+        $flexLight->addVariable('pages', $book->parametres->pages);
+        $flexLight->addVariable('fwidth', round($size[0], 4), false, true, 'Number');
+        $flexLight->addVariable('fheight', round($size[1], 4), false, true, 'Number');
+        $flexLight->addVariable('pagesInDatas', $complete, false, true, 'Boolean');
+        $flex->addVariable('index', $index, false, true, 'JSONObject', false, false);
+        $flex->addVariable('textes', $textes, false, true, 'JSONObject', false, false);
+
+        $rasterized = array();
+        $sizes = array();
+
+        foreach ($pages as $i => $infos) {
+            $base = wsDocument::getDir($infos['document_id']) . 'p' . $infos['document_page'];
+            $baset = wsDocument::getDir($infos['document_id']) . 't' . $infos['document_page'];
+            $swffile = $base . '.swf';
+            if (file_exists($swffile)) {
+                clearstatcache(true, $swffile);
+                $fsize = filesize($swffile);
+            } else {
+                $fsize = 0;
+            }
+
+            if ($complete) {
+                $flex->addSWF($swffile, 'page' . $i);
+            } else {
+                $filesToCopy['data/p' . $i . '.swf'] = $swffile;
+                if ($infos['method'] >= wsDocument::BARBARE_PNM) {
+                    $rasterized[$i] = true;
+                    $filesToCopy['data/t' . $i . '.swf'] = $baset . '.swf';
+                } else {
+                    $rasterized[$i] = false;
+                }
+            }
+
+            $thumb = false;
+            if ($book->parametres->pdfThumbnails) {
+                $thumb = wsPDFConvert::getThumbFromPDF($workingDir . '/' . $book->parametres->pdfThumbnails, $i);
+            }
+            if (!$thumb) {
+                $thumb = $base . '.jpg';
+            }
+
+            if ($i == 1) {
+                $flexLight->addBitmap($thumb, 'thumb1');
+            } else {
+                $flex->addBitmap($thumb, 'thumb' . $i);
+            }
+            $sizes[$i] = $fsize;
+        }
+
+        $flexLight->addVariable('rasterized', $rasterized, false, true, 'JSONObject');
+        $flexLight->addVariable('sizes', $sizes, false, true, 'JSONObject');
+
+        if ($book->parametres->soundTheme != '') {
+            $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/corner-drag.mp3', 'soundDragCorner');
+            $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/corner-release.mp3', 'soundReleaseCorner');
+            $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/page-flip-1.mp3', 'soundPage0');
+            $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/page-flip-2.mp3', 'soundPage1');
+            $flex->addSound(WS_SOUNDS . '/' . $book->parametres->soundTheme . '/cover-flip.mp3', 'soundCover0');
+        }
+        // Theme assets
+        $themeRoot = WS_THEMES . '/' . $theme->theme_id . '/';
+
+        if ($theme->parametres->backgroundImage != '') {
+            $flexLight->addBitmap($themeRoot . $theme->parametres->backgroundImage, 'background');
+        }
+        if ($theme->parametres->menuImage != '') {
+            $flex->addBitmap($themeRoot . $theme->parametres->menuImage, 'menu');
+        }
+        if ($theme->parametres->logoLoader != '') {
+            $flexLight->addBitmap($themeRoot . $theme->parametres->logoLoader, 'logoLoader');
+        }
+        if ($theme->parametres->topBar != '') {
+            $flexLight->addBitmap($themeRoot . $theme->parametres->topBar, 'topBar');
+        }
+        if ($theme->parametres->logo != '') {
+            $flex->addBitmap($themeRoot . $theme->parametres->logo, 'logo');
+        }
+        if ($theme->parametres->afterSearch != '') {
+            $flex->addBitmap($themeRoot . $theme->parametres->afterSearch, 'aftersearch');
+        }
+        if ($theme->parametres->favicon != '') {
+            $filesToCopy['data/fluidbook.ico'] = $themeRoot . 'fluidbook.ico';
+        }
+
+        // Icons assets
+        $iconsRoot = WS_ICONS . '/' . $theme->parametres->iconSet . '/';
+        foreach (wsIcone::$files as $file) {
+            $flex->addBitmap($iconsRoot . 'nav-' . $file . '.png', 'nav_' . $file);
+        }
+        // Share icons
+        $iconsRoot = WS_ICONS . '/share/';
+        foreach (wsIcone::$share as $file) {
+            $flex->addBitmap($iconsRoot . 'share-' . $file . '.png', 'share_' . $file);
+        }
+
+        // Multilang
+        if (trim($book->parametres->multilang) != '') {
+            $m = str_replace("\r", "\n", trim($book->parametres->multilang));
+            $langs = explode("\n", $m);
+            $langNames = array();
+            $countryNames = array();
+            $iso = l10n::getISOcodes();
+            $chars = '()';
+            $vuFlags = array();
+            foreach ($langs as $l) {
+                list($mlang, $flag, $url) = explode(',', trim($l), 3);
+                if (!isset($vuFlags[$flag])) {
+                    $flex->addBitmap(cubeMedia::getFlagFile($flag), 'flag_' . $flag);
+                    $vuFlags[$flag] = true;
+                }
+                $ll = explode('-', $mlang);
+                $n = cubeText::ucfirst($iso[$ll[0]]);
+                $langNames[$mlang] = $n;
+                $cn = cubeCountry::getCountryName($flag, $mlang);
+                $countryNames[$mlang . '_' . $flag] = $cn;
+                $chars .= $n . $cn;
+            }
+
+            $chars = preg_split('/(?<!^)(?!$)/u', $chars);
+            $chars = array_unique($chars);
+
+            $flex->addFont(WS_FILES . '/fonts/FluidbookMultilang.ttf', 'MultilangFont', $chars);
+            $flex->addVariable('langNames', $langNames, false, true, 'JSONObject');
+            $flex->addVariable('countryNames', $countryNames, false, true, 'JSONObject');
+        }
+        $flexLight->addVariable('lang', $book->lang);
+
+        // Basket
+        if ($book->parametres->basket) {
+            $formats = array('jpg', 'png', 'jpeg');
+            $referencesFile = self::getWorkingFile($book->parametres->basketReferences, $book_id, 'commerce');
+
+            if (file_exists($referencesFile) || CubeIT_Util_Url::isDistant($referencesFile)) {
+                $ext = CubeIT_Files::getExtension($referencesFile);
+                if ($ext == 'xml') {
+                    $xml = simplexml_load_file($referencesFile);
+                    $i = 0;
+                    $allref = array();
+                    foreach ($xml->item as $item) {
+                        $ref = (string)$item['reference'];
+                        if (isset($allref[$ref])) {
+                            continue;
+                        }
+                        $allref[$ref] = true;
+                        foreach ($formats as $f) {
+                            $refimage = $workingDir . 'commerce/' . $ref . '.' . $f;
+                            if (file_exists($refimage)) {
+                                $flex->addBitmap($refimage, "basket_image_" . $ref);
+                                break;
+                            }
+                        }
+                        $i++;
+                    }
+                } elseif ($ext == 'xlsx') {
+                    $references = wsUtil::excelToArray($referencesFile);
+                    if ($book->parametres->customLinkClass == 'AtlanticDownloadLink') {
+                        $references = wsUtil::atlanticReferences($references, 'local/', null, array($vdir, 'copy'));
+                    }
+                    $flex->addVariable('basketReferences', $references, false, true, "OrderedObject");
+                }
+            }
+            if (isset($xml)) {
+                $flex->addVariable('basketReferences', cubeXML::condense($xml->asXML()), false, true, "String");
+            }
+            if ($book->parametres->basketPDFBackground != '') {
+                $flex->addByteArray($workingDir . 'commerce/' . $book->parametres->basketPDFBackground, 'basket_pdf_background');
+            }
+        }
+        // Fonts
+        if ($theme->parametres->fontKit == 'auto') {
+            if ($lang->font != 'system') {
+                $font = FONT_PATH . '/' . $lang->font;
+                $bfont = FONT_PATH . '/B' . $lang->font;
+                if (!file_exists($bfont)) {
+                    $bfont = $font;
+                }
+
+                $flex->addFont($bfont, 'BoldFont', $lang->charset);
+                $flex->addFont($font, 'GeneralFont', $lang->charset);
+            }
+            $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
+            $flexLight->addFont(FONT_PATH . '/FluidbookLoader.ttf', 'LoaderFont', 'Numerals');
+        } else if ($theme->parametres->fontKit == 'vagrounded') {
+            $flex->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Bold.otf', 'BoldFont', $lang->charset);
+            $flex->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Light.otf', 'GeneralFont', $lang->charset);
+            $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
+            $flexLight->addFont(FONT_PATH . '/vagrounded/VAGRoundedStd-Bold.otf', 'LoaderFont', 'Numerals');
+        } else if ($theme->parametres->fontKit == 'gill') {
+            $flex->addFont(FONT_PATH . '/gill/gill.ttf', 'BoldFont', $lang->charset);
+            $flex->addFont(FONT_PATH . '/gill/gill.ttf', 'GeneralFont', $lang->charset);
+            $flex->addFont(FONT_PATH . '/FluidbookCredits.ttf', 'CreditsFont', 'ASCII');
+            $flexLight->addFont(FONT_PATH . '/gill/gill.ttf', 'LoaderFont', 'Numerals');
+        }
+
+        $flexLight->addVariable('checksum', $hash, false, true, 'String');
+    }
+
+
+    public static function getWorkingFile($path, $book_id, $dir = "")
+    {
+        if (CubeIT_Util_Url::isDistant($path) || (substr($path, 0, 1) == '/' && file_exists($path))) {
+            return $path;
+        }
+
+        $workingDir = WS_BOOKS . '/working/' . $book_id . '/';
+        return $workingDir . trim($dir, '/') . '/' . $path;
+    }
+
+    public function compileWidget($book, $pages)
+    {
+        if (!$book->parametres->widget) {
+            return;
+        }
+
+        global $core;
+
+        $finalDir = WS_BOOKS . '/final/' . $book->book_id . '/widget/';
+        $finalWidget = $finalDir . 'miniFluidbook.swf';
+
+        if (!file_exists($finalDir)) {
+            mkdir($finalDir, 0777, true);
+        }
+
+        if ($book->parametres->widgetCover) {
+            $file = 'miniFluidbookCouv.swf';
+        } else {
+            $file = 'miniFluidbook.swf';
+        }
+        $mini = WS_COMPILE_ASSETS . '/_widget/' . $file;
+
+        $from = max(1, $book->parametres->widgetStart);
+        $to = min($book->parametres->widgetEnd, count($pages));
+
+        $swfcombine = new cubeCommandLine('swfcombine');
+        $swfcombine->setPath(CONVERTER_PATH);
+        $swfcombine->setArg('merge');
+        $swfcombine->setArg('stack1');
+        $swfcombine->setArg('z');
+        $swfcombine->setArg('o', $finalWidget);
+        $swfcombine->setArg(null, $mini);
+
+        $tempimage = array();
+        $tempswf = array();
+        $timg = array();
+
+        for ($i = $from; $i <= $to; $i++) {
+            $page = $pages[$i];
+
+            $timg[$i] = $tempimage[$i] = cubeFiles::tempnam();
+            $tempswf[$i] = cubeFiles::tempnam();
+
+            $it = new imageTools();
+            $image = wsDocument::getDir($page['document_id']) . '/html/t150-' . $page['document_page'] . '.jpg';
+
+            try {
+                $it->loadImage($image);
+                $it->resize($book->parametres->widgetSize, 10000);
+                $it->output('jpeg', $tempimage[$i], 100);
+            } catch (Exception $e) {
+                $tempimage[$i] = $image;
+            }
+            $jpg2swf = new cubeCommandLine('jpeg2swf');
+            $jpg2swf->setEnv('PATH', '/bin:/usr/bin:/usr/local/bin');
+            $jpg2swf->setArg('q', $book->parametres->widgetQuality);
+            $jpg2swf->setArg('o', $tempswf[$i]);
+            $jpg2swf->setArg(null, $tempimage[$i]);
+            $jpg2swf->execute();
+
+            $swfcombine->setArg(null, $tempswf[$i]);
+        }
+        $swfcombine->execute();
+
+        foreach ($timg as $t) {
+            if (file_exists($t)) {
+                unlink($t);
+            }
+        }
+        foreach ($tempswf as $t) {
+            unlink($t);
+        }
+    }
+
+    public function compileHTML5($book_id, $book, $dev = false, $delete = true)
+    {
+        $version = $book->parametres->mobileLVersion;
+        if ($dev) {
+            $version = 'dev';
+        }
+
+        $htmlCompiler = wsHTML5::compilerFactory($book_id, $version, false, 'latest', null, false, false, false, $book);
+        $htmlCompiler->compile($delete);
+    }
+
+    /* public function indexPDF($book, $pages) {
+      $indexPath = WS_BOOKS . '/search/' . $book->book_id;
+
+      Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8Num_CaseInsensitive());
+
+      if (file_exists($indexPath)) {
+      files::deltree($indexPath);
+      }
+      $index = Zend_Search_Lucene::create($indexPath);
+
+      foreach ($pages as $i => $infos) {
+      $doc = new Zend_Search_Lucene_Document();
+      $doc->addField(Zend_Search_Lucene_Field::Text('url', '#' . $i));
+      $doc->addField(Zend_Search_Lucene_Field::UnStored('contents', file_get_contents(wsDocument::getDir($infos['document_id']) . 'p' . $infos['document_page'] . '.txt')));
+      $index->addDocument($doc);
+      }
+
+      $c = $this->con->openCursor('books');
+      $c->lucene_time = TIME;
+      $c->update('WHERE book_id=' . $book->book_id);
+      } */
+
+    public function compilePDF($book, $pages)
+    {
+        $res = wsUtil::compilePDF($book, $pages);
+
+        $finalPDF = WS_BOOKS . '/final/' . $book->book_id . '/data/' . $book->parametres->pdfName;
+        if ($res) {
+            $this->copy($res, $finalPDF);
+        }
+    }
+
+    public function generateCID()
+    {
+
+        do {
+            $res = '';
+            for ($i = 0; $i < 8; $i++) {
+                $j = rand(0, 61);
+                $res .= $this->base62($j);
+            }
+            $r = $this->con->select('SELECT book_id FROM books WHERE cid=\'' . $res . '\'');
+            if ($r->count() == 0) {
+                return $res;
+            }
+        } while (true);
+    }
+
+    protected function base62($val)
+    {
+        $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+        $base = strlen($chars);
+        $str = '';
+        do {
+            $i = $val % $base;
+            $str = $chars[$i] . $str;
+            $val = ($val - $i) / $base;
+        } while ($val > 0);
+        return $str;
+    }
 
 }