GIF89a{"117ZZ_116''+++///4&&+228oot++0%%)aafhhl]]bjjorrwVV[))-&&*--244:ddimmr55;QQU,,1((,005KKP..3**.339227!",{PHɄXBGU*"ht%D@wp @p!! !!!!!! CvGIKMOQSUWY[]_achjlnpr!tv!xz|~!щԐ!ݡBHKNQT WZ ]`cfjm(N;xÐ"zH4EL"`M:j)$R;v oT VK^r=|]Wo[0Gދ lH-cwNCy/6ATU{E8è+֟h $Ck6]^Ο+9 IӤ62"N8cF̸"cOl?&CwLka=IN۞=Zp|=G=mJ_/=?ۛ˿kl۵f`ԗoՏWCw",fw%Js_|kunk%/;}&կ'F'|ž5t||_Sx&O3k?(Ѭ4ЩZ"4hSprwX{?x9ŲSZŰsqQ i?~V8^h<.?miJxH};򒼣4|}闸xvBvEeWbvB1]vD9sKY@~: ޽|GyRUR񸓻ks꽍˿6w9Xsw2_casGٗǚ\xŗ9=%8ǟcY9kOG2ߩǟ{ek55y?dǏ:>W_x <~K?W?jqp]ilġGv,zul}hkKw[qػgExO{?Yq Y~V4w1U,us̱Wgy7[7ٰaIUS#GcǎUQv ~9@Nk:jF/M4ނTKQ*I,:h`&kF5_iҸNRwI?5n OF!M 噜uu6ol^tGp!ㅞz=1FC=t;=cXd]N40iM6?jc(hCڽx'K4Q(k Yk g` ^P(x0s?ɜ8q"H>@=j>\U4>s/)h (k4kT/t˖-Nj/hO4B(9'ꫯŋ#u|Ӈq9sl@k:Ƭ4fV>q?PC)CS,a(wXq!Ώ5H$+5_fƕ//QiBqX`6Lz Xeš( M׾1FXid]3k4YֳeufWkPPPPPbDPPPPP]gC@@@@XR-5V?.?Bǖ3NOƘL,gn5I<ۨ5*+kt߳u]<[8pήiMHXC'p#Е uf0Ϙ>z|y5:1 `uk^46K kWv[\OtOw74ˀGXC>zر gcO kPXp^_ ކZ _pɺmɂY3fb $ =/yNvpaTk9zc7z*ޕ{}uN)Gm6.5 Odݬd2gbBl怅l7Xg1>N! 0yYm'?!K?[ ײF2Mre9ni,.<-lB?k͡@!$om%Q?7o]Sd~vCrݬY\ `^U~@>;0QJl?PBb6b |ADLqO2yYN4K @x*XhD^/_Pm/\: ;"k4a\C9ni&3F `\·((i|et2 $ZY+(]zfъMX1$=M=[q-h n؄m:I:2L6s_0hg+U__yG 5 gjyp)VKs(((((U| @R<\: @}7߆(((((bO>(((((P_ͷ X,œϥ Wzm((((()VKs(((((U| @R<\: @}7߆(((((bO>(((((P_ͷ X,œϥ Wzm((((()VKs(((((U| @R<\: @}7߆(((((bO>(((((P_ͷ X,œϥ WAFB=`IENDB`OLt~k?mǨֽ{Szzg }?]'ũ2#hZJw{|(8`M3ZO[|Pkd2:{oTu$wL??'O?@ ڟk^нo=GAA=3> .{B-׿/jQOLt~zg k^нo=G ڟ}?]' ?׿/jQ{B-gI??'O?@:؅_ P,Xc`8,ֽ{Sz`<QĻ6/8 .{B-׿/jPuoi trovare altre immagini di bandiere da scaricare ai seguenti siti: You can find other flag images at these sites: Puedes encontrar otras imgenes de banderas en los siguientes sitios: http://www.specialgratis.it/fotoimmagini_bandiere.htm http://www.grafizz.com/ita/flags ;%ү-sf}>GcR}?]'js{yg4]V#q׌~5ϙT<ƯQE|Wa_]a_]ǎ |+#(C;Ե;K] PVwqfPp}5z.Zbq'>J.=_E؍WZO[u7 ?:"?^+?QE|7B?!^^{R'+Ы~(po*(0Yq-e= @@y;ZO[|X,|(#kqNsWOLt~N_/VqWsӮl3ۧ:|"ݢǮrޔ~H>O(0¿ kr+ V+GQ\yޥǪ]Zo#2׿/jUJpf-GOH^؁ |U??'O?_Elk?mǫtumHӬ.bX4$d 2+pzwAA=3#U#NÑj7QI,z]ٵ䍁.0ʖ/WOtn"mKt+W(.ur? cLt?15qjwrL] =N%'^]?$/&X[=ޜ"$}2nrʼn9قF(52u= 7X;|6s3Ԯ+F3$U] .m,u d [w6SF$#!W,,oXá2~F62_kHa|]5۹ns•g uz Ԣ񧉥ҥIIo223Mw׿/jWx |W^cד}oobA׮rs?zg / ڟk^нo=GAA=3> .$?^ZO[> .OLt~k?mǫq-7-ɊG1 .q/{<K0b|`sלEQEQEQEQEQEQEQEQEQEQEQE^^}[mgo+]A \jyHXj"cY%{PJ0#FpN*/~צ_&* 6wLLOS u)4yzZ!%aӴKrZ_My}5hŒ(]T "Er>+[k2]I9q͒P]C( 9$cGESww~_Ĩ |mۿ)}>W~.qmۿ|&cӮo7y91=)vwcv;_1~_;Z׿/jQ{B-ey+< jk^нo=G ڟxK?h%CW㵫{B-׿/jPW// _֯ ڟk^нo=@`-6c"qm&i탚 _Zܓ"6DwSI?^ ;_1~_;G//_k?mǨֽ{Sz2 wcv^ZO[%CWy+ֽ{Sz|E<;o : Xfx(_;_1~_;G//k%eQx}wMFXc8yd|'ܣsawfN3{g lNB,A@P10r{烜qW>(NJd,6HjxK?h%CW/&/Y5{Ԉ=P_// _֯ ڟk^нo=@ †O6˓2n^q$G|DGT2=W5/V~M4_kMvOUZR'+ ,x_~gQEGa\׍N].>me'.%xc8!(5d1gWg+ڱe&jko}vw׿/jR닓]*G;hH'v91~T>{8q-Q_~dxWArcqxWArcq㿂} z3r(<+5y|05qS <kn9D.l WםZz.J;a3(8>.=_E؍xK?k^{B-:"?^+?QE|7B?!^^{R'+Ы~(po*(9,'S$?h]}[O=%CW,KⲞl mn~vQ<{B-~¿.^l_I3/Rf1θsϦqW)_=O(0¿ kr+ V+GQ\yF/~.5*aq'ܱm#h큊xK?kR.t-BUYGǑA_k?mǫ/!#͖W//+k_I6=AVp!fG˰r 3Jֽ{Sz? A5lo/ˤHmQ4脌%?7/Cxq vw1_8 f7\:` uY|0n1|sgCdpV%<3s ^O;dHq,q2030> 4}H00<_ӑC ^1f_?pDItN;$[0.#(whS \buڴM>i@ >X/vwB*C[6ۜ Vc>qO̓^7  pE #9 LJn L 'cdāU ĠևI ! ~ t1t12<8FbS?OK9/)S] g}AzE. -Yrb12a0vo@a/+0` @5A[ 201/@,滼9_$V_2?A3#+`D 2`J:Wesfh(a^ ZIyIENDB` .OLt~u?mhɽSvfzg xK.t{MjR?0M;,@PH+ɽSvfiGwé\q#]ȩ+ [W$urwM_Z唟`7O]b+d<1b@O '!Hz_j͝Qyh6s$_YZ&gqm}ƚ'C9$)DBo˃kWᵅDŽ#-^|\) ^~x;%w1|w9#|Ǿ۬e;e-%s©]U?u.,8?ls1MkBX[o!{%9"dHHqy+FSVK" d{dh#F64+/cpQ_,Y6#U7B?!Uj֛!KO'UEWax/KYO2-4&PFe:\I'|! #kq ~lF4}L  .҈D9.˫DAɑ?Ou?miEű.yv, "8N̿*z=(?2 <+ V<+ V>bEW~z.Zbq'>JJKLTuur 7b'ܓ_eǫ3*?]'SoaݷW_ B(>@R'+Ыt ZdЅzy9_UQ^qFC/2Bemn0y  .cynt+NBFV3q70+"*=B??sȷh뜻g- vsyM}Җ/g0PQE9xWArcnV/v? xHs#u@+;Ԡvbt]>pU_zg kR..uB%i܄Dǁ$_u?mk/!#͖OLt~vGiclHBk/e,J$ctiPr|Wdé߻o3^yֶ-(PM\=Ěv>snvTFeR w%- p}5=P)Eo$F7$vNFЙN?#YWoxm:fR䵴$H|߻$`w)[V0Lr$[vjl7>-/Z $XacG* %Xfx>0$|Pi[%n-KC{a6&:A^OLt~]~%צ:Ծs]ZFg%P6ӵz7M :5VH; ?gIɽSvfu?mi> .OLt~u?mhɽSvfzg |?KĆ^L407,?p70q[ho[زTc4EQEQEQEQEQEQEQEQEQEQEQEQEQEQE+>&ڟښo1ysmǵ/+i5>mm>|}Ea=(|%BP%Ty>s(G?O1Gs(G?O1Gs(G?O1G<ᙹKJ4wxdLV6}D8F)jꑡb=>Kg9“5_ @QKKƫW f?h4(KKƫV΃YCat᧲<%_`<&3h4+z|:UCki,S3g dr$h t1_9+uS5QT-p3*pFiPNG  IHDR ogAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbdHbx`a._ i6i XYߧO _gxba`a9$3#3o...2:{IbI'v^п3>rd(?bdHac9+ÉزiZϣG  Hxt>?3B+#@Y Ø 988id@@((9h+++.jT  0* eE NAPm 7 X3fpa2 HFTR@ bA1j߿ڙ;`(˗/| d#4d`nbx LH|,e"DIENDB`qwc\gޮR 5 ? }"Ϯr޴~H>O(0¿ kr+ V+GQ\yF~n46cq''$nm'pKKƫR\؋N!;gu$n8$y''U~i1Wx_C~G-̯'_._5\m"ݭVêsKp_*-hn`T?ZMڞ_NJ5/v)FiSjHUX!A9u5Zw <,{[<0F+Jw j@guQsDx_Zv^)Gq>,km@h~DX/s(߆ڿ&[ -8VFzbV埉IKmu)?ǵ]Vj:Jݣ|%BP%Ty>s(G?O1GBw}Ѻ{cU%{]'$_SSMfoԒj0po4Jh- &x:+~\1: FooK#Ь$YnW_1c6ARv"-0êI08ojdEˣ4r39u(@BSoaݷ&O|%BP%Ty>s(b5oaݷ^-5k_WL62쪱e+pqjߓ/?//"M"+x[H[%h~/qM]Xȹ׵  ]~֛kAb)7|masqW_9Ǘ BW_6?qZdѷuTk2]E!^@YrP?=.Qqdʒ7#OR=fO@0bKclS/##o85·cɦ-m-NgFb;?uxrER_RYOL X:E}= xmCS+c+m*G5!vq\|KOxrk.5..ay64@ƇWcU1^><[;2e9ʩ_zS_6oaݷ&O|%BP%Ty>s(b54ccHҲ]> `Ȅ"P\~YjHp;`b_,Y6#U7B?!Uj֛!KO'UEWax[.${FՆ? [xtaBsUb88^G#>u~r70ҋc]VO&X@E9qd>s(ei?do'ce}72(<ӳ/Jg5} QE|Wa_]a_]ǎ |+#(C;Դ˹5K]wPZw!-qf"p=5^:<ٍĞdؒɹ2'Nk7}sb6Eu?miՑKKƫ^"?^+?QE|7B?!^^{R'+Ы~(po*(0Yo-ΗE{= BH|x;&O|nshNpvFmnvgw @W+"*-']ncob/_|v)ࡱ>   Root Entryُb1<Catalogp 0JFIF``C    C   ``" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?Ϗ-=06t}Bʵ2V|NL|KpC@L?L2klFqwm.mǥ@`A=E|S-k~Un 'rj"dS#q/?~H!t;{fV$d#Gjה⤽WLN%Wנɤ⮓G,m\^k?gv,[7o@3E9_8K{few۸\'tW`~f@0ucWC˱SaV[gAŗV"$0{a >ƧSNڏƯxr]tKQ$9pʑ#ڼLj4+6}li<m!c`:^MN{i'q9CH>fIҧM+6] 0#bQRWKw m?A-*ZME58`xbC>!Aj޹Ś0\M;L|pk?[_<7_.$o/&ቔDfWw'nEzm/ ϩb;>ojTZ[|؏jJn7ul[C ˽*5F䋩=ێ?S*\?nIӚWMi VG}߉:ΛMeƒA鶱%YNӼOR/OVP:޾_#iIP׳^6jڽVu^G_3 /Ss}S[/I񆉥j־'ЊVꅞ>f-:WxkZ>l_yفvs g7ou(tvhm4xeh%{s_{|'WM+h1;tO_3X<0UV:ҭ ƔTcE|l&7:YRg=e'gJ_~|s7h#%r;W<:Jzʾ[gKٹRpa|Yv|lm=jZ`Ny+_oY~ Uj٫wz9N[ѫ I^?4?nd Q>_Eo^gGaӿ:k_[/?ό$c>NmDSܩ1{g{z槦xS.혳 }  x ׿'gԵ/io/#ڡG r@J8PY*IFҨIPqmiⲨϔU^yJтvӚNENo?_xr}"xOo5% |k߈=>>ƫ.,|?RspmF̙uqzɡx~0x/@\zןjL_MRKnfy`n'OF]fcNsNNqI-#;6n{X5K,nrFMɶ:|bSw?wZig Hgco,w65o| &yKZttIMyo?ei*RE>쬻\2)MV{OkpIqYl.kx٢RVU)ӝ;ǚ)))txgZN\VN+ex.J/"mq|G?m>*떩Zb{L FxCA#*3>'g|ESucw4&6G$+r*+TϯX }fo(7ޏ7޼~=/?hkB1O]~7ޏ2QɟB(Z^𵭦qo^ZA<D-*X松_7Uߢ>Mig'^5ϟ,7[̥=r|w-H*o2#g> o_)q&q9_1sW۵-o̙#r>n2= k[~ i'QHoEKO܏7"2`8;{^%`" i\[5y.$ 1,6Y!cΪM粤j|jno=^B§"vr|THsxkf8UقfkϷDo*c5kMچk[Kl/t`e-&W'g}.-0?aqkɱM*R[9Փ_w;3bUjQri]&ht<H6-gi^/5Ro^<Fy\Z5jvM 4d`x9bi¶&W_ips)VOGf;/22oߞ^BǙGUZ7q<ʭnwO.Pض|{H+0**?z]'3L[MF59_NQ($a9+丿eߎȮ-U+~GGijCV&9m M(0D;<0Ü П}v~qL_+Im?g)+9=C : SF-37R4O?/O><Ino go gxKȟPt 7)0:3i>4xLmn/d2D+:hIPF 3ſ']3ſ']&:T mS9ʍ&hjП}v~П}v~xG{Z?2mƍo go g7 6L[>?w~wП}v~_>"{}ͤp@A$ATG#ِ@V8ƼeM%86$JIVƽj KT_U```=ib{A42CD7B6-E9B9-4D02-B7A6-288B71AD28BA}袊(((((((((((((+vZ[{yc!U2UHO\os,oXiBB #"+>&ڟښo1ysmǵ{NJ~ xo#/uXoH% ڊOE7@=eSӵ]rŭm~ r9| й O\j/Ϯ6bW)C>|O'_._5G/?/Kr3ͧϮ6b< @VB xB.?,ǵ{1]+\m?D~@I'ĺO/41ҳx]WN1ҳ3V62럕 k+4htmlArea License (based on BSD license) Copyright (c) 2002, interactivetools.com, inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3) Neither the name of interactivetools.com, inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >s(x$QbI;m9?Ϯ6bC q9访 k(coC.ZO OG|hBi Xˮ~Vbk4K/_'mm#T] )p%Ůh(.#7(QU\vG"77S'Xj,#S\?h]p[Gogǂ&$,A,?v1^rwh-# й O\j/Ϯ6bW)C>|O'_._5G/?/Kr3ͧϮ6b< @W3]9-5Y}17GF`I㷵M ?g?O1V3]^ -ŭm{~AX9#wuTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQESal]\w `z\uF[JG,;- K!;I\ ^SPdXʰX Ȯ1L8s\'i}8]}MKn("dw|hntBO-i>0L3xe%~@_[EyZ@Y}*a4^!HI *v\Ȥ'4IjX:&2C 2=GV0:q1 ='|"OϽt^7Z7~"an?=kb*բ^וŠ(Y^#׭3\pO AHŘ( zլ[MwZ1DRh$ ;6?_>4V!0(`7c# ʌnW.:GZY!Jd_UA=7TjO/@q VP -1, Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 }, BrowserFeatures: { XPath: !!document.evaluate, ElementExtensions: !!window.HTMLElement, SpecificElementExtensions: (document.createElement('div').__proto__ !== document.createElement('form').__proto__) }, ScriptFragment: ']*>([\u0001-\uFFFF]*?)', JSONFilter: /^\/\*-secure-\s*(.*)\s*\*\/\s*$/, emptyFunction: function() { }, K: function(x) { return x } } var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var Abstract = new Object(); Object.extend = function(destination, source) { for (var property in source) { destination[property] = source[property]; } return destination; } Object.extend(Object, { inspect: function(object) { try { if (object === undefined) return 'undefined'; if (object === null) return 'null'; return object.inspect ? object.inspect() : object.toString(); } catch (e) { if (e instanceof RangeError) return '...'; throw e; } }, toJSON: function(object) { var type = typeof object; switch(type) { case 'undefined': case 'function': case 'unknown': return; case 'boolean': return object.toString(); } if (object === null) return 'null'; if (object.toJSON) return object.toJSON(); if (object.ownerDocument === document) return; var results = []; for (var property in object) { var value = Object.toJSON(object[property]); if (value !== undefined) results.push(property.toJSON() + ': ' + value); } return '{' + results.join(', ') + '}'; }, keys: function(object) { var keys = []; for (var property in object) keys.push(property); return keys; }, values: function(object) { var values = []; for (var property in object) values.push(object[property]); return values; }, clone: function(object) { return Object.extend({}, object); } }); Function.prototype.bind = function() { var __method = this, args = $A(arguments), object = args.shift(); return function() { return __method.apply(object, args.concat($A(arguments))); } } Function.prototype.bindAsEventListener = function(object) { var __method = this, args = $A(arguments), object = args.shift(); return function(event) { return __method.apply(object, [event || window.event].concat(args)); } } Object.extend(Number.prototype, { toColorPart: function() { return this.toPaddedString(2, 16); }, succ: function() { return this + 1; }, times: function(iterator) { $R(0, this, true).each(iterator); return this; }, toPaddedString: function(length, radix) { var string = this.toString(radix || 10); return '0'.times(length - string.length) + string; }, toJSON: function() { return isFinite(this) ? this.toString() : 'null'; } }); Date.prototype.toJSON = function() { return '"' + this.getFullYear() + '-' + (this.getMonth() + 1).toPaddedString(2) + '-' + this.getDate().toPaddedString(2) + 'T' + this.getHours().toPaddedString(2) + ':' + this.getMinutes().toPaddedString(2) + ':' + this.getSeconds().toPaddedString(2) + '"'; }; var Try = { these: function() { var returnValue; for (var i = 0, length = arguments.length; i < length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); break; } catch (e) {} } return returnValue; } } /*--------------------------------------------------------------------------*/ var PeriodicalExecuter = Class.create(); PeriodicalExecuter.prototype = { initialize: function(callback, frequency) { this.callback = callback; this.frequency = frequency; this.currentlyExecuting = false; this.registerCallback(); }, registerCallback: function() { this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, stop: function() { if (!this.timer) return; clearInterval(this.timer); this.timer = null; }, onTimerEvent: function() { if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; this.callback(this); } finally { this.currentlyExecuting = false; } } } } Object.extend(String, { interpret: function(value) { return value == null ? '' : String(value); }, specialChar: { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\\': '\\\\' } }); Object.extend(String.prototype, { gsub: function(pattern, replacement) { var result = '', source = this, match; replacement = arguments.callee.prepareReplacement(replacement); while (source.length > 0) { if (match = source.match(pattern)) { result += source.slice(0, match.index); result += String.interpret(replacement(match)); source = source.slice(match.index + match[0].length); } else { result += source, source = ''; } } return result; }, sub: function(pattern, replacement, count) { replacement = this.gsub.prepareReplacement(replacement); count = count === undefined ? 1 : count; return this.gsub(pattern, function(match) { if (--count < 0) return match[0]; return replacement(match); }); }, scan: function(pattern, iterator) { this.gsub(pattern, iterator); return this; }, truncate: function(length, truncation) { length = length || 30; truncation = truncation === undefined ? '...' : truncation; return this.length > length ? this.slice(0, length - truncation.length) + truncation : this; }, strip: function() { return this.replace(/^\s+/, '').replace(/\s+$/, ''); }, stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); }, stripScripts: function() { return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); }, extractScripts: function() { var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); }, evalScripts: function() { return this.extractScripts().map(function(script) { return eval(script) }); }, escapeHTML: function() { var self = arguments.callee; self.text.data = this; return self.div.innerHTML; }, unescapeHTML: function() { var div = document.createElement('div'); div.innerHTML = this.stripTags(); return div.childNodes[0] ? (div.childNodes.length > 1 ? $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : div.childNodes[0].nodeValue) : ''; }, toQueryParams: function(separator) { var match = this.strip().match(/([^?#]*)(#.*)?$/); if (!match) return {}; return match[1].split(separator || '&').inject({}, function(hash, pair) { if ((pair = pair.split('='))[0]) { var key = decodeURIComponent(pair.shift()); var value = pair.length > 1 ? pair.join('=') : pair[0]; if (value != undefined) value = decodeURIComponent(value); if (key in hash) { if (hash[key].constructor != Array) hash[key] = [hash[key]]; hash[key].push(value); } else hash[key] = value; } return hash; }); }, toArray: function() { return this.split(''); }, succ: function() { return this.slice(0, this.length - 1) + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); }, times: function(count) { var result = ''; for (var i = 0; i < count; i++) result += this; return result; }, camelize: function() { var parts = this.split('-'), len = parts.length; if (len == 1) return parts[0]; var camelized = this.charAt(0) == '-' ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) : parts[0]; for (var i = 1; i < len; i++) camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); return camelized; }, capitalize: function() { return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); }, underscore: function() { return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); }, dasherize: function() { return this.gsub(/_/,'-'); }, inspect: function(useDoubleQuotes) { var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { var character = String.specialChar[match[0]]; return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); }); if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; return "'" + escapedString.replace(/'/g, '\\\'') + "'"; }, toJSON: function() { return this.inspect(true); }, unfilterJSON: function(filter) { return this.sub(filter || Prototype.JSONFilter, '#{1}'); }, evalJSON: function(sanitize) { var json = this.unfilterJSON(); try { if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json))) return eval('(' + json + ')'); } catch (e) { } throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); }, include: function(pattern) { return this.indexOf(pattern) > -1; }, startsWith: function(pattern) { return this.indexOf(pattern) === 0; }, endsWith: function(pattern) { var d = this.length - pattern.length; return d >= 0 && this.lastIndexOf(pattern) === d; }, empty: function() { return this == ''; }, blank: function() { return /^\s*$/.test(this); } }); if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { escapeHTML: function() { return this.replace(/&/g,'&').replace(//g,'>'); }, unescapeHTML: function() { return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); } }); String.prototype.gsub.prepareReplacement = function(replacement) { if (typeof replacement == 'function') return replacement; var template = new Template(replacement); return function(match) { return template.evaluate(match) }; } String.prototype.parseQuery = String.prototype.toQueryParams; Object.extend(String.prototype.escapeHTML, { div: document.createElement('div'), text: document.createTextNode('') }); with (String.prototype.escapeHTML) div.appendChild(text); var Template = Class.create(); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; Template.prototype = { initialize: function(template, pattern) { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { return this.template.gsub(this.pattern, function(match) { var before = match[1]; if (before == '\\') return match[2]; return before + String.interpret(object[match[3]]); }); } } var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead'); var Enumerable = { each: function(iterator) { var index = 0; try { this._each(function(value) { iterator(value, index++); }); } catch (e) { if (e != $break) throw e; } return this; }, eachSlice: function(number, iterator) { var index = -number, slices = [], array = this.toArray(); while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.map(iterator); }, all: function(iterator) { var result = true; this.each(function(value, index) { result = result && !!(iterator || Prototype.K)(value, index); if (!result) throw $break; }); return result; }, any: function(iterator) { var result = false; this.each(function(value, index) { if (result = !!(iterator || Prototype.K)(value, index)) throw $break; }); return result; }, collect: function(iterator) { var results = []; this.each(function(value, index) { results.push((iterator || Prototype.K)(value, index)); }); return results; }, detect: function(iterator) { var result; this.each(function(value, index) { if (iterator(value, index)) { result = value; throw $break; } }); return result; }, findAll: function(iterator) { var results = []; this.each(function(value, index) { if (iterator(value, index)) results.push(value); }); return results; }, grep: function(pattern, iterator) { var results = []; this.each(function(value, index) { var stringValue = value.toString(); if (stringValue.match(pattern)) results.push((iterator || Prototype.K)(value, index)); }) return results; }, include: function(object) { var found = false; this.each(function(value) { if (value == object) { found = true; throw $break; } }); return found; }, inGroupsOf: function(number, fillWith) { fillWith = fillWith === undefined ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); }, inject: function(memo, iterator) { this.each(function(value, index) { memo = iterator(memo, value, index); }); return memo; }, invoke: function(method) { var args = $A(arguments).slice(1); return this.map(function(value) { return value[method].apply(value, args); }); }, max: function(iterator) { var result; this.each(function(value, index) { value = (iterator || Prototype.K)(value, index); if (result == undefined || value >= result) result = value; }); return result; }, min: function(iterator) { var result; this.each(function(value, index) { value = (iterator || Prototype.K)(value, index); if (result == undefined || value < result) result = value; }); return result; }, partition: function(iterator) { var trues = [], falses = []; this.each(function(value, index) { ((iterator || Prototype.K)(value, index) ? trues : falses).push(value); }); return [trues, falses]; }, pluck: function(property) { var results = []; this.each(function(value, index) { results.push(value[property]); }); return results; }, reject: function(iterator) { var results = []; this.each(function(value, index) { if (!iterator(value, index)) results.push(value); }); return results; }, sortBy: function(iterator) { return this.map(function(value, index) { return {value: value, criteria: iterator(value, index)}; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck('value'); }, toArray: function() { return this.map(); }, zip: function() { var iterator = Prototype.K, args = $A(arguments); if (typeof args.last() == 'function') iterator = args.pop(); var collections = [this].concat(args).map($A); return this.map(function(value, index) { return iterator(collections.pluck(index)); }); }, size: function() { return this.toArray().length; }, inspect: function() { return '#'; } } Object.extend(Enumerable, { map: Enumerable.collect, find: Enumerable.detect, select: Enumerable.findAll, member: Enumerable.include, entries: Enumerable.toArray }); var $A = Array.from = function(iterable) { if (!iterable) return []; if (iterable.toArray) { return iterable.toArray(); } else { var results = []; for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]); return results; } } if (Prototype.Browser.WebKit) { $A = Array.from = function(iterable) { if (!iterable) return []; if (!(typeof iterable == 'function' && iterable == '[object NodeList]') && iterable.toArray) { return iterable.toArray(); } else { var results = []; for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]); return results; } } } Object.extend(Array.prototype, Enumerable); if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; Object.extend(Array.prototype, { _each: function(iterator) { for (var i = 0, length = this.length; i < length; i++) iterator(this[i]); }, clear: function() { this.length = 0; return this; }, first: function() { return this[0]; }, last: function() { return this[this.length - 1]; }, compact: function() { return this.select(function(value) { return value != null; }); }, flatten: function() { return this.inject([], function(array, value) { return array.concat(value && value.constructor == Array ? value.flatten() : [value]); }); }, without: function() { var values = $A(arguments); return this.select(function(value) { return !values.include(value); }); }, indexOf: function(object) { for (var i = 0, length = this.length; i < length; i++) if (this[i] == object) return i; return -1; }, reverse: function(inline) { return (inline !== false ? this : this.toArray())._reverse(); }, reduce: function() { return this.length > 1 ? this : this[0]; }, uniq: function(sorted) { return this.inject([], function(array, value, index) { if (0 == index || (sorted ? array.last() != value : !array.include(value))) array.push(value); return array; }); }, clone: function() { return [].concat(this); }, size: function() { return this.length; }, inspect: function() { return '[' + this.map(Object.inspect).join(', ') + ']'; }, toJSON: function() { var results = []; this.each(function(object) { var value = Object.toJSON(object); if (value !== undefined) results.push(value); }); return '[' + results.join(', ') + ']'; } }); Array.prototype.toArray = Array.prototype.clone; function $w(string) { string = string.strip(); return string ? string.split(/\s+/) : []; } if (Prototype.Browser.Opera){ Array.prototype.concat = function() { var array = []; for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); for (var i = 0, length = arguments.length; i < length; i++) { if (arguments[i].constructor == Array) { for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) array.push(arguments[i][j]); } else { array.push(arguments[i]); } } return array; } } var Hash = function(object) { if (object instanceof Hash) this.merge(object); else Object.extend(this, object || {}); }; Object.extend(Hash, { toQueryString: function(obj) { var parts = []; parts.add = arguments.callee.addPair; this.prototype._each.call(obj, function(pair) { if (!pair.key) return; var value = pair.value; if (value && typeof value == 'object') { if (value.constructor == Array) value.each(function(value) { parts.add(pair.key, value); }); return; } parts.add(pair.key, value); }); return parts.join('&'); }, toJSON: function(object) { var results = []; this.prototype._each.call(object, function(pair) { var value = Object.toJSON(pair.value); if (value !== undefined) results.push(pair.key.toJSON() + ': ' + value); }); return '{' + results.join(', ') + '}'; } }); Hash.toQueryString.addPair = function(key, value, prefix) { key = encodeURIComponent(key); if (value === undefined) this.push(key); else this.push(key + '=' + (value == null ? '' : encodeURIComponent(value))); } Object.extend(Hash.prototype, Enumerable); Object.extend(Hash.prototype, { _each: function(iterator) { for (var key in this) { var value = this[key]; if (value && value == Hash.prototype[key]) continue; var pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } }, keys: function() { return this.pluck('key'); }, values: function() { return this.pluck('value'); }, merge: function(hash) { return $H(hash).inject(this, function(mergedHash, pair) { mergedHash[pair.key] = pair.value; return mergedHash; }); }, remove: function() { var result; for(var i = 0, length = arguments.length; i < length; i++) { var value = this[arguments[i]]; if (value !== undefined){ if (result === undefined) result = value; else { if (result.constructor != Array) result = [result]; result.push(value) } } delete this[arguments[i]]; } return result; }, toQueryString: function() { return Hash.toQueryString(this); }, inspect: function() { return '#'; }, toJSON: function() { return Hash.toJSON(this); } }); function $H(object) { if (object instanceof Hash) return object; return new Hash(object); }; // Safari iterates over shadowed properties if (function() { var i = 0, Test = function(value) { this.key = value }; Test.prototype.key = 'foo'; for (var property in new Test('bar')) i++; return i > 1; }()) Hash.prototype._each = function(iterator) { var cache = []; for (var key in this) { var value = this[key]; if ((value && value == Hash.prototype[key]) || cache.include(key)) continue; cache.push(key); var pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } }; ObjectRange = Class.create(); Object.extend(ObjectRange.prototype, Enumerable); Object.extend(ObjectRange.prototype, { initialize: function(start, end, exclusive) { this.start = start; this.end = end; this.exclusive = exclusive; }, _each: function(iterator) { var value = this.start; while (this.include(value)) { iterator(value); value = value.succ(); } }, include: function(value) { if (value < this.start) return false; if (this.exclusive) return value < this.end; return value <= this.end; } }); var $R = function(start, end, exclusive) { return new ObjectRange(start, end, exclusive); } var Ajax = { getTransport: function() { return Try.these( function() {return new XMLHttpRequest()}, function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Microsoft.XMLHTTP')} ) || false; }, activeRequestCount: 0 } Ajax.Responders = { responders: [], _each: function(iterator) { this.responders._each(iterator); }, register: function(responder) { if (!this.include(responder)) this.responders.push(responder); }, unregister: function(responder) { this.responders = this.responders.without(responder); }, dispatch: function(callback, request, transport, json) { this.each(function(responder) { if (typeof responder[callback] == 'function') { try { responder[callback].apply(responder, [request, transport, json]); } catch (e) {} } }); } }; Object.extend(Ajax.Responders, Enumerable); Ajax.Responders.register({ onCreate: function() { Ajax.activeRequestCount++; }, onComplete: function() { Ajax.activeRequestCount--; } }); Ajax.Base = function() {}; Ajax.Base.prototype = { setOptions: function(options) { this.options = { method: 'post', asynchronous: true, contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', parameters: '' } Object.extend(this.options, options || {}); this.options.method = this.options.method.toLowerCase(); if (typeof this.options.parameters == 'string') this.options.parameters = this.options.parameters.toQueryParams(); } } Ajax.Request = Class.create(); Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; Ajax.Request.prototype = Object.extend(new Ajax.Base(), { _complete: false, initialize: function(url, options) { this.transport = Ajax.getTransport(); this.setOptions(options); this.request(url); }, request: function(url) { this.url = url; this.method = this.options.method; var params = Object.clone(this.options.parameters); if (!['get', 'post'].include(this.method)) { // simulate other verbs over post params['_method'] = this.method; this.method = 'post'; } this.parameters = params; if (params = Hash.toQueryString(params)) { // when GET, append parameters to URL if (this.method == 'get') this.url += (this.url.include('?') ? '&' : '?') + params; else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='; } try { if (this.options.onCreate) this.options.onCreate(this.transport); Ajax.Responders.dispatch('onCreate', this, this.transport); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); if (this.options.asynchronous) setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); this.body = this.method == 'post' ? (this.options.postBody || params) : null; this.transport.send(this.body); /* Force Firefox to handle ready state 4 for synchronous requests */ if (!this.options.asynchronous && this.transport.overrideMimeType) this.onStateChange(); } catch (e) { this.dispatchException(e); } }, onStateChange: function() { var readyState = this.transport.readyState; if (readyState > 1 && !((readyState == 4) && this._complete)) this.respondToReadyState(this.transport.readyState); }, setRequestHeaders: function() { var headers = { 'X-Requested-With': 'XMLHttpRequest', 'X-Prototype-Version': Prototype.Version, 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' }; if (this.method == 'post') { headers['Content-type'] = this.options.contentType + (this.options.encoding ? '; charset=' + this.options.encoding : ''); /* Force "Connection: close" for older Mozilla browsers to work * around a bug where XMLHttpRequest sends an incorrect * Content-length header. See Mozilla Bugzilla #246651. */ if (this.transport.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) headers['Connection'] = 'close'; } // user-defined headers if (typeof this.options.requestHeaders == 'object') { var extras = this.options.requestHeaders; if (typeof extras.push == 'function') for (var i = 0, length = extras.length; i < length; i += 2) headers[extras[i]] = extras[i+1]; else $H(extras).each(function(pair) { headers[pair.key] = pair.value }); } for (var name in headers) this.transport.setRequestHeader(name, headers[name]); }, success: function() { return !this.transport.status || (this.transport.status >= 200 && this.transport.status < 300); }, respondToReadyState: function(readyState) { var state = Ajax.Request.Events[readyState]; var transport = this.transport, json = this.evalJSON(); if (state == 'Complete') { try { this._complete = true; (this.options['on' + this.transport.status] || this.options['on' + (this.success() ? 'Success' : 'Failure')] || Prototype.emptyFunction)(transport, json); } catch (e) { this.dispatchException(e); } var contentType = this.getHeader('Content-type'); if (contentType && contentType.strip(). match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) this.evalResponse(); } try { (this.options['on' + state] || Prototype.emptyFunction)(transport, json); Ajax.Responders.dispatch('on' + state, this, transport, json); } catch (e) { this.dispatchException(e); } if (state == 'Complete') { // avoid memory leak in MSIE: clean up this.transport.onreadystatechange = Prototype.emptyFunction; } }, getHeader: function(name) { try { return this.transport.getResponseHeader(name); } catch (e) { return null } }, evalJSON: function() { try { var json = this.getHeader('X-JSON'); return json ? json.evalJSON() : null; } catch (e) { return null } }, evalResponse: function() { try { return eval((this.transport.responseText || '').unfilterJSON()); } catch (e) { this.dispatchException(e); } }, dispatchException: function(exception) { (this.options.onException || Prototype.emptyFunction)(this, exception); Ajax.Responders.dispatch('onException', this, exception); } }); Ajax.Updater = Class.create(); Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { initialize: function(container, url, options) { this.container = { success: (container.success || container), failure: (container.failure || (container.success ? null : container)) } this.transport = Ajax.getTransport(); this.setOptions(options); var onComplete = this.options.onComplete || Prototype.emptyFunction; this.options.onComplete = (function(transport, param) { this.updateContent(); onComplete(transport, param); }).bind(this); this.request(url); }, updateContent: function() { var receiver = this.container[this.success() ? 'success' : 'failure']; var response = this.transport.responseText; if (!this.options.evalScripts) response = response.stripScripts(); if (receiver = $(receiver)) { if (this.options.insertion) new this.options.insertion(receiver, response); else receiver.update(response); } if (this.success()) { if (this.onComplete) setTimeout(this.onComplete.bind(this), 10); } } }); Ajax.PeriodicalUpdater = Class.create(); Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { initialize: function(container, url, options) { this.setOptions(options); this.onComplet