]> _ Git - cubeextranet.git/commitdiff
fix #2124 @1.5
authorvincent@cubedesigners.com <vincent@cubedesigners.com@f5622870-0f3c-0410-866d-9cb505b7a8ef>
Fri, 13 Jul 2018 13:24:39 +0000 (13:24 +0000)
committervincent@cubedesigners.com <vincent@cubedesigners.com@f5622870-0f3c-0410-866d-9cb505b7a8ef>
Fri, 13 Jul 2018 13:24:39 +0000 (13:24 +0000)
inc/ws/Controlleur/class.ws.maintenance.php
inc/ws/DAO/class.ws.dao.book.php
inc/ws/DAO/class.ws.dao.document.php
inc/ws/Util/class.ws.links.php
inc/ws/Util/html5/master/class.ws.html5.links.php
inc/ws/Util/packager/class.ws.packager.html.php

index 3f0a50692a0930b47c33b5edb3f6feaa23466c90..51f8fe779f67b9530a1cc8896a99a5baff9e97df 100644 (file)
@@ -267,7 +267,8 @@ class wsMaintenance
 
        public static function copyLinks($args)
        {
-               list($from, $to) = $args;
+               $from=$args[0];
+               $to=$args[1];
                global $core;
 
                $dao = new wsDAODocument($core->con);
@@ -275,6 +276,7 @@ class wsMaintenance
                $dao->getLinksAndRulers($from, $fromlinks, $fromrulers);
                $dao->getLinksAndRulers($to, $tolinks, $torulers);
 
+
                $tolinks = array_merge($tolinks, $fromlinks);
                $torulers = array_merge($torulers, $fromrulers);
 
@@ -290,6 +292,7 @@ class wsMaintenance
                        $cmd = "cp -r $wf1 $wt";
                        echo `$cmd`;
                }
+
                $dao->setLinksAndRulers($to, $tolinks, $torulers, 'Copy links from #' . $from . '  to #' . $to, $core->user->utilisateur_id);
        }
 
@@ -783,7 +786,7 @@ class wsMaintenance
                        self::_duplicateLines('document_links', 'document_id', $doc, $newid);
                        self::_duplicateLines('document_links_versions', 'document_id', $doc, $newid);
 
-                       $f = WS_DOCS . '/' . $doc;
+                       $f = wsDocument::getDir($doc);
                        $t = WS_DOCS . '/' . $newid;
 
                        `cp -r $f $t`;
@@ -1146,6 +1149,29 @@ class wsMaintenance
                $dao->setLinksAndRulers($book_id, json_encode($newlinks), json_encode($rulers), 'Offset links positions (' . $direction . ' :: ' . $value . ')', $core->user->utilisateur_id);
        }
 
