/[openfoncier]/trunk/obj/dossier_instruction.class.php
ViewVC logotype

Contents of /trunk/obj/dossier_instruction.class.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3449 - (show annotations)
Thu Apr 30 14:58:06 2015 UTC (9 years, 9 months ago) by vpihour
File size: 23978 byte(s)
Correction de la gestion des droits dans tous les objets liés au dossier d'instruction.

1 <?php
2
3 //
4 require_once "dossier.class.php";
5
6 //
7 class dossier_instruction extends dossier {
8
9 function dossier_instruction($id, &$db, $DEBUG) {
10 //
11 //$this->constructeur($id, $db, $DEBUG);
12 $this->dossier($id, $db, $DEBUG);
13 }
14
15 /**
16 * Définition des actions disponibles sur la classe.
17 *
18 * @return void
19 */
20 function init_class_actions() {
21 //
22 parent::init_class_actions();
23
24 // ACTION - 001 - modifier
25 //
26 $this->class_actions[1]["portlet"]["libelle"] = _("Modifier");
27 $this->class_actions[1]["condition"] = "is_editable";
28
29 // ACTION - 002 - supprimer
30 //
31 $this->class_actions[2]["portlet"]["libelle"] = _("Supprimer");
32 $this->class_actions[2]["portlet"]["order"] = 125;
33
34 // ACTION - 100 - donnees_techniques
35 // Affiche dans un overlay les données techniques
36 $this->class_actions[100] = array(
37 "identifier" => "donnees_techniques",
38 "portlet" => array(
39 "type" => "action-self",
40 "libelle" => _("Données techniques"),
41 "order" => 100,
42 "class" => "rediger-16",
43 ),
44 "view" => "view_donnees_techniques",
45 "permission_suffix" => "donnees_techniques_consulter",
46 "condition" => "can_open_donnees_techniques",
47 );
48
49 // ACTION - 110 - rapport_instruction
50 // Affiche dans un overlay le rapport d'instruction
51 $this->class_actions[110] = array(
52 "identifier" => "rapport_instruction",
53 "portlet" => array(
54 "type" => "action-self",
55 "libelle" => _("Rapport d'instruction"),
56 "order" => 110,
57 "class" => "rediger-16",
58 ),
59 "view" => "view_rapport_instruction",
60 "permission_suffix" => "rapport_instruction_rediger",
61 "condition" => "can_open_rapport_instruction",
62 );
63
64 // ACTION - 120 - geolocalisation
65 // Affiche dans un overlay la géolocalisation
66 $this->class_actions[120] = array(
67 "identifier" => "geolocalisation",
68 "portlet" => array(
69 "type" => "action-self",
70 "libelle" => _("Geolocalisation"),
71 "order" => 120,
72 "class" => "rediger-16",
73 ),
74 "view" => "view_geolocalisation",
75 "permission_suffix" => "geolocalisation_consulter",
76 "condition" => "can_open_geolocalisation",
77 );
78
79 // ACTION - 130 - edition
80 // Affiche l'édition
81 $this->class_actions[130] = array(
82 "identifier" => "edition",
83 "portlet" => array(
84 "type" => "action-blank",
85 "libelle" => _("Recapitulatif"),
86 "order" => 130,
87 "class" => "pdf-16",
88 ),
89 "view" => "view_edition",
90 "permission_suffix" => "consulter",
91 );
92 }
93
94 /**
95 * Vérifie la division de l'instructeur et l'état du dossier.
96 *
97 * @return boolean
98 */
99 function check_instructeur_division_and_di_state() {
100
101 // Si l'utilisateur est un intructeur qui ne correspond pas à la
102 // division du dossier
103 if ($this->f->isUserInstructeur()
104 && $this->f->om_utilisateur["division"] != $this->getDivisionFromDossier()) {
105
106 //
107 return false;
108 }
109
110 // Si l'utilisateur est un instructeur et que le dossier est cloturé
111 if ($this->f->isUserInstructeur()
112 && $this->getStatut() == "cloture") {
113
114 //
115 return false;
116 }
117
118 //
119 return true;
120 }
121
122 /**
123 * CONDITION - is_editable.
124 *
125 * Condition pour la modification.
126 *
127 * @return boolean
128 */
129 function is_editable() {
130
131 // Contrôle si l'utilisateur possède un bypass
132 $bypass = $this->f->isAccredited(get_class()."_modifier_bypass");
133 //
134 if ($bypass == true) {
135
136 //
137 return true;
138 }
139
140 // Contrôle le droit de l'instruction
141 if ($this->check_instructeur_division_and_di_state() == false) {
142
143 //
144 return false;
145 }
146
147 //
148 return true;
149 }
150
151 /**
152 * CONDITION - can_open_donnees_techniques.
153 *
154 * Condition pour afficher les données techniques.
155 *
156 * @return boolean
157 */
158 function can_open_donnees_techniques() {
159
160 // Contrôle si l'utilisateur possède un bypass
161 $bypass = $this->f->isAccredited(get_class()."_donnees_techniques_consulter_bypass");
162 //
163 if ($bypass == true) {
164
165 //
166 return true;
167 }
168
169 //
170 return true;
171 }
172
173 /**
174 * CONDITION - can_open_rapport_instruction.
175 *
176 * Condition pour afficher le rapport d'instruction en overlay.
177 *
178 * @return boolean
179 */
180 function can_open_rapport_instruction() {
181
182 // Contrôle si l'utilisateur possède un bypass
183 $bypass = $this->f->isAccredited(get_class()."_rapport_instruction_rediger_bypass");
184 //
185 if ($bypass == true) {
186
187 //
188 return true;
189 }
190
191 // Si l'utilisateur est un intructeur qui ne correspond pas à la
192 // division du dossier
193 if ($this->f->isUserInstructeur()
194 && $this->f->om_utilisateur["division"] != $this->getDivisionFromDossier()) {
195
196 // Cache le lien du rapport d'instruction, si aucun n'est lié
197 if ($this->getRapportInstruction() == '') {
198
199 //
200 return false;
201 }
202 }
203
204 // Si l'utilisateur est un instructeur et que le dossier est cloturé
205 if ($this->f->isUserInstructeur()
206 && $this->getStatut() == "cloture") {
207
208 // Cache le lien du rapport d'instruction, si aucun n'est lié
209 if ($this->getRapportInstruction() == '') {
210
211 //
212 return false;
213 }
214 }
215
216 //
217 return true;
218 }
219
220 /**
221 * CONDITION - can_open_geolocalisation.
222 *
223 * Condition pour afficher la géolocalisation en overlay.
224 *
225 * @return boolean
226 */
227 function can_open_geolocalisation() {
228
229 // Si l'option sig n'est pas réglé sur 'sig_externe',
230 // l'action géolocalisation n'est pas affiché
231 if ($this->f->getParameter('option_sig') != 'sig_externe') {
232
233 //
234 return false;
235 }
236
237 // Contrôle si l'utilisateur possède un bypass
238 $bypass = $this->f->isAccredited(get_class()."_geolocalisation_consulter_bypass");
239 //
240 if ($bypass == true) {
241
242 //
243 return true;
244 }
245
246 // Contrôle le droit de l'instruction
247 if ($this->check_instructeur_division_and_di_state() == false) {
248
249 //
250 return false;
251 }
252
253 //
254 return true;
255 }
256
257 /**
258 * VIEW - view_edition.
259 *
260 * Affiche le récapitulatif du dossier d'instruction.
261 *
262 * @return void
263 */
264 function view_edition() {
265
266 // Identifiant du dossier
267 $idx = $this->getVal($this->clePrimaire);
268
269 // Redirection vers le script d'édition pdf avec les bons paramètres
270 header("Location: ../pdf/pdfetat.php?idx=".$idx."&obj=".$this->table);
271 exit();
272 }
273
274 /**
275 * VIEW - view_donnees_techniques.
276 *
277 * Redirige pour ouvrir le formulaire en ajaxIt dans un overlay.
278 * Cette action est bindée pour utiliser la fonction popUpIt.
279 *
280 * @return void
281 */
282 function view_donnees_techniques() {
283
284 // Vérification de l'accessibilité sur l'élément
285 $this->checkAccessibility();
286
287 //
288 $idx = $this->getVal($this->clePrimaire);
289 $obj = "donnees_techniques";
290
291 //
292 $this->redirect_onglet($idx, $obj, "", "dossier_instruction_donnees_techniques_consulter");
293 }
294
295 /**
296 * VIEW - view_rapport_instruction.
297 *
298 * Redirige pour ouvrir le formulaire en ajaxIt dans un overlay.
299 * Cette action est bindée pour utiliser la fonction popUpIt.
300 *
301 * @return void
302 */
303 function view_rapport_instruction() {
304
305 //
306 $idx = $this->getVal($this->clePrimaire);
307 $obj = "rapport_instruction";
308
309 //
310 $this->redirect_onglet($idx, $obj, "", "rapport_instruction_rediger");
311 }
312
313 /**
314 * Redirige vers un sousform.
315 *
316 * @return void
317 */
318 function redirect_onglet($idx = "", $obj = "", $sousform = "", $right) {
319 //
320 $this->f->disableLog();
321
322 // Seulement si le numéro de dossier est fourni
323 if ($this->f->isAccredited($right) != false
324 && isset($idx) && !is_null($idx)
325 && isset($obj) && !is_null($obj)){
326
327 // Vérifie que l'objet n'existe pas
328 $sql = "SELECT
329 ".$obj."
330 FROM
331 ".DB_PREFIXE.$obj."
332 where
333 dossier_instruction = '$idx'";
334 // Ajout au log
335 $this->f->addToLog($obj.".php: db->query(\"".$sql."\");", VERBOSE_MODE);
336 // Exécution de la requête
337 $res = $this->f->db->query($sql);
338 $this->f->isDatabaseError($res);
339
340 // S'il n'y en a pas, afficher le formulaire d'ajout
341 if ( $res->numrows() == 0 ){
342 //
343 echo '
344 <script type="text/javascript" >
345 overlayIt(\''.$obj.'\',\'../scr/sousform.php?objsf='.$obj.'&obj='.$obj.'&action=0&retourformulaire=dossier_instruction&idxformulaire='.$idx.'\', 1);
346 </script>
347 ';
348 }
349 // Sinon afficher l'objet en consultation
350 elseif ( $res->numrows() > 0 && $sousform != "dossier_autorisation" ){
351 //
352 $row = & $res->fetchRow(DB_FETCHMODE_ASSOC);
353 //
354 echo '
355 <script type="text/javascript" >
356 overlayIt(\''.$obj.'\',\'../scr/sousform.php?objsf='.$obj.'&idxformulaire='.$idx.'&retourformulaire='.$obj.'&obj='.$obj.'&action=3&idx='.$row[$obj].'\', 1);
357 </script>
358 ';
359 }
360 elseif ( $res->numrows() > 0 && $sousform == "dossier_autorisation" ){
361 //
362 $row = & $res->fetchRow(DB_FETCHMODE_ASSOC);
363 //
364 echo '
365 <script type="text/javascript" >
366 overlayIt(\''.$obj.'\',\'../scr/sousform.php?objsf='.$obj.'&idxformulaire='.$idx.'&retourformulaire='.$obj.'&obj='.$obj.'&action=3&idx='.$row[$obj].'&visualisation=dossier_autorisation\', 1);
367 </script>
368 ';
369 }
370 }
371 }
372
373 /**
374 * VIEW - view_geolocalisation.
375 *
376 * Redirige pour ouvrir le formulaire en ajaxIt dans un overlay.
377 * Cette action est bindée pour utiliser la fonction popUpIt.
378 *
379 * @return void
380 */
381 function view_geolocalisation() {
382
383 // Vérification de l'accessibilité sur l'élément
384 $this->checkAccessibility();
385
386 //
387 $idx = $this->getVal($this->clePrimaire);
388
389 // Récupération des données de sig_elyx
390 $sqlDonneesSIG = "SELECT *
391 FROM ".DB_PREFIXE."sig_elyx
392 WHERE dossier = '$idx'";
393 $resDonneesSIG = $this->f->db->query($sqlDonneesSIG);
394 $this->f->addToLog(__METHOD__."() : db->query(\"".$sqlDonneesSIG."\")", VERBOSE_MODE);
395 $this->f->isDatabaseError($resDonneesSIG);
396 $rowDonneesSIG = &$resDonneesSIG->fetchRow(DB_FETCHMODE_ASSOC);
397
398 // Récupération des données du dossier d'instruction
399 $sqlDonneesDI = "SELECT dossier, geom, dossier_libelle,
400 terrain_references_cadastrales, terrain_adresse_voie_numero,
401 terrain_adresse_voie, terrain_adresse_lieu_dit, terrain_adresse_localite,
402 terrain_adresse_code_postal, terrain_adresse_bp, terrain_adresse_cedex
403 FROM ".DB_PREFIXE."dossier
404 WHERE dossier = '$idx'";
405 $resDonneesDI = $this->f->db->query($sqlDonneesDI);
406 $this->f->addToLog(__METHOD__."() : db->query(\"".$sqlDonneesDI."\")", VERBOSE_MODE);
407 $this->f->isDatabaseError($resDonneesDI);
408 $rowDonneesDI = &$resDonneesDI->fetchRow(DB_FETCHMODE_ASSOC);
409
410 // Récupération des contraintes liées au DI
411 $sqlDossierContrainte = "SELECT dossier_contrainte, reference
412 FROM ".DB_PREFIXE." dossier_contrainte
413 WHERE dossier = '".$idx."'";
414 $resDossierContrainte = $this->f->db->query($sqlDossierContrainte);
415 $this->f->addToLog(__METHOD__."() : db->query(\"".$sqlDossierContrainte."\")", VERBOSE_MODE);
416 $this->f->isDatabaseError($resDossierContrainte);
417
418 //
419 $geom = "";
420 //
421 if (isset($rowDonneesDI) && $rowDonneesDI['geom'] != '') {
422 //
423 $sqlGEOM = "SELECT public.ST_AsText('".$rowDonneesDI['geom']."'::geometry)";
424 $geom = $this->f->db->getOne($sqlGEOM);
425 $this->f->addToLog(__METHOD__."() : db->getOne(\"".$sqlGEOM."\")", VERBOSE_MODE);
426 }
427
428 // Compteurs de contrainte manuelle et automatique
429 $nb_conrainte_man = 0;
430 $nb_conrainte_sig = 0;
431 // Nombre de contrainte du DI
432 while ($rowDossierContrainte = &$resDossierContrainte->fetchRow(DB_FETCHMODE_ASSOC)) {
433 //
434 if ($rowDossierContrainte['reference'] == 'f') {
435 $nb_conrainte_man++;
436 } else {
437 $nb_conrainte_sig++;
438 }
439 }
440 // Modifie les messages en fonction du nombre de contrainte
441 if ($nb_conrainte_man == 0) {
442 $msg_contrainte_man = _("Aucune contraintes ajoutees depuis l'application");
443 } else {
444 $msg_contrainte_man = $nb_conrainte_man." "._("contrainte(s) ajoutee(s) depuis l'application");
445 }
446 if ($nb_conrainte_sig == 0) {
447 $msg_contrainte_sig = _("Aucune contraintes ajoutees depuis le SIG");
448 } else {
449 $msg_contrainte_sig = $nb_conrainte_sig." "._("contrainte(s) ajoutee(s) depuis le SIG");
450 }
451 $contrainte_val = "<span id='msg_contrainte_man'>".$msg_contrainte_man."</span>"."<br />".
452 "<span id='msg_contrainte_sig'>".$msg_contrainte_sig."</span>";
453
454 // Affichage du fil d'Ariane
455 $this->f->displaySubTitle(_("Geolocalisation") . "->" . $rowDonneesDI["dossier_libelle"]);
456 $this->f->display();
457
458 // Message affiché
459 $message_field = '<div class="message ui-widget ui-corner-all ui-state-highlight ui-state-%s" id="%s">
460 <p>
461 <span class="ui-icon ui-icon-info"></span>
462 <span class="text">%s<br></span>
463 </p>
464 </div>';
465
466 // Message d'erreur si les références cadastrales ont été modifiées
467 // dans le dossier d'instruction
468 if (isset($rowDonneesSIG["terrain_references_cadastrales_archive"]) &&
469 $rowDonneesSIG["terrain_references_cadastrales_archive"] != $rowDonneesDI["terrain_references_cadastrales"]) {
470
471 $messageRefCadUtilisees = (is_null($rowDonneesSIG["terrain_references_cadastrales_archive"])&&
472 $rowDonneesSIG["terrain_references_cadastrales_archive"]!="")?
473 _("Les references cadastrales utilisees par le SIG")." : ".
474 $rowDonneesSIG["terrain_references_cadastrales_archive"] :
475 _("Aucune reference cadastrale n'est renseignee pour le SIG");
476
477 printf($message_field, "error", "geolocalisation-message",
478 "<p>"._("Les references cadastrales ont ete modifiees dans le dossier d'instruction.")."</p>".
479 "<p>".$messageRefCadUtilisees."</p>");
480 }
481
482 // Bouton retour
483 $button_return = '<div class="formControls">
484 <a id="retour-button" onclick="redirectPortletAction(1,\'main\'); refresh_page_return();" href="#" class="retour">Retour</a>
485 </div>';
486
487 // Affiche le bouton de retour
488 printf($button_return);
489
490 // Début du formulaire
491 printf("\n<!-- ########## START FORMULAIRE ########## -->\n");
492 printf("<div class=\"formEntete ui-corner-all\">\n");
493
494 // Champ pour le bouton
495 $button_field = '<div class="field field-type-static">
496 <div class="form-libelle">
497 <label id="lib-%1$s" class="libelle-%1$s" for="%1$s">
498 %2$s
499 </label>
500 </div>
501 <div class="form-content">
502 <span id="%1$s" class="field_value">
503 %3$s
504 </span>
505 </div>
506 </div>';
507
508 // Boutons d'action sur la géolocalisation
509 $button = '<input type="submit" class="om-button ui-button ui-widget ui-state-default ui-corner-all" id="%s-button" value="%s" onclick="%s" role="button" aria-disabled="false">';
510
511 // Affiche le bouton permettant de lancer tous les traitements
512 printf('<div class="alignBtnCenter">');
513 printf($button, "chance", "J'ai de la chance", "all_geolocalisation_treatments('$idx', '"._("Etes vous sur de vouloir recuperer les contraintes ?")."')");
514 printf('</div>');
515
516 // Tableau pour afficher l'interface sur deux colonnes
517 printf("<div class='sousform-geolocalisation'><div class='list-buttons-geolocalisation'>");
518
519 //Affichage des boutons
520 printf($button_field, 'verif_parcelle', sprintf($button, 'verif_parcelle', "Vérifier les parcelles", "geolocalisation_treatment('$idx', 'verif_parcelle', set_geolocalisation_message)"), $this->build_message('verif_parcelle', $message_field, $rowDonneesSIG, $this->f));
521
522 printf($button_field, 'calcul_emprise', sprintf($button, 'calcul_emprise', "Calculer l'emprise", "geolocalisation_treatment('$idx', 'calcul_emprise', '')"), $this->build_message('calcul_emprise', $message_field, $rowDonneesSIG, $this->f));
523
524 printf($button_field, 'dessin_emprise', sprintf($button, 'dessin_emprise', "Dessiner l'emprise", "geolocalisation_treatment('$idx', 'dessin_emprise', redirection_elyxweb)"), $this->build_message('dessin_emprise', $message_field, $rowDonneesSIG, $this->f));
525
526 printf($button_field, 'calcul_centroide', sprintf($button, 'calcul_centroide', "Calculer le centroïde", "geolocalisation_treatment('$idx', 'calcul_centroide', set_geolocalisation_centroide)"), $this->build_message('calcul_centroide', $message_field, $rowDonneesSIG, $this->f));
527
528 printf($button_field, 'recup_contrainte', sprintf($button, 'recup_contrainte', "Récupérer les contraintes", "geolocalisation_treatment('$idx', 'recup_contrainte', set_geolocalisation_contrainte, '"._("Etes vous sur de vouloir recuperer les contraintes ?")."')"), $this->build_message('recup_contrainte', $message_field, $rowDonneesSIG, $this->f));
529
530 //
531 printf("</div>");
532
533 // Le formulaire n'a pas été validé
534 $validation = 1;
535 // Le formulaire est en mode consultation
536 $maj = 3;
537
538 // Champs du formulaire
539 $champs = array("centroide", "contrainte", "adresse", "references_cadastrales");
540
541 // Création d'un nouvel objet de type formulaire
542 $form = new formulaire(NULL, $validation, $maj, $champs);
543
544 // Configuration des types de champs
545 foreach ($champs as $key) {
546 $form->setType($key, 'static');
547 }
548 $form->setType("references_cadastrales", "referencescadastralesstatic");
549
550 // Configuration des libellés
551 $form->setLib("references_cadastrales", _("terrain_references_cadastrales"));
552 $form->setLib("adresse", _("adresse"));
553 $form->setLib("centroide", _("centroide"));
554 $form->setLib("contrainte", _("contrainte"));
555
556 // Configuration des données
557 $form->setVal("references_cadastrales", $rowDonneesDI["terrain_references_cadastrales"]);
558 $form->setVal("adresse", $rowDonneesDI["terrain_adresse_voie_numero"]." ".$rowDonneesDI["terrain_adresse_voie"]." ".$rowDonneesDI["terrain_adresse_lieu_dit"]." ".$rowDonneesDI["terrain_adresse_code_postal"]." ".$rowDonneesDI["terrain_adresse_localite"]." ".$rowDonneesDI["terrain_adresse_bp"]." ".$rowDonneesDI["terrain_adresse_cedex"]);
559 if($geom != "") {
560 $form->setVal('centroide',
561 "<a id='action-form-localiser'".
562 " target='_SIG' href='../app/redirect_plan_sig.php?idx=".$rowDonneesDI["dossier"]."'>".
563 "<span class='om-icon om-icon-16 om-icon-fix sig-16' title='Localiser'>Localiser</span> ".
564 $geom.
565 " </a>");
566 } else {
567 $form->setVal('centroide', $geom);
568 }
569 $form->setVal("contrainte", $contrainte_val);
570
571 // Affichage des champs
572 $form->setBloc("centroide", "D", _("Donnees du dossier d'instruction"), "alignForm col_12");
573 $form->setBloc("centroide", "DF", "", "geoloc_form alignForm col_12");
574 $form->setBloc("contrainte", "DF", "", "geoloc_form alignForm col_12");
575 $form->setBloc("adresse", "DF", "", "geoloc_form alignForm col_12");
576 $form->setBloc("references_cadastrales", "DF", "", "geoloc_form alignForm col_12");
577 $form->setBloc("references_cadastrales", "F");
578
579 $form->afficher($champs, $validation, false, false);
580 // Ferme le tableau pour l'affichage sur deux colonnes
581 printf("</div></div>");
582
583 //Ajout d'un div vide pour éviter les superspositions des div
584 printf("<div class=\"both\"></div>");
585
586 // Fin du formulaire
587 printf("</div></div>");
588
589 // Affiche le bouton de retour
590 printf($button_return);
591 }
592
593 /**
594 * Compose le message affiché à l'utilisateur
595 * @param string $field_name Nom du champ
596 * @param string $message_field Code html du message
597 * @param array $rowDonneesSIG Tableau des données
598 * @param object $f Instance de la classe utils
599 * @return string Message
600 */
601 function build_message($field_name, $message_field, $rowDonneesSIG, $f) {
602
603 // Récupération des infos
604 $date = (isset($rowDonneesSIG["date_".$field_name])) ? $this->f->formatTimestamp($rowDonneesSIG["date_".$field_name]) : "";
605 $etat = (isset($rowDonneesSIG["etat_".$field_name])) ? $rowDonneesSIG["etat_".$field_name] : "";;
606 $text = (isset($rowDonneesSIG["message_".$field_name])) ? $rowDonneesSIG["message_".$field_name] : "";;
607
608 // id du message
609 $id_message = $field_name."-message";
610
611 // Définit le type du message "empty", "valid" ou "error"
612 // empty : message grisé
613 // valid : message de validation
614 // error : message d'erreur
615 $type_message = "empty";
616 if ($etat != "") {
617 //
618 $type_message = "valid";
619 if ($etat == 'f') {
620 $type_message = "error";
621 }
622 }
623
624 // Si il y a une date, un message est ajouté en debut
625 if ($date != "") {
626 //
627 $date = sprintf(_("Dernier traitement effectue le %s."), $date);
628 }
629
630 // Si aucun message alors l'action n'a jamais été effectuée
631 if ($text == "") {
632 //
633 $text = _("Action non effectuee.");
634 //
635 $type_message = "empty";
636 }
637
638 // Compose le message
639 $message = sprintf($message_field, $type_message, $id_message, $date." ".$text);
640
641 // retour
642 return $message;
643 }
644 }
645
646 ?>

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26