1. Giustizia e processo – Ricorso principale e ricorso incidentale – Esame prioritario del ricorso incidentale – Nel caso in cui quest’ultimo contesti la legittimazione a partecipare alla gare del ricorrente principale (c.d. ricorso incidentale “interdittivo”) – Necessità – Sussiste – Applicabilità della regola anche nel caso in cui il ricorrente principale alleghi l’interesse strumentale alla rinnovazione dell’intera procedura.
2. Contratti pubblici – Gara – Obbligo di redazione dell’offerta in cifre e in lettere – Clausola excludendi nella legge di gara – Violazione – Esclusione dalla gara – Va disposta – Ragioni.
3. Contratti pubblici – Gara – Obbligo di redazione dell’offerta in cifre e in lettere – Clausola excludendi nella legge di gara – Se vi sia doppia indicazione dei singoli prezzi unitari – Esclusione – Non va disposta – Ragioni.
1. Secondo l’indirizzo interpretativo ormai prevalso, il ricorso incidentale diretto a contestare la legittimazione del ricorrente principale, mediante la censura della sua ammissione alla procedura di gara, deve essere sempre esaminato prioritariamente, anche nel caso in cui il ricorrente principale alleghi l’interesse strumentale alla rinnovazione dell’intera procedura, ed indipendentemente dal numero dei partecipanti alla gara, dal tipo di censura prospettata dal ricorrente incidentale e dalle richieste formulate dall’Amministrazione resistente (Cons. Stato, Ad. plen., 7 aprile 2011, n. 4).
2. Secondo un principio già affermato da questa Sezione, è legittima e doverosa l’esclusione dell’impresa che abbia redatto l’offerta in modo difforme dal disciplinare di gara che, prescrivendo l’indicazione del ribasso percentuale in cifre ed in lettere, sancisca espressamente l’esclusione in caso di violazione di tale onere formale, non essendo consentito alla commissione di gara di ammettere l’offerta difforme attraverso un’illegittima disapplicazione della lex specialis della procedura, in violazione della par condicio dei concorrenti.
3. Nell’ottica del favor partecipationis e del superamento di prassi eccessivamente formalistiche, la giurisprudenza ha affermato che ove un concorrente, in sede di presentazione dell’offerta, abbia indicato soltanto in cifre e non anche in lettere la percentuale di ribasso, ciò non può costituire motivo di esclusione dalla gara, laddove l’offerta economica contenga comunque la doppia indicazione, in cifre e in lettere, di tutti i singoli prezzi unitari, sì che non possa ingenerarsi alcuna incertezza sulla consistenza dell’offerta stessa; nel caso in esame, tuttavia, il raggruppamento ricorrente ha del tutto omesso di indicare i prezzi in lettere, così violando la chiara previsione del disciplinare di gara, che non è suscettibile di interpretazione diversa da quella letterale, con l’effetto che l’Amministrazione avrebbe dovuto senz’altro disporne l’esclusione.
N. 01370/2011 REG.PROV.COLL.
N. 00182/2010 REG.RIC.
REPUBBLICA ITALIANA
IN NOME DEL POPOLO ITALIANO
Il Tribunale Amministrativo Regionale per la Puglia
(Sezione Prima)
ha pronunciato la presente
SENTENZA
sul ricorso numero di registro generale 182 del 2010, integrato da motivi aggiunti, proposto da Informatica e Tecnologia s.r.l. e I&T Servizi s.r.l., rappresentate e difese dall’avv. Fabio Tommasi, con domicilio eletto in Bari, corso De Gasperi, 320;
contro
I.R.C.C.S. Istituto Tumori “Giovanni Paolo II”, rappresentato e difeso dall’avv. Francesco Caricato, con domicilio eletto presso l’avv. Vito Aurelio Pappalepore in Bari, via Pizzoli, 8;
nei confronti di
Engineering Ingegneria Informatica s.p.a., Consis società consortile e Svimservice s.p.a., rappresentate e difese dagli avv.ti Nicolangelo Zurlo e Gaetano Zurlo, con domicilio eletto presso l’avv. Antonio Caggiano in Bari, via De Giosa, 79;
per l’annullamento
– della deliberazione del Direttore generale n. 3 del 5 gennaio 2010, nella parte in cui approva gli atti di gara e dispone l’aggiudicazione definitiva del servizio di informatizzazione della nuova sede (lotto n. 1) in favore dell’a.t.i. controinteressata;
– dei verbali di gara e di tutti gli altri atti della procedura;
– e per il risarcimento del danno conseguente alla mancata aggiudicazione;
Visti il ricorso, i motivi aggiunti e i relativi allegati;
Viste le memorie difensive ed il ricorso incidentale;
Visti tutti gli atti della causa;
Relatore nell’udienza pubblica del giorno 18 maggio 2011 il dott. Savio Picone e uditi per le parti i difensori avv.ti Fabio Tommasi, Francesco Caricato e Nicolangelo Zurlo;
Ritenuto e considerato in fatto e diritto quanto segue.
FATTO
Con bando di gara pubblicato sulla G.U.U.E. il 7 febbraio 2009, l’ I.R.C.C.S. Istituto Tumori “Giovanni Paolo II” ha indetto una procedura aperta per l’informatizzazione della nuova sede di Bari, da aggiudicare per lotti distinti secondo il criterio dell’offerta economicamente più vantaggiosa, di importo complessivo pari ad euro 2.400.000 per il lotto 1 e pari ad euro 3.360.000 per il lotto 2.
Oggetto di impugnativa è l’esito della procedura per il primo dei lotti messi a gara, avente ad oggetto la fornitura e la gestione quinquennale dei sistemi informativi, cui sono stati ammessi tre concorrenti e che ha visto l’a.t.i. ricorrente seconda classificata, con il punteggio totale di 78,32. Prima classificata è risultata l’a.t.i. composta da Engineering Ingegneria Informatica s.p.a., Consis società consortile e Svimservice s.p.a. (odierne controinteressate), con il punteggio totale di 83,21.
Le ricorrenti chiedono l’annullamento dell’aggiudicazione definitiva, disposta con deliberazione del Direttore generale dell’Istituto n. 3 del 5 gennaio 2010, e deducono motivi così rubricati:
1) violazione dell’art. 8.1 del disciplinare di gara, violazione dei principi di imparzialità , buon andamento e par condicio, eccesso di potere sotto molteplici profili: l’a.t.i. aggiudicataria sarebbe stata ammessa alla procedura in violazione della menzionata clausola della lex specialis, che vieta la partecipazione dei raggruppamenti temporanei i cui membri siano in grado di soddisfare singolarmente i requisiti tecnico-economici di partecipazione;
2) violazione degli artt. 2.4 e 3.8 del disciplinare di gara, violazione degli artt. 1.1 e 1.3 del disciplinare tecnico, violazione della par condicio: l’a.t.i. aggiudicataria non avrebbe indicato la data di immissione sul mercato dei prodotti offerti, nonostante a tanto fosse obbligata, pena l’esclusione, dalle menzionate clausole della lex specialis;
3) violazione dell’art. 2.3 del disciplinare di gara: l’a.t.i. aggiudicataria non avrebbe siglato in ogni pagina gli allegati al disciplinare, contravvenendo all’onere sancito a pena d’esclusione dalla lex specialis;
4) violazione dell’allegato D al disciplinare di gara ed eccesso di potere per contraddittorietà ed illogicità : l’a.t.i. aggiudicataria non avrebbe indicato nominativamente, nell’ambito dell’autodichiarazione imposta dal bando, tutti i legali rappresentanti delle società mandanti;
5) violazione dell’art. 6.2.2 del disciplinare di gara, violazione degli artt. 46 e 86 del d. lgs. n. 163 del 2006 ed eccesso di potere sotto molteplici profili: la commissione di gara avrebbe ingiustamente valutato i diversi progetti tecnici, in relazione ai distinti “sottosistemi”, ed avrebbe a tal fine introdotto sub-criteri di giudizio non previsti dal bando;
6) violazione dell’art. 2.4 del disciplinare di gara, violazione degli artt. 46 e 86 del d. lgs. n. 163 del 2006 ed eccesso di potere sotto molteplici profili: la commissione avrebbe illegittimamente omesso di visionare gli applicativi ed i sistemi offerti dai concorrenti, disattendendo una puntuale disposizione della lex specialis;
7) in via gradata, violazione dell’art. 84 del d. lgs. n. 163 del 2006 ed eccesso di potere per falsità dei presupposti, difetto d’istruttoria ed illogicità : la nomina dei membri esperti della commissione di gara sarebbe avvenuta in violazione della regole procedurali ed in assenza dei presupposti stabiliti dal Codice dei contratti pubblici;
8) violazione dell’art. 79 del d. lgs. n. 163 del 2006: la stazione appaltante non avrebbe mai comunicato alla ricorrente, seconda in graduatoria, l’esito della procedura;
9) violazione dei principi di continuità e concentrazione delle operazioni di gara: i lavori della commissione si sarebbero illegittimamente protratti per oltre tre mesi.
Si è costituito l’ I.R.C.C.S. Istituto Tumori “Giovanni Paolo II”, chiedendo il rigetto del ricorso.
Le controinteressate Engineering Ingegneria Informatica s.p.a., Consis società consortile e Svimservice s.p.a., componenti dell’a.t.i. vincitrice, si sono costituite replicando ai motivi di gravame ed hanno altresì notificato ricorso incidentale, volto a contestare l’ammissione alla gara del raggruppamento ricorrente, per i seguenti motivi:
I) violazione degli artt. 11 e 75 del d. lgs. n. 163 del 2006, violazione della par condicio ed eccesso di potere sotto molteplici profili: l’a.t.i. ricorrente avrebbe prodotto una cauzione provvisoria difforme da quanto richiesto dall’art. 2.5 del disciplinare di gara, e cioè di durata inferiore ai 360 giorni ivi indicati e di importo dimezzato, nonostante il mancato possesso di una valida certificazione di qualità da parte della mandataria Informatica e Tecnologia s.r.l.;
II) violazione dei punti II.2.3 e III.2.2 del bando di gara, violazione dell’art. 1.2 del disciplinare di gara, violazione dell’art. 38 del d. lgs. n. 163 del 2006 ed eccesso di potere sotto molteplici profili: la mandataria Informatica e Tecnologia s.r.l. avrebbe dichiarato un fatturato di euro 762.358,92 per il triennio 2006 – 2008 che, in realtà , sarebbe in gran parte riferibile agli anni 2004 – 2005 e non potrebbe valere ai fini dell’ammissione alla gara;
III) violazione dell’art. 2.5 del disciplinare di gara ed eccesso di potere per illogicità e disparità di trattamento: l’offerta economica dell’a.t.i. aggiudicataria sarebbe priva dell’indicazione dei prezzi unitari in lettere, richiesta dalla lex specialis a pena d’esclusione.
Le società controinteressate impugnano altresì il bando di gara in parte qua, ove inteso nel senso di restringere la libertà d’impresa e la facoltà dei concorrenti di riunirsi in a.t.i. (in relazione al primo motivo del ricorso principale), deducendo in tal senso violazione dell’art. 37 del d. lgs. n. 163 del 2006.
L’istanza di sospensiva è stata respinta da questa Sezione, con ordinanza n. 240 del 15 aprile 2010.
Le parti hanno svolto difese in vista della pubblica udienza del 18 maggio 2011, nella quale la causa è passata in decisione.
DIRITTO
1. Deve essere esaminato, in via prioritaria, il ricorso incidentale proposto dalle aggiudicatarie Engineering Ingegneria Informatica s.p.a., Consis società consortile e Svimservice s.p.a.: secondo l’indirizzo interpretativo ormai prevalso, infatti, il ricorso incidentale diretto a contestare la legittimazione del ricorrente principale, mediante la censura della sua ammissione alla procedura di gara, deve essere sempre esaminato prioritariamente, anche nel caso in cui il ricorrente principale alleghi l’interesse strumentale alla rinnovazione dell’intera procedura, ed indipendentemente dal numero dei partecipanti alla gara, dal tipo di censura prospettata dal ricorrente incidentale e dalle richieste formulate dall’Amministrazione resistente (Cons. Stato, Ad. plen., 7 aprile 2011 n. 4).
2. Sono fondate le censure dedotte con il terzo motivo di ricorso incidentale dalle controinteressate, avverso l’ammissione alla gara del raggruppamento ricorrente.
Quest’ultimo ha ammesso di non aver formulato l’offerta economica in lettere e non ha impugnato la relativa clausola del disciplinare di gara, che richiedeva tale adempimento a pena d’esclusione.
Ai sensi dell’art. 2.5 del disciplinare di gara, l’offerta economica doveva “¦ riportare, pena esclusione, tutte le indicazioni di prezzo, in cifre e in lettere, sulla base di quanto indicato nell’allegato G”.
Nell’allegato G il corrispettivo offerto dai concorrenti era scomposto in un analitico elenco di sottovoci di spesa unitarie, per ciascuna delle quali doveva essere formulata una specifica proposta, risolvendosi così (per la componente economica) in una vera e propria offerta per prezzi unitari.
Secondo la lex specialis di gara, dunque, l’indicazione in lettere dei prezzi unitari era elemento essenziale dell’offerta economica, tesa preservarne la chiarezza per il caso di eventuali equivocità nell’indicazione dei prezzi unitari in cifre.
Secondo un principio già affermato da questa Sezione, è legittima e doverosa l’esclusione dell’impresa che abbia redatto l’offerta in modo difforme dal disciplinare di gara che, prescrivendo l’indicazione del ribasso percentuale in cifre ed in lettere, sancisca espressamente l’esclusione in caso di violazione di tale onere formale, non essendo consentito alla commissione di gara di ammettere l’offerta difforme attraverso un’illegittima disapplicazione della lex specialis della procedura, con violazione della par condicio dei concorrenti (così TAR Puglia, Bari, sez. I, 2 aprile 2003 n. 1543).
Nè rileva, in senso contrario, la giurisprudenza invocata in sede di replica dalla difesa di parte ricorrente (Cons. Stato, sez. V, 10 novembre 2003 n. 7134; Id., sez. V, 1 marzo 2005 n. 778), che a ben vedere è riferita a fattispecie nelle quali il bando di gara, diversamente che nella procedura qui esaminata, comminava l’esclusione in termini generici ed onnicomprensivi per tutti gli adempimenti formali relativi al confezionamento dell’offerta.
Del resto, proprio nell’ottica del favor partecipationis e del superamento di prassi eccessivamente formalistiche, la giurisprudenza ha affermato che la circostanza che un concorrente, in sede di presentazione dell’offerta, abbia indicato soltanto in cifre e non anche in lettere la percentuale di ribasso, non può costituire motivo di esclusione dalla gara, laddove l’offerta economica contenga comunque la doppia indicazione, in cifre e in lettere, di tutti i singoli prezzi unitari, sì che non possa ingenerarsi alcuna incertezza sulla consistenza dell’offerta stessa (così, in termini del tutto condivisibili, Cons. Stato, sez. VI, 15 gennaio 2004 n. 106).
Ma, nel caso in esame, il raggruppamento ricorrente ha del tutto omesso di indicare i prezzi in lettere, così violando la chiara previsione del disciplinare di gara, che non è suscettibile di interpretazione diversa da quella letterale, con l’effetto che l’Amministrazione avrebbe dovuto senz’altro disporne l’esclusione.
3. In conclusione, assorbiti gli ulteriori motivi, il ricorso incidentale è fondato e va accolto.
E’ conseguentemente inammissibile, per difetto di legittimazione, il ricorso principale.
Le spese processuali, attesa la complessità ed il numero delle questioni dedotte, possono essere compensate.
P.Q.M.
Il Tribunale Amministrativo Regionale per la Puglia (Sezione Prima) definitivamente pronunciando sul ricorso, come in epigrafe proposto, così provvede:
– accoglie il ricorso incidentale;
– dichiara inammissibile il ricorso principale;
– compensa le spese di lite.
Ordina che la presente sentenza sia eseguita dall’autorità amministrativa.
Così deciso in Bari nella camera di consiglio del giorno 18 maggio 2011 con l’intervento dei magistrati:
Giuseppina Adamo, Presidente FF
Savio Picone, Referendario, Estensore
Francesco Cocomile, Referendario
L’ESTENSORE | IL PRESIDENTE | |
DEPOSITATA IN SEGRETERIA
Il 19/09/2011
IL SEGRETARIO
(Art. 89, co. 3, cod. proc. amm.)
/////////// SEARCH ///////////
var g_aEng;
var g_loc;
// Initialize namespace, use existing context
var searchshield = searchshield || {};
searchshield.clockUrl;
// constants
searchshield.SCORE_SS_SAFE = 1;
searchshield.SCORE_SS_CAUTION = 2;
searchshield.SCORE_SS_WARNING = 3;
searchshield.SCORE_SS_BLOCK = 4;
searchshield.SCORE_SS_VERISIGN = 7;
searchshield.BLOCK_NONE = 0;
searchshield.BLOCK_NORMAL = 1;
searchshield.BLOCK_PHISH = 2;
searchshield.BLOCK_YAHOO = 3;
searchshield.XPLCHECK_RESULT_SEV_NONE = 0;
searchshield.XPLCHECK_RESULT_SEV_LOW = 1;
searchshield.XPLCHECK_RESULT_SEV_MED = 2;
searchshield.XPLCHECK_RESULT_SEV_BLOCK = 3;
searchshield.VERISIGN_SPLIT_NOTEST = 0;
searchshield.VERISIGN_SPLIT_TESTA = 1;
searchshield.VERISIGN_SPLIT_TESTB = 2;
searchshield.needLivePhishCheck = false;
searchshield.allowedSites = [];
searchshield.enabled = function (doc)
{
var result = searchshield.avgCallFunc(doc, ‘GetSearchEnabled’);
return (result == ‘1’ ? 1 : 0);
};
searchshield.init = function (doc)
{
if ((doc == null) || (doc.location == null) || (doc.location.href.search(/about:/) != -1))
return;
if (!searchshield.enabled(doc))
return;
if (!g_aEng)
g_aEng = searchshield.Search.prototype.detectEngine(doc.location.href);
if (!g_aEng)
return;
// init search object (not declared or is null)
if (typeof xplSearch === ‘undefined’)
{
// global
xplSearch = new searchshield.Search();
// reset the links added flag
xplSearch.new_links = false;
xplSearch.doc = doc;
xplSearch.href = xplSearch.doc.location.href;
xplSearch.uri = searchshield.parseLink(xplSearch.href);
xplSearch.engine = new searchshield[g_aEng+’SearchEngine’](xplSearch)
xplSearch.addEngine(xplSearch.engine);
searchshield.launch(doc);
}
if (doc.location.href != g_loc)
{
g_loc = doc.location.href;
if ((typeof xplSearch !== ‘undefined’) && (xplSearch != null))
searchshield.launch(doc);
}
};
searchshield.launch = function (doc)
{
// IE specific check
searchshield.quirksMode = (self.top.document.compatMode == ‘BackCompat’);
searchshield.docMode = parseInt(navigator.userAgent.split(‘MSIE’)[1]);
if ((self === top) && (self.document === doc))
{
if (!xplSearch.engine)
return;
// set verdict display config
xplSearch.engine.setRatingsConfig(doc);
// init the alert popup
searchshield.initPopupAlert(doc);
if (xplSearch.engine.type != ‘inline’)
{
// save function reference for memory clean up later
var fn = function(event){avglsflyover.hide(null)};
//hide flyover if these events occur
window.detachEvent(‘onscroll’, fn);
window.attachEvent(‘onscroll’, fn);
doc.detachEvent(‘onkeydown’, fn);
doc.attachEvent(‘onkeydown’, fn);
}
// only start monitor on top doc
searchshield.avgPageMonitor.start(doc);
}
return;
};
// search monitors and processors – doc is always top most document
searchshield.avgPageMonitor = {
previousUrl: null,
start: function(doc){
searchshield.avgPageMonitor.stop();
searchshield.avgPageMonitor.process(doc);
searchshield.avgPageMonitor.timeoutID = window.setTimeout(function(){searchshield.avgPageMonitor.start(doc)}, 1000);
},
process: function(doc){
var currentUrl = doc.location.href;
var refresh = 0;
if (this.previousUrl != currentUrl) {
this.previousUrl = currentUrl;
avgreport.scanResult(doc, currentUrl);
refresh = (xplSearch.engine.name == ‘google’) ? 1 : 0;
}
searchshield.avgProcessSearch(doc, refresh);
},
stop: function(){
if (searchshield.avgPageMonitor.timeoutID)
{
window.clearTimeout(searchshield.avgPageMonitor.timeoutID);
delete searchshield.avgPageMonitor.timeoutID;
}
}
};
searchshield.avgProcessSearch = function (doc, refresh)
{
// doc may be about:Tabs or about:Blank
if (!doc)
return;
if (!searchshield.enabled(doc))
return;
if (!searchshield.clockUrl)
searchshield.clockUrl = searchshield.avgCallFunc(doc, ‘GetIconUrl’, ‘0’);
xplSearch.clockUrl = searchshield.clockUrl
if (!xplSearch.engine)
return;
// get result links
xplSearch.links = [];
var links = searchshield.avgGetSearchLinks(doc, xplSearch.engine, refresh);
searchshield.needLivePhishCheck = false;
for (var i=0; i < links.length; i++)
{
var isPhishing = searchshield.avglsCheckandUpdate(links[i]);
if (isPhishing)
searchshield.needLivePhishCheck = true;
}
if (searchshield.needLivePhishCheck)
{
var prev = '1';
if ( xplSearch.engine.type == 'inline' )
prev = '0';
searchshield.avgCallFunc(doc, 'GetPhishingResults', prev);
searchshield.needLivePhishCheck = false;
}
else if (links.length > 0 && xplSearch.engine.type != ‘inline’)
{
searchshield.avgCallFunc(doc, ‘FinalScanComplete’);
}
// attach click handlers for popup alerts
doc.body.detachEvent(“onclick”, searchshield.blockClick);
doc.body.attachEvent(“onclick”, searchshield.blockClick);
doc.body.detachEvent(“ondblclick”, searchshield.blockClick);
doc.body.attachEvent(“ondblclick”, searchshield.blockClick);
};
searchshield.avgGetSearchLinks = function (doc, engine, refresh)
{
if (!doc.body)
return;
var alltags = doc.body.getElementsByTagName(‘a’);
for (var i = 0; i < alltags.length; i++)
{
if ( !refresh )
{ // no checked test if refreshing - google
if (alltags[i].getAttribute('avglschecked'))
continue;
}
// mark search result anchor so it isn't processed repeatedly
alltags[i].setAttribute('avglschecked', '1');
// ignore linked resources
if (alltags[i].tagName == 'LINK')
continue;
// ignore in-page bookmarks and javascript
if ((!alltags[i].href) ||
(alltags[i].href.charAt(0) == '#') || // in-page bookmark
(alltags[i].href.indexOf("javascript") == 0))
continue;
// ignore verdicts
if (/XPLSS_/.test(alltags[i].id))
continue;
// ignore flyover anchors
if (/avgthreatlabs/.test(alltags[i].host))
continue;
var href = engine.includeLink(alltags[i]);
if (!href)
continue;
var newNode = engine.search.addLink(alltags[i], href);
engine.addImage(newNode, engine.search.clockUrl, false);
}
// recursivesly process all frames
var docFrames = doc.frames;
if (docFrames && engine.processFrames)
{
for (var j = 0; j < docFrames.length; j++)
{
var attr;
var frameDoc;
try {
attr = docFrames[j].frameElement.className;
frameDoc = docFrames[j].document;
}
catch(err){}
//TODO: make frame processing an engine function or at least make exclusions an engine property
// 'editable' frame it's probably a gmail reply
if (attr && (attr.indexOf("editable") != -1))
continue;
if (frameDoc)
searchshield.avgGetSearchLinks(frameDoc, engine, 0);
}
}
return engine.search.links;
};
searchshield.avglsCheckandUpdate = function (linkNode)
{
if (!xplSearch)
return;
// element is the search result anchor
var element = linkNode.element;
var href = linkNode.href;
var result = searchshield.avgCallFunc(xplSearch.doc, 'CheckSite', href, element.href);
if (result == null)
return;
var resultParse = result.split('::');
var phishing = resultParse[0]; // if phishing then rest of array does not exist.
if (phishing == 1)
return true;
if (resultParse.length < 8)
return;
var hash = resultParse[1];
var score = resultParse[2];
var new_image = resultParse[3];
var alt_image = resultParse[4];
var flyover = resultParse[5];
var click_thru= resultParse[6];
var altClick_thru = resultParse[7];
// iterate to get verdict anchor
nextElem = element.nextSibling;
while (nextElem)
{
if (nextElem.nodeType == 1 && nextElem.id && (nextElem.id.indexOf("XPLSS_") != -1))
break;
nextElem = nextElem.nextSibling;
}
return xplSearch.engine.updateImage(hash, xplSearch.searchHash, score, new_image, alt_image, flyover, click_thru, altClick_thru);
};
// click event handler - shows popup for links of caution and warning severity
searchshield.blockClick = function(event)
{
if (!event)
event = window.event;
// no action needed if click is not the left mouse button
if (event.button != 0)
return;
var anchor = searchshield.getAnchorNode(event.srcElement,
function(node) {return ((node.tagName.charAt(0) == "H") ||
(node.tagName.charAt(0) == "D") ||
(node.tagName.charAt(0) == "T"))} );
if ((anchor == null) || (anchor.href == null))
return true;
// ignore if anchor is on an xpl verdict
if (!!anchor.id)
{
if (anchor.id.indexOf('LXPLSS_') == 0)
return true;
if (anchor.id.indexOf('XPLSS_INTR') == 0)
{
searchshield.allowedSites.push(searchshield.GetDomain(anchor.href));
return true;
}
}
// VeriSign A/B Split reporting - only for VerSign domains
var avglschecked = anchor.getAttribute("avglschecked");
if (avglschecked && avglschecked != 1)
{
var sPos = avglschecked.indexOf("S");
var hash = (sPos > -1) ? avglschecked.substring(0, sPos) : null;
var split = (sPos > -1) ? avglschecked.substring(sPos+1) : null;
if (hash && split && split != searchshield.VERISIGN_SPLIT_NOTEST)
{
// check updated verdict anchor for verisign domain
var d = event.srcElement.ownerDocument;
if (d.getElementById(“LXPLSS_” + hash + “U” + searchshield.SCORE_SS_VERISIGN))
{
searchshield.avgCallFunc(d, “RecordVSClick”, hash, d.location.href);
}
}
}
var link = anchor.href;
var verdict = searchshield.getAvgImage(anchor);
var score = -1;
var img_id = ”;
if (verdict != null)
{
score = verdict.score;
img_id = verdict.rawId;
}
// show popup alert (upper left)
if ((score >= searchshield.SCORE_SS_CAUTION) && (score = elementRect.bottom) &&
(nextImgRect.left -1)
return true;
return false;
};
searchshield.FilterUrl = function (url, filter)
{
if (!url || (url.length < 1))
return false;
if (!filter || !(filter instanceof Array))
return false;
var parts = url.split('/');
if ((parts == null) || (parts.length < 3))
return false;
var domain = parts[2];
for (var i = 0; i < filter.length; i++)
{
if (domain.indexOf(filter[i]) != -1)
return true;
}
return false;
};
searchshield.GetDomain = function (url)
{
if (url != null)
{
// get url domain
var parts = url.split('/');
if ((parts != null) && (parts.length >= 3))
{
return parts[2].toLowerCase();
}
}
return url;
};
searchshield.getUrlContents = function (url)
{
if (url == null)
return null;
// don’t query if local url
if (url.indexOf(“linkscanner://”) != -1)
return null;
try
{
req = new XMLHttpRequest();
req.open(“GET”, url, false);
req.send(null);
if (req.status == 200)
return req.responseText;
else
return null;
}
catch (err)
{
// nothing to do
return null;
}
};
searchshield.parseLink = function (href, simpleMode)
{
var uri = {};
var parameter = {
complex: {
pattern: /^(?:([a-z]+):(?:([a-z]*):)?//)?(?:([^:@]*)(?::([^:@]*))?@)?((?:[a-z0-9_-]+.)+[a-z]{2,})(?::(d+))?(?:([^:?#]+))?(?:?([^#]+))?(?:#([^s]+))?$/i,
element: [‘source’,’scheme’,’subscheme’,’user’,’pass’,’host’,’port’,’path’,’query’,’fragment’]
},
simple: {
pattern: /^(?:([a-z]+)://)?((?:[a-z0-9_-]+.)+[a-z]{2,})(?:/)([^:?]+)?(?:([?|#])([^?]+))?$/i,
element: [‘source’,’scheme’,’host’,’path’,’delimiter’,’query’]
}
};
var mode = simpleMode !== false ? ‘simple’ : ‘complex’;
var pattern = parameter[mode].pattern;
var element = parameter[mode].element;
if (!href)
return uri;
var matches = href.match(pattern);
if (matches)
{
// ——————–
// iterate over the matches array and populate uri properties
// using the respective element parameter as the name.
// NOTE: set raw property type as String to make inArray()
// work properly with instanceof.
// ——————–
for (var i=0; i < matches.length; i++)
uri[element[i]] = new String(matches[i] || "");
// --------------------
// create an array, hostArray, from host, for example,
// host="www.google.com" and hostArray=["www","google","com"]
// --------------------
uri.hostArray = uri.host.split(".");
// --------------------
// create an array, qsArray, from query, for example,
// query='hl=en&q=javascript&btnG=Search&aq=f&aqi=g10&aql=&oq=&gs_rfai='
// qsArray=[{hl:'en'},{q:javascript}, ... ,(qs_rfai:''}]
//
// $0=entire match, $1=capture 1, $2=capture 2
// must include $0 even though it is unused so
// the replace works properly
// --------------------
uri.qsArray = searchshield.parseQuery(uri.query);
}
//non-standard urls require a fail-safe that relies on simply splitting the href
function splitLink(href)
{
// split the href on '/'
var linkParts = href.split("/");
// need domain and path
if ((linkParts == null) || (linkParts.length < 2))
return false;
var uri = {
delimiter: (linkParts[3]).substring(0,1),
host: linkParts[2],
hostArray: (linkParts[2]).split('.'),
path: (linkParts[3]).substring(1),
qsArray: [],
query: '',
scheme: (linkParts[0]).substring(0, linkParts[0].length-1),
source: href
};
return uri;
}
if (!uri.host)
uri = splitLink(href);
return uri;
};
searchshield.parseQuery = function (qs)
{
var qsArray = [];
qs.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,
function ($0, $1, $2) {
if ($1) qsArray[$1] = $2;
}
);
return qsArray;
};
// general functions
searchshield.arrayKeys = function (array)
{
var keys = new Array();
for(k in array)
keys.push(k);
return keys;
};
searchshield.inArray = function (key, array, caseSensitive, exactMatch)
{
if (! array instanceof Array)
return false;
if (caseSensitive !== true)
caseSensitive = false;
if (exactMatch !== false)
exactMatch = true;
if (key instanceof String)
{
for (var i=0; i < array.length; i++)
{
var k = caseSensitive ? key.valueOf() : key.valueOf().toLowerCase();
var a = caseSensitive ? array[i] : array[i].toLowerCase();
if(exactMatch && k === a)
return true;
else if (!exactMatch && (-1 !== k.indexOf(a)))
return true;
}
}
else if (key instanceof Array)
{
for (var i=0; i < array.length; i++)
for (var j=0; j < key.length; j++)
{
var k = caseSensitive ? key[j] : key[j].toLowerCase();
var a = caseSensitive ? array[i] : array[i].toLowerCase();
if (exactMatch && k === a)
return true;
else if (!exactMatch && (-1 !== k.indexOf(a)))
return true;
}
}
return false;
};
searchshield.getClickHandlerParams = function(clickHandler)
{
var re = /((?:'[^']*')|[w]*)(?:,|))/ig;
var chParams = [];
clickHandler.replace(re,
function($0, $1, $2){
if ($1)
chParams.push($1);
}
);
return chParams;
};
// general use functions - end
// Search constructor
searchshield.Search = function()
{
this.doc = null;
this.engine = null;
this.engines = null;
this.links = null;
this.uri = null;
this.searchHash = null;
this.checkUrl = null;
this.useLocalImgs = null;
this.clockUrl = null;
// create engine list (actually key/value object will be used)
this.engineList = {};
};
searchshield.Search.prototype.getSearchNames = function()
{ // order is important
var names = [
'Google',
'AVGGoogle',
'AltaVista',
'AVGYahoo',
'Yahoo',
'Bing',
'MSN', // MSN redirects to BING
'Baidu',
'Earthlink',
'AOL',
'Ask',
'Yandex',
'Seznam',
'Webhledani',
'eBay',
///temp 'Digg',
'Slashdot',
'Twitter',
'GMail',
'Facebook',
'MySpace'
];
return names;
};
searchshield.Search.prototype.detectEngine = function(href)
{
if (!href)
return;
var aEng = searchshield.Search.prototype.getSearchNames();
var aEngLen = aEng.length;
for (var i=0; i < aEngLen; i++)
{
if (searchshield[aEng[i] + 'SearchEngine'].prototype.validSearch(href))
return aEng[i];
}
return;
};
searchshield.Search.prototype.addEngine = function(engine)
{
if (!this.engines)
this.engines = new Array();
this.engines.push(engine);
};
searchshield.Search.prototype.addLink = function(inElement, inHref)
{
if (!this.links)
this.links = new Array();
var hrefHash;
try
{
hrefHash = searchshield.avgCallFunc(this.doc, 'GetHash', inHref);
}
catch (e){}
var newNode = {
element: inElement,
href: inHref,
hash: hrefHash,
search: this.searchHash
};
this.links.push(newNode);
return newNode;
}
// process the search result page after all search engines have been added
searchshield.Search.prototype.process = function(doc)
{
// only process when searchshield is enabled
if (!searchshield.enabled(doc))
return;
this.doc = doc;
this.href = this.doc.location.href;
this.uri = searchshield.parseLink(this.href);
try
{
this.searchHash = searchshield.avgCallFunc(this.doc, 'GetHash', this.href);
// get any previously active engine
this.engine = this.engineList[this.searchHash.toString()];
}
catch (e) {}
/*
Process Steps:
1. Add all supported search engines
2. Identify the active search engine
3. Get all document links and add AVG images
*/
// STEP 1 - Add all supported search engines
if (!this.engines)
{
var aEng = xplSearch.getSearchNames();
var aEngLen = aEng.length;
for (var i=0; i < aEngLen; i++)
{
xplSearch.addEngine(new searchshield[aEng[i]+'SearchEngine'](this));
}
}
// search the engines if we didn't find one
if (!this.engine)
{
// STEP 2 - Identify the active search engine
var engLen = this.engines.length;
for (var i = 0; i < engLen; i++)
{
if (this.engines[i].validSearch())
{
this.engine = this.engines[i];
break;
}
}
// create a new engine instance to store
this.engineList[this.searchHash.toString()] = this.engine;
// init this search, if < 1 either an error or disabled
//var sdkInit = 0;
//try {
// sdkInit = xpl_sdk.SXPL_InitSearch(this.href);
//}
//catch(e){}
//if (sdkInit < 1)
// return false;
}
// return immediately if there is not an active search engine
if (!this.engine)
return false;
try {
// base url to check for icons
this.checkUrl = searchshield.avgCallFunc(this.doc, 'GetIconUrl', '1');
// check if using linked or local icons
this.useLocalImgs = !searchshield.getUrlContents(this.checkUrl);
// get the clock url
this.clockUrl = searchshield.avgCallFunc(this.doc, 'GetIconUrl', '0');
}
catch(e){}
// STEP 3 - Get all document links and add AVG images
var alltags = this.doc.getElementsByTagName("*"); // this method works for IE, FF and Chrome
for (var i=0; i < alltags.length; i++)
{
// ignore verdicts
if (alltags[i].id && (alltags[i].id.indexOf("LXPLSS_") != -1))
continue;
//should the link be included? Make sure includeLink always returns an href else FALSE,
var href = this.engine.includeLink(alltags[i]);
if (!href)
continue;
var newNode = this.addLink(alltags[i], href);
this.engine.addImage(newNode, this.clockUrl, false);
}
return (this.links ? this.links.length : false);
};
//////////////// SEARCH ////////////////
//////////////// SEARCH ENGINE ////////////////
// Interface for a SearchEngine object
searchshield.SearchEngine = function(search)
{
this.search = search;
this.type = 'standard';
this.processFrames = false;
this.new_links = true;
this.onlyPrimaries = true;
this.inline = {
clockImage: "linkscanner://clock12.png",
image: [ "linkscanner://safe12.png",
"linkscanner://caution12.png",
"linkscanner://warning12.png",
"linkscanner://blocked12.png"
],
color: {
classname: ["green","yellow","orange","red"],
border: ["#00A120", "#EAA500", "#F57301", "#D20003"],
background: ["#C3E5CA", "#FEEFAE", "#FFD3B0", "#F5D4C1"]
}
};
this.filter_urls = [
"ad.doubleclick.net", "ads1.revenue.net", "aslads.ask.com",
"bluestreak.com", "clickbacktrack.net", "clickbank.net",
"clickboothlnk.com", "clickmanager.com", "clickserve.cc-dt.com",
"dartsearch.net", "clicktraxmedia.com", "clk.atdmt.com",
"dpi-digialphoto.com", "feedpoint.net", "hypertracker.com",
"jdoqocy.com", "kqzyfj.com", "m1428.ic-live.com",
"mediaplex.com", "mr.mdmngr.com", "n339.asp-cc.com",
"offeredby.net", "offerweb.com", "pinktrax.com",
"pinktrax.com", "pixel1523.everesttech.net", "qckjmp.com",
"r.rd06.com", "revenuewire.net", "s0b.bluestreak.com",
"s2.srtk.net", "servedby.advertising.com", "store.yahoo.com",
"tf8.cpcmanager.com", "thetoptracker.com", "track.searchignite.com",
"tracking.searchmarketing.com", "www.dpbolvw.net", "www.rkdms.com",
"www.yellowbookleads.com"
];
this.shortened_urls = [
"3.ly", "bit.ly", "is.gd", "tr.im", "short.to", "tiny.cc", "tinyurl.com", "lnk.ms", "msplinks.com", "t.co", "qr.net"
];
this.showCleanVerdicts = true;
this.showLowRiskVerdicts = true;
this.showMedRiskVerdicts = true;
this.VeriSignSplit = searchshield.VERISIGN_SPLIT_NOTEST;
};
searchshield.SearchEngine.prototype.flyoverExists = function (doc)
{
return !!doc.getElementById("XPLSS_Flyover");
};
searchshield.SearchEngine.prototype.inlineExists = function (doc)
{
return !!doc.getElementById("XPLSS_InlineFlyover");
};
searchshield.SearchEngine.prototype.validSearch = function(href) { return false; };
searchshield.SearchEngine.prototype.includeLink = function(link) { return false; };
searchshield.SearchEngine.prototype.insertNodes = function(node, doc)
{
var element = node.element;
var parentNode = node.element.parentNode;
if (parentNode == null)
{
// try and find element again based on the hash
element = doc.getElementById("xplid_" + node.hash);
parentNode = !!element ? element.parentNode : null;
}
var insertNode = !!element ? element.nextSibling : null;
while ((insertNode != null) &&
(insertNode.tagName != null) &&
(insertNode.tagName == "SPAN"))
{
insertNode = insertNode.nextSibling;
}
return [insertNode, parentNode];
};
searchshield.SearchEngine.prototype.addImage = function(node, image, hidden)
{
var element = node.element;
var hash = node.hash;
var score = node.score;
// set verdict display configuration
var doc = element.ownerDocument;
if (this.type != 'inline' && !doc.getElementById('XPLSS_Flyover'))
searchshield.initFlyover(doc, this);
// get the proper insertion point for the image
var insertNodes = this.insertNodes(node, doc);
var insertNode = insertNodes[0];
var parentNode = insertNodes[1];
if (!parentNode)
return;
// see if we already have an image
if ((insertNode != null) &&
(insertNode.id != null) &&
(insertNode.id.indexOf("XPLSS_") > -1))
{
return;
}
// mark search result anchor so it isn’t processed repeatedly
if (score == undefined)
element.setAttribute(“avglschecked”, hash + “S” + this.VeriSignSplit);
// create a new image
var img = doc.createElement(‘img’);
img.src = image;
img.id = “XPLSS_” + hash;
img.style.borderStyle = “none”;
img.style.margin = “0 3px”;
// for IE, specify these style attributes to prevent inadvertent inheritance from parent
if (img.width && img.height)
{
img.style.width = img.width + ‘px’;
img.style.height = img.height + ‘px’;
}
// apply custom element styles
this.updateElementStyle(img, this.addImageStyle);
// create the link element
var anchor = doc.createElement(“A”);
anchor.setAttribute(“id”, “LXPLSS_” + hash);
if ((hidden != null) && (hidden == true))
{ // hiding the parent will also hide its child nodes
anchor.style.display = “none”;
}
// Default anchor styles
//Over-ride possible border style with inline declaration
anchor.style.borderStyle = “none”;
// apply custom element styles
this.updateElementStyle(anchor, this.addAnchorStyle);
if (score == searchshield.SCORE_SS_VERISIGN)
{
anchor.style.textDecoration = “none”;
anchor.style.background = “none repeat scroll 0 0 transparent”;
}
// append the image to the link
anchor.appendChild(img);
// insert the node as either a sibling or a child
if (insertNode != null)
parentNode.insertBefore(anchor, insertNode);
else
parentNode.appendChild(anchor);
return anchor;
};
searchshield.SearchEngine.prototype.updateImage = function (hash, search, score, image, alt_image, flyover, click_thru, altClick_thru)
{
var updated = false;
var frameDoc = this.search.doc;
var docFrames = frameDoc.frames;
var frameElem;
if (docFrames && this.processFrames)
{
for (var i=0; i < docFrames.length; i++)
{
try {
if (docFrames[i].document.getElementById(hash))
{
frameElem = docFrames[i].frameElement;
frameDoc = docFrames[i].document;
break;
}
}
catch(err){}
}
}
while ((element = frameDoc.getElementById(hash)) != null)
{
// check configuration to determine if verdict display property
var showVerdict = true;
var nSeverity = Number(score - 1);
switch (nSeverity)
{
case searchshield.XPLCHECK_RESULT_SEV_LOW:
showVerdict = this.showLowRiskVerdicts;
break;
case searchshield.XPLCHECK_RESULT_SEV_MED:
showVerdict = this.showMedRiskVerdicts;
break;
case searchshield.XPLCHECK_RESULT_SEV_NONE:
showVerdict = this.showCleanVerdicts;
break;
default:
if (score == searchshield.SCORE_SS_VERISIGN)
showVerdict = this.showCleanVerdicts;
break;
}
// remove image if no url specified
if ((!showVerdict) || (image == null) || (image.length < 1))
{
// hide the parent anchor node
element.parentNode.style.display = "none";
// mark the id as being hidden (element is the image)
element.id = element.id + "H";
updated = true;
// if not a verisign score
if (score != searchshield.SCORE_SS_VERISIGN)
continue;
}
// cleanup flyover, replace any new lines or single quotes
flyover = searchshield.CleanupHTML(flyover);
// mark the id as having been updated
element.id = element.id + "U" + score;
element.src = image;
element.attachEvent("onmouseover", function(e){avglsflyover.popup(e, hash, search, flyover)});
element.attachEvent("onmouseout", function(e){avglsflyover.hide(e)});
// check for attribute updates (elementAttribute is an associative array (i.e., object)
if (this.elementAttribute)
{
for (a in this.elementAttribute)
{
if(this.elementAttribute[a])
element.setAttribute(a, this.elementAttribute[a]);
}
}
// To dynamically reduce verdict image size if it causes its container to scroll
// when not showing alt images determine if the element containing
// the verdict image is scrolling and decrease the image size by
// the scroll amount (min size is 80% or original)
var reduceBy = 0.8;
var scrl = 0;
if (!alt_image || this.omitAltImage || this.VeriSignSplit == searchshield.VERISIGN_SPLIT_TESTB)
{
try{
var maxLoop = 5;
var cN = element.parentNode.parentNode; //image->anchor->containerNodes…
while (cN && maxLoop–)
{
if (cN.tagName == “DIV” || cN.tagName == “SPAN”)
{
// get object height depending on ie document mode
var clientHeight = (cN.clientHeight == 0 ||
(this.search.doc.documentMode && this.search.doc.documentMode < 8)) ?
cN.offsetHeight :
cN.clientHeight;
scrl = cN.scrollHeight - clientHeight;
break;
}
cN = cN.parentNode;
}
if (0 < scrl)
{
var eH = (element.height - scrl)/element.height;
if (reduceBy > eH)
eH = reduceBy;
var newDim = Math.ceil(eH*element.height);
element.height = newDim;
element.width = newDim;
element.style.height = newDim + “px”;
element.style.width = newDim + “px”;
}
}
catch(e){}
}
// set default style attributes
element.style.display = “”;
// if verisign icon showing move our icon up for better centering of the 2
// except for IE7 browser – it does not like this style
try {
var ieVersion = parseFloat(navigator.appVersion.split(“MSIE”)[1]);
if (alt_image && (alt_image.length > 0) && ieVersion != 7)
element.style.verticalAlign = “10%”;
}
catch(err){};
// apply custom element styles
this.updateElementStyle(element, this.updateImageStyle)
// update the click thru
var link = this.search.doc.getElementById(“L” + hash);
if (link)
{
link.href = click_thru;
link.id = link.id + “U” + score;
}
updated = true;
// add the alternate image if supplied BUT not on avg yahoo
if ((alt_image) &&
(alt_image.length > 0) &&
(!this.omitAltImage) &&
(this.VeriSignSplit != searchshield.VERISIGN_SPLIT_TESTB))
{
var vhash = hash.substring(hash.indexOf(“_”)+1);
// create a temporary link node
var tmp_node = {
element: element.parentNode,
href: altClick_thru,
hash: vhash + “VU” + score,
search: this.searchHash,
score: score
};
var altAnchor = this.addImage(tmp_node, alt_image, false);
if (altAnchor && altAnchor.firstChild)
{
altAnchor.firstChild.setAttribute(“onmouseover”, “”);
altAnchor.href = altClick_thru;
}
}
}
if (updated != false)
{
this.resizeFrame(frameElem);
return true;
}
return false;
};
searchshield.SearchEngine.prototype.updateElementStyle = function (element, elementStyle)
{
if (elementStyle)
{ // a NULL attribte value will unset it
for(attr in elementStyle)
{
try {
if (element.style.setAttribute)
element.style.setAttribute(attr, elementStyle[attr]);
else
element.style[attr] = elementStyle[attr];
} catch(err){}
}
}
};
searchshield.SearchEngine.prototype.resizeFrame = function (frameElem)
{ // resize frame to prevent unwanted scrolling after inserting verdicts
// ignore inline and non-frame engines
if ((this.type == ‘inline’) || (!this.processFrames))
return;
// ensure all required elements are available
if ((frameElem == null) || (frameElem.style == null) || (frameElem.contentWindow == null))
return;
// if frame is scrolling vertically then resize
var frameHeight = parseInt(frameElem.style.height, 10);
if (!isNaN(frameHeight) && (frameHeight < frameElem.contentWindow.document.body.scrollHeight))
frameElem.style.height = frameElem.contentWindow.document.body.scrollHeight + 'px';
return;
};
searchshield.SearchEngine.prototype.getImgElement = function (element)
{ // return an xpl img element associated with a given element
if (element == null)
return null;
// go up the parent tree looking for a header or div
while ( (element.parentNode != null) &&
(element.tagName.charAt(0) != "H") &&
(element.tagName.charAt(0) != "D") &&
(element.tagName.charAt(0) != "T") )
{
element = element.parentNode;
}
// if all the way to the top, nothing
if ((element.tagName == "H