+       public static function duplicateBook($args)
+       {
+               global $core;
+
+               commonDroits::min(5);
+
+               $book_id = $args[0];
+               $times = isset($args[1]) ? $args[1] : 1;
+               $dao = new wsDAOBook($core->con);
+
+               for ($i = 0; $i < $times; $i++) {
+                       $newbook = $dao->duplicate($book_id, $core->user->utilisateur_id, null, false, true);
+                       $new_id = $newbook->book_id;
+                       self::copyComposition([$book_id, $new_id]);
+                       self::copyLinks([$book_id,$new_id]);
+
+                       $from_assets = WS_FILES . '/books/working/' . $book_id . '/';
+                       $to_assets = WS_FILES . '/books/working/' . $new_id . '/';
+
+                       `cp -r $from_assets $to_assets`;
+               }
+       }
+
        public static function extractTexts($args)
        {
                global $core;
index 36ff521b13820beac10b084f92cc7497f73f2fab..e7c238b96fa73a5ba4bd05b17ab9c854dc64d94f 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, $pages = 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);
-        $parametres->title = $nom;
-        $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);
-        }
-        $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 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)
-    {
-        if (!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;
-                        }
-                    }
-                }
-            }
-
-            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));
-        }
-
-        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) {
-            $c1->update('WHERE book_id=\'' . $this->con->escape($book_id) . '\' AND `update`=' . TIME);
-        }
-    }
-
-    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);
-
-        $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);
-
-                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)
-    {
-        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;
-        }
-
-        $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);
-            $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)
-    {
-        $version = $book->parametres->mobileLVersion;
-        if ($dev) {
-            $version = 'dev';
-        }
-
-        $htmlCompiler = wsHTML5::compilerFactory($book_id, $version);
-        $htmlCompiler->compile();
-    }
-
-    /* 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)
-    {
-        if (substr($book->parametres->pdfName, 0, 4) == 'http') {
-            return;
-        }
-        if (isset($book->parametres->pdfName) && $book->parametres->pdfName != '') {
-            $pdfName = $book->parametres->pdfName;
-        }
-
-        $cacheDir = WS_BOOKS . '/pdf/' . $book->book_id;
-        if (!file_exists($cacheDir)) {
-            mkdir($cacheDir, 0777, true);
-        }
-
-        $normalPDF = $cacheDir . '/normal.pdf';
-        $originalPDF = $cacheDir . '/original.pdf';
-        $compressedPDF = $cacheDir . '/compressed.pdf';
-
-        if (file_exists($originalPDF)) {
-            $fmtime = filemtime($originalPDF);
-            if ($fmtime >= $book->composition_update) {
-                $invalid = false;
-                foreach ($pages as $i => $infos) {
-                    $doc = wsDocument::getDir($infos['document_id']) . 'crop.pdf';
-                    if (filemtime($doc) > $fmtime) {
-                        $invalid = true;
-                    }
-                }
-            } else {
-                $invalid = true;
-            }
-        } else {
-            $invalid = true;
-        }
-
-
-        if ($invalid) {
-            $pdfList = array();
-            $pagesList = array();
-            $nb_pages = array();
-            $j = 0;
-            $k = 0;
-            $original = true;
-
-            foreach ($pages as $i => $infos) {
-                if (!isset($firstDoc)) {
-                    $firstDoc = $infos['document_id'];
-                }
-
-                $doc = wsDocument::getDir($infos['document_id']) . 'crop.pdf';
-                if (!isset($pdfList[$doc])) {
-                    $pdfList[$doc] = $j;
-                    $nb_pages[$doc] = $infos['nb_pages'];
-                    $k = $j;
-                    $j++;
-                } else {
-                    $k = $pdfList[$doc];
-                }
-                $pagesList[$i] = array($k, $infos['document_page']);
-
-                if ($i != $infos['document_page'] || $infos['document_id'] != $firstDoc) {
-                    $original = false;
-                }
-            }
-
-            if ($original) {
-
-                $this->copy(wsDocument::getDir($firstDoc) . 'crop.pdf', $originalPDF);
-            } else {
-                $args = '';
-                foreach ($pdfList as $doc => $index) {
-                    $lettre = cubeMath::toPDFLetter($index, true);
-                    $args .= $lettre . '=' . $doc . ' ';
-                }
-
-                $args .= ' cat ';
-
-                $ranges = array();
-                $currentRange = null;
-
-                foreach ($pagesList as $p) {
-                    $lettre = cubeMath::toPDFLetter($p[0], true);
-                    $page = $p[1];
-
-                    // Initialise l'intervale
-                    if (is_null($currentRange)) {
-                        $currentRange = array('lettre' => $lettre, 'start' => $page, 'end' => $page);
-                        continue;
-                    }
-
-                    // Poursuit le remplissage si la lettre est identique et si la page suivante est bien la page suivante dans le document
-                    if ($currentRange['lettre'] == $lettre && $currentRange['end'] + 1 == $page) {
-                        $currentRange['end'] = $page;
-                        continue;
-                    }
-
-                    // Ajoute l'intervale à la liste finale
-                    $ranges[] = $currentRange;
-
-                    // Réinitialise l'intervale suivant
-                    $currentRange = array('lettre' => $lettre, 'start' => $page, 'end' => $page);
-                }
-
-                // Ajoute la dernière
-                if (!is_null($currentRange)) {
-                    $ranges[] = $currentRange;
-                }
-                // Si le pdf final est constitué du document complet d'un document
-                if (count($ranges) == 1 && $ranges[0]['start'] == 1) {
-                    $alldocs = array_keys($pdfList);
-                    $doc = array_pop($alldocs);
-                    if ($nb_pages[$doc] == $ranges[0]['end']) {
-                        $this->copy($doc, $originalPDF);
-                        return;
-                    }
-                }
-
-                foreach ($ranges as $range) {
-                    $args .= ' ' . $range['lettre'] . $range['start'];
-                    if ($range['start'] == $range['end']) {
-                        continue;
-                    }
-                    $args .= '-' . $range['end'];
-                }
-
-                $hash = sha1($args);
-
-                $args .= ' output ' . $originalPDF;
-
-                $cached = WS_BOOKS . '/pdf/' . $hash . '.pdf';
-
-                if (file_exists($cached)) {
-                    $this->copy($cached, $originalPDF);
-                } else {
-                    $pdftk = new cubeCommandLine('pdftk');
-                    $pdftk->setPath(CONVERTER_PATH);
-                    $pdftk->setManualArg($args);
-                    $pdftk->execute();
-                    $this->copy($normalPDF, $cached);
-                }
-            }
-        }
-
-
-        if ($book->parametres->pdfReplace) {
-            $replace = WS_BOOKS . '/working/' . $book->book_id . '/' . $book->parametres->pdfReplace;
-            if (file_exists($replace)) {
-                if (!file_exists($normalPDF) || filemtime($normalPDF) < filemtime($replace) || filesize($normalPDF) != filesize($replace)) {
-                    $this->copy($replace, $normalPDF);
-                }
-            }
-        } else {
-            $this->copy($originalPDF, $normalPDF);
-        }
-        $finalPDF = WS_BOOKS . '/final/' . $book->book_id . '/data/' . $book->parametres->pdfName;
-
-        if ($book->parametres->pdfCompress) {
-            if (!file_exists($compressedPDF) || filemtime($compressedPDF) < filemtime($normalPDF)) {
-                $gs = new cubeCommandLine('gs', null, true);
-                $gs->setPath(CONVERTER_PATH);
-                $gs->setEnv('GS_FONTPATH', '/home/ws/fonts');
-                $gs->setArg('-dBATCH');
-                $gs->setArg('-dNOPAUSE');
-                $gs->setArg('-dNOPROMPT');
-                $gs->setArg('-sOutputFile=' . $compressedPDF);
-                $gs->setArg('-sDEVICE=pdfwrite');
-                $gs->setArg('-dPDFSETTINGS=/ebook');
-                $gs->setArg('-dColorImageResolution=72');
-                $gs->setArg('-dAutoRotatePages=/None');
-                $gs->setArg('-dColorConversionStrategy=/LeaveColorUnchanged');
-                $gs->setArg(null, $normalPDF);
-                $gs->execute();
-            }
-            copy($compressedPDF, $finalPDF);
-        } else {
-            copy($normalPDF, $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 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)
+       {
+               if (!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));
+               }
+
+               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);
+
+               $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);
+
+                               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)
+       {
+               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;
+               }
+
+               $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);
+                       $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)
+       {
+               $version = $book->parametres->mobileLVersion;
+               if ($dev) {
+                       $version = 'dev';
+               }
+
+               $htmlCompiler = wsHTML5::compilerFactory($book_id, $version);
+               $htmlCompiler->compile();
+       }
+
+       /* 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)
+       {
+               if (substr($book->parametres->pdfName, 0, 4) == 'http') {
+                       return;
+               }
+               if (isset($book->parametres->pdfName) && $book->parametres->pdfName != '') {
+                       $pdfName = $book->parametres->pdfName;
+               }
+
+               $cacheDir = WS_BOOKS . '/pdf/' . $book->book_id;
+               if (!file_exists($cacheDir)) {
+                       mkdir($cacheDir, 0777, true);
+               }
+
+               $normalPDF = $cacheDir . '/normal.pdf';
+               $originalPDF = $cacheDir . '/original.pdf';
+               $compressedPDF = $cacheDir . '/compressed.pdf';
+
+               if (file_exists($originalPDF)) {
+                       $fmtime = filemtime($originalPDF);
+                       if ($fmtime >= $book->composition_update) {
+                               $invalid = false;
+                               foreach ($pages as $i => $infos) {
+                                       $doc = wsDocument::getDir($infos['document_id']) . 'crop.pdf';
+                                       if (filemtime($doc) > $fmtime) {
+                                               $invalid = true;
+                                       }
+                               }
+                       } else {
+                               $invalid = true;
+                       }
+               } else {
+                       $invalid = true;
+               }
+
+
+               if ($invalid) {
+                       $pdfList = array();
+                       $pagesList = array();
+                       $nb_pages = array();
+                       $j = 0;
+                       $k = 0;
+                       $original = true;
+
+                       foreach ($pages as $i => $infos) {
+                               if (!isset($firstDoc)) {
+                                       $firstDoc = $infos['document_id'];
+                               }
+
+                               $doc = wsDocument::getDir($infos['document_id']) . 'crop.pdf';
+                               if (!isset($pdfList[$doc])) {
+                                       $pdfList[$doc] = $j;
+                                       $nb_pages[$doc] = $infos['nb_pages'];
+                                       $k = $j;
+                                       $j++;
+                               } else {
+                                       $k = $pdfList[$doc];
+                               }
+                               $pagesList[$i] = array($k, $infos['document_page']);
+
+                               if ($i != $infos['document_page'] || $infos['document_id'] != $firstDoc) {
+                                       $original = false;
+                               }
+                       }
+
+                       if ($original) {
+
+                               $this->copy(wsDocument::getDir($firstDoc) . 'crop.pdf', $originalPDF);
+                       } else {
+                               $args = '';
+                               foreach ($pdfList as $doc => $index) {
+                                       $lettre = cubeMath::toPDFLetter($index, true);
+                                       $args .= $lettre . '=' . $doc . ' ';
+                               }
+
+                               $args .= ' cat ';
+
+                               $ranges = array();
+                               $currentRange = null;
+
+                               foreach ($pagesList as $p) {
+                                       $lettre = cubeMath::toPDFLetter($p[0], true);
+                                       $page = $p[1];
+
+                                       // Initialise l'intervale
+                                       if (is_null($currentRange)) {
+                                               $currentRange = array('lettre' => $lettre, 'start' => $page, 'end' => $page);
+                                               continue;
+                                       }
+
+                                       // Poursuit le remplissage si la lettre est identique et si la page suivante est bien la page suivante dans le document
+                                       if ($currentRange['lettre'] == $lettre && $currentRange['end'] + 1 == $page) {
+                                               $currentRange['end'] = $page;
+                                               continue;
+                                       }
+
+                                       // Ajoute l'intervale à la liste finale
+                                       $ranges[] = $currentRange;
+
+                                       // Réinitialise l'intervale suivant
+                                       $currentRange = array('lettre' => $lettre, 'start' => $page, 'end' => $page);
+                               }
+
+                               // Ajoute la dernière
+                               if (!is_null($currentRange)) {
+                                       $ranges[] = $currentRange;
+                               }
+                               // Si le pdf final est constitué du document complet d'un document
+                               if (count($ranges) == 1 && $ranges[0]['start'] == 1) {
+                                       $alldocs = array_keys($pdfList);
+                                       $doc = array_pop($alldocs);
+                                       if ($nb_pages[$doc] == $ranges[0]['end']) {
+                                               $this->copy($doc, $originalPDF);
+                                               return;
+                                       }
+                               }
+
+                               foreach ($ranges as $range) {
+                                       $args .= ' ' . $range['lettre'] . $range['start'];
+                                       if ($range['start'] == $range['end']) {
+                                               continue;
+                                       }
+                                       $args .= '-' . $range['end'];
+                               }
+
+                               $hash = sha1($args);
+
+                               $args .= ' output ' . $originalPDF;
+
+                               $cached = WS_BOOKS . '/pdf/' . $hash . '.pdf';
+
+                               if (file_exists($cached)) {
+                                       $this->copy($cached, $originalPDF);
+                               } else {
+                                       $pdftk = new cubeCommandLine('pdftk');
+                                       $pdftk->setPath(CONVERTER_PATH);
+                                       $pdftk->setManualArg($args);
+                                       $pdftk->execute();
+                                       $this->copy($normalPDF, $cached);
+                               }
+                       }
+               }
+
+
+               if ($book->parametres->pdfReplace) {
+                       $replace = WS_BOOKS . '/working/' . $book->book_id . '/' . $book->parametres->pdfReplace;
+                       if (file_exists($replace)) {
+                               if (!file_exists($normalPDF) || filemtime($normalPDF) < filemtime($replace) || filesize($normalPDF) != filesize($replace)) {
+                                       $this->copy($replace, $normalPDF);
+                               }
+                       }
+               } else {
+                       $this->copy($originalPDF, $normalPDF);
+               }
+               $finalPDF = WS_BOOKS . '/final/' . $book->book_id . '/data/' . $book->parametres->pdfName;
+
+               if ($book->parametres->pdfCompress) {
+                       if (!file_exists($compressedPDF) || filemtime($compressedPDF) < filemtime($normalPDF)) {
+                               $gs = new cubeCommandLine('gs', null, true);
+                               $gs->setPath(CONVERTER_PATH);
+                               $gs->setEnv('GS_FONTPATH', '/home/ws/fonts');
+                               $gs->setArg('-dBATCH');
+                               $gs->setArg('-dNOPAUSE');
+                               $gs->setArg('-dNOPROMPT');
+                               $gs->setArg('-sOutputFile=' . $compressedPDF);
+                               $gs->setArg('-sDEVICE=pdfwrite');
+                               $gs->setArg('-dPDFSETTINGS=/ebook');
+                               $gs->setArg('-dColorImageResolution=72');
+                               $gs->setArg('-dAutoRotatePages=/None');
+                               $gs->setArg('-dColorConversionStrategy=/LeaveColorUnchanged');
+                               $gs->setArg(null, $normalPDF);
+                               $gs->execute();
+                       }
+                       copy($compressedPDF, $finalPDF);
+               } else {
+                       copy($normalPDF, $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;
+       }
 
 }
index 05cb8608e3cf55ce274d76d2b1d350e38b835dc9..6856063ebd3c87d9413d38b3477d0a7de0bec6fc 100644 (file)
@@ -194,7 +194,6 @@ class wsDAODocument extends commonDAO {
                foreach ($links as $document_id => $dummy) {
                        wsLinks::setDocumentLinks($document_id, json_encode($links[$document_id]), json_encode($rulers[$document_id]), $user, $comments, TIME);
                }
-
                $daoBook->setSpecialLinksAndRulers($book_id, $specialLinks, $specialRulers);
 
                $c = $this->con->openCursor('books');
index 45030d8763637b0e46e603d0641169fb9cb5a5f9..f75fac90915166e9e613f1cd3edd7da1b805ad26 100644 (file)
  *
  * @author Vincent
  */
