From 71149c972fc9054b59fecb035b07e631f22a6d1b Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 5 Oct 2007 15:06:27 +0000 Subject: [PATCH] - fixed not copied constrains and milestones in PM templates - fixed not creatable milestones in templates - when deleting a project you can now choose to delete the datasources of the elements (eg. InfoLog entries) too - new stati 'template', 'nonactive' and 'archive' for InfoLog, which get not displayed by any standard filter, but choosing them from the status column filter - InfoLog tasks in PM templates get now automatic activated, there stati is set depending of the percentage to not-started, in-progress or done - changing the status of a project you can now choose to change the stati of InfoLog tasks (or other types having the needed stati) too --> these features have been sponsored by Arne Reith from Reith-IT --- infolog/inc/class.boinfolog.inc.php | 85 +++++++++++++++- infolog/inc/class.datasource_infolog.inc.php | 94 ++++++++++++++---- infolog/inc/class.soinfolog.inc.php | 6 +- infolog/inc/class.uiinfolog.inc.php | 8 +- infolog/inc/class.vcalinfolog.inc.php | 33 ++---- infolog/setup/phpgw_de.lang | 6 +- infolog/setup/phpgw_en.lang | 3 + infolog/templates/default/images/archive.png | Bin 0 -> 759 bytes .../templates/default/images/nonactive.png | Bin 0 -> 830 bytes infolog/templates/default/images/template.png | Bin 0 -> 249 bytes .../inc/class.datasource_timesheet.inc.php | 15 +++ 11 files changed, 196 insertions(+), 54 deletions(-) create mode 100644 infolog/templates/default/images/archive.png create mode 100644 infolog/templates/default/images/nonactive.png create mode 100644 infolog/templates/default/images/template.png diff --git a/infolog/inc/class.boinfolog.inc.php b/infolog/inc/class.boinfolog.inc.php index 845c68c2c1..154720aba1 100644 --- a/infolog/inc/class.boinfolog.inc.php +++ b/infolog/inc/class.boinfolog.inc.php @@ -20,6 +20,7 @@ define('EGW_ACL_UNDELETE',EGW_ACL_CUSTOM_1); // undelete right class boinfolog { var $enums; + var $status; /** * Instance of our so class * @@ -164,7 +165,10 @@ class boinfolog 'ongoing' => 'ongoing', // iCal IN-PROCESS 'done' => 'done', // iCal COMPLETED 'cancelled' => 'cancelled', // iCal CANCELLED - 'billed' => 'billed' ), // --> DONE + 'billed' => 'billed', // --> DONE + 'template' => 'template', // --> cancelled + 'nonactive' => 'nonactive', // --> cancelled + 'archive' => 'archive' ), // --> cancelled 'phone' => array( 'not-started' => 'call', // iCal NEEDS-ACTION 'ongoing' => 'will-call', // iCal IN-PROCESS @@ -1419,5 +1423,84 @@ class boinfolog $GLOBALS['egw_info']['user']['account_id'] = $save_account_id; $GLOBALS['egw_info']['user']['preferences'] = $save_prefs; } + + /** conversion of infolog status to vtodo status + * @private + * @var array + */ + var $_status2vtodo = array( + 'offer' => 'NEEDS-ACTION', + 'not-started' => 'NEEDS-ACTION', + 'ongoing' => 'IN-PROCESS', + 'done' => 'COMPLETED', + 'cancelled' => 'CANCELLED', + 'billed' => 'COMPLETED', + 'template' => 'CANCELLED', + 'nonactive' => 'CANCELLED', + 'archive' => 'CANCELLED', + ); + + /** conversion of vtodo status to infolog status + * @private + * @var array + */ + var $_vtodo2status = array( + 'NEEDS-ACTION' => 'not-started', + 'IN-PROCESS' => 'ongoing', + 'COMPLETED' => 'done', + 'CANCELLED' => 'cancelled', + ); + + /** + * Converts an infolog status into a vtodo status + * + * @param string $status see $this->status + * @return string {CANCELLED|NEEDS-ACTION|COMPLETED|IN-PROCESS} + */ + function status2vtodo($status) + { + return isset($this->_status2vtodo[$status]) ? $this->_status2vtodo[$status] : 'NEEDS-ACTION'; + } + + /** + * Converts a vtodo status into an infolog status using the optional X-INFOLOG-STATUS + * + * X-INFOLOG-STATUS is only used, if translated to the vtodo-status gives the identical vtodo status + * --> the user did not changed it + * + * @param string $vtodo_status {CANCELLED|NEEDS-ACTION|COMPLETED|IN-PROCESS} + * @param string $x_infolog_status preserved original infolog status + * @return string + */ + function vtodo2status($vtodo_status,$x_infolog_status=null) + { + $vtodo_status = strtoupper($vtodo_status); + + if ($x_infolog_status && $this->status2vtodo($x_infolog_status) == $vtodo_status) + { + $status = $x_infolog_status; + } + else + { + $status = isset($this->_vtodo2status[$vtodo_status]) ? $this->_vtodo2status[$vtodo_status] : 'not-started'; + } + return $status; + } + + /** + * Activates an InfoLog entry (setting it's status from template or inactive depending on the completed percentage) + * + * @param array $info + * @return string new status + */ + function activate($info) + { + switch((int)$info['info_percent']) + { + case 0: return 'not-started'; + case 100: return 'done'; + } + return 'ongoing'; + } } diff --git a/infolog/inc/class.datasource_infolog.inc.php b/infolog/inc/class.datasource_infolog.inc.php index 12543438ad..634452e68b 100644 --- a/infolog/inc/class.datasource_infolog.inc.php +++ b/infolog/inc/class.datasource_infolog.inc.php @@ -25,6 +25,13 @@ include_once(EGW_INCLUDE_ROOT.'/projectmanager/inc/class.datasource.inc.php'); */ class datasource_infolog extends datasource { + /** + * Reference to boinfolog + * + * @var boinfolog + */ + var $boinfolog; + /** * Constructor */ @@ -33,6 +40,14 @@ class datasource_infolog extends datasource $this->datasource('infolog'); $this->valid = PM_COMPLETION|PM_PLANNED_START|PM_PLANNED_END|PM_REAL_END|PM_PLANNED_TIME|PM_USED_TIME|PM_RESOURCES; + + // we use $GLOBALS['boinfolog'] as an already running instance might be availible there + if (!is_object($GLOBALS['boinfolog'])) + { + include_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.boinfolog.inc.php'); + $GLOBALS['boinfolog'] =& new boinfolog(); + } + $this->boinfolog =& $GLOBALS['boinfolog']; } /** @@ -43,15 +58,9 @@ class datasource_infolog extends datasource */ function get($data_id) { - // we use $GLOBALS['boinfolog'] as an already running instance might be availible there - if (!is_object($GLOBALS['boinfolog'])) - { - include_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.boinfolog.inc.php'); - $GLOBALS['boinfolog'] =& new boinfolog(); - } if (!is_array($data_id)) { - $data =& $GLOBALS['boinfolog']->read((int) $data_id); + $data =& $this->boinfolog->read((int) $data_id); if (!is_array($data)) return false; } @@ -60,7 +69,7 @@ class datasource_infolog extends datasource $data =& $data_id; } return array( - 'pe_title' => $GLOBALS['boinfolog']->link_title($data), + 'pe_title' => $this->boinfolog->link_title($data), 'pe_completion' => $data['info_percent'], 'pe_planned_start'=> $data['info_startdate'] ? $data['info_startdate'] : null, 'pe_planned_end' => $data['info_enddate'] ? $data['info_enddate'] : null, @@ -88,19 +97,14 @@ class datasource_infolog extends datasource */ function copy($element,$target,$extra=null) { - if (!is_object($GLOBALS['boinfolog'])) - { - include_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.boinfolog.inc.php'); - $GLOBALS['boinfolog'] =& new boinfolog(); - } - $info =& $GLOBALS['boinfolog']->read((int) $element['pe_app_id']); + $info =& $this->boinfolog->read((int) $element['pe_app_id']); if (!is_array($info)) return false; // unsetting info_link_id and evtl. info_from if ($info['info_link_id']) { - $GLOBALS['boinfolog']->link_id2from($info); // unsets info_from and sets info_link_target + $this->boinfolog->link_id2from($info); // unsets info_from and sets info_link_target unset($info['info_link_id']); } // we need to unset a view fields, to get a new entry @@ -108,26 +112,72 @@ class datasource_infolog extends datasource { unset($info[$key]); } - if(!($info['info_id'] = $GLOBALS['boinfolog']->write($info))) return false; + if(!($info['info_id'] = $this->boinfolog->write($info))) return false; // link the new infolog against the project and setting info_link_id and evtl. info_from - $info['info_link_id'] = $GLOBALS['boinfolog']->link->link('projectmanager',$target,'infolog',$info['info_id'],$element['pe_remark'],0,0,1); + $info['info_link_id'] = $this->boinfolog->link->link('projectmanager',$target,'infolog',$info['info_id'],$element['pe_remark'],0,0,1); if (!$info['info_from']) { - $info['info_from'] = $GLOBALS['boinfolog']->link->title('projectmanager',$target); + $info['info_from'] = $this->boinfolog->link->title('projectmanager',$target); } - $GLOBALS['boinfolog']->write($info); + if ($info['info_status'] == 'template') + { + $info['info_status'] = $this->boinfolog->activate($info); + } + $this->boinfolog->write($info); // creating again all links, beside the one to the source-project - foreach($GLOBALS['boinfolog']->link->get_links('infolog',$element['pe_app_id']) as $link) + foreach($this->boinfolog->link->get_links('infolog',$element['pe_app_id']) as $link) { if ($link['app'] == 'projectmanager' && $link['id'] == $element['pm_id'] || // ignoring the source project - $link['app'] == $GLOBALS['boinfolog']->link->vfs_appname) // ignoring files attachments for now + $link['app'] == $this->boinfolog->link->vfs_appname) // ignoring files attachments for now { continue; } - $GLOBALS['boinfolog']->link->link('infolog',$info['info_id'],$link['app'],$link['id'],$link['remark']); + $this->boinfolog->link->link('infolog',$info['info_id'],$link['app'],$link['id'],$link['remark']); } return array($info['info_id'],$info['info_link_id']); } + + /** + * Delete the datasource of a project element + * + * @param int $id + * @return boolean true on success, false on error + */ + function delete($id) + { + if (!is_object($GLOBALS['boinfolog'])) + { + include_once(EGW_INCLUDE_ROOT.'/infolog/inc/class.boinfolog.inc.php'); + $GLOBALS['boinfolog'] =& new boinfolog(); + } + return $this->boinfolog->delete($id); + } + + /** + * Change the status of an infolog entry according to the project status + * + * @param int $id + * @param string $status + * @return boolean true if status changed, false otherwise + */ + function change_status($id,$status) + { + //error_log("datasource_infolog::change_status($id,$status)"); + if (($info = $this->boinfolog->read($id)) && $this->boinfolog->check_access($info,EGW_ACL_EDIT)) + { + if ($status == 'active' && in_array($info['info_status'],array('template','nonactive','archive'))) + { + $status = $this->boinfolog->activate($info); + } + if($info['info_status'] != $status && isset($this->boinfolog->status[$info['info_type']][$status])) + { + //error_log("datasource_infolog::change_status($id,$status) setting status from ".$info['info_status']); + $info['info_status'] = $status; + return $this->boinfolog->write($info) !== false; + } + } + return false; + } } \ No newline at end of file diff --git a/infolog/inc/class.soinfolog.inc.php b/infolog/inc/class.soinfolog.inc.php index bc6acdb287..ed743eaa6d 100644 --- a/infolog/inc/class.soinfolog.inc.php +++ b/infolog/inc/class.soinfolog.inc.php @@ -274,10 +274,10 @@ class soinfolog // DB-Layer switch ($filter) { case 'done': $filter = "info_status IN ('done','billed','cancelled')"; break; - case 'open': $filter = "NOT (info_status IN ('done','billed','cancelled','deleted'))"; break; + case 'open': $filter = "NOT (info_status IN ('done','billed','cancelled','deleted','template','nonactive','archive'))"; break; case 'offer': $filter = "info_status = 'offer'"; break; case 'deleted': $filter = "info_status = 'deleted'"; break; - default: $filter = "info_status <> 'deleted'"; break; + default: $filter = "NOT (info_status IN ('deleted','template','nonactive','archive'))"; break; } return ($prefix_and ? ' AND ' : '').$filter; } @@ -655,7 +655,7 @@ class soinfolog // DB-Layer $ordermethod = 'ORDER BY info_datemodified DESC'; // newest first } $acl_filter = $filtermethod = $this->aclFilter($query['filter']); - $filtermethod .= $this->statusFilter($query['filter']); + if (!$query['col_filter']['info_status']) $filtermethod .= $this->statusFilter($query['filter']); $filtermethod .= $this->dateFilter($query['filter']); if (is_array($query['col_filter'])) diff --git a/infolog/inc/class.uiinfolog.inc.php b/infolog/inc/class.uiinfolog.inc.php index 9e7ef6bace..aaa5461d2d 100644 --- a/infolog/inc/class.uiinfolog.inc.php +++ b/infolog/inc/class.uiinfolog.inc.php @@ -142,10 +142,6 @@ class uiinfolog $this->duration_format = str_replace(',','',$pm_config->config_data['duration_units']).','.$pm_config->config_data['hours_per_workday']; unset($pm_config); } - if ($this->bo->history) - { - $this->filters['deleted'] = 'deleted'; - } /* these are just for testing of the notifications for($i = -1; $i <= 3; ++$i) { @@ -596,6 +592,10 @@ class uiinfolog { if ($typ != 'defaults') $all_stati += $stati; } + if ($this->bo->history) + { + $all_stati['deleted'] = 'deleted'; + } if (!$called_as) { $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => 'ManualInfologIndex'); diff --git a/infolog/inc/class.vcalinfolog.inc.php b/infolog/inc/class.vcalinfolog.inc.php index 22d6f341cf..df66f462a3 100644 --- a/infolog/inc/class.vcalinfolog.inc.php +++ b/infolog/inc/class.vcalinfolog.inc.php @@ -15,30 +15,11 @@ class vcalinfolog extends boinfolog { - var $status2vtodo = array( - 'offer' => 'NEEDS-ACTION', - 'not-started' => 'NEEDS-ACTION', - 'ongoing' => 'IN-PROCESS', - 'done' => 'COMPLETED', - 'cancelled' => 'CANCELLED', - 'billed' => 'DONE', - 'call' => 'NEEDS-ACTION', - 'will-call' => 'IN-PROCESS', - ); - - var $vtodo2status = array( - 'NEEDS-ACTION' => 'not-started', - 'IN-PROCESS' => 'ongoing', - 'COMPLETED' => 'done', - 'CANCELLED' => 'cancelled', - ); - var $egw_priority2vcal_priority = array( 0 => 3, 1 => 2, 2 => 1, 3 => 1, - ); var $vcal_priority2egw_priority = array( @@ -82,8 +63,9 @@ $vevent->setAttribute('LAST-MODIFIED',$GLOBALS['egw']->contenthistory->getTSforAction($eventGUID,'modify')); $vevent->setAttribute('UID',$taskGUID); $vevent->setAttribute('CLASS',$taskData['info_access'] == 'public' ? 'PUBLIC' : 'PRIVATE'); - $vevent->setAttribute('STATUS',isset($this->status2vtodo[$taskData['info_status']]) ? - $this->status2vtodo[$taskData['info_status']] : 'NEEDS-ACTION'); + $vevent->setAttribute('STATUS',$this->status2vtodo($taskData['info_status'])); + // we try to preserv the original infolog status as X-INFOLOG-STATUS, so we can restore it, if the user does not modify STATUS + $vevent->setAttribute('X-INFOLOG-STATUS',$taskData['info_status']); $vevent->setAttribute('PRIORITY',$this->egw_priority2vcal_priority[$taskData['info_priority']]); if (!empty($taskData['info_cat'])) @@ -198,8 +180,13 @@ } break; case 'STATUS': - $taskData['info_status'] = isset($this->vtodo2status[strtoupper($attributes['value'])]) ? - $this->vtodo2status[strtoupper($attributes['value'])] : 'ongoing'; + // check if we (still) have X-INFOLOG-STATUS set AND it would give an unchanged status (no change by the user) + foreach($component->_attributes as $attr) + { + if ($attr['name'] == 'X-INFOLOG-STATUS') break; + } + $taskData['info_status'] = $this->vtodo2status($attributes['value'], + $attr['name'] == 'X-INFOLOG-STATUS' ? $attr['value'] : null); break; case 'SUMMARY': $taskData['info_subject'] = $attributes['value']; diff --git a/infolog/setup/phpgw_de.lang b/infolog/setup/phpgw_de.lang index 681be115e2..5197684edf 100644 --- a/infolog/setup/phpgw_de.lang +++ b/infolog/setup/phpgw_de.lang @@ -42,6 +42,7 @@ all infolog de alle all links and attachments infolog de alle Verknüpfungen und Anhänge allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog de erlaubt den Status eines Eintrags zu setzen, zB. eine Aufgabe auf erledigt wenn sie beendet ist (Werte hängen vom Type des Eintrags ab) apply the changes infolog de Übernimmt die Änderungen +archive infolog de Archiviert are you shure you want to delete this entry ? infolog de Sind Sie sicher, dass Sie diesen Eintrag löschen wollen? attach a file infolog de Datei anhängen attach file infolog de Datei anhängen @@ -51,7 +52,7 @@ billed infolog de abgerechnet both infolog de Annahme+erledigt call infolog de anrufen cancel infolog de Abbruch -cancelled infolog de Abgesagt +cancelled infolog de abgesagt categories infolog de Kategorien category infolog de Kategorie change the status of an entry, eg. close it infolog de Status eines Eintrags ändern, zB. ihn als erledigt markieren @@ -197,6 +198,7 @@ no details infolog de Keine Details no entries found, try again ... infolog de Kein Einträge gefunden, nochmal versuchen ... no filter infolog de kein Filter no links or attachments infolog de keine Verknüpfungen oder Anhänge +nonactive infolog de Nicht aktiv none infolog de keine normal infolog de normal not infolog de nicht @@ -304,6 +306,7 @@ sub infolog de Unter-
eintr sub-entries become subs of the parent or main entries, if there's no parent infolog de Untereinträge gehören dann zum übergeordneten Eintrag oder werden Haupteinträge wenn es keinen übergeordneten gibt. subject infolog de Titel task infolog de Aufgabe +template infolog de Vorlage test import (show importable records only in browser) infolog de Test Import (zeige importierbare Datensätze nur im Browser) the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog de der Name wird intern benutzt (<= 10 Zeichen), wenn er geändert wird, werden existierende Daten unzugänglich the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog de der Name wird intern benutzt (<= 20 Zeichen), wenn er geändert wird, werden existierende Daten unzugänglich @@ -330,6 +333,7 @@ urgent infolog de Dringend used time infolog de benötigte Zeit valid path on clientside
eg. \\server\share or e:\ infolog de gültiger Pfad clientseitig
zB. \\Server\Share oder e:\ valid path on clientside
eg. \servershare or e: infolog de gültiger Pfad clientseitig
zB. \\Server\Share oder e:\ +valid path on clientside
eg. servershare or e: infolog de gültiger Pfad clientseitig
zB. \\Server\Share oder e:\ values for selectbox infolog de Werte für die Auswahlbox view all subs of this entry infolog de alle Untereinträge dieses Eintrag anzeigen view other subs infolog de andere Untereinträge anzeigen diff --git a/infolog/setup/phpgw_en.lang b/infolog/setup/phpgw_en.lang index 265f4c8d2c..0ca931df7e 100644 --- a/infolog/setup/phpgw_en.lang +++ b/infolog/setup/phpgw_en.lang @@ -42,6 +42,7 @@ all infolog en All all links and attachments infolog en all links and attachments allows to set the status of an entry, eg. set a todo to done if it's finished (values depend on entry-typ) infolog en allows to set the status of an entry, eg. set a ToDo to done if it's finished (values depend on entry-type) apply the changes infolog en Apply the changes +archive infolog en archive are you shure you want to delete this entry ? infolog en Are you sure you want to delete this entry ? attach a file infolog en Attach a file attach file infolog en Attach file @@ -197,6 +198,7 @@ no details infolog en no details no entries found, try again ... infolog en no entries found, try again ... no filter infolog en no Filter no links or attachments infolog en no links or attachments +nonactive infolog en nonactive none infolog en None normal infolog en normal not infolog en not @@ -303,6 +305,7 @@ sub infolog en Sub sub-entries become subs of the parent or main entries, if there's no parent infolog en Sub-entries become subs of the parent or main entries, if there's no parent subject infolog en Subject task infolog en ToDo +template infolog en Template test import (show importable records only in browser) infolog en Test Import (show importable records only in browser) the name used internaly (<= 10 chars), changeing it makes existing data unavailible infolog en the name used internaly (<= 10 chars), changeing it makes existing data unavailible the name used internaly (<= 20 chars), changeing it makes existing data unavailible infolog en the name used internaly (<= 20 chars), changeing it makes existing data unavailible diff --git a/infolog/templates/default/images/archive.png b/infolog/templates/default/images/archive.png new file mode 100644 index 0000000000000000000000000000000000000000..945a6ebc8c2bd35acfe9d32ad016022b8f1e2756 GIT binary patch literal 759 zcmV5 zlg(~hRS?I2XJ*d1_c~5&H&zj@+_Y+GRFy@LKt+f}gv6p7o}kar_h7*$uYp*zLPDrW ztyB;yP_?uYkfbf4DUM@b$G#uuvT&OnNF8Z3tC{(K%((2v7dN-BZ|-zEtsZX>N8{P( z+q;i$+4l9#olZOL#e7OD4J1Jc<_SRw!3f?6Uh($2Dyl+hp$F{P+G^HoPI5l`=rX2) ziPCO)E)BY@w-XxRuhEPblL8Sz)uAH%b}(gaHS1Z74T57dSzxC0I~gBe8_-JpDcoK= z2Cc+1o}Tc_lYJ1!dsoi0wvw`*H9VWu zXoQHPsv}a@k)yoi&cg%pqGH%zCC12?-`wMer*nQjh}?d30Kn$(EaOSeqKY&)>N;X& z70FW1ypG)eW5ieA{mN`I=FekCd(BZv&Evo4v>)t}PbcJah#@ks8_FtTWmS`=o-7Fr z&#uzxbm*Vya`}>CCa4G^4(A+Mma$i!ke3bK8)a255v-(vEcI-^JK)o;;s5&o`|gkY zlMXPGC4!=?=yx-c;4yUoeEt1TJluPUsw`6+A6~o2);mKS4Q7H@r6?M-bL0Ely# z31&)B)Yzh^NP;Ix3|TVZ{i_%LQ-g*EGeyL)D5~Xv5R5cP)5 zlQC?QR}_W6``+_!`?sye5L<#sE(vyqgdmj(kp)I1rig(7Au_TscjyiS69Wq)D-{wF z5*~<1%vPEVAp>q{>x6{H)NzRG*uVY1_ZZSxUAfa8?m0U5o^$0VV{ZOXDm~1lQhC0i zI{kioZFBRk{5&gv@II6X0e6pMs~0?vE7%_f6SpU8GPC=rwhhsKa;H1fuKkBcJuySu0$;Kb$2jL*(8 z==W(h8YmIQ&z>cion>on4Ov|!qZHa&y!ROIJ>5ow%$YMx+_=HXnHhe4{+!P8GN-dy zQi%kcfVp&u@2_0p&nO~TSwTe+-g}gFj^54=K8`6|xWF$@pCT__a5|33&dt%AoW!)- z1l20LuU;{A@gh56i1hnd=TOc$jMj|J&l7dKY(IWX^56j1YEis)jmd=t{{Hw8zqf}x zdq&*rk*-wm%_hz{jP;(h*5uEhXJ>t#@3yxYb~;EdhbV;t;{AQZTD-M%>vam{GMy;G zdXI6=kq811K}5(HgBlKzFJDHk$o@VO$43?dR)iRE&Y@y!Nf^Vy#s;U(oud~7B(%n8 zJt8>HfKDb!S1Nqo*kC-BBDVJEhzYIfzJ5(Ili|djJDC3n{#jY!kEJDYi3CO|Qj3e2 zFr-zhkv0bF9L8FU(VDncWBcVx<`x(E-5Au9C%Aj}NO?~-mm|1+n{Z))57jD@@7^KF zB-UEYu>zwty$2820xGv|F}!}AgZJ-Ai;$h3#)Kgss#T&#k0>RRD3K!tv9;*qtVa=Y z|31GhFQez@8Jn5G0e>wmvH#``rS)}6L4XngAhs6M9Sqvt!61J!2u8b)y?u*bT}6~) z2uvgrl$1jL2i|J6=ne*L`BCI%Aq*b|T7T0!53Fr}K0Lhp6)*fWl%x)x#sB~S07*qo IM6N<$f{(R(NB{r; literal 0 HcmV?d00001 diff --git a/infolog/templates/default/images/template.png b/infolog/templates/default/images/template.png new file mode 100644 index 0000000000000000000000000000000000000000..ef0e2e3ed3d8c4a77bfd234c44328ba60a0b5222 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAd%)r3NvA|#jkRuV`6XN>+|9>_%wmp0Hbai#5 zrKNd#da9|Z0R_!@hljQC0!qCAg>jC75mAFQf1m~xflqVLY zGNfmw85QKED;VjS=ou}JbLRu9Nbq!V45_%4oB#yo2?-_)mmcvn@$|6r@bo-YkPC^QABBT!(;0uKh4Y0Xb2da4`_cgF$1OmYCInnF~AF m0@MPeSNfEx8fZ9_DKY$delete($id); + } }