-class wsLinks {
+class wsLinks
+{
        protected static $_testLinkCache = null;
 
-       public static function linksToExcel($links, $rulers, $pages = null) {
+       public static function linksToExcel($links, $rulers, $pages = null)
+       {
                set_time_limit(0);
 
                $cols = array(
-                       'uid'=>__('Identifiant unique'),
+                       'uid' => __('Identifiant unique'),
                        'page' => __('Page de la publication'), 'left' => __('x'), 'top' => __('y'), 'width' => __('Largeur'), 'height' => __('Hauteur'), 'rot' => __('Rotation'),
                        'type' => __('Type'), 'to' => __('Destination'), 'target' => __('Cible'),
                        'infobulle' => __('Infobulle'), 'numerotation' => __('Numérotation'),
@@ -140,7 +142,8 @@ class wsLinks {
                return $xls;
        }
 
-       public static function testLink($uri) {
+       public static function testLink($uri)
+       {
                $client = new Zend_Http_Client($uri);
                try {
                        $client->request('head');
@@ -150,7 +153,8 @@ class wsLinks {
                return false;
        }
 
-       public static function setDocumentLinks($document_id, $links, $rulers, $user, $comments, $time) {
+       public static function setDocumentLinks($document_id, $links, $rulers, $user, $comments, $time)
+       {
                global $core;
                $c = $core->con->openCursor('document_links_versions');
                $c1 = $core->con->openCursor('document_links');
@@ -166,7 +170,8 @@ class wsLinks {
                $c1->insert();
        }
 
-       public static function getDocumentLastLinks($document_id) {
+       public static function getDocumentLastLinks($document_id)
+       {
                global $core;
 
                $r = $core->con->select('SELECT * FROM document_links WHERE document_id=\'' . $document_id . '\'');
@@ -186,13 +191,15 @@ class wsLinks {
                return self::_recordToLinks($r);
        }
 
-       public static function getDocumentVersionLinks($document_id, $time) {
+       public static function getDocumentVersionLinks($document_id, $time)
+       {
                global $core;
                $r = $core->con->select('SELECT * FROM document_links_versions WHERE document_id=' . $document_id . ' AND `update`<=' . $time . ' ORDER BY `update` DESC LIMIT 1');
                return self::_recordToLinks($r);
        }
 
-       protected static function _recordToLinks($r) {
+       protected static function _recordToLinks($r)
+       {
                if (mb_substr($r->links, 1, 1) == ':') {
                        $ll = unserialize($r->links);
                        $rr = unserialize($r->rulers);
@@ -204,13 +211,15 @@ class wsLinks {
                return array('links' => $ll, 'rulers' => $rr);
        }
 
-       public static function getLinksAndRulers($book_id, &$links, &$rulers, $time = null) {
+       public static function getLinksAndRulers($book_id, &$links, &$rulers, $time = null)
+       {
 
                global $core;
 
                $daoBook = new wsDAOBook($core->con);
                $pages = $daoBook->getPagesOfBookAt($book_id, $time);
 
+               $documents = [];
                foreach ($pages as $p => $infos) {
                        $documents[] = $infos['document_id'];
                }
@@ -262,7 +271,8 @@ class wsLinks {
                $links = array_merge($links, $book->specialLinks);
        }
 
-       public static function getLinksFromExcel($xls, &$links, &$rulers) {
+       public static function getLinksFromExcel($xls, &$links, &$rulers)
+       {
                $s = $xls->setActiveSheetIndexByName('Links');
                $i = 0;
                $links = array();
@@ -318,7 +328,8 @@ class wsLinks {
                }
        }
 
-       public static function getLinksFromAutobookmarkText($txt, &$links, &$rulers) {
+       public static function getLinksFromAutobookmarkText($txt, &$links, &$rulers)
+       {
                $links = array();
                $rulers = array();
 
@@ -344,9 +355,9 @@ class wsLinks {
 
                        $links[] = array(
                                'page' => $page,
-                                        'left' => $left, 'top' => $top, 'width' => $width, 'height' => $height, 'rot' => '',
-                                        'type' => $type, 'to' => $to, 'target' => $target,
-                                        'infobulle' => '', 'numerotation' => $numerotation, 'display_area' => '1');
+                               'left' => $left, 'top' => $top, 'width' => $width, 'height' => $height, 'rot' => '',
+                               'type' => $type, 'to' => $to, 'target' => $target,
+                               'infobulle' => '', 'numerotation' => $numerotation, 'display_area' => '1');
                }
        }
 }
\ No newline at end of file
index 46c6738a404c41a692f979b400e7662e93c5922d..5d2126afbcb1c07a6b1afbf18bba953711e13882 100644 (file)
@@ -1003,11 +1003,13 @@ class htmlMultimediaLink extends wsHTML5Link
                        } elseif ($ext == 'zip') {
                                $d = $this->unzipFile($this->alternative, false);
                                $this->_config = $this->getConfigZIP($d['dir']);
-                               $html = file_get_contents($d['dir'] . '/index.html');
-                               $html = str_replace('var pRatio = window.devicePixelRatio || 1,', 'var pRatio = 0.5,', $html);
-                               $this->copyExternalDir($d['dir'], $d['fdir']);
-                               $this->_config['lowDef'] = 'index_ld.html';
-                               $this->compiler->vdir->file_put_contents($d['fdir'] . '/' . $this->_config['lowDef'], $html);
+                               if(file_exists($d['dir'] . '/index.html')) {
+                                       $html = file_get_contents($d['dir'] . '/index.html');
+                                       $html = str_replace('var pRatio = window.devicePixelRatio || 1,', 'var pRatio = 0.5,', $html);
+                                       $this->copyExternalDir($d['dir'], $d['fdir']);
+                                       $this->_config['lowDef'] = 'index_ld.html';
+                                       $this->compiler->vdir->file_put_contents($d['fdir'] . '/' . $this->_config['lowDef'], $html);
+                               }
                        } elseif ($ext == 'html') {
                                $fdir = 'data/links';
                                $dir = $fdir;
index 73e953f43c4ebc0082d02ed65130b1a4e8fcd463..46dd4d262800a7ded863d38757aa3cb66fe049a2 100644 (file)
@@ -174,18 +174,16 @@ class wsPackagerHTML extends wsPackager {
                        }
                        $alt = '';
 
-
-
-                       if ($seoVersion && CubeIT_Util_Gzip::file_exists($htmlfile)) {
-                               $html = CubeIT_Util_Gzip::file_get_contents($htmlfile);
-                               $alt .= "\n" . $html . "\n";
-
-                               if ($page == 1) {
-                                       $alt .= $nav1;
-                               } else {
-                                       $alt .= $nav;
-                               }
-                       }
+//                     if ($seoVersion && CubeIT_Util_Gzip::file_exists($htmlfile)) {
+//                             $html = CubeIT_Util_Gzip::file_get_contents($htmlfile);
+//                             $alt .= "\n" . $html . "\n";
+//
+//                             if ($page == 1) {
+//                                     $alt .= $nav1;
+//                             } else {
+//                                     $alt .= $nav;
+//                             }
+//                     }
 
                        $alt .= $footer;