stapler-stapler-parent-1.231/0000775000175000017500000000000012414640747015474 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/0000775000175000017500000000000012414640747016270 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/0000775000175000017500000000000012414640747017057 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/0000775000175000017500000000000012414640747020003 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/java/0000775000175000017500000000000012414640747020724 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/java/org/0000775000175000017500000000000012414640747021513 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/java/org/kohsuke/0000775000175000017500000000000012414640747023164 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/java/org/kohsuke/stapler/0000775000175000017500000000000012414640747024636 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/java/org/kohsuke/stapler/jsp/0000775000175000017500000000000012414640747025432 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/java/org/kohsuke/stapler/jsp/JSPFacet.java0000664000175000017500000001172412414640747027701 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jsp; import org.kohsuke.stapler.Facet; import org.kohsuke.stapler.MetaClass; import org.kohsuke.stapler.Dispatcher; import org.kohsuke.stapler.RequestImpl; import org.kohsuke.stapler.ResponseImpl; import org.kohsuke.stapler.Stapler; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.lang.Klass; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletContext; import java.util.List; import java.util.logging.Level; import java.io.IOException; /** * {@link Facet} that adds JSP file support. * * @author Kohsuke Kawaguchi */ @MetaInfServices public class JSPFacet extends Facet { public void buildViewDispatchers(MetaClass owner, List dispatchers) { dispatchers.add(new Dispatcher() { public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException { String next = req.tokens.peek(); if(next==null) return false; // only match the end of the URL if (req.tokens.countRemainingTokens()>1) return false; // and avoid serving both "foo" and "foo/" as relative URL semantics are drastically different if (req.getRequestURI().endsWith("/")) return false; Stapler stapler = req.getStapler(); // check static resources RequestDispatcher disp = createRequestDispatcher(req,node.getClass(),node,next); if(disp==null) { // check JSP views disp = createRequestDispatcher(req,node.getClass(),node,next+".jsp"); if(disp==null) return false; } req.tokens.next(); if(traceable()) trace(req,rsp,"Invoking "+next+".jsp"+" on "+node+" for "+req.tokens); stapler.forward(disp,req,rsp); return true; } public String toString() { return "TOKEN.jsp for url=/TOKEN/..."; } }); } public RequestDispatcher createRequestDispatcher(RequestImpl request, Klass type, Object it, String viewName) throws IOException { ServletContext context = request.stapler.getServletContext(); // JSP support is deprecated, and this doesn't work with non-Java objects for( Class c = type.toJavaClass(); c!=Object.class; c=c.getSuperclass() ) { String name = "/WEB-INF/side-files/"+c.getName().replace('.','/').replace('$','/')+'/'+viewName; if(context.getResource(name)!=null) { // Tomcat returns a RequestDispatcher even if the JSP file doesn't exist. // so check if the resource exists first. RequestDispatcher disp = context.getRequestDispatcher(name); if(disp!=null) { return new RequestDispatcherWrapper(disp,it); } } } return null; } public boolean handleIndexRequest(RequestImpl req, ResponseImpl rsp, Object node, MetaClass nodeMetaClass) throws IOException, ServletException { Stapler stapler = req.stapler; // TODO: find the list of welcome pages for this class by reading web.xml RequestDispatcher indexJsp = createRequestDispatcher(req,node.getClass(),node,"index.jsp"); if(indexJsp!=null) { if(LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Invoking index.jsp on "+node); stapler.forward(indexJsp,req,rsp); return true; } return false; } } stapler-stapler-parent-1.231/jsp/src/main/java/org/kohsuke/stapler/jsp/RequestDispatcherWrapper.java0000664000175000017500000000561012414640747033277 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jsp; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.IOException; /** * {@link RequestDispatcher} that sets "it" before the invocation. * * @author Kohsuke Kawaguchi */ final class RequestDispatcherWrapper implements RequestDispatcher { private final RequestDispatcher core; private final Object it; public RequestDispatcherWrapper(RequestDispatcher core, Object it) { this.core = core; this.it = it; } public void forward(ServletRequest req, ServletResponse rsp) throws ServletException, IOException { req.setAttribute("it",it); req.setAttribute("staplerRequest",req); req.setAttribute("staplerResponse",rsp); core.forward(req,rsp); } public void include(ServletRequest req, ServletResponse rsp) throws ServletException, IOException { Object oldIt = push(req, "it", it); Object oldRq = push(req, "staplerRequest", req); Object oldRs = push(req, "staplerResponse",rsp); try { core.include(req,rsp); } finally { req.setAttribute("it",oldIt); req.setAttribute("staplerRequest",oldRq); req.setAttribute("staplerResponse",oldRs); } } private Object push(ServletRequest req, String paramName, Object value) { Object old = req.getAttribute(paramName); req.setAttribute(paramName,value); return old; } } stapler-stapler-parent-1.231/jsp/src/main/java/org/kohsuke/stapler/tags/0000775000175000017500000000000012414640747025574 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/java/org/kohsuke/stapler/tags/Include.java0000664000175000017500000001246512414640747030032 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.tags; import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.SimpleTagSupport; import java.io.IOException; import java.io.PrintWriter; /** * Includes a side JSP file for the "it" object. * *

* This tag looks for a side JSP file of the given name * from the inheritance hierarchy of the it object, * and includes the contents of it, just like <jsp:include>. * *

* For example, if the "it" object is an instance of the Foo class, * which looks like the following: * *

 * class Foo extends Bar { ... }
 * class Bar extends Zot { ... }
 * 
* *

* And if you write: *


 * <st:include page="abc.jsp"/>
 * 
* then, it looks for the following files in this order, * and includes the first one found. *
    *
  1. a side-file of the Foo class named abc.jsp (/WEB-INF/side-files/Foo/abc.jsp) *
  2. a side-file of the Bar class named abc.jsp (/WEB-INF/side-files/Bar/abc.jsp) *
  3. a side-file of the Zot class named abc.jsp (/WEB-INF/side-files/Zot/abc.jsp) *
* * @author Kohsuke Kawaguchi */ public class Include extends SimpleTagSupport { private Object it; private String page; /** * Specifies the name of the JSP to be included. */ public void setPage(String page) { this.page = page; } /** * Specifies the object for which JSP will be included. */ public void setIt(Object it) { this.it = it; } private Object getPageObject( String name ) { return getJspContext().getAttribute(name,PageContext.PAGE_SCOPE); } public void doTag() throws JspException, IOException { Object it = getJspContext().getAttribute("it",PageContext.REQUEST_SCOPE); final Object oldIt = it; if(this.it!=null) it = this.it; ServletConfig cfg = (ServletConfig) getPageObject(PageContext.CONFIG); ServletContext sc = cfg.getServletContext(); for( Class c = it.getClass(); c!=Object.class; c=c.getSuperclass() ) { String name = "/WEB-INF/side-files/"+c.getName().replace('.','/')+'/'+page; if(sc.getResource(name)!=null) { // Tomcat returns a RequestDispatcher even if the JSP file doesn't exist. // so check if the resource exists first. RequestDispatcher disp = sc.getRequestDispatcher(name); if(disp!=null) { getJspContext().setAttribute("it",it,PageContext.REQUEST_SCOPE); try { HttpServletRequest request = (HttpServletRequest) getPageObject(PageContext.REQUEST); disp.include( request, new Wrapper( (HttpServletResponse)getPageObject(PageContext.RESPONSE), new PrintWriter(getJspContext().getOut()) ) ); } catch (ServletException e) { throw new JspException(e); } finally { getJspContext().setAttribute("it",oldIt,PageContext.REQUEST_SCOPE); } return; } } } throw new JspException("Unable to find '"+page+"' for "+it.getClass()); } } class Wrapper extends HttpServletResponseWrapper { private final PrintWriter pw; public Wrapper(HttpServletResponse httpServletResponse, PrintWriter w) { super(httpServletResponse); this.pw = w; } public PrintWriter getWriter() throws IOException { return pw; } }stapler-stapler-parent-1.231/jsp/src/main/resources/0000775000175000017500000000000012414640747022015 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/resources/META-INF/0000775000175000017500000000000012414640747023155 5ustar ebourgebourgstapler-stapler-parent-1.231/jsp/src/main/resources/META-INF/taglib.tld0000664000175000017500000000154512414640747025131 0ustar ebourgebourg 1.0 1.1 stapler http://stapler.dev.java.net/ The stapler tag library contains tags that takes advantage of the stapler request dispatching mechanism. include org.kohsuke.stapler.tags.Include empty page yes yes it no yes stapler-stapler-parent-1.231/jsp/pom.xml0000664000175000017500000000204412414640747017605 0ustar ebourgebourg 4.0.0 org.kohsuke.stapler stapler-parent 1.231 stapler-jsp Stapler JSP module JSP binding for Stapler ${project.groupId} stapler ${project.version} javax.servlet jsp-api 2.0 provided org.kohsuke.metainf-services metainf-services true stapler-stapler-parent-1.231/.gitignore0000664000175000017500000000007712414640747017470 0ustar ebourgebourg.idea/ *.ipr *.iml *.iws target .project .settings/ .classpathstapler-stapler-parent-1.231/src/0000775000175000017500000000000012414640747016263 5ustar ebourgebourgstapler-stapler-parent-1.231/src/site/0000775000175000017500000000000012414640747017227 5ustar ebourgebourgstapler-stapler-parent-1.231/src/site/site.xml0000664000175000017500000000112512414640747020714 0ustar ebourgebourg org.kohsuke maven-skin 1.0 ${reports} stapler-stapler-parent-1.231/src/site/markdown/0000775000175000017500000000000012414640747021051 5ustar ebourgebourgstapler-stapler-parent-1.231/src/site/markdown/index.md0000664000175000017500000000065012414640747022503 0ustar ebourgebourg * [What is Stapler?](what-is.html) * [Download](http://repo.jenkins-ci.org/public/org/kohsuke/stapler/) * [Getting Started](getting-started.html) * Developer Reference * [URL binding reference](reference.html) * [HTTP compression](compression.html) * [Internationalization support](i18n.html) * [Javadoc](apidocs/) * [Stapler jelly tag library reference and XML Schema](jelly-taglib-ref.html) stapler-stapler-parent-1.231/src/site/resources/0000775000175000017500000000000012414640747021241 5ustar ebourgebourgstapler-stapler-parent-1.231/src/site/resources/what-is.html0000664000175000017500000001060312414640747023503 0ustar ebourgebourg What is Stapler?

Stapler is a library that "staples" your application objects to URLs, making it easier to write web applications. The core idea of Stapler is to automatically assign URLs for your objects, creating an intuitive URL hierarchy.

Normally, most of your JSP and servlet goes like this; first, you use parameters and extra path info to locate the object to work with, then use some more parameters and such to perform some operations against it (or perhaps render HTML). Stapler takes care of this first portion by dispatching requests to that object you'll be working with.

Suppose you are building a web application like the system of java.net, where you got projects, mailing lists, documents and files section, and etc. The following figure shows how Stapler works.

The left half shows your code. OOP lets you model those concepts straight-forwadly into classes that refer to each other. Through reflection, Stapler assigns URLs to your application objects. The root of your application object gets the root URL /. The object you can access with root.getProject("stapler") would be assigned to the URL /project/stapler. In this way, your object model directly turns into the URL hierarchy, as partially shown in purple arrows.

JSPs and servlets

Most of the times JSPs are used to show an object in your application. Stapler allows you to associate JSPs to your application classes, as shown in green circles in the above figure. Stapler weaves those JSPs into the URL hierarchy, and when they get requested, Stapler sets up the environment such that they can access the corresponding application object very easily, by the "it" variable (like ${it.name}).

Similarly, often you want to run some Java code when a certain URL is requested, as shown in red circles in the above figure. For example, when /project/stapler/delete is requested, you'd like to delete the project and redirect the user to /. With Stapler, this is as easy as defining a method on your application objects. Stapler invokes the method on the right object.

Problems That Stapler Solves

Servlet (and technologies like JSP/JSF that builds on top of it) can only bind request URLs into your static resources, JSPs, and/or servlets in a very limited way. You can even tell that from the java.net system. For example, the URL to view the archive of a mailing list is /servlets/SummarizeList?listName=announce, the URL to search the archive if /servlets/SearchList?listName=announce, and the URL to manage it is /servlets/MailingListEdit?list=announce.

This has some problems.

Relative URLs are useless

Ordinary servlet/JSP prevents you from using the URL hierarchy to organize your application. In the java.net system, if you want to generate a link from the archive to the search page, you have to put the whole URL including all the parameters. You'll be writing something like /servlets/SearchList?list=${listName}. As your application gets more complicated, the number of parameters will increase, making your application harder and harder to maintain.

Stapler allows you to use URLs like list/announce/summarize, list/announce/search, and list/announce/edit. Thus a link from the summary page to the search is simply search.

A lot of boiler-plate code

Most of the times, the first thing your JSPs and servlets need to do is to locate the object that you'll be working with. This is tedious. Even worse, it needs to be repeated in many places.

Stapler takes care of this for you. When your JSP is invoked, you can access the target object by the variable "it". Or when your action method (the equivalent of the servlet) is invoked, it is invoked on the target object. This cuts down a lot of boring boiler-plate code in your application.

Recursive Structure

Servlets can't handle recursive directory structure very well. In the above figure, I have recursive Folder class that has two JSPs each. The only way to make this work in servlet is to assign unique IDs to each folder and define those JSPs at the top-level. The actual URLs will be very different from the natural tree structure.

Stapler maps this very naturally to URLs. stapler-stapler-parent-1.231/src/site/resources/taglib.xsd0000664000175000017500000002562312414640747023233 0ustar ebourgebourg Optional Jelly support, to write views in Jelly. Sets HTTP status code.

This is generally useful for programatically creating the error page.

Kohsuke Kawaguchi Sends HTTP redirect. Kohsuke Kawaguchi Sets the target URL to redirect to. Executes the body in the parent scope.This is useful for creating a 'local' scope. Kohsuke Kawaguchi Tag that outputs the specified value but with escaping,so that you can escape a portion even if the org.apache.commons.jelly.XMLOutputis not escaping. Kohsuke Kawaguchi Tag that only evaluates its body once during the entire request processing. Kohsuke Kawaguchi Writes out '&nbsp;'. Kohsuke Kawaguchi Kohsuke Kawaguchi The name of the role against which the user is checked. Tag that includes views of the object. Kohsuke Kawaguchi Specifies the name of the JSP to be included. Specifies the object for which JSP will be included.Defaults to the "it" object in the current context. When loading the script, use the classloader from this objectto locate the script. Otherwise defaults to "it" object. When loading script, load from this class.By default this is "from.getClass()". This takesprecedence over the org.kohsuke.stapler.jelly.IncludeTag.setFrom(Object)method. If true, not finding the page is not an error. Adds an HTTP header to the response. Kohsuke Kawaguchi Documentation tag.

At the runtime, this is no-op.

Kohsuke Kawaguchi
Writes out DOCTYPE declaration. Kohsuke Kawaguchi Copies a stream as text. Kohsuke Kawaguchi Set the HTTP Content-Type header of the page. Kohsuke Kawaguchi The content-type value, such as "text/html". Outer-most wrapper tag to indicate that the gzip compression is desirablefor this output. Kohsuke Kawaguchi Writes out links to adjunct CSS and JavaScript, if not done so already. Kohsuke Kawaguchi Comma-separated adjunct names. stapler-stapler-parent-1.231/src/site/resources/stapler.png0000664000175000017500000020365512414640747023434 0ustar ebourgebourgPNG  IHDRsRGBgAMA a cHRMz&u0`:pQ<IDATx^ ]Wy}tܓ[(E`g^0r1-8B162Nda؊-;klö#Vy`53\fD iݫn2R ]S5T墧?g?<ǧ>kZ|{{\Wpf7WÙ3w\W@\Wpf?g}ve]WpTV/+ cU!~-r\W%[֓u\W` ˃+ "+ \7p\a)?Һ8pgz\WhM֤]WC|e<+ i+0{g^WpC+/ǒgjM z&QZE3# {Kw^Kj&!o]'EK -y@@σsl{iӦ |qۺ`ʕV<B}9RB+-n4U.})g s)ҿ<әlM3dKHO; 7ܐ[ Jd :ShDޞ{c/ ^1OâHxёxr-*yxi^\͚,Gw(5SasEFg6@6 7h/j=" 'm!‡8fwb'gC,*i k03A +7 I,ʇ]hVJ^J]nco^]!؉m #{εkNLEY)Dh.jDD=#*f&Y  =٣Q`*aU ^N3܋QMRSYB{X{ֻ$E"ǃ\GLOW^rEJ7Mu]bkuTϾO˾hZnœl 5ѽ%2ś̕h^Y)0xPHB>7r\jE3W`2ɜ1B(D"E$_߳G*JM"'NB MLBO]*;vC%(UrV&ޮdsD,pz<#f~hUȝY] U556rf^YwZ3FWں!6Z>4:%9֊7ؙk u! |/x妣;] ar_WIӺMTN]{-;}sl 0hfH9kZ,\uY*y*=Rɹn={qTyKQ[j˽J laLp\ n;)\pddgZ0"$ Ä&:>WҨwp1;(]~rnb":7D~uY >/yRLu/ҡjv Ew6lP%Mz(gsjڧF>슡y ]A|29 a[䊘-.@@ +אY¦Lh8 7zdCW1Oxhmr7"؇˞ }as%2u&"G NUZ3kDPA|OC'V0-A| ēCeaբkb("'B|=?*i! sǴOG|8;βBmhp 9 ]\Z&GoQKnwMn"a9 A"1ȷ2""+B|;fS>< )oUp}YpaԂ."E_aVi#Y"O*{1P#$NS % ;FJk&Ӑ›^N2 *򦳮\a}t$t!Q44\?6 >4_kOViE%]WzdD/yER=̅xRԈ(hSgf #ޑ%h>N}}t;ZxqKYAEm(Bd`4[fiR.Hͽ0壯j%^cUQh #[ITR6t:>z{L՚aMRH=täJ,aG-{ӈDc*~05& 0Z^D⧽E,5ٽԱ|>L:K37IYF.\i빌LC|vh>J(@&Ly9 3ʙ5"Ga*Rkzk"$4/8lNf3#/?|G2T9-ćkU A٩,*G&F$rك4p6 Zd?Z⧽sK[m h޴lxϙL\S#>Nyc=+0c85w a"g\EvE(9ErݻKY4-W6A|c,A-Ui&&-dSZ\WTYgVd}4ggRkja}}Kl!~G.hb6-u >לf'6 W!XӜHEuD=răDnzAӜd5!\hׅk& ˝޶wln=%`ZK|OS#Wө^iܛWm8*|TW,$aL|5$`'0QC(ogL\VEp1Ȟ;)\ ̊2e'\h;o-T0;Miօ/3O gLrkzDWw"+q-J'LI *snӢKQ"M*_䌪P2iIBى$v;m}(@ŗVqZ'w(*R5#%kbZǪPE=m~-_O!;6/]%wE+F.O{/幓nvٶbPAW>!V@|`Pd]rWB0%%W)6#l 2V+YkZK|tCK R‡LvɾS6T( dEMg:; [LF*),U.$\q:w3Y-"[QkFB֩>-ӠE)z!HEK8W> D+JslۨCm "D0U!opMBFw˩,{rnfk@ZO>o#*0|tXѭ4 J*T.Z$$lP#}G/m_ >;[1*M.%[>!-e USѓ,v{M.DWD&dGQs[GE bkUɚU5RDr4j>viFxt.zDo'wE슋Ey{m@Dn}b&DMև}JȮUg0/}rRϾ ͹lK<#3@N|wsVԈ?%|qyn#& {Ty[# s^M;7|BKDX%lZ# "ArըH4sut,/O};C|0f(`?I݋&w%iJryV4<+P@/ ^;SՁYdnϢ7VP)14j;R}_~rOd} Ç'\T {eִ}}";:Z"-B9"%#'CCXkN4+ %k+(G#BԮwl|.Tdm!^CϏdʦY5EQ]_#a;^MW몟؁+JT:x8w rYZ2 \_sG "sk:QRRM]hUn(#dஒj1zZGFog}Ss@/ >1OZB|E[gU#~Ym/0Bq*By0W ~-l4 GidM9X¡C|[ TQ zI^%q(_Gf:7(R)򞟸(j?וp_V^pN뢜g)A.WY<75$*(Gs@h>eR Uٷh#WK0&mj30Wg1C|K LnDŽiQ!~6{+ 8{p\WJ+ + p}x \Wp\Wp\pJ. + + ^ٷ&T}?¶Zf37WEr\WpZR!%a=YW_ |1=tXpTw}x=61KU[|_ ~p\*ۦUQW=4o{R;Uo.C|sZzJ+ ̅s^(HHtҭq pCϖC /r tWuEjB9?+ sC\5Wv 7XƧ8~O5݊GIPHJFe"6 60!*up~@z~cO|ujod \+?bVOJc:o0 ÁSQvT[_&M-T,C|E<+ p t֙Q>##nw!VЋ.>M+$ 8 "܅t^WpCɋ88LN?'^O`E/9hqx5]WhJtW` &v6dͯ| W!}OG%x⃷ +  +߰ *8`|9-;Y+^VP}FkT k=C^lWp\poIXOv< ` 'WYvzx*j6m_q{r>Uo p[s}X]8q),#d[D|u~2}L O?+ 'Dc8>>?^=C;θL`B<+@"ULxmivh:1ĭnZhdRxD+0fܺ#VbF1|L]0xc jC|-V|Fۋ䮀+0W 8Us,ASe L˜ #Wc qywH{WpCp*$˿Of:%ćZ7W )~)%9Cf^~Wcj͑%\J^)0+db7j,LY%O }:WpC,[~ *7A[ EѣKKK?ܶ㶵f۶o0#K/4u_{LR'/+ R!~ -,,eN:uر={ܵ.0ee/[n-n=??{f:3^y+I߽{75C: ATkʕ̈Wm|!pFC<{G?[6 kqͻoӏ<}(^Xƫ$LlM0Xߋ80YMO#+ D 8ďK8Ϥq|;>Kǖ@4EC1̟8qb&x ⭾`ַg/UC<+ #7*;w){>3 O|[w (vw'JP`|o";:MuQ\W`4 8ď)iELWb8w 5bU[7o _v#2#xӡن p+. Fvs,[[͓uU ri>Lm6kOp\*ۦ`S5MЋ.jj2k#_s FgI܄pF RhO.ٞw;\Yv\W+R|PUW[]ws 3Ob vr`$:/3("> pZ/>ENSM$+\y64EcIiJ [15 ppnm]e-%(,be/O`z04gͱA<'P;DIGcK. 6~P.ʎHDť^׆tfEcCrW(_ z0WpC@NJF+`nEh}@9ϟ~ ?Kxk׭mC:O3Az8y`+ Q!Z\f6Z_F!ˋƾ .4Xe/xYQGCPY7smHi&(_EM4kWvșg5СCU*a\WC|} gC|my>P#MVxXܜ`f򜑣|tl5!C|XDRϺ`:߯IV ;&u*6fRt\W(W!~ =!VmmﹽfBx9E͈_3 ͜oR $NqvjlT=xƫڐLP!h`:[$C|E<+ T6܏!VvuCdpܼյdqkC˸OA<=8w"6l!C|hQt\^)߫H,C|pXC}媕8{wk8 6ohX/=?|y 8'߸h+ H5VaQ[jÇ]v"w,rNWo}' A +Оi]iwwY_rbSZ0rpO[xI\W P4SNp>97U7yÉ'SvC|Z )ߞݥߪȻfݚqp<+>ty@pC+x\W=Ӷ5$O<"3e9mn}sx 8voIK'V!qI=AWj8' 7M48u>q7 F_qk^#9xN'/ZsX<I 8;!qI=AWj8' 7eSN]pvo"Cr߱ 8'1O߄gGH᪭W|V]ؠϭoųlN;7.wMy晩J;N%v\ 8;k8zβ8? ;2i*oflO'1p u /ЙJQ GTW\sMU*+PS"C|5,=zj51!LR 3x1s猌Wn5C|n%@ 7ܰiӦi?bp(_GuIK 5+]ݫ>yFg~jO5>xLLpO=KMX4]v4 qOͣ@(C|gqС׬x ^컇2r铝}P Y]FuC{\Q!~ mM+~po\Feƭ߳=幸}P w܉%>iy,WHS!>M~r=nq?,vJ@Y3W ߻woZtX+C|nv{`޹g ^}p/m%; ^'!>Y:  8'ֻ(6U†=WjIK'V+Y>mJx#z+PCLj!n߹-ZJ2K뜷SNToi!T-Jx#z+?>*ă %8^<%^|EJдK Xx'W~?Uܔ9HPϣC|N EEuo=AWpyhM/L"46r}Td"ka7Dtw<$%E^4y!z( 8kw^ t7q:\́u; ODΓa,0BϯQbY6ۼ(6NȭuxzK>`w8ħ\W MOӭ_x\b  ~S$>BpNNDXx'WxzcNMyJHN&*o߾7A<.ce/3I[OyQ8΅x˙Ԕ3O ǜ!M+Fn-n}]WW87SA|򛽰7' % 8ď{ "c9 M;{ 3kVh/yU]= M)`GAhZS/ͯzb.ۯC憭btTlV 5 Q\FH0kηgcFQƛq*o$wFdD\Wu |TBG*)˰ 2rbOQaT8c(L!ćar!>-R]8>k+ 6w{ FAئf9hId]W' 8!jjlZ6Tokh P:MQ,[pFU rR*9GkhdŅ6l==5+[%[3 ojća4U+/+A@?^g"7.y=n/+ 4C|"< u\#m<32-k;m"dy K"h$%hQ=ʗJJ?Q>kwe{v:WnN:7.7~zn}nʦWt\W W1t Z=mںضmW]{ΊE ƗXKPZNyx[,pO<ʱc%}^ORuj"+ 4cK-YX:Tajv6_fq/~֣{w|#`|u݆H3^.-T8kyЍPK k[֓u\pK|b,)ΤǶwɚK~5 <|/j- syDX/ܟ{n\X}?xnyz߅ >|3<Dk)C|Kz+Ь9;}D=1n>[6k8_i<-pdV!/'np'@d8ǔOsl|2 {w^b)%E{䇟n\pO(- ɺ@ 87lRs@ǬY_l9 as &fD! _L&vEW`WF +_䧢 GlCO~<Dk)C|Kz+Ь97%pN 9(r}ě<`xH0*Yro^zOۖOP!>A8ķ$' *߬I!U>iluЩ rџo#3̃2+ Fn&0͢YMosoä%[Pt\po\$ߞ謳꼟ݹi*Ǧ.kZ=և&EFf3Lu%k3i);ħF,6T4]Wqt :ķ'7Li&K .UIEK^\Yf |MB !%a=YWhVfMj-Ƕn\Wro4iZSah*Y'M#&jM~dN(7bIoZ=-&( ZKQ[֓u\fpoV٤߆WUr4Y,nyد`h0pv(&)ڑaax-L"q<B+-g?c¶߯ɢ,7~ p+ TW!V F:thKCi۷ OShͯ/aw|?[l 7O}Uoqe<6poCUOpW!qIgC|of^RCUlC4ga߯=W:oKvvTʚ]?۴!%a=YWhVfMjme|7F ǖZsې$N=__(, 6ȡd|流a0*j{#łP{}? *pȑSfۖ-W 89 (\iuiAz`W!҄0M{ԆPGR__+|l`w &֗IGm֟7x+Q^7'6:,ܩ(C|#0•Fz5Kւ) T.DmPUX:,lQak?}/ݟpOu>qû77Ս4Rc64TqeW~Q8ķъ⍿2-ij$>꛻SIZZ%k`*!a0PI;feءN-"($ښp_]^\zP HkYRpoI.uR*y9WQah!^.\p޴|:ZE!9;SQ:vc`uى}D׉O T> LķP4;|bv%@)- ^jKWˡm\@i&6r2g#'mſ+ YHha⦭`lU]N.LrȡaQN_@ xb?C|!o-R*9yg_FvqL`ůJ:*5 ar,C| ߆߱s(8ķHgqd,^rڵ<c֋Οj`Ҽ'Jb9~뵿.wvwhՇlTO]Sj_r#=2:ķP4;|bv%@饗^Z"bxK-D1.o wO/wܙ%R벵'l ,0f-_0a-K糁hw6T8MCD!Fz׽e5[#UН^^eW_}~w>|Wn.2njCm1cns4FuoCՎtX9Ohn^xaek1@k\ᕬY)c7Mc9Llܞ6^G.{=dx/ 5%[bg^,ӝG?so?;ķji:w,'J44~5_k[gy:<#gxAy24 #r-kݯ|o/rρݔ;wgn=Ė%/]hˋF:ķji:w,'J44֛Y1; C|&Pk.y֍^8's9e(mI*)O4_uewC`bkZ,ΒE1388*P4;|bv%@i铏xͫv]Kz pO /fS;~wz|ۏpͫWShx J8'=9]!>O?Qp[9ERZ8v+z7|7&bz_kw}%h?r+~9l]ͺ:k t DA |њl 7֞wo;ķji:w,'J4mÇov\&GK]Fwpu+]uT:R`o2/gmAmtz6T8MCD!WbŊO}S;nea_m mĹ%o~x=}oClN$(0뎳 k΋7Ё'Fq(Q8")~ا+~(?VH˖-38yr+~ 8nsǯ@v*CzӦu/N [pq{ʥ8xӻY毟r9w|x?g7uD9R N]ƅ4xFwcy p. 772DnEkUVafggܣ·J_Wx+rgYer+z6REi][!8wÛko3{~ STg~=3/Ձ瞫XH~qqC):E6<^*\]ٔ7q2GFiSYX ^/!gW*`xBx92gϽuf_zy 8(RGʖW^"SS>ɶnݪ0|C<8phN٬:رcGXF#%pelb Vd!7mdx?;wXq8O7pC]vqKWR'Rd)3Qd+M0:y.s p> aγs;CatRI8=/ " ZŰګ2 +]@C|8ħqsb97xoj) 7;lx֬YwSZEu׮] &jR1}Cv{m9_ؓ[HAmApcv:#OW06@7s`$%E+Aۯ#QT$~C YcW:d) xGU\RxK-<[GwwFS-a8 ?Ս7d`` GŽ`1oi;dN>+4ɓ'W(BG/_CAC4Rqc 9g pL\ MʜiBѳye7:.%N;2d}"H 7WH22eX].Js5Z8's":ħqsb9׿y S(X ;..]A 6*6sdY?x9 (yȁa M)} 35_ p͓ (I/82dW+}·Z_Lo!Kh\Wm"R{g@dG2kg07>iCEr:œK+O+C|[VN0cLĴyH%0%O PT/ dsRFZ}R]yXjOo*~=ǿZi+e޽#~&7L`v8]):oN 7|F_÷g?/>c>Mi/qdtOD4nU,)r}g0t"QC&(0yڱ<|[L^D7 ~V_I#ضoa}nդ@Aԛ]py %p( SɝFHm@^Ej^71x.w D4x(q~{Qhbkpތ!?,\^xZap,;th۬<J-VE&6)))X?5̞+VXB[M>(_cM3lЄRSʔП6 CId ۾}P!qSIyf?V ȷJ+1Ӌ>ЅGSK%W8T>*:kZ].E ȑF]a\nHM0&(";57''SᄎZѹ?ӸW<0Քy\哪$B' AWSʹrcC#V=U~3)OIHVKA+UZ݂3< 58PDр`#-*~LT1 3S2QG}yU ٫0u}GlZה t'|9ĕ+]wz|%KLFdmJFQ\lT,dvm yxrI{iq?}3 x2Q sk\Ő7E }1_Qh$`i mPt>]TZ4JQ zy!;&U|f0rOUJx0 ,n3CНXr̙w(^ڋ.g9pCHN_FOw"1s!^7 eHcO7Fm'ͽ^gwѭ6\L%O~!&d@}[lMr:N'yN ƝgGFů5}-me-Qå̈́#liɩ*GIe* V3x8[?Ξd}Έy%#sp6Ȁx>tslos}l`'l;|0^NLg pT _W.g<,ImLwoze kC>+×Gφ$UWP*oVrLXyms>5ն0ChXq9I]Er`-k«P"VbhkFs @.sA1 SWgb\ _3I6ouCZT("qbov͙j]?a*Oz1T_OcJirK"]Y术^xn#)9 vFnxzm<kī.5c B-&anrE@$-7Z.M`ksl {3W rhkPj\hn+h1J<5[W>66>0c??Dm#5fuМD!",? 90{ \bNjF(;})XpνwR.uLQ.-Gg}}!Fn- R[`EJM )Xkg=dHD!!M~%J-y樴]XRf' Mc-)SesXc~Z'!ْ(Z3l[~2\ZJUV-_4uM 4* g5IUrUXJ-0*Ͽ-kc!i>6ڦ0i?!^6 a/fAΣ{w˪OEIVeb}) ð_IYO9bnYg`,߶m ϗ]OD!НR.qQ.ʕ;ň ,vW.an-n $ :v|ZD &V9}FIc%-ڳ 0+Y$gXVU@֡ RC%TdE7=9S}ۦi=z<}O[SGQ?za'{HƊb-FܹBֲVXB䮰xJS-p!^sn'`1dcF2wR>#C7h0@'K|HKXx]*{̝r*1: a''$Y A]gdυx: ,@W"`<R4\h: э*ӄ^u0jQ& f+ !֖1wSC]=ppwIXg4]7"vdž_!A;3=wӷ1`BTעSgpira= 幎%^%vzuD(Ѕ\.w6vdO%k /lx;&)_2?գ+? ."EE:xKC+\d3*G=>`<[xꑂzV䌞a:r8͗08ۯ[ю0ޜyfXT^!>D\0!_l{ owU*|fQƬ!x;meF m5[22HW+9q/\tdhw5VTG?kVtw5޵-l+IE+WUD{%w mp$*ٱk-;Yrƍ\(_v5!^ ^qr7 9Z-#Q=se k6X`XN1T$K}xP(NtWd$T6CCLcőDSؓi_Ú;y=y `Ed Vvhb߿uI~&7g!(0cYv x7a^ԑzKPYiokvXK\AS"Y[ #Y63i,A[D`n֒]Wg;>f8ʧ5l PuK?6|?|Ѿoyׇ1$'^!^n0/M3*Lb[;wdA|GN?16oHsf՘Q)?!󹭿3d}ϳ'O~UW L6ŷ /z>2| '!mښA„YΈ`>1t_k33C|w/&F߂>XشtZ;j6}߆XviN*uckdݝf&lNz Gu*[lGAp ᴊ'+/y^*in=ؼeuk{βsx'<ɱ3V~skK,5 s[!YIjw;{;v,݆]*;{tiz!.4!s|_vx/ܔ b-\꼵n[V׾G?'DxcްuuIևoq ͧx%cZt)!wlOqo L!~&li0)؅^ȲMraƹ/ ؼӨ&?dtJ0Bc5K\rƙg\rÏ<~F >d7o|sXm6 sՑxFnvYg25k*$>p?FM!YIjCNQ~LN>P!SD?T;eL*4pdM7GY 2< kuұ Oz}w3TxY`؀y~K12>3L)k!~@4V45n>f!~&ls f[VC5k֌kZЧ>YZb9PTLdrJ]9ѶE3l< y2(-!~pO t89NX!~VuogC|{ϸޥmWb _f`fPYBuu[;{٠'h^')Fq0_}@V8zsJ!~2n0Z9YrsI\`w:Wk >8Ҍ\Y#r-> ,\@?qK_ɓ *ylS;nr<3ūX8Ur NS_]yTLRsxC0cy晾FSm1xs]n_'NleB-37.[|̩eq;ŰMa¡?tX=Zeg(pgf_5`xd+_ga{K8{bpQӋ_t~> rK`ݷ2ZԈrī ܩpk܎!~@⢢:73I!G'6oӓφ zRBeԢ\ҏ㖏M_wqwoSwuk_ڏG`fݚ?ȕ7Wԭ`K.(;>tFŤϲ|j{}k{Go(M M\*mC*n:W%4"bů];~_ЈYe/++jXGY'A;nVlo+6^'Z<2m6d(=@_~ȮU [C) f۪/ڠSH{MʭxеY90O7ar!Jʍ57[S{^%e\kcuA0pIaqFTMPT}YP+\N5(* cR!~ Ƽ . UH}b3u/,pO454ɳwI*?FOf䈃SCھ}"O r7M M$L׫qUxU[|3,^Wk'xra X$PMoXryEȮzy12a|i=gZxJ5*[Xӏ^R+ C|vf2'G캆c$YIފ7R%Ȅ]]YDճǟ c~k42zE\WmA عsgD9G`҉Ώ 7* %%Vk]7ᄍ:fG@4< ms,s%NHAn_Qr#9g9 w!/rx(XO!>YD Q5jXYZoh@ 8ğ׈!8ȟ Lbn30 StQ c@d+%.X58٠1CnãI"H13{n&D8(S7UEZ$BݰkBQ@8yј5(SНƼwBP't ZFsT3vMYi[?AdFKh 埾叿<="+В)21Y6%MMVn?rRfBIFstutr~,h; ħA,&c0͋X⋖%_CAZa uV4~:D7 >Ta0niC5ddEx[ʆZFΗXZBwk򫥬XZ|'<{:|chhur╚}0'~!>YD!ģM{Bq5#T^W s]C|Z?(Tru(R) \'~{z,lf?1rf"Υ~}!>MqĚ-ģ! P~τ]տ^ WhP3x~ }ppޤщ&qsp Gm7}hKNXѲՓ&Gdpa\mWҌ|B?)SZ$t7wl 0˽YkB|vlDp"x&KKY vtOmf1ޮk M)093ˇpF[JEc)k!"IhdOX+$iAx9L%GvyuR!~*z8œ#T z.[wԩ֬[+uB@|4C|(~B_8~ߚ|L1!S6NQJXXXXZZЕEm\%A,ql.K7oټvZ":!.4u媕'NhD cM4k ;C_@ 9Bv8sR!]T߬3o-G ÇbvJex#[xݝL^&d#ۨB!*Sj_5˷k"D)wE",1[3mq+.E|=/~8^\Z-ʃae*V.] Bv,͔Ikַ&ԺbdŦ X!/)s¶t NrE6x< )n׊x|E}sF(wUĊKfSA\,k ZbhPr[vrVTS-RlF.eB޲p?L oBIYښ3w{1 W,_|ٻ ӆo}37qWmJ 2Q+Ţַ\i  UPGٮSIOǩYaA%)IY4 +Tgy۶o[n-Lvc5f5P=|˺:413U <-WzT?Gw(ʻP?}bkS~:Cx՚\읻X''9d"vj `M Z?b}dk\KH(i{S]-EKg⅋VIOE3]}5|kV*PKnؓCu >R2!~ai&|1G?GN7C|;7.#7`xb oD =l >,|H򻰋!xޣOzu > ݻw[{骕kVm|_>'>/ݣ`|w߼i淯[}Y^OHs`0}M/5Y+~wkn{`S`O-lSGO̪W!qI!> #kzUb"h楂97Ryi?f9m7̝p|D,'\M=%k380UiTp_^q:Pjuas0K:0`uO ]F´o8|+ zTQ~Y*f;wg=99_SK: 4F:c}k }Ba7Z#}NGUMɎ93EDUXh y#?۹)turϊں4JV MX.WrǖºπaƷvvi!],a{ԩZV])TLU ?RO <\g2kLM.C3!qtp Y4,_=T뾓+fu.!ޤ-< dExK'd'^^wͲwSO=b؀y~y6Ķ  [?WXWW^Kz OlMh Y}[lvɯ-VC|wj `MlbܙT(ARHUǢ6$m~놷xͫ?6P>⫴1]SR%VtttO%KPgp{׼TUk*tSMeOTZ}]ϯ׾\nH#xPF xkH\luMC|-X'B;\c׿~d]Z#2uӽk%\k;OՊ…zUr 9VKT- _"?cMdgNOOǶZ*|?CC|^A ֯g߆>??bŊβ##*KFy3x?t=]V8={t?-n?zիVZe7nɮ&]ri/fn4i,i71}_{*7+'ּ]|~%af񶖨-_-EwWK&$maa;9r _BgّRT $Gar.~ x6Y e.sԕ GiIaFg&3'oC7(i,t{#^U㻇xmuv/COl-j[rwwf^OrL*Yyg9zF 8O!pd5ݍ8 |JXTp.GL$M$) vɈ7_жٺ-tr'a i F{rwoVI!JSqJ.܈?& 6'ҟ`v5Tr 7ym5 6ܹ$&3IR휪MR.7:OU6> 5칻{k};}Æ|GFHn$ -i{?jJ,֩ڈmO_բC|DF& d4ƈ8cLp9 H~%G̖! V#K|Dϒ%1 !1MO9f(^:i*7mljߕ)'~ҙ TdKȄIZC2kPT6)ΐVʹXC[ZTZg V!fuo\ROp L)D7$pwR$?#Bwqr߽{,`HZ27\X$vq댢.CC|8!|-ñīt2qP4E}TeM[oY%'*_X !;Md68d) +h$@C.9b.Se>1wYhuG~J!+>6^n,#sz5KMx3ϋeeB9wMvTP"a˟!^mg}F룾F.tU 6MVC|!qI= 8ėA~ ' jQ]ȼbʹrJusN憱qQݦjE>~y" CDO0s10;s0!))?ЮX=Ϥ]z :F*i6UG"`I*}ķ$iݦ%Q͞J!GJbԪ)fnJI[%GlFM^<}cr|`@9]vzIKZ4L~%: (J8$[!U9uaJOuk/Mh@|B;=TuPfm jĿQ 6d7-IHۀxUF{kLU;7.i$ ׼VvoRʣ'߭#6^Jj=?Q70mSx*3ڳ뻃6$мUDE܍r+W0EUq;ٓ"%uU -8'QM9G7ͦflLu5JE3z%Su;w rY$߭#^F3]D[:: }bkQs6qv?hto!s:!Vuk#C|vfC.9b5?»}Cٺq'K!!>tmW!3gϦD|#fKخDJ{NNVnaH$ EMZHUi#wr?1NsF;mmf!>tǯy(]z9O+߶]|JE҅wCsRH^dm%V6NI\TdEID4ȵtruzT" p,n#Dh0Ӫ+QiT[h[nk+V) rmB|Ɛbt>.?^a.ERtRr$߭#βy3:y5oxɓ'Sp/S{rwh6g Ĕ72V b쾿Mt5G-#V.ZWavV25mjf!>T aձGNn`6C|z&UrԳ^pKC=kк5 'N#[K;xNYAĔY~HU.DHR[eؚ(P"4L̲~-RwtkKCldaUby6 ~ ~~UzƙD@Iǎ;묳zR m¼o',V _ k<gyfOv^e˖aUSUk!#j5ДSy5#xfnh!k- rQk ͜CFA/6C|^,ݻq$n(S% 3x淟|#SŻ 4fŹvyǜ;6B!4[FNr[ۜmf!UG^SWpn.vYÉJD Mha~sWx >efZD#ukMHso}׮]#vWW%=STU+[ji=?t o]vOnMy'K m@H$^aV"a-RI̝Fi"~(xij7U6:MQ%Bf{fTDqp? pV5;^\3xS9[f?aЃ ͟xo޴׬<uԍ7qhp \EW$+[oDF$5ʹ3O([SQRt徉:;4 mgrl 5FVgX27[^ n]wy)mA_D>VIʨ?߸uMZatXu;ǴɕfskcZ+m(^[}ѮsGQs.,)|72`t_ռBY @}[T:WC|O. ^7go\):Wj`nJăL8@\bZV~Gwv˺.;a{:'9V`RGRزW9Ȝ݋zHMo=M#=?eߧo/l{(xokﻴnG6SJ3GbSiƺs߽}qKLz3A"Y9s%-g̘P ѵq@0:$ I=N,:87ވD\L]ŭwkz!WQ0r' =J ъnOzq GK$-j^WU}tJ{!o|K(ɛx XUCD }q<|}FxݡvfO;G)8wyS9ʺ BiN_uBǏe '??}<\NlApg3e!.7-׎< M(2M\1>"c` wrvOcӖ~xF)tmoDOpÆxa#xz߰}b6C|FV[LVA:: >j]Z.m:KKA9,\iM-Yq1a=뻧[!qͻ67'8QC<wfgn:{!~& $_jTqK >X%b͝Jta&!7S 4G^DS8wOc߸w@[aӹl j35y)i>|-`4uo|#:_}b(C|7f3Ȫ͆jVWԧ>e~zm& t;Ft0Vˡ#MYG"T[b _wȚv2./pzވukijb^ C<Z,pm2N…ϯ`^M[ xǍCKO!>[AsĚ8wBL/ߛVGSk儈D4=x< 4 "ZTqHG1/[L \S5 _10[q1] S$fr.XDɓ'yhU4X֎D=nD*ltiG QE/&˖0=/4AQ %߸K:t3۷o%x|aQ_|?M%?SJOb SiV̢`F`i9=N׍i\|&ZKCc/3l޽-m ̟V< ޸ Cʜ4C;ig8i?IB|`Pmt`gT-)PN;C-,w~>Z8)ؒ(xfBC6SM=^:j^W}nJTzV1j)HXķW-K:S 3em@nQb+r{^%EX/CL8CHYe֟ܢx3[Qv}x)s}Xlư̗qb1ySu>Ozsley!߸K:!>*t[{Rc7FRaDaq!Ze}E< EEe .i3Fʔv^H%%>Emo@p7w=8U:sw-M!qUݝqI aL$nzΡXy m1,Ebz %VfT.Ȗy I&LXSexo3'Jk2G֝0--P31<]ja. ?PfQEWZ_OY{-mt$UuK|. x噸bs^cOrGմNM$-nXL+:ۛl*gyn:QMGF.v{w!_j}2{xW xHRAÙdĵ9J9j#uN/,nw~š@Z`(W|+)`N}mIf&[tU,vs㾑n6^(pd j&KTהa@0axST]B| L_cIq lrԪ/Fu.|MrZ<ӴvwOӭ464?n6]{+H@ ԩS$[fi~濦|^W wY@Q`nL3{^ʘcԘ;z{6{Y2ݖo$bNC<[&/ȶeѶM˵xHŵvf[X 7dHQH{䓈R0RvRaMR"4HZ&k3LujrAg,O|A.OK GsW{+ YS5f^\bҎ.@` &4­bw4-»SB6X =+` pܣ>6x +8\v^*p^5əzQ*5xZ!~V{#V4cO޺gF{E4AѼi Yd蹮O zd êɣf/MM1 U*x_u>.Qx#)fvZV{0qH{w^M-r'4J ޲VvJ$M&G6Y? ֑Y#Kl1X8P[:'X/eZC\g0y\NB<> `6ظq^ZDyԔ3Pv9\ݿ[^^]l`#McOZ ey"^U M"˴oHpྑQQ|bkt#8]TVzv &WxFKH>PJ LCx C.J /W 3/|9.GSd/y=;}Z;=K0XRmy-l2{Zr!DiU2[EXMMv pwqJ-1uz-aF@6gzdb2`?I^sds!`DxҙVYƌgKLlaIp9]^|ʾyYu啹5:y[s=OQf͚iӔO|^r^3L{-V P/cgp}iJ5'O~Ӛ7a;޹ _ryEȮzy12n[lar'ҵp2qZU,&l߾]bn `!sn >Byu/X%GvmR ^qG٢g zs@<2K ů<̓'9 㓚 빔`\&zrq5lilIi$45w@1RyA_{3FQ,;(Ƽ&(&1l*/eW g,a&bׯ7|- a޶mv絡%'/ʗ|/e Vnh$p-Rsf 4Rja"_nNcK: zi9a<2۝@0 C+1 [s,u ߇||@NƟ:ГI`AU~ PR>yOc:'k`sah=JPm74`Hi,M9ݦI'-^%2j4՟ao 96waB& |e?,5Ozj}<{B^6W` |rʹwPYH[Gճ0rQdN=߈nNc8oxi qM?r6sk]qxa,\N/197f'0F$c)kH2$*zwqiUlcFM_~o3sXPh?V_a mڂxsk֬a5ɤC͚cN;]J騯Y#H6j?,XӄYiSR66d̠Al1 UnY '.)w_4V_9LM[O{46Hm70Pqi3 {7|h{WׄFZNKǖ.YsI&3sסmԔMxq}y衇.+Еg}6ZD|f͡"o]\j 8ѽ۴JZ:@fB=;:m|Wő]Em@߿?). Pt> ]xNOIo*.ּa=x\uXe/$k۶mq+ЉM7)2<5j:cĻMOհycy$Ɩm3!BwQ7c_|qO|Jm} }q?^h5eZkϴnjg_nD34UFF۷f9/:9Qonz{&Z:[`#\ San/ U=n7mB3<078p3IR 9ď8ϜgX\uē&k䖌Bp%pgV]wF o竬,YE#P%JVZfaqiqyڰu9ٶ}۴{/TiOdjHHo#3dg?Knڀei|VGnuq ԩ CBe|]řO@<L⬃.U^? 5@0|3Q:%gĵmZ^DqÒ)Fl┡bQʙ!)%CIzp5ps0OOԫuKS`wyͼ83x/p/6,T C1󞍚E$M0cbw}3l~&: ]Y8O+oP2̳voRjR%-Ҽ*l5xs .׭e6Vևw=_zOߵj}s!>! th*v_9OxI[x@Iq_Sʟ:($&;:e˜9lFĥGDD,Dkb%-0ϧ:g3 l)s^ePC^V12ebdvpOؘ;ϜgX1]ˉuq/N .lHt;.?wP>WxWǯ8?Oi' ۣu@E`Dx(@,+\m#ZI'bUe)*#A6*u,gl!tnB:*T!/bxP sTC\CltXOoZis!ůOke>>~ZX]>ZʂuɅs=W' [b)(#礵lNu?~^nD;LLp\;#G'wRVo1@ge͊h96`b曪ә!>rXZ!wO-bMxQjk>3: [sI[D^Ƽ_fX[46!0όF0Ie0yCǘ5KV HMo~1-Ӊ:xp vYq2hrgl # PͫW.?',)CakۊU:ܮz/ވ- Ӣ}^b*>33kóLv y1]!^'@%ϯr({x,o֝]R!lyғMlͺ^3nO"ByUr !^c }Fn-򉗞+{9ćUsGQ6o$70~c-䵑_.ۯ}G{xPRIt) U&4s Nϳ%(PB 7 Ygum8]03K9b5O b1:OD'F /\U#Q0o} a}?tQW#G9wAqyB ˫^-e}T0 5m47%*CԞZS%^jPpl]2*՚UrdG\X:*+RU`/jA;O)@؈\waw'fwlm_+qe B^}s3b#!Cpo L0{g}I mb2 JSpY^M?w`)?|ϹlȝF˯iMo{X,.W熟C|g ۀɟzdF>!?ExF fw,ti{O:py߮18|ݨ<ѰsH ehP~W]u-!(z Z_!~OhCܿ:2ć"wyE4dwl}=;E^gK][߲|%?@x<MA|ȖatRƋ97&2XrhU6w ZӋ hbk%^ !^zHTRC7u5xwMߘܐgs)_'{ 6׬b&s  .]knpҜ/'_\YH<0,-ן8q"=Zk @ {p=HN1̪uldw^ٿCAscǻ=>߷% T,|,_& ֶzSh k׊剂MeI,G:V/v,aIeg~^C2|g+(_ujvOXʹ4 4-R^S >!l_Ruĩ^{L`8oe)u<]M%+vz*$r1”IҊ6╂yغ&xZ-͵-HBgkӯe}-Wq?[7py:3m:6Bvΐ)B7E̞H3xFT8˹ k8|FE)la0>iV.OE.b{$ UFpVD*L xh)EԮI|ˆQĎ¯~D%Q,! jACÿ*4{H)) \WM1 q6Cr躓͎H?\âvSO= [6d*v9X2,@vjep 2kl厝/!F[73Q,%85[Tr!K< glAw~2 'LKݵ|h1O%g:MSрә9۶۶og=ɠ*?̓|Ȅ/:v~G|zA^Й`"h^>j?#KQsK)4BkG!Tj SI\Y4ж>G/V,Ki| ܭ:aI|Qq8=@J*6'E*ʦp٪c@!iEK!7;)L}ElcoRP}Y6 E]Y~xO 10S/&o[;eg_R_y+7sOf M -\\;}׷mz!IRd%k'#S↉J$."7۷m= B<zJHȠцcXڬ_LFQX² Wi0A6OUsSaYCMvFYm-Lnv!D.?3ބrxE9C|ٺ"9lr˕FuY>@Bgs'8S:9Xx ss 'WD8|q3!/>EH&Cc8l漑pj%b3s=;c; !>!fef2R1Z }N|CM"[)HAnr$ BshkϺd-KR3wvJ4uo9wF=!Wg'_\\ܶ:ě4tb1Ϯc=۟ o*lv>E_!B&5C|rcCHcka -.-&@ĉ .ȺMlf79#'&ņuF2 YWyj)8! xཹ' d!>jěEXleO}Nbxty=dΊ?AšcǎyoU* ODy}k1󒏩U[n}}utΈ9ď[yģÇ׮_%왊_%aH=t cUwo޲n?) US#CzC|ٺ"9ď[9xdt݉`zRO;m*U]#U6}]?_xH)͑!~!3baF#Va~ ҅wiQ~ <~ $CUE?.CH#Va~ >[׿u4sl}OV .7 $7Έ9ď[ ~aa9xo{ٳg#/m~߂PBY<+߀Voƫ~z!\~R|K~ww ں~uF]兓 wu3Y /YrYg<1r+a-ݛWxS곟Ly6m3y@2T~@ 4-7bzҁ 0H6BKw l-#ٸu%k.IrOP5&u9zZV!e2yھ}eBjt0`<@B^l˚8@vZ5x3u>Ʉ:zpX9C_s^}9MV&ޱc08۷ɅK$+i/o6:3n8g95t7j͆wg?wZ{w\Nꪫ?>m/N3ut>PW\̱c/'|b+Bw]?[<ݍ3<I© O=q|S}?¶}_mߥu;0: K{䁥w{Woø~]^C!~(-嬣C|:L1㡞`oI:/0s7oߌm(o[ܶfgrmѳN3}[4WJ|:$LVݿtJ *H>l=+ Ayh&_3:MhZ*7y* Q̓Ԁ5y>qf&F7^^ݝ7 }ֳq̭ElzG;0g-⑁<ϯ=j^r'.@_>@FVH!>(,<1W`.pfJ:},GK K'> kSRfJN 1)_`7V=O{7uvѝM5ELyb09̻>\kcg_ؓBwF 3{Qz曑G>/]atAėɚ G=v<)cƘQVu6%Ԃq܇nWm 7s?u}uVA{/!EF1 @EN82$^}QE|XuC{!mٽ sC6V!~}*# ^`P#9}C0uE FsI-ɍ."8*(`7O}[#T6{*⧒ktU`(M4%,Mg%M0ŭI&zz#ojyB:s>f+xA(?fBT!# ..yJÌtE{_fȂSܦ^#8#v^ϴ&#qq{4  Xgm-y6}{po^SO 8M:/7kt^V2uxФ j$ i#5) E8?UCGskL WL~(үm՟ɲ2gQѷ۪*#:ad_*;}ۦD⧒T6\3Ɠ׭[zz3%e*&(39 \3%6O^ꅚ >*8kuK4_2f/A2̭U%nx@Zjx΃uU׬Y+AiQ}N<٥>՝dx.$Ԏ%z^-)j'9O\1}1[~;)'4Y#X_6{ҝʓj =vWrq4BI x~'uS'ė0D;z{轻ۀTcSuׯֵ,,s4ډ\>TQG׾c︅Ûwqw?ȮvK7k m{Kn`sI"w7>^>hC.4IF]?MdSlxs_Gsn4C_7ׯwz;~n~﷡p}4ś봋}HV;m#ro8wpL^dԁil_\1uSzO|l ^!^/- [tF8x?ީ8 _{i7T4l 4W;KEGMG+^oG&Wil\;vnK.a 3|Or.2$N2kXZŦNts??p$_ZGWдfx]WЬZK 8C|ǂC|{(e|Bo.45Dرg!u`Ȟ% 5]iP yDRHf|h()v) ė箵嬯3HOsYKn Ty:3o 9lzN={xp|X]7EFG,'J|ײ᦭9ՄHhS2z:WJ 0g M7-C:>J__ÞߓhZ'їoVcǎ?;^ 掿*g!>q9о.7"Hu]+=VGc?3"1AK%.kv/W]FwuoCՙ?ٻT.4}رv{y j3VCOcY}ʩزo vɛFo!>rjo+:B>}~qaORpIC4\ ~ƍBӔXe,w|4t&B<'Uٱ}XˢYEWTGըWZxՐ}rX_B}/0Kϋ^@kKnUƴr?T[阮2 : L?\{ #hHOWr/ID4Db8װ)5Ys@~Ms|qw'CWhV +N +vͿFڍXv}^ ˁb0Y\*yr_k{X]v\!CAF؀l:.zZ.j]6h#{i5Jj6fV,a%͙!3C|?eRX$fqނse}R={رcR(} еxS%2*Vʍ{W>z`n,ƼڃNW =`ԯ8c~!MY=gC o kH^l %[ _ ]gD{U80?G9M\hpxCO%!n!xUR|#Xף@ &`'4JDK^eD'8!gVxK:g||MA|3G\l$Lu;,k!ȒtpNj#e􉭍X칈?ܫ++V9)!Zm6>P ^DCPȅ 6 C6mtŢ4TjXcrf0SÙyrV ҝP1!6Z<C|pC(1^0u-c~p~X87p /{xʒnǃhoDQmoS wQ%TңLx+m( 332ݼ::;i'(:X aWlE] :-1i4IW.^k B7$Gϟ8X!2r)Z^Ό [} 8ķLm:4GmjCi,Y+uuWȩ kq,'Xċ&.E*ڎC Sٻ>_.]EAf"kքX!GcŬ%> ^ 80_On:OۮGm4i-mP9U$W50 Eˆ@=C95H}=RBAഅ6:awU̸ftfa'kֺd'"m W.:9ra*rB}+ ʿf0:ΦM. /l{(r|54W.r*q,U>ܒTmeweYa!JW&L w zNv:z%K~d*oaZ?m 9nS_S@&U fdVb[5CWGki7JrO G4!Fr4 SF)4Okq#(","_ýh+*?k#=Mm4:OF8'z wH(u$}ɿ"i}E Dކ_RM洱U!DMNț@< wW9?} ?V,v4& 5̈́/cyL';IU'!ބn}f^T"7C|MϯX⥗^j>6SdKfY{mָikZvo,^&r3[vrOnИC[{ȾYd&7zߑ_H(&_mQ"OBqWHLU:[n!%aӓݺu+ow3wm=&)v^f8{aUvgU"\ۣbwߕ!y*/T3y]$ET RxWfh-Kg"oiiu!~޺NUt}yt)`O8p%g x9F ~B~F{ @]gh?TnOTx9zׄ܉$H6o Y rtL E hi LGOcm1sm[9ķ$lbk֬9vXbew6OoFiFa"W5$vw{gg]QOT& Ϣ9HxSZ oɄ@Qߛn!+^ 6Tjd;ڸqc)V߁3iZmC3,){ d!< LDO \j<+W?IF7=r)rQ:E;AjYPXuK|tYۨno^ߒS'UV:uj]E>ޕC5ew6b _QN@EK0r Ő̴+E:M8#V|J@,fDW܉2+$@ DӇ[#w0hd gXoqOp#:ķ$ٳgǎSG${'2΄>@O,7R*&E8' @EN83tUsTK >\8RCzQQGQh\b+X ėWi5x4W݆j"z3nS) _SfvYIfr*=_n)K;V!^Ƙ OR8iq-)@0墈䫲e `@휢$uі=O GOcSIe{Ɗ?6u( _Sfwi{3M;}*|'ÊC?q"|3"ogTV!Fil*]Uw9].+ P{Z/{JUq‰-ii6b4ݦ t^8>|rjnvݴ\0 ߘtN~U%3Sj`6uoCѧ9nSk X7zJX:lђum,7 0x`\ϝ1t;(=6ei~4*`06 w)`bdnCf,*z.Lٽ{m;n[n\K%.R^#[ɓ'k3ߑd-±.dff7iT߂t|nsƙgT6lVrarO8ķ1x6m(PC|2! /t6D˺5pxy7_V{W[}os= O<`K]Upƫ3]Mӝ'4L8ë ÌUtgD4c0`}=~Am ހuukv\v*恃\p믠^ woC[6T}65[!)YgqgĔq23Oxsӆ_&z9g< `ӟ<oC':C t2m>w*LOűߵ.8jr˕ 6尞m9W5nߟ!=%޻M %{U'g"N닷lOXi<K\-Uf]OU /};Í"n6aF[^(w,LKf mC|:ķ}قn)`J}uY: Qp`O_ tl ,Ⱥm:fBz} RFݘ)bw3KX󮦑ONĻMB7(*?bU_LffZA5LUp6S8f%;~ģ/{x`O66%į|H;ofGǒو. 8>YGK3eڽ%K@%رc+W|߮an}[J8QǠOlO9ķ1{iCwWXс ԗZi߳=xװbZnF,,,T}~~o .w{'ǿ`߯>/+noYHHy4U@|?*o`f/kv8^'w̹pSNռ-$CLd͔GWomKe***q;fmrMȑ#k߾v:0ԇk.!qg|}~\!}?QG|݆ m_6! Udۡ_=,W!nF<k.,@ Y0abKpٺ _٬sx_}pw&C t5 vX+ ̭jz\g=}ʀ=Mk4=u筻omܙtC|tp\T!~<΢"LI,BT 7ls熜*ǒ8GXaO>W^JŞTcI08?+ #kEXMo*e 7SEG"s, d7jYiEO Š@݆ɀjz+ ̓#imVgeƩKy9gՕrTܓZ8tTLr˕c6~Wtm<;Wp\Wѹ\֮[[r@;`:_%;p_x,XF-ßU^M ,u ٻ+04bybR irMf8(%:-\lCɆ3eCOhXɺGg:t%1'zaM s*d{`m OZNruO#+0 8ďYvΑ珔FC]3 i:#ɯW8C1\F^njd%pb+Y(p$PTVxyxvDz%ݦ6K6:6tvN`A\h&/+ Q!?mQ$mnqi f.7=H׃Zyx5pBs`)+Ll$(|_-_ـs><@]e-%[Om0ku#}iz6 kN?=WWpC|GMwnXnN d|'~贚 o+j&N[UGشfV{u<4<+ sC|boڴß% b+W(:V&6g*-)yM-1Cc勲c?QvMӤN6 nCNM }?R r~ջ q{ ou󸮀+ ̡Eܹ3sWpqYmj߰ gHlڀFMOvA6t^!Q]WG[s Ý"3<0<# 8w^+֋/Hx$|>̦HOf7᣻?HEtXnCRVF3mL|7ܳkc;w pOl\up 6(-Okcy;('=y+p>@<LlѺx5.m-l CKCpEnQ#:D1>4o8PdX iXy*bIj:skzBXp-=6 Ek &aYmLm.]w#IhG۰#C{j=Wp\W 8'6O;MFTEF60Hx2ek$uٸuc&P3gekVĆi.ZKPBm!>ۤA<미r˕6t!_u~{6<%Wp\W`j⧖L >t`0#*y6[%&'> ܳ^znaXZu c̞, cwĭ⣮@f۵6}Xtbu ܺ^x![^WpC|b3B[~x0P4D & ''IAx9ՐNM'fms(Yn-oۣhAV6"xu' mbkQIětT}6?릙@xso\ROp\q+ؾX@s|ThL,k@yY: |*?=mm?3?'#mOq ˰u[;gȺ++mڞLw]OyY cLh:7.' pwNk֬# T@mqx԰8uaY|q~سgπܗzmYyЃ5]n0ޣۜq̔ؽ{M !>Y: |*?ZCcI*a _\\/Zf^#,AȞn|/7;ߺ?7ްQb%0D\b9;Sm9ԟp/nsƫpndeu?pum{{om4ҳnxn3V{$+ BA4S[ ^0?hMKg1m;n*CXiwV2M6oe/s?n3B+ @1wxiEleoozO{_b55X5pK.(]B|ikXv|tgv ݆q L\94|o\WpƥC|Y'!4Rîp>f>ֻ2u*C{\ 1^II6wƁ 26̣yI$=+ +C|h?ž;#.p' $h[VJ!v֛$EO(7LkffΚ8^3:+ZwY|xn`KmdWӇ=u6}&&(+ @ Khߪ@h+VӢܹ~bqR0-4C>8$`?&|7\&>h'Z_mlVw݆nxCM;5~%h's{+ Vn -3CfF]7<6W YnbEFKcDU^MEZUG!u d3) h!D[÷.Sg݆W"t{b^!s\W` 8ħToN4Ʊܝ7N_H2 f}`[By^umKJdW1!>^q\WcSZ#1‡4VZ!{{g5fּa@8ėtn0Xn@]kSp\9V!>,M3t^љBP# F\[?><aUVgLU@8[Sf }&Zh&MUa6o]֧?xa.C]W͆V1WB2Zd&L=1&/Z0\0Y#{~%W'5ٛ׽yV6 hG'u$MyӚ7۰;'ދ=+ C|w-_+gSbӶQG^53YC Oh hk.Gy5!>(+ ̳񭷾jdJuj6>-fl8a޶m7Srt"B8\YY6[۰+5MIWOAɆmvz5Uø+ CT!VOV fY -Ԅjd׏-/;6`:6:iI C.pp\W\%o'/~#z'C7*;}Q'#'ʢc?'';p_.QS2LDT"E+9vv+LuA}Y%6j>QG[mxCvYvf JLsǮzɚK:ѳp\WpW!{[ɑNCJe/xaFW#$oaD`'gmP,,֯IR)x85(;p64KR00j\rßX}LېHV7CsWzM\r+ +0Sg*CqƙgdE0SHcp`50}NA-? Ck*8LvV]#aFO)FaѫJ˪DIBȝF9*Ǫۄ#ؕ[Y: |*?vr M ⱪr`-VpX9?. g/;; C|nIx'PN#GsQ9,Fc;bYts !Zc>,լ}ݼ/Bsi詹4&['˺06J*̱9lmM6z._$7C|tp\T!~$|Br1+VME Fc$QNjӐQćfylOxa"jbA<6; ][X%:ۨmb.3WǢn&L͎C:&U+en\@y;y .rA4p\(ߟUvv۳rBC+3Ld%T.@) h)Z2R!- f&Up:,X-CUd&kLj+a1yR2aS#u "OZ!W TKQaXuad\WchEꀕ͞p4љ߃q վKdd.LeԽ/ OGX{i;Fy*ݦdMK x(WCPZ IDAT@OpIC4PG=z'̢E'Ɲ6&RXdWpݠY>{ 4eHUZP1LnC1Od9믘g!~{ޮ+ P6Zqs]+S?n7 {K9xj 삼iK_޷y+ + 8ďG0 kp#iӷX ="/>;1ozy6mc2+ C'޸#2W"K]ǫr?Cj7n3ۋp\W? ̅%c5 dxѼyݛ> /[U?'m4dvop\W` ʏ[ֽe瞝4 l;PqRGܺ!v!}f;#Olu\W`pmduaBv7"WnyC٠g|ns;ʺ'Q6ndVC&+ *ߪO{6pғU-af!^/4vZȸwKz9+ tC|ǂ&;?g9nx%l`⍋7l g#皧deݷm۷8U +0S5/U+qY\Zd iwg]|x3Y ~Umxs=6(WmuטVwS{>+ D4dj`s|CB|{7`Cݝg7lCtuh{7YfKKUPt\W` 8ďq˪$yWJQY=]u a={Ɇ:?}HNa0Vxۜqtݻwzjy?qk @# 87" 1†.xm=a/؎D0^d/Z>|xJy6 `kuP[&y4H!u/uzFC+ @ 87S: @ܾxYݼ}s+0G #G(^I m@mu˻ &nC\6t]Wp\BsLP@>xYٷo_+0為(Pm0{~ + Q!zp\Wp\W3ݳt\Wp\Wp(_G= @3 ftT\W禩+c{8^4WpC|[ Cp\ 8У+Ѐ I+0O 8Sk{]]W 8e\+ T6pJjn+ p @]*]W3+K{,^(WpC|K + + *p\Wp\Wk0/+ + +}p\Wp\Wk0/+ R:fJ+Оi)+PUJy8Wp\+p\+?6+0(\^XW#mX+ m)ߖ+ pt\W@x+ ^ٷp\A)?ºHpiz\WhKt]WC|u<+  8{7p\Wp\WpC̋ + + 8{p\Wp\WpC̋ + + 8{p\W` ٷ:&AؿqH` oς8%ğKX $iZ /0I7S6IENDB`stapler-stapler-parent-1.231/src/site/resources/getting-started.html0000664000175000017500000002052412414640747025237 0ustar ebourgebourg Getting Started

Getting Started

Distribution packages of Stapler comes with a sample application that illustrates how to use Stapler. This document explains the basic usage of Stapler by using this sample application.

Setting up your web app

First, put stapler.jar into your application's WEB-INF/lib directory. Then put the following XML into your WEB-INF/web.xml so that the stapler will be recognized by the container.

<servlet>
  <servlet-name>Stapler</servlet-name>
  <servlet-class>org.kohsuke.stapler.Stapler</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>Stapler</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

Registering the root object

Stapler needs to know the root object of your application. It does that by SerlvetContext.getAttribute("app"), so your application needs to set the root object into a ServletContext. The easiest to do that is to write a ServletContextListener and use the helper method from Stapler.

Specifically, you write the following class:

package example;
import org.kohsuke.stapler.Stapler;

public class WebAppMain implements ServletContextListener {
    public void contextInitialized(ServletContextEvent event) {
        // BookStore.theStore is the singleton instance of the application
        Stapler.setRoot(event,BookStore.theStore);
    }

    public void contextDestroyed(ServletContextEvent event) {
    }
}

You also have to put the following XML in WEB-INF/web.xml so that the container recognizes this class.

<listener>
  <listener-class>example.WebAppMain</listener-class>
</listener>

In this way, the WebAppMain.contextInitialized method is executed as soon as the web app starts, and you get a chance to initialize your web application.

Root BookStore class

In this tutorial, we are going to write a very simple book store that sells books and CDs.

We first introduce the root BookStore class. Because this web application is about a book store, an object that represents the whole book store would be suitable as the root object.

By setting an object of BookStore as the root object, the root URL '/' and its immediate subordinates will be served by this object. First, to serve the root URL '/' by using JSP, let's put index.jsp into WEB-INF/side-files/example/BookStore/index.jsp. These JSP files are called side files. They are somewhat like methods, in the sense that they are used to display objects of a particular class. Side files are organized according to the class they are associated with.

Here is a part of this index.jsp:

<html>...<body>
  <%-- side files can include static resources. --%>
  <img src="logo.png">

  <h2>Inventory</h2>
  <c:forEach var="i" items="${it.items}">
    <a href="items/${i.key}">${i.value.title}</a><br>
  </c:forEach>
  ...

Side files can contain resources other than JSPs. In the example, logo.png is also placed as a side file for BookStore, allowing index.jsp to refer to logo.png by using this simple relative URL.

Side JSP files can access their target object by the implicit "it" variable. For example, the EL expression ${it.items} refers to the getItems method defined on the BookStore class. The "it" variable makes it easy for side JSPs to access the target object.

More on side files

index.jsp is a special JSP used to serve the '.../' address, but you can have more JSP files. For example, you can write count.jsp and refer to it by '.../count'. Note that it doesn't have the .jsp extension --- this is necessary to work around the short-coming of the servlet specification.

Delegating to descendants

Stapler uses public get methods of application objects reflexively to bind reachable child objects to URLs.

In our example, a BookStore has a map from the stock keeping unit (SKU) number to the corresponding Item object. The corresponding Java class looks like this:

public class BookStore {
    public Map/*<String,Item>*/ getItems() {
        return items;
    }
    ...
}

When a client requests an URL "/items/b1", Stapler takes the following steps to decide how to serve this request.

  1. Stapler knows '/' is mapped to the singleton instance of the BookStore class.
  2. Stapler takes the next portion 'items' and notice that the BookStore class has a method getItems, so Stapler evaluates x=bookStore.getItems().
  3. Stapler takes the next portion 'b1' from the URL and notice that x is a Map, so Stapler evaluates y=x.get("b1").
  4. Finally, because the whole URL is processed, Stapler looks for the index.jsp for y.

In the example, bookStore.getItems().get("b1") returns a Book object, so the side file /WEB-INF/side-files/example/Book/index.jsp is used to serve this request, with the "it" object being set to this Book instance.

As you see, in this way, you can define the URL hierarchy just by defining get methods.

Polymorphism

When you got two classes Book and CD that both derives from Item, you often want to have some commonality between the ways those two classes are served. There are ways to do this.

When a side file is searched for a particular object, all of its implementation hierarchy are checked. Fore example, if the "it" object is an instance of the Book class and Stapler is looking for footer.jsp, then first it looks for /WEB-INF/side-files/example/Book/footer.jsp, then /WEB-INF/side-files/example/Item/footer.jsp.

In a sense, it is as if the side files of the derived class would override those of the base class.

You can also use this semantics when you include one JSP from another JSP. Book/index.jsp and CD/index.jsp uses this mechanism to refer to the common footer defined in Item/footer.jsp.

Action methods

Sometimes you want to perform some operations when a particular URL is requested. Normally, you'd use servlets to do so, but with Stapler, you can define a whole servlet as a method on your application object. We call these methods "action methods".

Action methods take the following signature:

public void do[Name]( StaplerRequest request, StaplerResponse response ) {
    ...
}

Action methods can throw any exception. Unlike servlets where you are discouraged to use instance variables, action methods are invoked on the "it" object, allowing you to access the "it" object quickly.

In our example, we define an action method called "hello" in BookStore. To invoke this action method, access /hello. Again, just like servlets, you can serve the request from this action method (perhaps by sending the contents out or redirecting clients) in exactly the same way as you'd do in servlets. In the following example, we use a method on StaplerResponse to forward to another side JSP file to generate the response.

public void doHello( StaplerRequest request, StaplerResponse response ) {
    ...
    response.forward(this,"helloJSP",request);
}

Conclusion

Hopefully, the basic concept of Stapler is easy to grasp. For the exact rules of how URLs are evaluated against your application objects, see the reference guide.

If you have any suggestions on how to improve this documentation, please let me know. stapler-stapler-parent-1.231/src/site/resources/compression.html0000664000175000017500000000310312414640747024465 0ustar ebourgebourg HTTP compression support

Static resources are sent with gzip

When clients request static resources, stapler will send it with gzip as the content encoding whenever it can, to minimize the size of the data to be transferred. This only happens when the MIME type of the resource is "text/*", or the file extension is one of the well-known text file type.

This happens all transparently, so there's nothing you nor the browser have to do.

Sending compressed stream from the doXXX methods

If you are writing action methods that serve text content, and if you'd like to compress the stream, you can call StaplerResponse.getCompressedOutputStream (instead of StaplerResponse.getOutputStream) or StaplerResponse.getCompressedWriter (instead of StaplerResponse.getWriter) and then write to them normally.

If the client doesn't support HTTP compression, these methods will silently revert to the normal uncompressed streams.

Using compression from Jelly view

If your view script produces text content, and if you'd like to compress the stream, put <st:compress xmlns:st="jelly:stapler"> as the root element of your view, like this:


<st:compres xmlns:st="jelly:stapler" ... other ns decls ...>
  <html>
    <head>
      ...

If the client doesn't support HTTP compression, stapler will silently revert to the normal uncompressed stream. stapler-stapler-parent-1.231/src/site/resources/i18n.html0000664000175000017500000000306112414640747022706 0ustar ebourgebourg i18n support

i18n support

Stapler depends on localizer for the i18n support.

i18n from Jelly view scripts

For Jelly view scripts, the convention is to place localized message resource files by using the same base name. For example, if you are writing foo.jelly, its property files will be placed in files like foo.properties and foo_ja.properties.

In this set up, Jelly view scripts can refer to message resources by using a special expression of the form ${%KEY(arg1,arg2,...)}. The messages are formatted by using MessageFormat, and arguments are individually parsed as JEXL scripts. If there's no arguments, parenthesis can be omitted and thus it can be simply written as ${%KEY}.

If you need to refer to message resources from within a JEXL expression, you can use a string literal notation "%KEY(arg1,arg2,...)" or its argument-less short form "%KEY". For example, ${obj.methodCall(1,true,"%Message")}

If the specified KEY is not available in the property files, the key itself will be used as a formatting string. The key can contain any character except '(' and '}'. This convenient defaulting allows you to skip writing foo.properties most of the time (that is, you'd only need property files for translations.) stapler-stapler-parent-1.231/src/site/resources/jelly-taglib-ref.html0000664000175000017500000003472212414640747025270 0ustar ebourgebourg Stapler - Jelly Taglib references

The following Jelly tag libraries are defined in this project.

jelly:stapler

Optional Jelly support, to write views in Jelly.

This tag library is also available as an XML Schema

Tag Name Description
statusCode Sets HTTP status code.

This is generally useful for programatically creating the error page.

redirect Sends HTTP redirect.
parentScope Executes the body in the parent scope. This is useful for creating a 'local' scope.
out Tag that outputs the specified value but with escaping, so that you can escape a portion even if the org.apache.commons.jelly.XMLOutput is not escaping.
once Tag that only evaluates its body once during the entire request processing.
nbsp Writes out '&nbsp;'.
isUserInRole
include Tag that includes views of the object.
header Adds an HTTP header to the response.
findAncestor Finds the nearest tag (in the call stack) that has the given tag name, and sets that as a variable.
documentation Documentation for a Jelly tag file.

This tag should be placed right inside the root element once, to describe the tag and its attributes. Maven-stapler-plugin picks up this tag and generate schemas and documentations.

The description text inside this tag can also use Textile markup

doctype Writes out DOCTYPE declaration.
customTagLibrary.StaplerDynamic When <d:invokeBody/> is used to call back into the calling script, the Jelly name resolution rule is in such that the body is evaluated with the variable scope of the <d:invokeBody/> caller. This is very different from a typical closure name resolution mechanism, where the body is evaluated with the variable scope of where the body was created.

More concretely, in Jelly, this often shows up as a problem as inability to access the "attrs" variable from inside a body, because every

org.apache.commons.jelly.impl.DynamicTag invocation sets this variable in a new scope.

To couner this effect, this class temporarily restores the original "attrs" when the body is evaluated. This makes the name resolution of 'attrs' work like what programmers normally expect.

The same problem also shows up as a lack of local variables ? when a tag calls into the body via <d:invokeBody/>, the invoked body will see all the variables that are defined in the caller, which is again not what a normal programming language does. But unfortunately, changing this is too pervasive.

copyStream Copies a stream as text.
contentType Set the HTTP Content-Type header of the page.
compress Outer-most wrapper tag to indicate that the gzip compression is desirable for this output.
attribute Documentation for an attribute of a Jelly tag file.

This tag should be placed right inside

org.kohsuke.stapler.jelly.DocumentationTag to describe attributes of a tag. The body would describe the meaning of an attribute in a natural language. The description text can also use Textile markup
adjunct Writes out links to adjunct CSS and JavaScript, if not done so already.

statusCode

Sets HTTP status code.

This is generally useful for programatically creating the error page.

Attribute Name Type Description
value (required) int HTTP status code to send back.

This tag does not accept any child elements/text.

redirect

Sends HTTP redirect.
Attribute Name Type Description
url (required) String Sets the target URL to redirect to. This just gets passed to org.kohsuke.stapler.StaplerResponse.sendRedirect2(String).

This tag does not accept any child elements/text.

parentScope

Executes the body in the parent scope. This is useful for creating a 'local' scope.

out

Tag that outputs the specified value but with escaping, so that you can escape a portion even if the org.apache.commons.jelly.XMLOutput is not escaping.
Attribute Name Type Description
value (required) Expression

This tag does not accept any child elements/text.

once

Tag that only evaluates its body once during the entire request processing.

nbsp

Writes out '&nbsp;'.

This tag does not accept any child elements/text.

isUserInRole

Attribute Name Type Description
role (required) String The name of the role against which the user is checked.

include

Tag that includes views of the object.
Attribute Name Type Description
page (required) String Specifies the name of the JSP to be included.
it Object Specifies the object for which JSP will be included. Defaults to the "it" object in the current context.
from Object When loading the script, use the classloader from this object to locate the script. Otherwise defaults to "it" object.
class java.lang.Class When loading script, load from this class. By default this is "from.getClass()". This takes precedence over the org.kohsuke.stapler.jelly.IncludeTag.setFrom(Object) method.
optional boolean If true, not finding the page is not an error.

This tag does not accept any child elements/text.

header

Adds an HTTP header to the response.
Attribute Name Type Description
name (required) String Header name.
value (required) String Header value.

This tag does not accept any child elements/text.

findAncestor

Finds the nearest tag (in the call stack) that has the given tag name, and sets that as a variable.
Attribute Name Type Description
var String Variable name to set the discovered org.apache.commons.jelly.Tag object.
tag String QName of the tag to look for.
namespaceContext java.util.Map

This tag does not accept any child elements/text.

documentation

Documentation for a Jelly tag file.

This tag should be placed right inside the root element once, to describe the tag and its attributes. Maven-stapler-plugin picks up this tag and generate schemas and documentations.

The description text inside this tag can also use Textile markup

doctype

Writes out DOCTYPE declaration.
Attribute Name Type Description
publicId (required) String
systemId (required) String

This tag does not accept any child elements/text.

customTagLibrary.StaplerDynamic

When <d:invokeBody/> is used to call back into the calling script, the Jelly name resolution rule is in such that the body is evaluated with the variable scope of the <d:invokeBody/> caller. This is very different from a typical closure name resolution mechanism, where the body is evaluated with the variable scope of where the body was created.

More concretely, in Jelly, this often shows up as a problem as inability to access the "attrs" variable from inside a body, because every

org.apache.commons.jelly.impl.DynamicTag invocation sets this variable in a new scope.

To couner this effect, this class temporarily restores the original "attrs" when the body is evaluated. This makes the name resolution of 'attrs' work like what programmers normally expect.

The same problem also shows up as a lack of local variables ? when a tag calls into the body via <d:invokeBody/>, the invoked body will see all the variables that are defined in the caller, which is again not what a normal programming language does. But unfortunately, changing this is too pervasive.

Attribute Name Type Description
template Script

copyStream

Copies a stream as text.
Attribute Name Type Description
reader Reader
inputStream InputStream
file File
url URL

This tag does not accept any child elements/text.

contentType

Set the HTTP Content-Type header of the page.
Attribute Name Type Description
value (required) String The content-type value, such as "text/html".

This tag does not accept any child elements/text.

compress

Outer-most wrapper tag to indicate that the gzip compression is desirable for this output.

attribute

Documentation for an attribute of a Jelly tag file.

This tag should be placed right inside

org.kohsuke.stapler.jelly.DocumentationTag to describe attributes of a tag. The body would describe the meaning of an attribute in a natural language. The description text can also use Textile markup
Attribute Name Type Description
name (required) String Name of the attribute.
use String If the attribute is required, specify use="required". (This is modeled after XML Schema attribute declaration.)

By default, use="optional" is assumed.

type String If it makes sense, describe the Java type that the attribute expects as values.
deprecated boolean If the attribute is deprecated, set to true. Use of the deprecated attribute will cause a warning.

adjunct

Writes out links to adjunct CSS and JavaScript, if not done so already.
Attribute Name Type Description
includes (required) String Comma-separated adjunct names.

This tag does not accept any child elements/text.

stapler-stapler-parent-1.231/src/site/resources/stapler.vsd0000664000175000017500000034400012414640747023432 0ustar ebourgebourgࡱ> Root EntryRoot EntryF` VisioDocumentSummaryInformation( DocumentSummaryInformation8h  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~VisioInformation" ՜.+,D՜.+,h@HP\h t   y[W}X^ VFCv y[W - 1 y[W - 2o (2-D)ȐRlN^ _`͂o (2-D).6 (p) ~ʖ~ʃRlN^8_VPID_ALTERNATENAMES:?_VPID_PREVIEWS?_PID_LINKBASE?A Oh+'0THP`lxkohsuke1C:\kohsuke\My Projects\stapler\www\~$stapler.vsdstaplerG|| EMFtl"l`[VISIODrawingL|} ??d(H(}Hopo=@==@==@=痗^`^=@==@=EHEwxwFUFrrff6@6翿`b`TgTff)0)585@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@()(9G9̹*0*```(((@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@!ThT̟ǟ$($```585ǟyyfhf```K]KUhU```熇@N@ffffffff3<3```MPMttffffffffYoY ```}} TiTǟƙO`O ```]`]&,&rr׬￙IXI%(%```    OOO```eee   ^^^```]`]080yyϦ̙gg#(#```=@=FUF߲ƙ[p[$($```npngg̙̙̙̙>>@@@G>QJ=V,(2EUĒ̙̙̙%(%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@xxx@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@III~d2]4fsnllffaxa#(#%(%￿<<k:f3f3f3`fffffffffffVf3f3f3S)|M&s@ `3M-C & &ppp```000ppp(((輥ҥÍfyMf3~Sfɲ岙̲̲̩ƍfYf3YsϿ@@@׿<<<***___wwwBBBhhhMOM  O`Offffffff080巟ϲ̍fffffffffffmFL3fL3fL3fJ3`@3L<3F333333333333333333333333333333333333333333333333333333333333333333333333333fffϿ000@@@@@@@@@@@@222 ***:::>>>vv̹JXJfffMMM@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@$$$888@@@@@@@@@@@@@@@@@@@@@@@@@@@888000-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@")0CEHCPC3@33@33@33@33@3fff̙MMM@@@ >O`s9=@#(#ffffffffmm585fff333333333333333333333333333333333333```@@@ >O`LfLfLfVrs9=@$($d}ď߲O`O585fffFFFCCC===``` >O`:M`s9=@#$#.2.fff333333333333333333333333333333333333333@@@yyy<<< >O`ssswǙs9=@ϗ@@@@@@@@@%(%:G:axa#(#ehefffMMM wwwoooppp (0LfLfLfLf@VkJc{LfLfLfLfLfLfLfLfLfLfLfLf:M`9=@```888@@@@@@XXX$($׬ttUXU888888xxx (((XXXmmmYYYfff```eeeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff```SSSug4j?~}??????000OOO888xxxCPCXXXpppXXXyyMv```PPP׿000888{sqiyǟ̙̙̙ggUXU```hhh Ͽߍf`ʹooo???000XXX 888JJJvef3mGj]v!$!.8.[p[ vxvyMswww???ppp666Ų؍fyMu_Yg=@==@==@==@=000奆tF@@@@@@~SY奆tFf۳쥆tFmhhh 奆tFZhhhⲙ̍ff3f000PPPŲةƍff3f@@@ (((hhh@@@```巟ϑmk9Yʹ'''xxx Ųةƍff3YxJ=V@@@@@@@@@@@@222@@@@@@@@@@@@PPPHHH@@@@@@@@@@@@$$$"""@@@@@@@@@@@@@@@hhh@@@@@@@@@@@@::: @@@@@@@@@@@@@@@mmm@@@߿Ųز̛yftFf3c8fƲ̦̲̲̲̲̲̲̄kuf`f3f3~Sf```000000 xxx`````` hhh@@@9=@ -6@-6@-6@-6@ [^`ZRb弥Ҳ̲̲̲̲̲̲̲̲̄k@@@@@@ ``` "-8s_ $( @@@@@@ ``````@@@ -6@LfLfLfLf ```XXX@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@```@@@ -6@|ϙ&3@&3@&3@5FX ```@@@@@@ ```@@@ aeh:IX|ϙd+18 ``` @@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@%.8%.8%.8%.8RUX @@@@@@@@@@@@@@@```@@@UwJ @@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@vxv BPBL_LL_LL_LL_L)0)  @@@@@@@@@@@@```@@@zRs`````` @@@ 484nn̲߲=H= ```@@@000@@@@@@@@@@@@@@@L<\`5H=S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@xxx@@@ CPC3@33@33@33@3̿ ```@@@s000%3@33@33@33@3585HHH000wMϿ׿HHH@@@@@@@@@@@@@@@@@@111@@@@@@@@@@@@@@@@@@PPP```@@@@@@@@@@@@@@@@@@222@@@Q:g[7I=U-.-"yy̦Ϧ[p[484PPP@@@@@@@@@@@@@@@@@@---@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@&&&:::A@CR:j]6F>N6@66@66@66@66@66@66@66@66@66@66@66@66@66@66@66@66@66@66@6-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@-6@ZZZ444qCwKfhf)0)-0-CCCyM   ```qyMߏ(((~}i=}x ffffffffffff sLfLfLfLfLfLfLfi xxx@@@@@@@@@@@@@@@@@@@@@D?HvJ000 ppp-CyM9V ff  ppphhhyMſXXX(((@@@xxx|us[uIƷ ̙̙̙̙̙̙ ߙsssssssי RRR  000?????? 222??????  9Vb2U.{F/\`Yf@@@@@@@@@@@@@@@@@@@@@ﲙ̃Yi=T9o}xccc{{{ffffffffffffffYoYYoYffffffffffffffffffffLfLfLfLfLfLfLfG`w>SgLfLfLfLfLfLfLfLfLfLf  pppsss_________OOO??????''';;;??????____________\\\369)2<>O`SYXE_4Y.Q8o¹쮓~S~S ___??????OOO000 148YtYw&3@&3@=CbmiZ1n@òʹܲ̑myMY@@@``` H\pLfLfLfw75Aղ̑m`f3yMfƲ̲̲̲̲̲̲̲̲̲̮ɍftFf3fy,,,___??????PPP``` 6CPLfLfLfLfiJMP弥Ҳ̷̲̲̲̲̲̲̲̲̲ϔ444___wwwwww aeh$+d%2>&3@&3@|&),0@@@ vxv"("-93*6= )-%#0:0363@@@@@@555@@@PPP 2P5QM@vQ2!2..vRe/%d.Auѻ1l=<M?dvQm/)/;/M//?? D̷OU0O贁Nka>FSqvյ^uA]q___w3D4V04FXab9?1o?o Z=OqQpVhvA7MKɺFRzqhzw)qo .k0BlImFQ䌵`ĴO8A@OX-PvAv5A]o_+=O/GSTќSޯ_?q?EWi{ß՞_G!3EWϟïZ;=<koo6o"4D/;Ͽ/OO/??p EWIpЇIkD+=u 4C 4dXXA4`K _fzDINU":4M'T$6HZl~/ /2/D/V/h/z///.} DisplayUFDfP h-RTUU!UUF~?x<F BP(?d Hx A@9I bcbK))~W  eqYkYdUHu 8$+3EXWV XW^m b㉺EɃ|C^ło B ύXeLXgɍ킹x to fit text.b\.~??}La?D?f'[3CH D # =hj,>TYY9 AUF~?\.u?Q6 URmu` 7??uJM blr rVYA| {ң Lq& >jU5 @"9-0%?l bS9#Ҥ!$5 I1`?Copyright (c) 2001 Microsoft Corporation. All "s reserved.`Vis_SE.chm!#26942G9#2q:0?9?K60#?KVA;l>`>Ud11 Y# Bl M$ (|1P"= DaՊ-(q9#@F?z^\0 -F1\b{r$"  "|1xC1 eXB](A0'M?OP"VCA%S9#FbXܳQB\F\GJFBY X1C*5ZD A%r]`B V@g@!1t[\SA|ED|>I Wr ]G1C3]WWDFN /m7G3i|1P"CB1O_\0RsT{[SnRTe@TWAEWnSooQ~CclHf-F1k 0GGA13\Xx~br7SnM$XT\XxnY{_S XurW1y@ET44'LXxAMf3"+IwAMRVCeS"2AyL&d2ٿ,ɿ sTv'iLo42'O9Et$N}kpA^*59 y'x-!AjA~ \@b)BmYBa,R$-?r^15VWF;S1;SP!;S;SlE/"""#!(`|C^ĔzudjAau Q?PjK;?aK+!x`C *Q(-DT! n 1rl iHjBXGL `%An0#1zPԧ`C7@8 @6.$6 ^:EW9-R[-Re-Ro@-R#y1*5o[^̐ołB}`IqēquKvɉđ傫ύXRgc nhψړb҂Ɍj4Tџ㟜8ʜ8g9'?;!3WAFE$0"~ \@i488#,9/'K4D0"0Oa1!/g 882T1?a?ay"11B1D|1|1R%9K#t<;tQ3tR$գC!E/>KpoS?a}? $J*|1%((B!K#h;2A#2`k,6,,,,,TY,{bNX,킹,eLXg,m/7R70,`,2r!Us%$@"Bh@>E@IR3KrH0-, r :#EFU_ S #u_ % BKv_ ]laDSV O @}+w_ POaRV /PU_ UU 129:;< U  t4!@K&@ r_ C- u_ 7AU /t4!@K&@ q_ *C-3'7AU:U !"#U$%&'()*t4n!@&@ \r_ p1C>-$q_ 7"AU t4!@K&@ -^ C-O^ 7AU 12t4n!@&@ T oF7C-OT ]7"AU 9:t4n!@&@ ,f 7C>-f 7"AU ;</t4!@K&@ 0b 7C-r` A @p_ ER@f_ -CR@|f_ AR@^ ER@_ _?R@c AR@f CRH<( H<( H<( H<( H<( H<( H<(  E,e_ ( REe_ 5 REf_ B REU O RE$T \ REc i RE f v RUFDfP h-RTUUUUF~@xT $PYY9 #AU@~?} ?FP!?3|@Au `u`b]u  - ">u` ?Zu`be"D4Wn#  A* 8AUlA[e""""8,8'>\.@u'L&d2k?&!"u&Z,&Z'.@'W""//<7"?5H''F?X:_+Uf$d$ ΍ tNzsW2 <b',3e&G@A4@dQD6 86<"<"hB'"V F LW-$]{eE?FM"?2rq?@I@EE??rUzRS*/@`A.@b>SY@j$Ru FTSRvkudvu4`u#[`@ #@@;u`hBwH28&"'<"3Q137 `Vis_SE.chm!#27279I`?Copyright (c) 2001 Microsoft Corporation. All @bs reserved.G32Bq?of1?w"?vAT|Q`0l> (>U [(HE=30YaTr+a\scpc(RU%a#a83@<oE?.?@rUq1C.U4.6F1HBt9Bq&}nva3 9 T1v;s`̌`ύX..z`Rob)P@߁f%QG1QVAW kU &U`Q`_ƂĐݒ&]` Controls.X1`Width/2~ΘY8ڐ`pA^&y="GM#ckv~p XrQ$ Z;.--~` ȗ h#<" (mG<2<6i 3QG/'drf"2,jH akXٿqPXjP\@?#xhYaAalD#Tg4 U(QQ2HB(QQc(9%v?gBtcVF|X_ S#x_ mB y_ ar>azV oO@+,z_K o8at} :UFDfP h RTBUUUF~?x<F BP(?x TQC b9bR))TeqYk:UHot*w  !2 !Q` lbg[NB`K:bRBJ:@@Q]&I:@ @ `Net?worku :?R&?A SWK\Hww w wp pwwz wڍׂ\Kv̂lbg[NVXe̍x̃r[łBWAN CÃ^ Ƃɂgp4.b~߿\.??PjTk??3CH D  # =hj4>TYY>yU@_~?\.?P6 Uk000$0 ^<brmbmbmbmYbDm_m _u`} ?đm,2)& "h"|""""""u)#b#&& !mU)"T)>U5 DL@)93o1t45 h`Vis_SBN.chm!#26535I`?Copyright (c) 2001 Microsoft Corporation. All 2s reserved.i700'59903{302" b$J&!G93o2qr@?qOLF03? KA(93!|603CA" @@l>#@>UdA#3 YP2=0a-8`93@ d?@H"OXjÔ@#KҡQ #XX ")"]8zT;+?@kW[?@1x!v l"a\'Yб|U#1Z] ӧU#@o%!2"" Ia Q5U8Ş BW@FP?@o#o` [Kq_TWiRQ{;*jl?|oojEZ?@L%K?@Bo@SF@{7l\dP|jkjl?ҒYiaL^c5n'( ܖxҩX ^ڨo ?S S2q!cE^z$&hC>>Tk(o:o i`p}/ @Տ珤f|UVRfx.@_XojljzywՔj-bs~?:XNYяujz_dءBrCB$5i, ^ -GT1<05I2 !ϐ)`7/K)_//,Y/+#1 GID 7?K)Er^?p?>` VA= I?K)˕]??-ݒuꏊ?/ D9OK)f`OrO_r)SOK)WOO_%QS/_`K)U_g_y^_Sa_B؊4sN ,CBǟg2gї ž !RT_ggJ´\^`,,x,P[,lbg[N, @X4,ڍ,Kv,,,ʏ,gp,\+pWApCσ^pr,{,\q rqpVgqaŞT$@bH-r6 s~,J nF^_ $"#|_ %B }_ &~c V '@+~_ BBoV ZPUFDfP h-RTUU!UUF~?x<F BP(?d Hx A@9I bcbK))~W  eqYkYdUHu 8$+3EXWV XW^m b㉺EɃ|C^ło B ύXeLXgɍ킹x to fit text.b\.~??}La?D?f'[3CH D # =hj,>TYY9 AUF~?\.u?Q6 URmu` 7??uJM blr rVYA| {ң Lq& >jU5 @"9-0%?l bS9#Ҥ!$5 I1`?Copyright (c) 2001 Microsoft Corporation. All "s reserved.`Vis_SE.chm!#26942G9#2q:0?9?K60#?KVA;l>`>Ud11 Y# Bl M$ (|1P"= DaՊ-(q9#@F?z^\0 -F1\b{r$"  "|1xC1 eXB](A0'M?OP"VCA%S9#FbXܳQB\F\GJFBY X1C*5ZD A%r]`B V@g@!1t[\SA|ED|>I Wr ]G1C3]WWDFN /m7G3i|1P"CB1O_\0RsT{[SnRTe@TWAEWnSooQ~CclHf-F1k 0GGA13\Xx~br7SnM$XT\XxnY{_S XurW1y@ET44'LXxAMf3"+IwAMRVCeS"2AyL&d2ٿ,ɿ sTv'iLo42'O9Et$N}kpA^*59 y'x-!AjA~ \@b)BmYBa,R$-?r^15VWF;S1;SP!;S;SlE/"""#!(`|C^ĔzudjAau Q?PjK;?aK+!x`C *Q(-DT! n 1rl iHjBXGL `%An0#1zPԧ`C7@8 @6.$6 ^:EW9-R[-Re-Ro@-R#y1*5o[^̐ołB}`IqēquKvɉđ傫ύXRgc nhψړb҂Ɍj4Tџ㟜8ʜ8g9'?;!3WAFE$0"~ \@i488#,9/'K4D0"0Oa1!/g 882T1?a?ay"11B1D|1|1R%9K#t<;tQ3tR$գC!E/>KpoS?a}? $J*|1%((B!K#h;2A#2`k,6,,,,,TY,{bNX,킹,eLXg,m/7R70,`,2r!Us%$@"Bh@>E@IR3KrH( r :#EFL` 0#=a g1? a %2laDJU oy+/@a oO?` o/PUFDfP h-RTUUUUF~@xh @JT(  PG#Q? (UF~?N&d2?FTP u `u`buU $ )-'"->9Z[su` n?uʑ"`Ps b* ]M] \" #" #/" #C"Y #W"] #k"z'&&"/""C""W""k"""""w{&J3U2N贁Nk?HuH3w6i 3FM\.@44X6vDvj6v6$72?5& G='O , 36aGLW bA3 4?aZ[D DLsa/M_Q ZV5"z'_#"Qa`Q(-DT!7? [ @@9VT @@S> 3EaAC I4`?Copyright (c) 2001 Microsoft Corporation. All obs reserved.`Vis_SE.chm!#27283Gn 4q`?ofA?l2?A0rAe:a0lJ1U|EREjI  3C@Bas p84R4V~4P~3.F80R4^CyS~EqYUtwYEI  -t6 & 4&M 4&"M4&6M4&JM4&U8J & &&&yBLIrM ɒr#S& RE2R4⦅ޓ՗EqK]o5ǏȟڒВ䐢{0ׯ ) 9cHZl~ƯH.Ϸ# Itd/#+ 9S%ѿ^p= Oo߁#ϮC#+9a 2DV߭߿ߌ@߾ۑ#W#+9A=Oas#ۑ#坠GYik#+p8d9TXqXq@9Eq!!D T4sxCbbUA!ۇr?%{&C{ C4"H& F1`ʒu/Xjq&'"W"'"'"'"2&5WTL^ew1T  gޓ'&Eң_Wlq/,C/"wV/?$ :?PGV?h?VE???????9O;OMOV^!nOOOOOOOM__._RxtV_h_z_____],"tamU--sT. q^%+wE=+wNa+w#g`!9jp@aa^"!!E"PhhR[(9sYa`?b#"tQatR&y?ELdKaR? `b -1`! uhV,6%P&_2&L ?saa[`f,c[,`,,!2,6,},Rg[_,nhߏ,嚑lN^,g킹,ڑ,֘Aʐ,aUhQ$@[ d:az>y&E?7l/aHyf !OyaZECWcVFe ;#te <@ Le :=o>ad oD+e o2?ko4PUFDfP h-RTUUUUF~@xN#MUF~?FX,?F\.?FM&d2?FhH-u`u bu @-"1f#wu` ?4uA`b:OU t>Q&MQPPM(#P]/&& V>PR",p& f"G"5JUF`0 x@%5&44!&46p&,2;?M5f"@y7E=R'? ^#$x$ a  3tNQs1B% L>,# 8#Mb6_@e:M$L1N&0[ F . &1 'PG"NQ#2q@?O V1?4AH1R)" LbV? I]Bu(FU`Qps-8R?]%d@A`1"R"#uazdKI`?Copyright (c) 2001 Microsoft Corporation. All bs reserved.`Vis_SE.chm!#27241Ard|D`0lJApUl5 1E #0202axsp(P'x?FPArM uMBUsz8$?wtPu[_VAkro fqFr y ur 3yBS4^Adai5pE $e@jN?@X$@ WCU^F1)hز?R.8N&  !MQc(Bg"% ƃ F "K*>`sw>`/s]F@WC2Sr l^@^@+3,'"BF#4ˣ & Rg#5|隠 Pc?P[i?P0dQfx/aT6-wnƶb#ʖr#wsny̜Qh@ÜBA#`Ьzf"H1E#5r? %qL p@&1P;~q;zǎq>MiډFKXZ 7#$n#wPk2D[og}a12K` Sc`ch.b1~1`o" 2%>PIaw?p5wAE=rQ0(wlULUOZy?@:Dnvt~q'ogyul`@sKGu̎ y6G)\y6 8v$ &k/ zЮ !zdvTAcF ˓&1EYP$݀jWpEnVFѨC\'I HցWC"q%2&uFw"vr>RsqrBSu-BG r]CXb XQn,LtPc9zu7i5nV'9js99BDpE5JAtP9u7C]-P?)Z)jCpcdas%Νףp sPT$TE=#AUFf&Ц?F~} ??FP!3|@Au `u bu  - ">@ڍuv` ?jSuu"D4WUbh#  A .2AU\&5&[ W8">,>'>@F\. \Z b?FM&d2?[{&Z&Z&Z%'D]"/?@B7(? 5#'L?^:Z^Ul$j$a ΍ tNzsTW2 62,3k&G@b6<@QxD6 A"LW\'V F "0B2B"B"!#?2rq?@WI@EES??rUR S*/t@`A.@b SԐ@j)RuKTXRvnPmY(`u#`e@;@;@k@u`xCH>&8"W񂂦3Q137 `Vis_SE.chm!#27278I`?Copyright (c) 2001 Microsoft Corporation. All 9bs reserved.ԉG32Bq?of1?V"?nPAT|a0l>hUdB!PE=30202a*QsXpi(439#q$A8sEHPnT&sS [V[aB;A8annQa3 5=T1nT;c`ύX..s`%b)P@l%VG>[A Ws kU &#``_ƂĐݒ]` Controls.X1`Width/2~WY8`pA^ME9 'GzLDcksnXk ]rc=ZwDA` ȗ h#B" (GB2΢#&iȟڟ3VG/'&d?#F8,Aal%.RTrgda W8B!ģcc2NNMBQQBi(9vp##_!tU@gtR$O5j\`KSB!cnT? Gb Xb;@ QŐZ#SO MEoQkË`V,~,RlN^,,oH},,ڑ,,BJ֑gݍ킹c֘AcЍ,±ES6a$@kBh[aВˤ5M''KvH( !Oya ZE_=cVFa S#\^a Tw8OF _`a -r?>fda -OD+k-6?Daa -P_,( PV S{a hFB?q_ XPD~ r_ P"YV #/" V /t ` ;we @d 3Sw` Z]/  ?fl@d2?L@g 9Oas=*4 G #5GYk}D C:\Program Files\Applications\Office\Visio10\1041\Solu GLXg\oA$.vss= 2DVhz  C:\Program Files\Applications\Office\Visio10\1041\Solu GLXg\RlN^.vssC 2DVhz{D :\Program Files\Applications\Office\Visio10\1041\Solulbg[N\{}.vss՜(h*Qa ^UC!ke :_/f =/f s`$/UQW>QXBQWBQXFQWFQXJQWJQX+1W+1XRQWRQXWT51W51X^QW^QXbQWbQXq1Wq1X!W!X!W!XrQWrQXvQWvQXzQWzQX~QW~QX!W!XQWQXM!WM!Xa!WQX9!W9!X%!W%!X/!S#PAE?1g1AI1E1GAIbU]1jUrU"g1!Q{1M!a!&17TE+1YzU51=>D1/!a!Cb9!3EV%!GT/!u o" њ"PA`RlN^~`?1 ` Connectorr5Rߑ"PGB` bg[NANetworkQei]k FQGԀe ?14|>@@vݿ@@@&+7?@`?f ?(LFQABBB: 9 FOW?4:Ds lOi8#U bb:zP@_AlHCGN`}U84?^XMBbXrC.Q8TUindex.jspiCGe< 5XBQ@'G?@T?BTfx?'9 RT*J$4h!AC% & n2&&&  :/CUgy/ 2uploadASewA//'/?K/~?@Vju///NO/,)EE ,f%-f7fPf?-???Q?c?__??????OO)O;O__O 2OOOOOOQ __1_C_U_g_y_o_^x< ___o)m#~ }%~moooooЏoo!3EWi{MqOO@ .@[mǏ!zZ(R@@_$6HZl# %ƾП"4`TCE2N" E2 FyA6O SDA%N5O__WA%EzFI_Om_A9!vOarRSf1wRoot object//%/7 rqLS/e/w////п///U @ @dW? ɻ%u vvvvas 91?"4Xj|sIo [omoo1/ oooooXjRbu 6sp(%L KLVo);ˏݏ%7I[?configğ֟ `+=Oas񿻯XbX . z% =挿̙IJbȿڿ"4FXj|ώϠϲϖ8doCreatePro9o(:L^E' {ߍߟ߱ .@,T*JR?@l605\.?ߝ\e8O3k3P?:+gc; ?O O^DOVOhO__LI86O=P/[_ ?,_d8w??u__???_/_oK%Y6d fo?r jaxb`roH DYu|>ݠ r8J HXe WfuXfbf{f¿&__/n'o"OOO _9T 5_G_Y_k_}___o__@@@ _oo y%{Your Application O>BModelcucڴAٿ!3EWi|p8ϜϮ A%7I[mߑߣ%PtEW?////M/{.3URL Hierarchyz0&8 1K1Ra[4Qf scZV>:`0 @6C)'P-DT!-4P`u bu`u FL@"PXHp@QɣABA8SRRIT 0(mV옶F?nF4RcmVlWmV^B2_jWob:oLiW80zGz?"6r1bbc&15????0U#r(wcy {,zE_CljO|OSU*?].? -uN#1L@tφϘϐАP݆ѷ}߀#h4H#=t@P_$X,?@"@@#{?F"'P%0O贁Nk*rK& !(x#Љ%f} _S/RZ0PpEe @?B%@-MLn{qT5khQѦeRa5on66zQFf6gU8ХyϑQ&.h́ɒ*e֨V[?q^d%d(AjQTk^1q!__ψBw(Չ 5z3Zgetc(jaxb)f0"q rn5x8BT3А C 99h92Ӓϑ$ϑ /ş0/B/T/f/x//. 5&P&_d2(@h("-DT!)3# ??@@ 5: /A2K [R#FI"bO%O7F AOSO"TT%=OY1q*Һs=x̰PTq?#/Ib?(\!3ti_ jlnU=Oz$#(M?*_<_!z*(K]Syfoov'E1gga{Lgr[omoU~?@t:N@?@\.??P&Y1b%5?b" $A31 AEz/GzCvSLa'1^3?E01qqkq2tTkq kuwmLaUwĕȡb%2`;ְdk$aް(:B$D"ȡ^}ƣoe2K;gƣ8u2mhtqM~p!b""ACob%$ Ժ&kr'#1ObA+2)=O22.T$same struc?tureiDhhDQ/V'2SB,ϨϺtπQ^AD`1[_1FBcu6@m?@Nt:@@v3/(}+(TAB%N#X/k$T*JR|>ybZV// @@p3,=.R@z33=O9+b"D"א'?9?K?U@@(ɷ.υ?2rqt0x78>1CD" D" 4 OOOOTOOj)_ߨR_`BP(?_2MS____"ooo^?;oMo[`ooooj#*oo z*oO`OO//vJp"@OdvЏTQSco<;8Q@R?v,?n@ß՟c,>Pt1QNZQ41!YN] cA.F?DqOU@ d?@H"Xj )HSQ;+?@kW[?@1x!v."w lUud8Ş BL@FP?@5deɭL%K?@BُUE'( ҩX ^$UEdz$&LjC>>ToU^dEV~xടdܯՔj-fSC>A61AT]AE c5_U-Z_5%Ѿ v!,E[muJR_5K;E-mXmD _SN>q>q5"" ,B!#`$2I% b&B'"^UU7711]xQӕXsame struc?tureiC_D_$21/-6'203"TRϧϹS61U,Ber62=$u uj/@a\qR@l\q1]ipU:1eQOԾ,7Xe1qi_n_>`Mt:q 1OPX{PWPeV:? \qS\qSz85DD"H$a|>~x-Y`ZV@"]D&" < tg+!@Rfp`ѧ4B (|4B | -qfqruO贁Nk_#o;` #6B`ٶ} 3LF\q52ߝo@ EC?= Lnhi1${}ky1U?>O1B[?m>qecrooIU 1UQVHgxvz@+d&+?!x4zWj:ߺO0kبOO0//8EoϸYєGi@q!O.>TadVk/22ǯٯ?UI`#' #% gy+rm 2<8 ufCwՁ~ee [Ձu`VEiՁNr|rGrqPAoSoeowolqt17.oU@.x?@F$D" @@_Ÿۣ};aMv5sQs?5A3ll?5| Rr / 1q ?Qc០sԏ@ۦ7W[(䥲q2I!Ο,y VFolder objectwqx s-?Qcui7 @ѯ0+C@Xj|¿Կ ϚYk߬ΈϞϋ.@Mq|߾*s+qqAD5)14g"s'&<5p tqQ9_bX?@S*JR@@U կ*?FTrwPo2#`0EB)1 rTQ h^=2@ȧ<{@ug`kufle`zp%dj|u|U1LR2t؈ r`0tTQ[5S/WU?@LDZ?@IGWRJoۿe?w?#5GYk}ϏY/ 'W0UMDaa"ߓߥ߷tx^@@|>pdv//&@/%/7/I/[/m/>`f/__///x;7jaxb)?;?M?_?q???OO>O> v?OOEOiOOOMqO|_O$A_S_e_w__YN`a_U@T*JR!@@UP^ݓo&o8oJo\a,A9gjzoooooo:&foo*<N`r Ŷݖ].񸞏V@ɏۏ4Y%R%pk1For example the URL ofis /project/7star/MQgta|^TpB!!G2+HO#p_G5yEkB3(CԿSLaҿktooxxq"'"4FXj|zԲߛP@@!H$@@DrA 02 IS3ֆqzs#;?subF?older2Yk}J`/n u-r9]R.@Rdp0BU@sE/ 'sq(1"4FXvn!@@"j|ߎߠ߲ߌ߅E(1ٛ&&']o8er1&cnw}:FOUZO~OO0BOOO?/?,>Pb)D1QsPbtpt7PR??=8_TD!sPG Y@ƞV ";Tb`VUږSӟ) %@@@@`ԅӁSSVǟÑ>Xjtj kЦ?? OD0WpWDpDȩ 'Dh¿ݡ!3/AS)z^׃جֲƾձP-DT!z&Ru u`bu  .* @". @@ QSݡu ’IfybX@x<?@$ptuܢ*'/B/T)!3EWi{Ԣ*5*en5?1%7I[ 7"$?6?aU@L@@?p*<N`P1yYVfFFZѡ@FYVXWYV$_@^~W o]&&o8ih$0zGzM"u63A///////??XOjOJ?\?n????????OO,O>OPOJgT*JR!OOODc_ß՛"<_7W*__]OOF_UR[""<# c&!Im hozoooooooo .rRdv3 1C[m؜|#@@@@Z@?&8.̡羠3Ţbbbzʯܯ$2dele teѮ**}`4SRi SRVUǠ-|gUfiUn rZ 24'9K]U߭ߏȮU@n @@v@@?~ŹSS8]_,_ғߩ$6;(NSQYmy/M /7@5@ XQ1W*W3(+ŋsX8~AUZ@ \.XȢiO@F%C,GPfaw@zSSQ1&bX@@Fh@@B@@+P@L*)ȬD02`0UEE@@2rq?o@IP? TU?HE,#4PГ71U8Q?$3fTq{b3bf!X)]E} {?VQ1p~+$OT6O[U :ooSӿvo"2앓oooo oQ#5GYk}zoV+=Oas@9d7 Ἇ<(:LRT*J@@=df,H>HROK ᫟sEH$D"@@?xFM( BL+M  /AlsPuz8'fx?A ʢ ӣĨHٯ!?Q w忂"G?K'9zόoϥߴyRdv߈ߚ߬߾: ﮇ1+?OasLJ@@ 4ceIkylCkhPxu 𝗘1,&d2@@SR@@ _p_ ?@Vhz1VPfe@@jF 2ˡ1LWgyE}m10);Z_?}Os'<//n!/3/E/W/i/{///#lO]^//??(?@:?L?^?p??1;?&?X??OO%O7OD\DbK@@!dE3u/L塉4?%}|K&O,@  @@BCh @@OOt&$_6_H_~+ cP69m__?P$___D&Ld_oo+o=oa2[omo &o0ooo? ַMp1CU -) nȏڏU+U U UUU !"#U$%&'U()*+U,-./U0123U4567U8;<=U>CDEFGH/t42Z&@! Ca ŧC-e_ k A/t4!@C&@ X A-TQ[ 7;n@d_ uGR@dg_ ̨FRH<( H<( nEP[ RE Q[ RUP (4FDTe]y ah$^T ^UY!@F&@?x_^r0bc #rootiA'Q #(T/'2rq? 4aU?g?y???????%4F@@nv@@H&d2ٷ?@T4?2:3OEOWOiIayIG3T YG3ԢT tG3T "G3 T G3$T ȳ"G3DT G3\T "G3ğa %E3̤a 4E3{a DE3{a UG3$f qG3h G3.g E3/g E34d E3d E3lh G3h Ӵ G34Wf G3d\f G3g ,G3g E G  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHU*U /t4 !@&@ dq_ ˻ CJ-T37A/t4 h_ 9}A-q_ G7;J@=_ CR@4,^ M8RH<( H<( JE>_ RE,^ R{ : g'9K] (h(#a@(=3>9p~M#S T :NB j 0&V !F4S >@WO;0F-S ]R$^wD`M)TIV _ aY'yS 1~P1$|S Ҕ2T eof? Optional Jelly support, to write views in Jelly. Sets HTTP status code.

This is generally useful for programatically creating the error page.

HTTP status code to send back.
Sends HTTP redirect. Sets the target URL to redirect to. This just gets passed to org.kohsuke.stapler.StaplerResponse.sendRedirect2(String). Executes the body in the parent scope. This is useful for creating a 'local' scope. Tag that outputs the specified value but with escaping, so that you can escape a portion even if the org.apache.commons.jelly.XMLOutput is not escaping. Tag that only evaluates its body once during the entire request processing. Writes out '&nbsp;'. The name of the role against which the user is checked. Tag that includes views of the object. Specifies the name of the JSP to be included. Specifies the object for which JSP will be included. Defaults to the "it" object in the current context. When loading the script, use the classloader from this object to locate the script. Otherwise defaults to "it" object. When loading script, load from this class. By default this is "from.getClass()". This takes precedence over the org.kohsuke.stapler.jelly.IncludeTag.setFrom(Object) method. If true, not finding the page is not an error. Adds an HTTP header to the response. Header name. Header value. Documentation for a Jelly tag file.

This tag should be placed right inside the root element once, to describe the tag and its attributes. Maven-stapler-plugin picks up this tag and generate schemas and documentations.

The description text inside this tag can also use Textile markup

Writes out DOCTYPE declaration. When <d:invokeBody/> is used to call back into the calling script, the Jelly name resolution rule is in such that the body is evaluated with the variable scope of the <d:invokeBody/> caller. This is very different from a typical closure name resolution mechanism, where the body is evaluated with the variable scope of where the body was created.

More concretely, in Jelly, this often shows up as a problem as inability to access the "attrs" variable from inside a body, because every

org.apache.commons.jelly.impl.DynamicTag invocation sets this variable in a new scope.

To couner this effect, this class temporarily restores the original "attrs" when the body is evaluated. This makes the name resolution of 'attrs' work like what programmers normally expect.

The same problem also shows up as a lack of local variables — when a tag calls into the body via <d:invokeBody/>, the invoked body will see all the variables that are defined in the caller, which is again not what a normal programming language does. But unfortunately, changing this is too pervasive.

Copies a stream as text. Set the HTTP Content-Type header of the page. The content-type value, such as "text/html". Outer-most wrapper tag to indicate that the gzip compression is desirable for this output. Documentation for an attribute of a Jelly tag file.

This tag should be placed right inside

org.kohsuke.stapler.jelly.DocumentationTag to describe attributes of a tag. The body would describe the meaning of an attribute in a natural language. The description text can also use Textile markup
Name of the attribute. If the attribute is required, specify use="required". (This is modeled after XML Schema attribute declaration.)

By default, use="optional" is assumed.

If it makes sense, describe the Java type that the attribute expects as values. If the attribute is deprecated, set to true. Use of the deprecated attribute will cause a warning.
Writes out links to adjunct CSS and JavaScript, if not done so already. Comma-separated adjunct names.
stapler-stapler-parent-1.231/src/site/resources/reference.html0000664000175000017500000002510612414640747024071 0ustar ebourgebourg Reference

Reference

This document explains the details of how Stapler "staples" your objects to URLs.

The way Stapler works is some what like Expression Language; it takes an object and URL, then evaluate the URL against the object. It repeats this process until it hits either a static resource, a view (such as JSP, Jelly, Groovy, etc.), or an action method.

This process can be best understood as a recursively defined mathematical function evaluate(node,url). For example, the hypothetical application depicted in the "getting started" document could have an evaluation process like the following:


Scenario: browser sends "POST /project/jaxb/docsAndFiles/upload HTTP/1.1"

   evaluate(<root object>, "/project/jaxb/docsAndFiles/upload")
-> evaluate(<root object>.getProject("jaxb"), "/docsAndFiles/upload")
-> evaluate(<jaxb project object>, "/docsAndFiles/upload")
-> evaluate(<jaxb project object>.getDocsAndFiles(), "/upload")
-> evaluate(<docs-and-files-section-object for jaxb>, "/upload")
-> <docs-and-files-section-object for jaxb>.doUpload(...)

The exact manner of recursion depends on the signature of the type of the node parameter, and the following sections describe them in detail. Also see a document in Hudson that explains how you can see the actual evaluation process unfold in your own application by monitoring HTTP headers.

Evaluation of URL: Reference

This section defines the evaluate(node,url) function. Possible branches are listed in the order of preference, so when the given node and url matches to multiple branches, earlier ones take precedence.

Notation

We often use the notation url[0], url[1], ... to indicate the tokens of url separated by '/', and url.size to denote the number of such tokens. For example, if url="/abc/def/", then url[0]="abc", url[1]="def", url.size=2. Similarly if url="xyz", then url[0]="xyz", url.size=1

List notation [a,b,c,...] is also used to describe url. Lower-case variables represent a single token, while upper-case variables represent variable-length tokens. For example, if we say url=[a,W] and the actual URL was "/abc/def/ghi", then a="abc" and W="/def/ghi". If the actual URL was "/abc", then a="abc" and W="".

Stapler Proxy

node can implement the StaplerProxy interface to delegate the UI processing to another object. There's also a provision for selectively doing this, so that node can intelligently decide if it wants to delegate to another object.

Formally,

evaluate(node,url) := evaluate(target,url)   — if target instanceof StaplerProxy, target=node.getTarget(), and target!=null

Index View

If there's no remaining URL, then a welcome page for the current object is served. A welcome page is a side-file of the node named index.* (such as index.jsp, index.jelly, etc.

Formally,

evaluate(node,[]) := renderView(node,"index")

Action Method

If url is of the form "/fooBar/...." and node has a public "action" method named doFooBar(...), then this method is invoked.

The action method is the final consumer of the request. This is is convenient for form submission handling, and/or implementing URLs that have side effects. Formally,

evaluate(node,[x,W]) := node.doX(...)

Stapler performs parameter injections on calling action methods.

View

If the remaining URL is "/xxxx/...." and a side file of the node named xxxx exists, then this view gets executed. Views normally have their view-specific extensions, like xxxx.jelly or xxxx.groovy.

Formally,

evaluate(node,[x,W]) := renderView(node,x)

Index Action Method

This is a slight variation of above. If there's no remaining URL and there's an action method called "doIndex", this method will be invoked. Formally,

evaluate(node,[]) := node.doIndex(...)

Public Field

If url is "/fooBar/..." and node has a public field named "fooBar", then the object stored in node.fooBar will be evaluated against the rest of the URL. Formally,

evaluate(node,[x,W]) := evaluate(node.x,W)

Public Getter Method

If url is "/fooBar/..." and node has a public getter method named "getFooBar()", then the object returned from node.getFooBar() will be evaluated against the rest of the URL.

Stapler also looks for the public getter of the form "getXxxx(StaplerRequest)". If such a method exists, then this getter method is invoked in a similar way. This version allows the get method to take sophisticated action based on the current request (such as returning the object specific to the current user, or returning null if the user is not authenticated.)

Formally,

evaluate(node,[x,W]) := evaluate(node.getX(...),W)

Public Getter Method with a String Argument

If url is "/xxxx/yyyy/..." and node has a public method named "getXxxx(String arg)", then the object returned from currentObject.getXxxx("yyyy") will be evaluated against the rest of the URL "/...." recursively.

Formally,

evaluate(node,[x,y,W]) := evaluate(node.getX(y),W)

Public Getter Method with an int Argument

Really the same as above, except it takes int instead of String.

evaluate(node,[x,y,W]) := evaluate(node.getX(y),W)   — if y is an integer

Array

If node is an array and url is "/nnnn/...." where nnnn is a number, then the object returned from node[nnnn] will be evaluated against the rest of the URL "/...." recursively.

Formally,

evaluate(node,[x,W]) := evaluate(node[x],W)   — if node instanceof Object[]

List

If node implements java.util.List and the URL is "/nnnn/...." where nnnn is a number, then the object returned from node.get(nnnn) will be evaluated against the rest of the URL "/...." recursively.

Formally,

evaluate(node,[x,W]) := evaluate(node.get(x),W)   — if node instanceof List

Map

If node implements java.util.Map and the URL is "/xxxx/....", then the object returned from node.get("xxxx") will be evaluated against the rest of the URL "/...." recursively.

evaluate(node,[x,W]) := evaluate(node.get(x),W)   — if node instanceof Map

Dynamic Action Method

If the current object has a public "action" method doDynamic(StaplerRequest,StaplerResponse), then this method is invoked. From within this method, the rest of the URL can be accessed by StaplerRequest.getRestOfPath(). This is convenient for an object that wants to control the URL mapping entirely on its own.

The action method is the final consumer of the request.

Formally,

evaluate(node,url) := node.doDynamic(request,response)

Dynamic Getter Method

If the current object has a public method getDynamic(String,StaplerRequest,StaplerResponse), and the URL is "/xxxx/..." and then this method is invoked with "xxxx" as the first parameter. The object returned from this method will be evaluated against the rest of the URL "/...." recursively.

This is convenient for a reason similar to above, except that this doesn't terminate the URL mapping.

Formally,

evaluate(node,[x,W]) := evaluate(node.getDynamic(x,request,response),W)

If None of the Above Works

... then the client receives 404 NOT FOUND error.

Views

A Java class can have associated "views", which are the inputs to template engines mainly used to render HTML. Views are placed as resources, organized by their class names. For example, views for the class org.acme.foo.Bar would be in the /org/acme/foo/Bar/ folder, like /org/acme/foo/Bar/index.jelly or /org/acme/foo/Bar/test.jelly. This structure emphasizes the close tie between model objects and views.

Views are inherited from base classes to subclasses.

Jelly

Jelly script can be used as view files. When they are executed, the variable "it" is set to the object for which the view is invoked. (The idea is that "it" works like "this" in Java.)

For example, if your Jelly looks like the following, then it prints the name property of the current object.

<html><body>
  My name is ${it.name}
</body></html>
stapler-stapler-parent-1.231/jrebel/0000775000175000017500000000000012414640747016737 5ustar ebourgebourgstapler-stapler-parent-1.231/jrebel/src/0000775000175000017500000000000012414640747017526 5ustar ebourgebourgstapler-stapler-parent-1.231/jrebel/src/main/0000775000175000017500000000000012414640747020452 5ustar ebourgebourgstapler-stapler-parent-1.231/jrebel/src/main/java/0000775000175000017500000000000012414640747021373 5ustar ebourgebourgstapler-stapler-parent-1.231/jrebel/src/main/java/org/0000775000175000017500000000000012414640747022162 5ustar ebourgebourgstapler-stapler-parent-1.231/jrebel/src/main/java/org/kohsuke/0000775000175000017500000000000012414640747023633 5ustar ebourgebourgstapler-stapler-parent-1.231/jrebel/src/main/java/org/kohsuke/stapler/0000775000175000017500000000000012414640747025305 5ustar ebourgebourgstapler-stapler-parent-1.231/jrebel/src/main/java/org/kohsuke/stapler/JRebelFacet.java0000664000175000017500000000525712414640747030267 0ustar ebourgebourgpackage org.kohsuke.stapler; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.export.ModelBuilder; import org.kohsuke.stapler.lang.Klass; import org.zeroturnaround.javarebel.ClassEventListener; import org.zeroturnaround.javarebel.ReloaderFactory; import javax.servlet.RequestDispatcher; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Logger; import static java.util.logging.Level.*; /** * Adds JRebel reloading support. * * @author Kohsuke Kawaguchi */ @MetaInfServices public class JRebelFacet extends Facet { private Map metaClasses; public class ReloaderHook implements Runnable { public void run() { ReloaderFactory.getInstance().addClassReloadListener(new ClassEventListener() { public void onClassEvent(int eventType, Class klass) { synchronized (metaClasses) { for (Entry e : metaClasses.entrySet()) { if (klass.isAssignableFrom(e.getKey())) { LOGGER.fine("Reloaded Stapler MetaClass for "+e.getKey()); e.getValue().buildDispatchers(); } } } // purge the model builder cache ResponseImpl.MODEL_BUILDER = new ModelBuilder(); } public int priority() { return PRIORITY_DEFAULT; } }); metaClasses = new HashMap(); } } public JRebelFacet() { try { Runnable r = (Runnable)Class.forName(JRebelFacet.class.getName()+"$ReloaderHook") .getConstructor(JRebelFacet.class).newInstance(this); r.run(); } catch (Throwable e) { LOGGER.log(FINE, "JRebel support failed to load", e); } } @Override public void buildViewDispatchers(MetaClass owner, List dispatchers) { if (metaClasses != null && owner.klass.clazz instanceof Class) { synchronized (metaClasses) { metaClasses.put((Class)owner.klass.clazz,owner); } } } @Override public RequestDispatcher createRequestDispatcher(RequestImpl request, Klass type, Object it, String viewName) { return null; } @Override public boolean handleIndexRequest(RequestImpl req, ResponseImpl rsp, Object node, MetaClass nodeMetaClass) { return false; } private static final Logger LOGGER = Logger.getLogger(JRebelFacet.class.getName()); } stapler-stapler-parent-1.231/jrebel/pom.xml0000664000175000017500000000314112414640747020253 0ustar ebourgebourg 4.0.0 org.kohsuke.stapler stapler-parent 1.231 stapler-jrebel Stapler JRebel module JRebel reloading support for Stapler ${project.groupId} stapler ${project.version} javax.servlet servlet-api 2.3 provided org.zeroturnaround jr-sdk 2.1.1 provided org.kohsuke.metainf-services metainf-services true stapler-stapler-parent-1.231/core/0000775000175000017500000000000012414640747016424 5ustar ebourgebourgstapler-stapler-parent-1.231/core/TODO0000664000175000017500000000054212414640747017115 0ustar ebourgebourg- need to redesign duck-typing - document duck-typing. - embed jasper to allow multiple class loader system. generate servlets from jsps/tags. (needs a ServletContext that can load from hierarchy of webapps) - generated servlets need to be wrapped into ResourceDispatcher. - if we create child class loaders we have to be careful cleaning them up stapler-stapler-parent-1.231/core/example/0000775000175000017500000000000012414640747020057 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/example.iml0000664000175000017500000000532612414640747022223 0ustar ebourgebourg jar://$MODULE_DIR$/WEB-INF/lib/standard.jar!/ stapler-stapler-parent-1.231/core/example/src/0000775000175000017500000000000012414640747020646 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/src/example/0000775000175000017500000000000012414640747022301 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/src/example/BookStore.java0000664000175000017500000000430012414640747025050 0ustar ebourgebourgpackage example; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import java.io.IOException; import java.util.Hashtable; import java.util.Map; /** * Root object of this web application. * * This object is bound to URL '/' in this application. * * @author Kohsuke Kawaguchi */ public class BookStore { private final Map items = new Hashtable(); /** * Singleton instance, to make it easier to access. */ public static final BookStore theStore = new BookStore(); private BookStore() { addItem(new Book("b1","The life of Calvin McCoy")); addItem(new CD("c1","Beethoven: Sonatas",new Track[]{ new Track("Sonata, Op.57 'Appassionata' In F Minor: Allegro assai",180), new Track("Sonata, Op.53 'Waldstein' In C: Introduzione: Adagio molto",172) })); } private void addItem(Item item) { items.put(item.getSku(),item); } /** * Bind "/items/[sku]" to the {@link Item} object * in the list. * *

* Alternatively, you can define the following: *

     * public Item getItem(String id) {
     *     return items.get(id);
     * }
     * 
* ..., which works in the same way. */ public Map getItems() { return items; } /** * Define an action method that handles requests to "/hello" * (and below, like "/hello/foo/bar") * *

* Action methods are useful to perform some operations in Java. */ public void doHello( StaplerRequest request, StaplerResponse response ) throws IOException, ServletException { System.out.println("Hello operation"); request.setAttribute("systemTime",new Long(System.currentTimeMillis())); // it can generate the response by itself, just like // servlets can do so. Or you can redirect the client. // Basically, you can do anything that a servlet can do. // the following code shows how you can forward it to // another object. It's almost like a relative URL where '.' // corresponds to 'this' object. response.forward(this,"helloJSP",request); } } stapler-stapler-parent-1.231/core/example/src/example/Book.java0000664000175000017500000000165012414640747024040 0ustar ebourgebourgpackage example; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import java.io.IOException; /** * A book in the bookstore. * *

* In this example we define a few side JSP files to * define views of this object. See * /resources/WEB-INF/side-files/example/Book/*.jsp * * @author Kohsuke Kawaguchi */ public class Book extends Item { private String isbn; public Book(String isbn, String title) { super(isbn,title); this.isbn = isbn; } public String getIsbn() { return isbn; } /** * Defines an action to delete this book from the store. */ public void doDelete( StaplerRequest request, StaplerResponse response ) throws IOException, ServletException { BookStore.theStore.getItems().remove(getSku()); response.sendRedirect(request.getContextPath()+'/'); } } stapler-stapler-parent-1.231/core/example/src/example/WebAppMain.java0000664000175000017500000000111412414640747025124 0ustar ebourgebourgpackage example; import org.kohsuke.stapler.Stapler; import javax.servlet.ServletContextListener; import javax.servlet.ServletContextEvent; /** * This class is invoked by the container at the beginning * and at the end. * * @author Kohsuke Kawaguchi */ public class WebAppMain implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { // BookStore.theStore is the singleton instance of the application Stapler.setRoot(event,BookStore.theStore); } public void contextDestroyed(ServletContextEvent event) { } } stapler-stapler-parent-1.231/core/example/src/example/Track.java0000664000175000017500000000056612414640747024217 0ustar ebourgebourgpackage example; /** * A track of a CD. * * @author Kohsuke Kawaguchi */ public class Track { private String name; private int length; public Track(String name, int length) { this.name = name; this.length = length; } public String getName() { return name; } public int getLength() { return length; } } stapler-stapler-parent-1.231/core/example/src/example/Item.java0000664000175000017500000000121712414640747024043 0ustar ebourgebourgpackage example; /** * Item in the bookstore. * * This example shows the power of the polymorphic behavior that * Stapler enables. * * We have two kinds of Item in this system -- Book and CD. * They are both accessible by the same form of URL "/items/[sku]", * but their index.jsp are different. * * @author Kohsuke Kawaguchi */ public abstract class Item { private final String sku; private final String title; protected Item(String sku,String title) { this.sku = sku; this.title = title; } public String getSku() { return sku; } public String getTitle() { return title; } } stapler-stapler-parent-1.231/core/example/src/example/CD.java0000664000175000017500000000064112414640747023433 0ustar ebourgebourgpackage example; /** * @author Kohsuke Kawaguchi */ public class CD extends Item { private final Track[] tracks; public CD(String sku, String title, Track[] tracks ) { super(sku,title); this.tracks = tracks; } /** * Allocates the sub directory "track/[num]" to * the corresponding Track object. */ public Track[] getTracks() { return tracks; } } stapler-stapler-parent-1.231/core/example/build.xml0000664000175000017500000000146012414640747021701 0ustar ebourgebourg stapler-stapler-parent-1.231/core/example/WEB-INF/0000775000175000017500000000000012415270723021100 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/WEB-INF/side-files/0000775000175000017500000000000012414640747023132 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/0000775000175000017500000000000012414640747024565 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/CD/0000775000175000017500000000000012414640747025053 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/CD/index.jsp0000664000175000017500000000166212414640747026705 0ustar ebourgebourg<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@taglib prefix="st" uri="http://stapler.dev.java.net/" %> <%-- "index.jsp" is used to serve the URL of the object itself. In this example, this JSP is used to serve "/items/[id]/" --%> CD ${it.title} <%-- "it" variable is set to the target CD object by the Stapler. --%> Name: ${it.title}
SKU: ${it.sku}

Track list

  1. ${t.name}
<%-- st:include tag lets you include another side JSP from the inheritance hierarchy of the "it" object. Here, we are referring to the footer.jsp defined for the Item class, allowing CD and Book to share some JSPs. --%> stapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/BookStore/0000775000175000017500000000000012414640747026474 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/BookStore/index.jsp0000664000175000017500000000136712414640747030330 0ustar ebourgebourg<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- This side JSP for example.BookStore is used to serve the URL "/" --%> Book Store <%-- side files can include static resources. --%>

Inventory

${i.value.title}

Others

<%-- this jumps to another side file "count.jsp" --%> count inventory

invoke action method

<%-- resources files are served normally. --%> regular resources

stapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/BookStore/helloJSP.jsp0000664000175000017500000000021412414640747030667 0ustar ebourgebourg<%@ page contentType="text/html;charset=UTF-8" language="java" %> Current system time is ${systemTime} stapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/BookStore/count.jsp0000664000175000017500000000027212414640747030343 0ustar ebourgebourg<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <%-- An example of another side JSP. --%> # of items: ${fn:length(it.items)} stapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/BookStore/logo.png0000664000175000017500000000232712414640747030146 0ustar ebourgebourgPNG  IHDR+jgAMA aIDATx^Z"1 *ɉII ծ_k< e7?c5GH0G`J@a 0HX/ʒj_lEՆ'b5Thu^|~zjO Lgv#A EI SH FSN0r +HD$x :+BL$@䛮 uVԖA$6e&ah$F .H@OwS>*Iv>gf9nsӁu٠*6~r<{$SHnvu|K#|:NEIp]QSx&@>k.4 Jpnjo$v n##xtcO;: IFk]3 1 @bHy_NVTx.uڙ  :!V 5eF+F怌bmFHb1k ?ׁ_R}@Eϥ9p8V.X50o X)[t1Q$^* ={Dy+4S @!hֈWĈAAz#7 3rb{M>7B~Uׯ Ox8jjUTzc$3𢻱,@꯻ Vbn˓P ZA#%|ŔXrIzc4Z)aUkG~Ay )v bDB/WtyWzcF[K`;;$͕b#"AAPl(4.(@zcF[q*)f*C_ܭJ?6^Rh#_E8Vۦjօ fpw eI:7ƁӞT!x _<~\=b r@fFcXtzHFLRmmr pPԏ})"=VjnSlk mW qփ{)[R(qO|v1߰I 4e#NmH_4 ϡ}b&HODWF,xx#UE-M>k }$4g.j_[`,2eVfkimF]$"`A7 A ,8Q H-Xn`6HEjrߞPMIENDB`stapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/Book/0000775000175000017500000000000012414640747025457 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/Book/index.jsp0000664000175000017500000000127212414640747027306 0ustar ebourgebourg<%@taglib prefix="st" uri="http://stapler.dev.java.net/" %> <%-- "index.jsp" is used to serve the URL of the object itself. In this example, this JSP is used to serve "/items/[id]/" --%> Book ${it.title} <%-- "it" variable is set to the target Book object by the Stapler. --%> Name: ${it.title}
ISBN: ${it.isbn}
<%-- st:include tag lets you include another side JSP from the inheritance hierarchy of the "it" object. Here, we are referring to the footer.jsp defined for the Item class, allowing CD and Book to share some JSPs. --%> stapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/Item/0000775000175000017500000000000012414640747025463 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/Item/footer.jsp0000664000175000017500000000007312414640747027477 0ustar ebourgebourg
Common footer for ${it.title}
stapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/Track/0000775000175000017500000000000012414640747025631 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/WEB-INF/side-files/example/Track/index.jsp0000664000175000017500000000040412414640747027454 0ustar ebourgebourg Track ${it.name} Name: ${it.name}
<%-- because of the way we organize URL, going back to the parent CD objcet is as easy as this --%> back stapler-stapler-parent-1.231/core/example/WEB-INF/web.xml0000664000175000017500000000110112414640747022376 0ustar ebourgebourg Stapler org.kohsuke.stapler.Stapler Stapler / example.WebAppMain stapler-stapler-parent-1.231/core/example/resources/0000775000175000017500000000000012414640747022071 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/resources/help/0000775000175000017500000000000012414640747023021 5ustar ebourgebourgstapler-stapler-parent-1.231/core/example/resources/help/help.html0000664000175000017500000000034112414640747024635 0ustar ebourgebourg Resources can be placed normally, and they can be accessed normally. This is often useful for site-wide resources (such as images) and other static resources (like documentations) stapler-stapler-parent-1.231/core/src/0000775000175000017500000000000012414640747017213 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/0000775000175000017500000000000012414640747020172 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/0000775000175000017500000000000012414640747021113 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/org/0000775000175000017500000000000012414640747021702 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/0000775000175000017500000000000012414640747023353 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/0000775000175000017500000000000012414640747025025 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/MockServletContext.java0000664000175000017500000000417012414640747031475 0ustar ebourgebourgpackage org.kohsuke.stapler; import javax.servlet.ServletContext; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletException; import java.util.Set; import java.util.Enumeration; import java.net.URL; import java.net.MalformedURLException; import java.io.InputStream; /** * @author Kohsuke Kawaguchi */ public class MockServletContext implements ServletContext { public ServletContext getContext(String uripath) { return null; } public int getMajorVersion() { return 0; } public int getMinorVersion() { return 0; } public String getMimeType(String file) { return null; } public Set getResourcePaths(String s) { return null; } public URL getResource(String path) throws MalformedURLException { return null; } public InputStream getResourceAsStream(String path) { return null; } public RequestDispatcher getRequestDispatcher(String path) { return null; } public RequestDispatcher getNamedDispatcher(String name) { return null; } public Servlet getServlet(String name) throws ServletException { return null; } public Enumeration getServlets() { return null; } public Enumeration getServletNames() { return null; } public void log(String msg) { } public void log(Exception exception, String msg) { } public void log(String message, Throwable throwable) { } public String getRealPath(String path) { return null; } public String getServerInfo() { return null; } public String getInitParameter(String name) { return null; } public Enumeration getInitParameterNames() { return null; } public Object getAttribute(String name) { return null; } public Enumeration getAttributeNames() { return null; } public void setAttribute(String name, Object object) { } public void removeAttribute(String name) { } public String getServletContextName() { return null; } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/framework/0000775000175000017500000000000012414640747027022 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/framework/io/0000775000175000017500000000000012414640747027431 5ustar ebourgebourg././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/framework/io/WriterOutputStreamTest.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/framework/io/WriterOutputStreamT0000664000175000017500000000131412414640747033350 0ustar ebourgebourgpackage org.kohsuke.stapler.framework.io; import junit.framework.TestCase; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; /** * TODO: make it a real junit test * * @author jglick */ public class WriterOutputStreamTest extends TestCase { public void testFoo() {} // otherwise surefire will be unhappy public static void main(String[] args) throws IOException { OutputStream os = new WriterOutputStream(new OutputStreamWriter(System.out)); PrintStream ps = new PrintStream(os); for (int i = 0; i < 200; i++) { ps.println("#" + i + " blah blah blah"); } os.close(); } } ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/framework/io/LineEndNormalizingWriterTest.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/framework/io/LineEndNormalizingW0000664000175000017500000000176512414640747033244 0ustar ebourgebourgpackage org.kohsuke.stapler.framework.io; import junit.framework.TestCase; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; /** * @author Kohsuke Kawaguchi */ public class LineEndNormalizingWriterTest extends TestCase { public void test1() throws IOException { StringWriter sw = new StringWriter(); Writer w = new LineEndNormalizingWriter(sw); w.write("abc\r\ndef\r"); w.write("\n"); assertEquals(sw.toString(),"abc\r\ndef\r\n"); } public void test2() throws IOException { StringWriter sw = new StringWriter(); Writer w = new LineEndNormalizingWriter(sw); w.write("abc\ndef\n"); w.write("\n"); assertEquals(sw.toString(),"abc\r\ndef\r\n\r\n"); } public void test3() throws IOException { StringWriter sw = new StringWriter(); Writer w = new LineEndNormalizingWriter(sw); w.write("\r\n\n"); assertEquals(sw.toString(),"\r\n\r\n"); } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/ClassDescriptorTest.java0000664000175000017500000000623112414640747031636 0ustar ebourgebourgpackage org.kohsuke.stapler; import java.io.IOException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import static org.junit.Assert.*; import org.junit.Test; /** * @author Alan Harder */ public class ClassDescriptorTest { @Test public void loadConstructorParam() throws Exception { assertEquals(0,ClassDescriptor.loadParameterNames(C.class.getConstructor()).length); String[] names = ClassDescriptor.loadParameterNames(C.class.getConstructor(int.class, int.class, String.class)); assertEquals("[a, b, x]",Arrays.asList(names).toString()); } @Test public void loadParametersFromAsm() throws Exception { // get private method that is being tested Method lpfa = ClassDescriptor.class.getDeclaredClasses()[0].getDeclaredMethod( "loadParametersFromAsm", Method.class); lpfa.setAccessible(true); // collect test cases Map testCases = new HashMap(); for (Method m : ClassDescriptorTest.class.getDeclaredMethods()) if (m.getName().startsWith("methodWith")) testCases.put(m.getName().substring(10), m); // expected results Map expected = new HashMap(); expected.put("NoParams", new String[0]); expected.put("NoParams_static", new String[0]); expected.put("ManyParams", new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i" }); expected.put("Params_static", new String[] { "abc", "def", "ghi" }); // run tests for (Map.Entry entry : expected.entrySet()) { Method testMethod = testCases.get(entry.getKey()); assertNotNull("Method missing for " + entry.getKey(), testMethod); String[] result = (String[])lpfa.invoke(null, testMethod); assertNotNull("Null result for " + entry.getKey()); if (!Arrays.equals(entry.getValue(), result)) { StringBuilder buf = new StringBuilder('|'); for (String s : result) buf.append(s).append('|'); fail("Unexpected result for " + entry.getKey() + ": " + buf); } } } @Test public void inheritedWebMethods() throws Exception { // http://bugs.sun.com/view_bug.do?bug_id=6342411 assertEquals(1, new ClassDescriptor(Sub.class).methods.name("doDynamic").signature(StaplerRequest.class, StaplerResponse.class).size()); } public static class C { public C() {} public C(int a, int b, String x) {} } private void methodWithNoParams() { } private static void methodWithNoParams_static() { } private void methodWithManyParams(String a, boolean b, int c, long d, Boolean e, Integer f, Long g, Object h, ClassDescriptorTest i) { } private static void methodWithParams_static(String abc, long def, Object ghi) { } protected static abstract class Super { public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {} } public static class Sub extends Super {} } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/ResponseImplTest.java0000664000175000017500000000350612414640747031154 0ustar ebourgebourgpackage org.kohsuke.stapler; import org.kohsuke.stapler.test.AbstractStaplerTest; import javax.servlet.ServletOutputStream; import java.io.IOException; import static javax.servlet.http.HttpServletResponse.*; import static org.mockito.Mockito.*; /** * @author Kohsuke Kawaguchi */ public class ResponseImplTest { public static class RedirectTest extends AbstractStaplerTest { @Override protected void setUp() throws Exception { super.setUp(); when(rawRequest.getScheme()).thenReturn("http"); when(rawRequest.getServerName()).thenReturn("example.com"); when(rawRequest.getServerPort()).thenReturn(80); when(rawRequest.getRequestURI()).thenReturn("/foo/bar/zot"); when(rawResponse.getOutputStream()).thenReturn(new ServletOutputStream() { public void write(int b) throws IOException { throw new AssertionError(); } }); } public void testSendRedirectRelative() throws IOException { response.sendRedirect(SC_SEE_OTHER, "foobar"); verify(rawResponse).setStatus(SC_SEE_OTHER); verify(rawResponse).setHeader("Location", "http://example.com/foo/bar/foobar"); } public void testSendRedirectWithinHost() throws IOException { response.sendRedirect(SC_SEE_OTHER, "/foobar"); verify(rawResponse).setStatus(SC_SEE_OTHER); verify(rawResponse).setHeader("Location", "http://example.com/foobar"); } public void testSendRedirectAbsoluteURL() throws IOException { response.sendRedirect(SC_SEE_OTHER, "https://jenkins-ci.org/"); verify(rawResponse).setStatus(SC_SEE_OTHER); verify(rawResponse).setHeader("Location", "https://jenkins-ci.org/"); } } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/MockRequest.java0000664000175000017500000001445012414640747030136 0ustar ebourgebourgpackage org.kohsuke.stapler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Cookie; import javax.servlet.http.HttpSession; import javax.servlet.ServletInputStream; import javax.servlet.RequestDispatcher; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Locale; import java.security.Principal; import java.io.UnsupportedEncodingException; import java.io.IOException; import java.io.BufferedReader; /** * @author Kohsuke Kawaguchi */ public class MockRequest implements HttpServletRequest { public String getAuthType() { // TODO throw new UnsupportedOperationException(); } public Cookie[] getCookies() { // TODO throw new UnsupportedOperationException(); } public long getDateHeader(String name) { // TODO throw new UnsupportedOperationException(); } public String getHeader(String name) { // TODO throw new UnsupportedOperationException(); } public Enumeration getHeaders(String name) { // TODO throw new UnsupportedOperationException(); } public Enumeration getHeaderNames() { // TODO throw new UnsupportedOperationException(); } public int getIntHeader(String name) { // TODO throw new UnsupportedOperationException(); } public String getMethod() { // TODO throw new UnsupportedOperationException(); } public String getPathInfo() { // TODO throw new UnsupportedOperationException(); } public String getPathTranslated() { // TODO throw new UnsupportedOperationException(); } public String getContextPath() { // TODO throw new UnsupportedOperationException(); } public String getQueryString() { // TODO throw new UnsupportedOperationException(); } public String getRemoteUser() { // TODO throw new UnsupportedOperationException(); } public boolean isUserInRole(String role) { // TODO throw new UnsupportedOperationException(); } public Principal getUserPrincipal() { // TODO throw new UnsupportedOperationException(); } public String getRequestedSessionId() { // TODO throw new UnsupportedOperationException(); } public String getRequestURI() { return ""; } public StringBuffer getRequestURL() { // TODO throw new UnsupportedOperationException(); } public String getServletPath() { // TODO throw new UnsupportedOperationException(); } public HttpSession getSession(boolean create) { // TODO throw new UnsupportedOperationException(); } public HttpSession getSession() { // TODO throw new UnsupportedOperationException(); } public boolean isRequestedSessionIdValid() { // TODO throw new UnsupportedOperationException(); } public boolean isRequestedSessionIdFromCookie() { // TODO throw new UnsupportedOperationException(); } public boolean isRequestedSessionIdFromURL() { // TODO throw new UnsupportedOperationException(); } public boolean isRequestedSessionIdFromUrl() { // TODO throw new UnsupportedOperationException(); } public Object getAttribute(String name) { // TODO throw new UnsupportedOperationException(); } public Enumeration getAttributeNames() { // TODO throw new UnsupportedOperationException(); } public String getCharacterEncoding() { // TODO throw new UnsupportedOperationException(); } public void setCharacterEncoding(String s) throws UnsupportedEncodingException { // TODO throw new UnsupportedOperationException(); } public int getContentLength() { // TODO throw new UnsupportedOperationException(); } public String getContentType() { // TODO throw new UnsupportedOperationException(); } public ServletInputStream getInputStream() throws IOException { // TODO throw new UnsupportedOperationException(); } public Map parameters = new HashMap(); public String getParameter(String name) { return parameters.get(name); } public Enumeration getParameterNames() { // TODO throw new UnsupportedOperationException(); } public String[] getParameterValues(String name) { String v = getParameter(name); if (v==null) return new String[0]; return new String[]{v}; } public Map getParameterMap() { return parameters; } public String getProtocol() { // TODO throw new UnsupportedOperationException(); } public String getScheme() { // TODO throw new UnsupportedOperationException(); } public String getServerName() { // TODO throw new UnsupportedOperationException(); } public int getServerPort() { // TODO throw new UnsupportedOperationException(); } public BufferedReader getReader() throws IOException { // TODO throw new UnsupportedOperationException(); } public String getRemoteAddr() { // TODO throw new UnsupportedOperationException(); } public String getRemoteHost() { // TODO throw new UnsupportedOperationException(); } public void setAttribute(String name, Object o) { // TODO throw new UnsupportedOperationException(); } public void removeAttribute(String name) { // TODO throw new UnsupportedOperationException(); } public Locale getLocale() { // TODO throw new UnsupportedOperationException(); } public Enumeration getLocales() { // TODO throw new UnsupportedOperationException(); } public boolean isSecure() { // TODO throw new UnsupportedOperationException(); } public RequestDispatcher getRequestDispatcher(String path) { // TODO throw new UnsupportedOperationException(); } public String getRealPath(String path) { // TODO throw new UnsupportedOperationException(); } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/ObjectWithCustomConverter.java0000664000175000017500000000117312414640747033017 0ustar ebourgebourgpackage org.kohsuke.stapler; import org.apache.commons.beanutils.Converter; /** * @author Kohsuke Kawaguchi */ public class ObjectWithCustomConverter { public final int x,y; public ObjectWithCustomConverter(int x, int y) { this.x = x; this.y = y; } public static class StaplerConverterImpl implements Converter { public Object convert(Class type, Object value) { String[] tokens = value.toString().split(","); return new ObjectWithCustomConverter( Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1])); } } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/StaplerTest.java0000664000175000017500000000611712414640747030147 0ustar ebourgebourgpackage org.kohsuke.stapler; import junit.framework.TestCase; import java.io.File; import java.net.URL; import java.util.Arrays; /** * @author Kohsuke Kawaguchi */ public class StaplerTest extends TestCase { public void testNormalization() { assertIdemPotent("/"); assertIdemPotent(""); assertIdemPotent("/foo"); assertIdemPotent("/bar/"); assertIdemPotent("zot/"); testC12n("","."); testC12n("","foo/.."); testC12n("foo", "foo/bar/./.."); testC12n("/abc","/abc"); testC12n("/abc/","/abc/"); testC12n("/","/abc/../"); testC12n("/","/abc/def/../../"); testC12n("/def","/abc/../def"); testC12n("/xxx","/../../../xxx"); } private void testC12n(String expected, String input) { assertEquals(expected, Stapler.canonicalPath(input)); } private void assertIdemPotent(String str) { assertEquals(str,Stapler.canonicalPath(str)); } private void assertToFile(String s, URL... urls) { for (URL url : urls) assertEquals(s,new Stapler().toFile(url).getPath()); } public void testToFileOnWindows() throws Exception { if (File.pathSeparatorChar==':') return; // this is Windows only test // these two URLs has the same toExternalForm(), but it'll have different components String a = "\\\\vboxsvr\\root"; assertToFile(a, new URL("file://vboxsvr/root/"), new File(a).toURL() ); // whitespace + UNC a = "\\\\vboxsvr\\root\\documents and files"; assertToFile(a, new URL("file://vboxsvr/root/documents and files"), new URL("file://vboxsvr/root/documents%20and%20files"), new File(a).toURL() ); // whitespace for (String path : Arrays.asList("","Documents and files","Documents%20and%20Files")) { assertToFile("c:\\"+path.replace("%20"," "), new URL("file:///c:/"+path), new URL("file://c:/"+path), new URL("file:/c:/"+path) ); assertToFile(path.length()==0 ? "\\\\vboxsvr" : "\\\\vboxsvr\\"+path.replace("%20"," "), new URL("file://vboxsvr/"+path), new URL("file:////vboxsvr/"+path) ); } } public void testToFileOnUnix() throws Exception { if (File.pathSeparatorChar==';') return; // this is Unix only test // these two URLs has the same toExternalForm(), but it'll have different components String a = "/tmp/foo"; assertToFile(a, new URL("file:///tmp/foo/"), new URL("file://tmp/foo/"), new URL("file:/tmp/foo/") ); // whitespace for (String path : Arrays.asList("foo bar","foo%20bar")) { assertToFile("/tmp/"+path.replace("%20"," "), new URL("file:///tmp/"+path), new URL("file://tmp/"+path), new URL("file:/tmp/"+path) ); } } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/bind/0000775000175000017500000000000012414640747025741 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/bind/BoundObjectTableTest.java0000664000175000017500000000230212414640747032607 0ustar ebourgebourgpackage org.kohsuke.stapler.bind; import com.gargoylesoftware.htmlunit.TextPage; import com.gargoylesoftware.htmlunit.WebClient; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.test.JettyTestCase; import java.io.IOException; import java.net.URL; /** * @author Kohsuke Kawaguchi */ public class BoundObjectTableTest extends JettyTestCase { /** * Exports an object and see if it can be reached. */ public void testExport() throws Exception { TextPage page = new WebClient().getPage(new URL(url, "/bind")); assertEquals("hello world",page.getContent()); } public HttpResponse doBind() throws IOException { Bound h = webApp.boundObjectTable.bind(new HelloWorld("hello world")); System.out.println(h.getURL()); return h; } public static class HelloWorld { private final String message; public HelloWorld(String message) { this.message = message; } public void doIndex(StaplerResponse rsp) throws IOException { rsp.setContentType("text/plain;charset=UTF-8"); rsp.getWriter().write(message); } } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/bind/JavaScriptProxyTest.java0000664000175000017500000000652112414640747032560 0ustar ebourgebourgpackage org.kohsuke.stapler.bind; import com.gargoylesoftware.htmlunit.AlertHandler; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.test.JettyTestCase; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; /** * @author Kohsuke Kawaguchi */ public class JavaScriptProxyTest extends JettyTestCase { private String anonymousValue; private Object anonymous = new MyObject(); /** * Exports an object and see if it can be reached. */ public void testBind() throws Exception { final String[] msg = new String[1]; // for interactive debugging // System.out.println(url); // System.in.read(); WebClient wc = new WebClient(); wc.setAlertHandler(new AlertHandler() { public void handleAlert(Page page, String message) { msg[0] = message; } }); HtmlPage page = wc.getPage(new URL(url, "/")); page.executeJavaScript("v.foo(3,'test',callback);"); assertEquals("string:test3",msg[0]); msg[0] = null; // test null unmarshalling and marshalling page.executeJavaScript("v.foo(0,null,callback);"); assertEquals("object:null",msg[0]); } /** * Tests that an anonymous object can be bound. */ public void testAnonymousBind() throws Exception { WebClient wc = new WebClient(); HtmlPage page = wc.getPage(new URL(url, "/bindAnonymous")); page.executeJavaScript("v.xyz('hello');"); assertEquals("hello",anonymousValue); } public String jsFoo(int x, String y) { if (x==0) return y; return y+x; } public void doIndex(StaplerRequest req,StaplerResponse rsp) throws IOException { rsp.setContentType("text/html"); String crumb = req.getWebApp().getCrumbIssuer().issueCrumb(); PrintWriter w = rsp.getWriter(); w.println(""); w.println(""); w.println(""); } public void doBindAnonymous(StaplerResponse rsp) throws IOException { rsp.setContentType("text/html"); PrintWriter w = rsp.getWriter(); w.println(""); w.println(""); w.println(""); } public HttpResponse doPrototype() { return HttpResponses.staticResource(getClass().getResource("/org/kohsuke/stapler/framework/prototype/prototype.js")); } public HttpResponse doScript() { return HttpResponses.staticResource(getClass().getResource("/org/kohsuke/stapler/bind.js")); } public class MyObject { public void jsXyz(String s) { anonymousValue = s; } } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/test/0000775000175000017500000000000012414640747026004 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/test/AbstractStaplerTest.java0000664000175000017500000000040212414640747032601 0ustar ebourgebourgpackage org.kohsuke.stapler.test; import org.kohsuke.stapler.AbstractStaplerTestBase; /** * Just to make the class visible in the test package. * @author Kohsuke Kawaguchi */ public abstract class AbstractStaplerTest extends AbstractStaplerTestBase { } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/test/package-info.java0000664000175000017500000000011112414640747031164 0ustar ebourgebourg/** * Reusable test utility code. */ package org.kohsuke.stapler.test; stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/test/JettyTestCase.java0000664000175000017500000000316612414640747031410 0ustar ebourgebourgpackage org.kohsuke.stapler.test; import junit.framework.TestCase; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.WebApp; import org.mortbay.jetty.Server; import org.mortbay.jetty.bio.SocketConnector; import org.mortbay.jetty.servlet.Context; import org.mortbay.jetty.servlet.ServletHolder; import org.mortbay.jetty.webapp.WebAppContext; import javax.servlet.ServletContext; import java.net.URL; /** * Base test case for embedded Jetty. * * @author Kohsuke Kawaguchi */ public abstract class JettyTestCase extends TestCase { protected Server server; /** * The top URL of this test web application. */ protected URL url; protected Stapler stapler; protected ServletContext servletContext; protected WebApp webApp; @Override protected void setUp() throws Exception { super.setUp(); server = new Server(); server.setHandler(new WebAppContext("/noroot", "")); final Context context = new Context(server, "", Context.SESSIONS); context.addServlet(new ServletHolder(new Stapler()), "/*"); server.setHandler(context); SocketConnector connector = new SocketConnector(); server.addConnector(connector); server.start(); url = new URL("http://localhost:"+connector.getLocalPort()+"/"); servletContext = context.getServletContext(); webApp = WebApp.get(servletContext); // export the test object as the root as a reasonable default. webApp.setApp(this); } @Override protected void tearDown() throws Exception { super.tearDown(); server.stop(); } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/ServletConfigImpl.java0000664000175000017500000000110712414640747031263 0ustar ebourgebourgpackage org.kohsuke.stapler; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import java.util.Enumeration; /** * @author Kohsuke Kawaguchi */ public class ServletConfigImpl implements ServletConfig { ServletContext context = new MockServletContext(); public String getServletName() { return ""; } public ServletContext getServletContext() { return context; } public String getInitParameter(String name) { return null; } public Enumeration getInitParameterNames() { return null; } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/HttpResponseRendererTest.java0000664000175000017500000000410512414640747032655 0ustar ebourgebourg/* * Copyright (c) 2013, Jesse Glick * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * 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 HOLDER 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. */ package org.kohsuke.stapler; import net.sf.json.JSONArray; import org.junit.Test; import static org.junit.Assert.*; public class HttpResponseRendererTest { @Test public void quoteSimple() { testQuoteOn("foo"); } @Test public void quoteBackslash() { testQuoteOn("to sleep \\ perchance to dream"); } @Test public void quoteQuotes() { testQuoteOn("this \"thing\" should work"); } @Test public void quoteNewlines() { testQuoteOn("one line\nsecond line"); } private static void testQuoteOn(String text) { String quoted = HttpResponseRenderer.quote(text); assertEquals(text + " → " + quoted, text, JSONArray.fromObject("[" + quoted + "]").getString(0)); } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/AbstractStaplerTestBase.java0000664000175000017500000000313712414640747032425 0ustar ebourgebourgpackage org.kohsuke.stapler; import junit.framework.TestCase; import org.kohsuke.stapler.test.AbstractStaplerTest; import org.mockito.Mockito; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; /** * This class needs to be in this package to access package-protected stuff. * You should extend from {@link AbstractStaplerTest}. * * @author Kohsuke Kawaguchi */ public abstract class AbstractStaplerTestBase extends TestCase { protected WebApp webApp; protected RequestImpl request; protected ResponseImpl response; protected Stapler stapler = new Stapler(); protected HttpServletRequest rawRequest; protected HttpServletResponse rawResponse; @Override protected void setUp() throws Exception { super.setUp(); ServletContext servletContext = Mockito.mock(ServletContext.class); webApp = new WebApp(servletContext); ServletConfig servletConfig = Mockito.mock(ServletConfig.class); Mockito.when(servletConfig.getServletContext()).thenReturn(servletContext); stapler.init(servletConfig); rawRequest = Mockito.mock(HttpServletRequest.class); rawResponse = Mockito.mock(HttpServletResponse.class); this.request = new RequestImpl(stapler, rawRequest,new ArrayList(),new TokenList("")); Stapler.CURRENT_REQUEST.set(this.request); this.response = new ResponseImpl(stapler, rawResponse); Stapler.CURRENT_RESPONSE.set(this.response); } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/NestedJsonTest.java0000664000175000017500000000501712414640747030607 0ustar ebourgebourgpackage org.kohsuke.stapler; import junit.framework.TestCase; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import javax.servlet.ServletException; import java.util.Collections; import java.util.List; /** * Tests the instantiation of nested objects. * * @author Kohsuke Kawaguchi */ public class NestedJsonTest extends TestCase { public static final class Foo { public Bar bar; @DataBoundConstructor public Foo(Bar bar) { this.bar = bar; } } public static interface Bar {} public static final class BarImpl implements Bar { public final int i; @DataBoundConstructor public BarImpl(int i) { this.i = i; } } public void testCreateObject() throws Exception { Foo o = createRequest().bindJSON(Foo.class, createDataSet()); assertNotNull(o); assertTrue(o.bar instanceof BarImpl); assertEquals(123, ((BarImpl)o.bar).i); } public void testInstanceFill() throws Exception { Foo o = new Foo(null); createRequest().bindJSON(o, createDataSet()); assertTrue(o.bar instanceof BarImpl); assertEquals(123, ((BarImpl)o.bar).i); } public void testCreateList() throws Exception { // Just one List list = createRequest().bindJSONToList(Foo.class, createDataSet()); assertNotNull(list); assertEquals(1, list.size()); assertTrue(list.get(0).bar instanceof BarImpl); assertEquals(123, ((BarImpl)list.get(0).bar).i); // Longer list JSONArray data = new JSONArray(); data.add(createDataSet()); data.add(createDataSet()); data.add(createDataSet()); list = createRequest().bindJSONToList(Foo.class, data); assertNotNull(list); assertEquals(3, list.size()); assertEquals(123, ((BarImpl)list.get(2).bar).i); } private RequestImpl createRequest() throws Exception { return new RequestImpl(createStapler(), new MockRequest(), Collections.EMPTY_LIST,null); } private JSONObject createDataSet() { JSONObject bar = new JSONObject(); bar.put("i",123); JSONObject foo = new JSONObject(); foo.put("bar",bar); foo.getJSONObject("bar").put("stapler-class", BarImpl.class.getName()); return foo; } private Stapler createStapler() throws ServletException { Stapler stapler = new Stapler(); stapler.init(new ServletConfigImpl()); return stapler; } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/interceptor/0000775000175000017500000000000012414640747027363 5ustar ebourgebourg././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/interceptor/JsonOutputFilterTest.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/interceptor/JsonOutputFilterTest0000664000175000017500000001225312414640747033451 0ustar ebourgebourgpackage org.kohsuke.stapler.interceptor; import com.gargoylesoftware.htmlunit.AlertHandler; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.bind.JavaScriptMethod; import org.kohsuke.stapler.test.JettyTestCase; import org.mortbay.util.ajax.JSON; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import java.util.Arrays; import java.util.List; import java.util.Map; /** * Tests {@link JsonOutputFilter}. * * @author Robert Sandell <sandell.robert@gmail.com> */ public class JsonOutputFilterTest extends JettyTestCase { public void testExclude() throws Exception { final String[] msg = new String[1]; WebClient wc = new WebClient(); wc.setAlertHandler(new AlertHandler() { public void handleAlert(Page page, String message) { msg[0] = message; } }); HtmlPage page = wc.getPage(new URL(url, "/")); page.executeJavaScript("v.getSomeExcludedData(callback);"); Map json = (Map)JSON.parse(msg[0]); assertTrue(json.containsKey("name")); assertTrue(json.containsKey("description")); assertFalse(json.containsKey("secret")); } public void testInclude() throws Exception { final String[] msg = new String[1]; WebClient wc = new WebClient(); wc.setAlertHandler(new AlertHandler() { public void handleAlert(Page page, String message) { msg[0] = message; } }); HtmlPage page = wc.getPage(new URL(url, "/")); page.executeJavaScript("v.getSomeIncludedData(callback);"); Map json = (Map)JSON.parse(msg[0]); assertTrue(json.containsKey("name")); assertFalse(json.containsKey("description")); assertFalse(json.containsKey("secret")); } public void testExcludeList() throws Exception { final String[] msg = new String[1]; WebClient wc = new WebClient(); wc.setAlertHandler(new AlertHandler() { public void handleAlert(Page page, String message) { msg[0] = message; } }); HtmlPage page = wc.getPage(new URL(url, "/")); page.executeJavaScript("v.getSomeExcludedList(callback);"); Object[] json = (Object[])JSON.parse(msg[0]); assertEquals(3, json.length); for (Object o : json) { Map map = (Map)o; assertTrue(map.containsKey("name")); assertTrue(map.containsKey("description")); assertFalse(map.containsKey("secret")); } } @JsonOutputFilter(excludes = {"secret"}) @JavaScriptMethod public MyData getSomeExcludedData() { return new MyData("Bob", "the builder", "super secret value"); } @JsonOutputFilter(excludes = {"secret"}) @JavaScriptMethod public List getSomeExcludedList() { return Arrays.asList(new MyData("Bob", "the builder", "super secret value"), new MyData("Lisa", "the coder", "even more super secret"), new MyData("Jenkins", "the butler", "really secret as well")); } @JsonOutputFilter(includes = {"name"}) @JavaScriptMethod public MyData getSomeIncludedData() { return new MyData("Bob", "the builder", "super secret value"); } public void doIndex(StaplerResponse rsp) throws IOException { rsp.setContentType("text/html"); PrintWriter w = rsp.getWriter(); w.println(""); w.println(""); w.println(""); w.println(""); } public HttpResponse doPrototype() { return HttpResponses.staticResource(getClass().getResource("/org/kohsuke/stapler/framework/prototype/prototype.js")); } public HttpResponse doScript() { return HttpResponses.staticResource(getClass().getResource("/org/kohsuke/stapler/bind.js")); } public static class MyData { private String name; private String description; private String secret; public MyData(String name, String description, String secret) { this.name = name; this.description = description; this.secret = secret; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getSecret() { return secret; } public void setSecret(String secret) { this.secret = secret; } } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/export/0000775000175000017500000000000012414640747026346 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/export/XMLDataWriterTest.java0000664000175000017500000000677312414640747032515 0ustar ebourgebourgpackage org.kohsuke.stapler.export; import junit.framework.TestCase; import org.xml.sax.InputSource; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; public class XMLDataWriterTest extends TestCase { public XMLDataWriterTest(String n) { super(n); } private static String serialize(T bean, Class clazz) throws IOException { StringWriter w = new StringWriter(); Model model = new ModelBuilder().get(clazz); model.writeTo(bean, Flavor.XML.createDataWriter(bean, w)); return w.toString(); } @ExportedBean public static class X { @Exported public String a = "aval"; public String b = "bval"; @Exported public String getC() {return "cval";} public String getD() {return "dval";} } public void testSimpleUsage() throws Exception { assertEquals("avalcval", serialize(new X(), X.class)); } @ExportedBean(defaultVisibility=2) public static abstract class Super { @Exported public String basic = "super"; @Exported public abstract String generic(); } public static class Sub extends Super { public String generic() {return "sub";} @Exported public String specific() {return "sub";} } @ExportedBean public static class Container { @Exported public Super polymorph = new Sub(); } public void testInheritance() throws Exception { assertEquals("supersub" + "sub", serialize(new Container(), Container.class)); } public static class Sub2 extends Super { @Exported @Override public String generic() {return "sub2";} } public void testInheritance2() throws Exception { // JENKINS-13336 assertEquals("supersub2", serialize(new Sub2(), Sub2.class)); } private void assertValidXML(String s) throws Exception { SAXParser p = SAXParserFactory.newInstance().newSAXParser(); p.parse(new InputSource(new StringReader(s)),new DefaultHandler()); } /** * Can we write out anonymous classes as the root object? */ public void testAnonymousClass() throws Exception { assertValidXML(serialize(new X() {},X.class)); } @ExportedBean public static class PA { @Exported public int[] v = new int[]{1,2,3}; } public void testPrimitiveArrays() throws Exception { assertEquals("123",serialize(new PA(),PA.class)); } public void testMakeXmlName() { assertEquals("_", XMLDataWriter.makeXmlName("")); assertEquals("abc", XMLDataWriter.makeXmlName("abc")); assertEquals("abc", XMLDataWriter.makeXmlName("/abc")); assertEquals("abc", XMLDataWriter.makeXmlName("/a/b/c/")); } @ExportedBean public static class Arrays { @Exported public String[] categories = {"general", "specific"}; @Exported public String[] styles = {"ornate", "plain"}; } public void testToSingular() throws Exception { assertEquals("generalspecific", serialize(new Arrays(), Arrays.class)); } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/export/RangeTest.java0000664000175000017500000000235312414640747031110 0ustar ebourgebourgpackage org.kohsuke.stapler.export; import com.google.common.collect.Iterables; import org.junit.Assert; import org.junit.Test; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; public class RangeTest extends Assert { String[] array = new String[]{"a", "b", "c", "d", "e", "f"}; List list = Arrays.asList(array); Set set = new LinkedHashSet(list); @Test public void normalRange() { Range r = new Range(2,4); assertEquals("[c, d]", toS(r.apply(array))); assertEquals("[c, d]", toS(r.apply(list))); assertEquals("[c, d]", toS(r.apply(set))); } @Test public void maxOnlyRange() { Range r = new Range(-1,2); assertEquals("[a, b]", toS(r.apply(array))); assertEquals("[a, b]", toS(r.apply(list))); assertEquals("[a, b]", toS(r.apply(set))); } @Test public void minOnlyRange() { Range r = new Range(4,Integer.MAX_VALUE); assertEquals("[e, f]", toS(r.apply(array))); assertEquals("[e, f]", toS(r.apply(list))); assertEquals("[e, f]", toS(r.apply(set))); } private String toS(Iterable i) { return Iterables.toString(i); } }stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/export/NamedPathPrunerTest.java0000664000175000017500000001020412414640747033103 0ustar ebourgebourgpackage org.kohsuke.stapler.export; import java.io.StringWriter; import java.util.Arrays; import java.util.List; import junit.framework.TestCase; public class NamedPathPrunerTest extends TestCase { public NamedPathPrunerTest(String name) { super(name); } public void testParse() throws Exception { assertEquals("{a={}, b={c={}}}", NamedPathPruner.parse("a,b[c]").toString()); assertEquals("{a={}, b={c={}, d={}}}", NamedPathPruner.parse("a,b[c,d]").toString()); assertEquals("{a={}, b={c={}, d={}}, e={}}", NamedPathPruner.parse("a,b[c,d],e").toString()); assertEquals("{a={}, b={c={}, d={}}, e={}}", NamedPathPruner.parse("a,b[c,d]{,10},e").toString()); assertParseError(""); assertParseError("a,"); assertParseError(",b"); assertParseError("a["); assertParseError("a[b,c"); assertParseError("a[]"); assertParseError("a[b,,]"); assertParseError("a]"); assertParseError("a{}"); assertParseError("a{b}"); } private static void assertParseError(String spec) { try { NamedPathPruner.parse(spec); fail(); } catch (IllegalArgumentException x) { // pass } } public void testPruning() throws Exception { Jhob job1 = new Jhob("job1", "Job #1", "whatever"); Jhob job2 = new Jhob("job2", "Job #2", "junk"); Vhew view1 = new Vhew("All", "crap", new Jhob[] {job1, job2}); Vhew view2 = new Vhew("Some", "less", new Jhob[] {job1}); Stuff bean = new Stuff(new Jhob[] {job1, job2}, Arrays.asList(view1, view2)); assertResult("{jobs:[{displayName:Job #1,name:job1},{displayName:Job #2,name:job2}]," + "views:[{jobs:[{name:job1},{name:job2}],name:All},{jobs:[{name:job1}],name:Some}]}", bean, "jobs[name,displayName],views[name,jobs[name]]"); assertResult("{jobs:[{displayName:Job #1,name:job1}],views:[{jobs:[],name:All}," + "{jobs:[],name:Some}]}", bean, "jobs[name,displayName]{,1},views[name,jobs[name]{,0}]"); } public void testRange() throws Exception { Jhob[] jobs = new Jhob[100]; for (int i=0; i views; public Stuff(Jhob[] jobs, List views) { this.jobs = jobs.clone(); this.views = views; } } @ExportedBean public static class Jhob { @Exported public String name; @Exported public String displayName; @Exported public String trash; public Jhob(String name, String displayName, String trash) { this.name = name; this.displayName = displayName; this.trash = trash; } } @ExportedBean public static class Vhew { @Exported public String name; @Exported public String trash; @Exported public Jhob[] jobs; public Vhew(String name, String trash, Jhob[] jobs) { this.name = name; this.trash = trash; this.jobs = jobs.clone(); } } @SuppressWarnings({"unchecked", "rawtypes"}) // API design flaw prevents this from type-checking private static void assertResult(String expected, Object bean, String spec) throws Exception { Model model = new ModelBuilder().get(bean.getClass()); StringWriter w = new StringWriter(); model.writeTo(bean, new NamedPathPruner(spec), Flavor.JSON.createDataWriter(bean, w)); assertEquals(expected, w.toString().replace("\\\"", "").replace("\"", "")); } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/export/SchemaGeneratorTest.java0000664000175000017500000000553012414640747033123 0ustar ebourgebourg/* * Copyright (c) 2012, Jesse Glick * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * 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 HOLDER 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. */ package org.kohsuke.stapler.export; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.StringReader; import java.io.StringWriter; import javax.xml.XMLConstants; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.SchemaFactory; import static org.junit.Assert.*; import org.junit.Test; import org.xml.sax.SAXParseException; public class SchemaGeneratorTest { @Test public void basics() throws Exception { validate(new XMLDataWriterTest.X(), XMLDataWriterTest.X.class); } /* TODO currently fails @Test public void inheritance() throws Exception { validate(new XMLDataWriterTest.Container(), XMLDataWriterTest.Container.class); } */ private static void validate(T bean, Class clazz) throws Exception { Model model = new ModelBuilder().get(clazz); ByteArrayOutputStream schema = new ByteArrayOutputStream(); new SchemaGenerator(model).generateSchema(new StreamResult(schema)); StringWriter xml = new StringWriter(); model.writeTo(bean, Flavor.XML.createDataWriter(bean, xml)); try { SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(new StreamSource(new ByteArrayInputStream(schema.toByteArray()))).newValidator().validate(new StreamSource(new StringReader(xml.toString()))); } catch (SAXParseException x) { fail(x + "\n" + xml + "\n" + schema); } } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/DataBindingTest.java0000664000175000017500000002400512414640747030675 0ustar ebourgebourgpackage org.kohsuke.stapler; import junit.framework.TestCase; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import javax.annotation.PostConstruct; import java.lang.reflect.Type; import java.net.Proxy; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; /** * @author Kohsuke Kawaguchi */ public class DataBindingTest extends TestCase { public class Data { public int a; String myB; public void setB(String s) { myB = s; } } public void test1() { JSONObject json = new JSONObject(); json.put("a",123); json.put("b","string"); Data data = bind(json, new Data()); assertEquals(123,data.a); assertEquals("string",data.myB); } public class DataEnumSet { public EnumSet set; } public void testEnumSet() { JSONObject json = new JSONObject(); json.put("DIRECT",false); json.put("HTTP",true); json.put("SOCKS",null); JSONObject container = new JSONObject(); container.put("set",json); DataEnumSet data = bind(container,new DataEnumSet()); assertTrue(data.set.contains(Proxy.Type.HTTP)); assertFalse(data.set.contains(Proxy.Type.DIRECT)); assertFalse(data.set.contains(Proxy.Type.SOCKS)); } public void testFromStaplerMethod() throws Exception { MockRequest mr = new MockRequest(); mr.getParameterMap().put("a","123"); mr.getParameterMap().put("b","string"); RequestImpl req = new RequestImpl(new Stapler(), mr, Collections.emptyList(), null); new Function.InstanceFunction(getClass().getMethod("doFromStaplerMethod",StaplerRequest.class,int.class,Binder.class)) .bindAndInvoke(this,req,null); } public void doFromStaplerMethod(StaplerRequest req, @QueryParameter int a, Binder b) { assertEquals(123,a); assertSame(req,b.req); assertEquals("string",b.b); } public static class Binder { StaplerRequest req; String b; @CapturedParameterNames({"req","b"}) public static Binder fromStapler(StaplerRequest req, @QueryParameter String b) { Binder r = new Binder(); r.req = req; r.b = b; return r; } } public void testCustomConverter() throws Exception { ReferToObjectWithCustomConverter r = bind("{data:'1,2'}", ReferToObjectWithCustomConverter.class); assertEquals(r.data.x,1); assertEquals(r.data.y,2); } public static class ReferToObjectWithCustomConverter { final ObjectWithCustomConverter data; @DataBoundConstructor public ReferToObjectWithCustomConverter(ObjectWithCustomConverter data) { this.data = data; } } public void testNullToFalse() throws Exception { TwoBooleans r = bind("{a:false}", TwoBooleans.class); assertFalse(r.a); assertFalse(r.b); } public static class TwoBooleans { private boolean a,b; @DataBoundConstructor public TwoBooleans(boolean a, boolean b) { this.a = a; this.b = b; } } public void testScalarToArray() throws Exception { ScalarToArray r = bind("{a:'x',b:'y',c:5,d:6}", ScalarToArray.class); assertEquals("x",r.a[0]); assertEquals("y",r.b.get(0)); assertEquals(5,(int)r.c[0]); assertEquals(6,(int)r.d.get(0)); } public static class ScalarToArray { private String[] a; private List b; private Integer[] c; private List d; @DataBoundConstructor public ScalarToArray(String[] a, List b, Integer[] c, List d) { this.a = a; this.b = b; this.c = c; this.d = d; } } private T bind(String json, Class type) { return bind(json,type,BindInterceptor.NOOP); } private T bind(String json, Class type, BindInterceptor bi) { RequestImpl req = createFakeRequest(); req.setBindInterceptpr(bi); return req.bindJSON(type, JSONObject.fromObject(json)); } private RequestImpl createFakeRequest() { Stapler s = new Stapler(); s.setWebApp(new WebApp(null)); return new RequestImpl(s, new MockRequest(), Collections.emptyList(), null); } private T bind(JSONObject json, T bean) { RequestImpl req = createFakeRequest(); req.bindJSON(bean,json); return bean; } public static class RawBinding { JSONObject x; JSONArray y; @DataBoundConstructor public RawBinding(JSONObject x, JSONArray y) { this.x = x; this.y = y; } } public void testRaw() { RawBinding r = bind("{x:{a:true,b:1},y:[1,2,3]}", RawBinding.class); // array coersion on y RawBinding r2 = bind("{x:{a:true,b:1},y:{p:true}}", RawBinding.class); JSONObject o = (JSONObject)r2.y.get(0); assertTrue(o.getBoolean("p")); // array coersion on y RawBinding r3 = bind("{x:{a:true,b:1},y:true}", RawBinding.class); assertTrue((Boolean)r3.y.get(0)); } public static class SetterBinding { private int w,x,y,z; private Object o; private List children; @DataBoundConstructor public SetterBinding(int x, int y) { this.x = x; this.y = y; } /** * Setter not annotated with {@link DataBoundSetter}, so it should be ignored */ public void setW(int w) { this.w = w; } @DataBoundSetter public void setZ(int z) { this.z = z; } /** * We expect y to be set through constructor */ @DataBoundSetter public void setY(int y) { throw new IllegalArgumentException(); } @DataBoundSetter public void setAnotherObject(Object o) { this.o = o; } @DataBoundSetter public void setChildren(List children) { this.children = children; } } public static class Point { int x,y; @DataBoundConstructor public Point(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Point rhs = (Point) o; return x == rhs.x && y == rhs.y; } @Override public int hashCode() { int result = x; result = 31 * result + y; return result; } } public void testSetterInvocation() { SetterBinding r = bind("{x:1,y:2,z:3,w:1, children:[{x:5,y:5,z:5},{x:6,y:6,z:6}], anotherObject:{stapler-class:'org.kohsuke.stapler.DataBindingTest$Point', x:1,y:1} }",SetterBinding.class); assertEquals(1,r.x); assertEquals(2,r.y); assertEquals(3,r.z); assertEquals(0,r.w); assertEquals(2,r.children.size()); SetterBinding c1 = r.children.get(0); assertEquals(5, c1.x); assertEquals(5, c1.y); assertEquals(5, c1.z); SetterBinding c2 = r.children.get(1); assertEquals(6, c2.x); assertEquals(6, c2.y); assertEquals(6, c2.z); Point o = (Point)r.o; assertEquals(1,o.x); assertEquals(1,o.y); } public static abstract class Point3 { @DataBoundSetter private int x,y,z; int post=1; public void assertValues() { assertEquals(1,x); assertEquals(2,y); assertEquals(3,z); } @PostConstruct private void post1() { post += 4; } } public static class Point3Derived extends Point3 { @DataBoundConstructor public Point3Derived() { } @PostConstruct private void post1() { post *= 2; } } public void testFieldInjection() { Point3Derived r = bind("{x:1,y:2,z:3} }",Point3Derived.class); r.assertValues(); assertEquals(10,r.post); } public void testInterceptor1() { String r = bind("{x:1}", String.class, new BindInterceptor() { @Override public Object onConvert(Type targetType, Class targetTypeErasure, Object jsonSource) { assertEquals(targetType, String.class); assertEquals(targetTypeErasure, String.class); return String.valueOf(((JSONObject) jsonSource).getInt("x")); } }); assertEquals("1",r); } public void testInterceptor2() { RequestImpl req = createFakeRequest(); req.setBindInterceptpr(new BindInterceptor() { @Override public Object onConvert(Type targetType, Class targetTypeErasure, Object jsonSource) { if (targetType==String.class) return String.valueOf(((JSONObject) jsonSource).getInt("x")); return DEFAULT; } }); String[] r = (String[]) req.bindJSON(String[].class, String[].class, JSONArray.fromObject("[{x:1},{x:2}]")); assertTrue(Arrays.equals(r,new String[]{"1","2"})); } public void testInterceptor3() { RequestImpl req = createFakeRequest(); req.setBindInterceptpr(new BindInterceptor() { @Override public Object instantiate(Class actualType, JSONObject json) { if (actualType.equals(Point.class)) return new Point(1,2); return DEFAULT; } }); Object[] r = (Object[]) req.bindJSON(Object[].class, Object[].class, JSONArray.fromObject("[{stapler-class:'"+Point.class.getName()+"'}]")); assertTrue(Arrays.equals(r,new Object[]{new Point(1,2)})); } } stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/0000775000175000017500000000000012414640747026064 5ustar ebourgebourg././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/SourceGeneratingAnnotation.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/SourceGeneratingAnnotatio0000664000175000017500000000407612414640747033137 0ustar ebourgebourg/* * Copyright (c) 2014, Jesse Glick * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * 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 HOLDER 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. */ package org.kohsuke.stapler.jsr269; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.annotation.processing.RoundEnvironment; /** * Stick this on something to demonstrate that your processor is wrong if it writes a resource before {@link RoundEnvironment#processingOver}. * You will get a {@code javax.annotation.processing.FilerException: Attempt to reopen a file for path …} error because the processor is run in two rounds. * @see HICKORY-14 */ @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface SourceGeneratingAnnotation {} stapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/Utils.java0000664000175000017500000000622612414640747030035 0ustar ebourgebourgpackage org.kohsuke.stapler.jsr269; import java.io.FileNotFoundException; import java.io.IOException; import java.io.StringReader; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.TreeMap; import javax.annotation.processing.SupportedSourceVersion; import javax.tools.Diagnostic; import javax.tools.FileObject; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardLocation; import net.java.dev.hickory.testing.Compilation; class Utils { /** * Filter out warnings about {@link SupportedSourceVersion}. * {@code metainf-services-1.1.jar} produces {@code warning: No SupportedSourceVersion annotation found on org.kohsuke.metainf_services.AnnotationProcessorImpl, returning RELEASE_6.} which is irrelevant to us. * (Development versions have already fixed this; when released and used here, delete this method.) */ public static List> filterSupportedSourceVersionWarnings(List> diagnostics) { List> r = new ArrayList>(); for (Diagnostic d : diagnostics) { if (!d.getMessage(Locale.ENGLISH).contains("SupportedSourceVersion")) { r.add(d); } } return r; } private static JavaFileManager fileManager(Compilation compilation) { try { Field f = Compilation.class.getDeclaredField("jfm"); f.setAccessible(true); return (JavaFileManager) f.get(compilation); } catch (Exception x) { throw new AssertionError(x); } } /** * Replacement for {@link Compilation#getGeneratedResource} that actually works. * https://code.google.com/p/jolira-tools/issues/detail?id=11 */ public static String getGeneratedResource(Compilation compilation, String filename) { try { FileObject fo = fileManager(compilation).getFileForOutput(StandardLocation.CLASS_OUTPUT, "", filename, null); if (fo == null) { return null; } return fo.getCharContent(true).toString(); } catch (FileNotFoundException x) { return null; } catch (IOException x) { throw new RuntimeException(x); } } /** * Converts the text content of a properties file to a sorted map. * Otherwise you get junk like the header comment with a timestamp, the list is randomly sorted, etc. * @param props text content in *.properties format * @return string representation of a map (sorted ascending by key) */ public static String normalizeProperties(String props) { if (props == null) { return null; } Properties p = new Properties(); try { p.load(new StringReader(props)); } catch (IOException x) { throw new AssertionError(x); } return new TreeMap(p).toString(); } private Utils() {} } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/ConstructorProcessorTest.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/ConstructorProcessorTest.0000664000175000017500000001043112414640747033151 0ustar ebourgebourgpackage org.kohsuke.stapler.jsr269; import java.util.Collections; import java.util.List; import java.util.Locale; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import net.java.dev.hickory.testing.Compilation; import org.junit.Test; import static org.junit.Assert.*; public class ConstructorProcessorTest { @Test public void basicOutput() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.DataBoundConstructor;"). addLine("public class Stuff {"). addLine(" @DataBoundConstructor public Stuff(int count, String name) {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); assertEquals("{constructor=count,name}", Utils.normalizeProperties(Utils.getGeneratedResource(compilation, "some/pkg/Stuff.stapler"))); } @Test public void preAnnotationCompatibility() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("public class Stuff {"). addLine(" /** @stapler-constructor */ public Stuff(String name, int count) {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); assertEquals("{constructor=name,count}", Utils.normalizeProperties(Utils.getGeneratedResource(compilation, "some/pkg/Stuff.stapler"))); } @Test public void JENKINS_11739() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.DataBoundConstructor;"). addLine("public class Stuff {"). addLine(" @DataBoundConstructor public Stuff(int count, String name) {}"). addLine("}"); compilation.addSource("some.pkg.package-info"). addLine("package some.pkg;"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); assertEquals("{constructor=count,name}", Utils.normalizeProperties(Utils.getGeneratedResource(compilation, "some/pkg/Stuff.stapler"))); } @Test public void privateConstructor() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.DataBoundConstructor;"). addLine("public class Stuff {"). addLine(" @DataBoundConstructor Stuff() {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); List> diagnostics = Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics()); assertEquals(1, diagnostics.size()); String msg = diagnostics.get(0).getMessage(Locale.ENGLISH); assertTrue(msg, msg.contains("public")); } @Test public void abstractClass() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.DataBoundConstructor;"). addLine("public abstract class Stuff {"). addLine(" @DataBoundConstructor public Stuff() {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); List> diagnostics = Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics()); assertEquals(1, diagnostics.size()); String msg = diagnostics.get(0).getMessage(Locale.ENGLISH); assertTrue(msg, msg.contains("abstract")); } // TODO nested classes use qualified rather than binary name // TODO behavior when multiple @DataBoundConstructor's specified on a single class - error? } ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/ExportedBeanAnnotationProcessorTest.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/ExportedBeanAnnotationPro0000664000175000017500000001331712414640747033110 0ustar ebourgebourgpackage org.kohsuke.stapler.jsr269; import java.util.Collections; import net.java.dev.hickory.testing.Compilation; import static org.junit.Assert.*; import org.junit.Test; import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; public class ExportedBeanAnnotationProcessorTest { private void assertEqualsCRLF(String s1, String s2) { assertEquals(s1.replace("\r\n","\n"), s2.replace("\r\n","\n")); } @Test public void basicOutput() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.export.*;"). addLine("@ExportedBean public class Stuff {"). addLine(" /* this is not Javadoc */"). addLine(" @Exported public int getCount() {return 0;}"). addLine(" /** This gets the display name. */"). addLine(" @Exported(name=\"name\") public String getDisplayName() {return null;}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); assertEqualsCRLF("some.pkg.Stuff\n", Utils.getGeneratedResource(compilation, "META-INF/annotations/org.kohsuke.stapler.export.ExportedBean")); assertEqualsCRLF("some.pkg.Stuff\n", Utils.getGeneratedResource(compilation, ExportedBeanAnnotationProcessor.STAPLER_BEAN_FILE)); assertEquals("{getDisplayName=This gets the display name. }", Utils.normalizeProperties(Utils.getGeneratedResource(compilation, "some/pkg/Stuff.javadoc"))); } @Test public void noJavadoc() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.export.*;"). addLine("@ExportedBean public class Stuff {"). addLine(" @Exported public int getCount() {return 0;}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); assertEqualsCRLF("some.pkg.Stuff\n", Utils.getGeneratedResource(compilation, "META-INF/annotations/org.kohsuke.stapler.export.ExportedBean")); assertEqualsCRLF("some.pkg.Stuff\n", Utils.getGeneratedResource(compilation, ExportedBeanAnnotationProcessor.STAPLER_BEAN_FILE)); // TODO should it be null, i.e. is it desired to create an empty *.javadoc file? assertEquals("{}", Utils.normalizeProperties(Utils.getGeneratedResource(compilation, "some/pkg/Stuff.javadoc"))); } @ExportedBean public static abstract class Super { @Exported public abstract int getCount(); } @Test public void subclassOfExportedBean() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.export.*;"). addLine("public class Stuff extends " + Super.class.getCanonicalName() + " {"). addLine(" @Override public int getCount() {return 0;}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); /* #7188605: broken in JDK 6u33 + org.jvnet.hudson:annotation-indexer:1.2: assertEquals("some.pkg.Stuff\n", Utils.getGeneratedResource(compilation, "META-INF/annotations/org.kohsuke.stapler.export.ExportedBean")); */ // TODO is it intentional that these are not listed here? (example: hudson.plugins.mercurial.MercurialSCM) assertEquals(null, Utils.getGeneratedResource(compilation, ExportedBeanAnnotationProcessor.STAPLER_BEAN_FILE)); assertEquals(null, Utils.normalizeProperties(Utils.getGeneratedResource(compilation, "some/pkg/Stuff.javadoc"))); } @Test public void incremental() throws Exception { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.export.*;"). addLine("@" + SourceGeneratingAnnotation.class.getCanonicalName()). addLine("@ExportedBean public class Stuff {"). addLine(" @Exported public int getCount() {return 0;}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); assertEqualsCRLF("some.pkg.Stuff\n", Utils.getGeneratedResource(compilation, ExportedBeanAnnotationProcessor.STAPLER_BEAN_FILE)); compilation = new Compilation(compilation); compilation.addSource("some.pkg.MoreStuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.export.*;"). addLine("@ExportedBean public class MoreStuff {"). addLine(" @Exported public int getCount() {return 0;}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); assertEqualsCRLF("some.pkg.MoreStuff\nsome.pkg.Stuff\n", Utils.getGeneratedResource(compilation, ExportedBeanAnnotationProcessor.STAPLER_BEAN_FILE)); } // TODO nested classes - currently saved as qualified rather than binary name, intentional? } ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/SourceGeneratingAnnotationProcessor.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/SourceGeneratingAnnotatio0000664000175000017500000000617512414640747033141 0ustar ebourgebourg/* * Copyright (c) 2014, Jesse Glick * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * 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 HOLDER 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. */ package org.kohsuke.stapler.jsr269; import java.io.IOException; import java.io.Writer; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import org.kohsuke.MetaInfServices; @SupportedSourceVersion(SourceVersion.RELEASE_6) @SupportedAnnotationTypes("org.kohsuke.stapler.jsr269.SourceGeneratingAnnotation") @MetaInfServices(Processor.class) public class SourceGeneratingAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return false; } for (Element e : roundEnv.getElementsAnnotatedWith(SourceGeneratingAnnotation.class)) { TypeElement te = (TypeElement) e; try { JavaFileObject f = processingEnv.getFiler().createSourceFile(te.getQualifiedName() + "Gen", te); Writer w = f.openWriter(); try { w.write("package " + processingEnv.getElementUtils().getPackageOf(te).getQualifiedName() + ";\n"); w.write("class " + te.getSimpleName() + "Gen {}"); } finally { w.close(); } } catch (IOException x) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, x.toString()); } } return true; } } ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/RequirePOSTAnnotationProcessorTest.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/RequirePOSTAnnotationProc0000664000175000017500000001247112414640747033015 0ustar ebourgebourg/* * Copyright (c) 2013, Jesse Glick * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * 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 HOLDER 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. */ package org.kohsuke.stapler.jsr269; import java.util.Collections; import java.util.List; import java.util.Locale; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import net.java.dev.hickory.testing.Compilation; import org.junit.Test; import static org.junit.Assert.*; public class RequirePOSTAnnotationProcessorTest { @Test public void fine() throws Exception { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.interceptor.RequirePOST;"). addLine("public class Stuff {"). addLine(" @RequirePOST public void doSomething() {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); } @Test public void noAbstract() throws Exception { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.interceptor.RequirePOST;"). addLine("public abstract class Stuff {"). addLine(" @RequirePOST public abstract void doSomething();"). addLine("}"); compilation.doCompile(null, "-source", "6"); List> diagnostics = Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics()); assertEquals(1, diagnostics.size()); assertEquals(Diagnostic.Kind.ERROR, diagnostics.get(0).getKind()); String msg = diagnostics.get(0).getMessage(Locale.ENGLISH); assertTrue(msg, msg.contains("abstract")); } @Test public void failsToOverride() throws Exception { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.interceptor.RequirePOST;"). addLine("public class Stuff {"). addLine(" @RequirePOST public void doSomething() {}"). addLine("}"); compilation.addSource("some.pkg.SpecialStuff"). addLine("package some.pkg;"). addLine("public class SpecialStuff extends Stuff {"). addLine(" @Override public void doSomething() {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); List> diagnostics = Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics()); assertEquals(1, diagnostics.size()); assertEquals(Diagnostic.Kind.WARNING, diagnostics.get(0).getKind()); assertEquals("some/pkg/SpecialStuff.java", diagnostics.get(0).getSource().toUri().toString()); String msg = diagnostics.get(0).getMessage(Locale.ENGLISH); assertTrue(msg, msg.contains("overrid")); } @Test public void overridesOK() throws Exception { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.interceptor.RequirePOST;"). addLine("public class Stuff {"). addLine(" @RequirePOST public void doSomething() {}"). addLine("}"); compilation.addSource("some.pkg.SpecialStuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.interceptor.RequirePOST;"). addLine("public class SpecialStuff extends Stuff {"). addLine(" @RequirePOST @Override public void doSomething() {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); } }././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessorTest.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationP0000664000175000017500000000234412414640747033133 0ustar ebourgebourgpackage org.kohsuke.stapler.jsr269; import java.util.Collections; import net.java.dev.hickory.testing.Compilation; import org.junit.Test; import static org.junit.Assert.*; public class QueryParameterAnnotationProcessorTest { @Test public void basicOutput() { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.QueryParameter;"). addLine("public class Stuff {"). addLine(" public void doOneThing(@QueryParameter String key) {}"). addLine(" public void doAnother(@QueryParameter(\"ignoredHere\") String name, @QueryParameter String address) {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), Utils.filterSupportedSourceVersionWarnings(compilation.getDiagnostics())); assertEquals("key", Utils.getGeneratedResource(compilation, "some/pkg/Stuff/doOneThing.stapler")); assertEquals("name,address", Utils.getGeneratedResource(compilation, "some/pkg/Stuff/doAnother.stapler")); } // TODO nested classes use qualified rather than binary name } ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/WebMethodAnnotationProcessorTest.javastapler-stapler-parent-1.231/core/src/test/java/org/kohsuke/stapler/jsr269/WebMethodAnnotationProces0000664000175000017500000000572312414640747033103 0ustar ebourgebourg/* * Copyright (c) 2013, Jesse Glick * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * 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 HOLDER 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. */ package org.kohsuke.stapler.jsr269; import java.util.Collections; import java.util.List; import java.util.Locale; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import net.java.dev.hickory.testing.Compilation; import org.junit.Test; import static org.junit.Assert.*; public class WebMethodAnnotationProcessorTest { @Test public void doMethods() throws Exception { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.WebMethod;"). addLine("public class Stuff {"). addLine(" @WebMethod(name=\"hello\") public void doSomething() {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); assertEquals(Collections.emptyList(), compilation.getDiagnostics()); } @Test public void nonDoMethods() throws Exception { Compilation compilation = new Compilation(); compilation.addSource("some.pkg.Stuff"). addLine("package some.pkg;"). addLine("import org.kohsuke.stapler.WebMethod;"). addLine("public class Stuff {"). addLine(" @WebMethod(name=\"hello\") public void something() {}"). addLine("}"); compilation.doCompile(null, "-source", "6"); List> diagnostics = compilation.getDiagnostics(); assertEquals(1, diagnostics.size()); String msg = diagnostics.get(0).getMessage(Locale.ENGLISH); assertTrue(msg, msg.contains("something")); } }stapler-stapler-parent-1.231/core/src/main/0000775000175000017500000000000012414640747020137 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/0000775000175000017500000000000012414640747021060 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/0000775000175000017500000000000012414640747021647 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/0000775000175000017500000000000012414640747023320 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/0000775000175000017500000000000012414640747024772 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/StaticViewFacet.java0000664000175000017500000001001212414640747030654 0ustar ebourgebourgpackage org.kohsuke.stapler; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.lang.Klass; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; /** * @author Kohsuke Kawaguchi */ // @MetaInfServices - this facet needs to be manually configured public class StaticViewFacet extends Facet { private final List allowedExtensions = new ArrayList(); public StaticViewFacet(String... allowedExtensions) { this(Arrays.asList(allowedExtensions)); } public StaticViewFacet(Collection allowedExtensions) { for (String extension : allowedExtensions) { addExtension(extension); } } public void addExtension(String ext) { if (!ext.startsWith(".")) ext='.'+ext; allowedExtensions.add(ext); } public void buildViewDispatchers(final MetaClass owner, List dispatchers) { dispatchers.add(new Dispatcher() { public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException { // check Jelly view String next = req.tokens.peek(); if(next==null) return false; // only match the end of the URL if (req.tokens.countRemainingTokens()>1) return false; // and avoid serving both "foo" and "foo/" as relative URL semantics are drastically different if (req.getRequestURI().endsWith("/")) return false; URL res = findResource(owner.klass,next); if(res==null) return false; // no Jelly script found req.tokens.next(); if (traceable()) { // Null not expected here trace(req,rsp,"-> %s on <%s>", next, node); } rsp.serveFile(req, res); return true; } public String toString() { return "static file for url=/VIEW"+StringUtils.join(allowedExtensions,"|"); } }); } /** * Determines if this resource can be served */ protected URL findResource(Klass c, String fileName) { boolean ends = false; for (String ext : allowedExtensions) { if (fileName.endsWith(ext)) { ends = true; break; } } if (!ends) return null; for ( ; c!=null; c=c.getSuperClass()) { URL res = c.getResource(fileName); if (res!=null) return res; } return null; } public RequestDispatcher createRequestDispatcher(RequestImpl request, Klass type, Object it, String viewName) throws IOException { final Stapler stapler = request.getStapler(); final URL res = findResource(type,viewName); if (res==null) return null; return new RequestDispatcher() { public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { stapler.serveStaticResource((HttpServletRequest)request, new ResponseImpl(stapler, (HttpServletResponse) response), res, 0); } public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { throw new UnsupportedOperationException(); } }; } public boolean handleIndexRequest(RequestImpl req, ResponseImpl rsp, Object node, MetaClass nodeMetaClass) throws IOException, ServletException { URL res = findResource(nodeMetaClass.klass,"index.html"); if (res==null) return false; rsp.serveFile(req,res); return true; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/HttpDeletable.java0000664000175000017500000000335512414640747030364 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import javax.servlet.ServletException; import java.io.IOException; /** * Marks the object that can handle HTTP DELETE. * * @author Kohsuke Kawaguchi */ public interface HttpDeletable { /** * Called when HTTP DELETE method is invoked. */ void delete( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/Facet.java0000664000175000017500000001306512414640747026664 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import org.apache.commons.discovery.ResourceNameIterator; import org.apache.commons.discovery.resource.ClassLoaders; import org.apache.commons.discovery.resource.names.DiscoverServiceNames; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.lang.Klass; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * Aspect of stapler that brings in an optional language binding. * * Put {@link MetaInfServices} on subtypes so that Stapler can discover them. * * @author Kohsuke Kawaguchi */ public abstract class Facet { /** * Adds {@link Dispatcher}s that look at one token and binds that * to the views associated with the 'it' object. */ public abstract void buildViewDispatchers(MetaClass owner, List dispatchers); /** * Adds {@link Dispatcher}s that do catch-all behaviours like "doDispatch" does. */ public void buildFallbackDispatchers(MetaClass owner, List dispatchers) {} /** * Discovers all the facets in the classloader. */ public static List discover(ClassLoader cl) { return discoverExtensions(Facet.class, cl); } public static List discoverExtensions(Class type, ClassLoader... cls) { List r = new ArrayList(); Set classNames = new HashSet(); for (ClassLoader cl : cls) { ClassLoaders classLoaders = new ClassLoaders(); classLoaders.put(cl); DiscoverServiceNames dc = new DiscoverServiceNames(classLoaders); ResourceNameIterator itr = dc.findResourceNames(type.getName()); while(itr.hasNext()) { String name = itr.nextResourceName(); if (!classNames.add(name)) continue; // avoid duplication Class c; try { c = cl.loadClass(name); } catch (ClassNotFoundException e) { LOGGER.log(Level.WARNING, "Failed to load "+name,e); continue; } try { r.add((T)c.newInstance()); } catch (InstantiationException e) { LOGGER.log(Level.WARNING, "Failed to instanticate "+c,e); } catch (IllegalAccessException e) { LOGGER.log(Level.WARNING, "Failed to instanticate "+c,e); } } } return r; } public static final Logger LOGGER = Logger.getLogger(Facet.class.getName()); /** * Creates a {@link RequestDispatcher} that handles the given view, or * return null if no such view was found. * * @param type * If "it" is non-null, {@code it.getClass()}. Otherwise the class * from which the view is searched. */ public RequestDispatcher createRequestDispatcher(RequestImpl request, Klass type, Object it, String viewName) throws IOException { return null; // should be really abstract, but not } public RequestDispatcher createRequestDispatcher(RequestImpl request, Class type, Object it, String viewName) throws IOException { return createRequestDispatcher(request,Klass.java(type),it,viewName); } /** * Attempts to route the HTTP request to the 'index' page of the 'it' object. * * @return * true if the processing succeeds. Otherwise false. */ public abstract boolean handleIndexRequest(RequestImpl req, ResponseImpl rsp, Object node, MetaClass nodeMetaClass) throws IOException, ServletException; /** * Maps an instance to a {@link Klass}. This is the generalization of {@code o.getClass()}. * * This is for those languages that use something other than {@link Class} to represent the concept of a class. * Those facets that are fine with {@code o.getClass()} should return null so that it gives other facets a chance * to map it better. */ public Klass getKlass(Object o) { return null; } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/NoStaplerConstructorException.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/NoStaplerConstructorException.ja0000664000175000017500000000342712414640747033350 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; /** * @author Kohsuke Kawaguchi */ public class NoStaplerConstructorException extends IllegalArgumentException { public NoStaplerConstructorException(String s) { super(s); } public NoStaplerConstructorException(String message, Throwable cause) { super(message, cause); } public NoStaplerConstructorException(Throwable cause) { super(cause); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/MetaClassLoader.java0000664000175000017500000000641212414640747030643 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.util.Map; import java.io.File; import java.net.URLClassLoader; import java.net.URL; import java.net.MalformedURLException; import java.util.HashMap; /** * The stapler version of the {@link ClassLoader} object, * that retains some useful cache about a class loader. * * @author Kohsuke Kawaguchi */ public class MetaClassLoader extends TearOffSupport { public final MetaClassLoader parent; public final ClassLoader loader; public MetaClassLoader(ClassLoader loader) { this.loader = loader; this.parent = get(loader.getParent()); } public static MetaClassLoader get(ClassLoader cl) { if(cl ==null) return null; // if no parent, delegate to the debug loader if available. synchronized(classMap) { MetaClassLoader mc = classMap.get(cl); if(mc==null) { mc = new MetaClassLoader(cl); classMap.put(cl,mc); } return mc; } } /** * If non-null, delegate to this classloader. */ public static MetaClassLoader debugLoader = null; /** * All {@link MetaClass}es. * * Note that this permanently holds a strong reference to its key, i.e. is a memory leak. */ private static final Map classMap = new HashMap(); static { try { String path = System.getProperty("stapler.resourcePath"); if(path!=null) { String[] tokens = path.split(";"); URL[] urls = new URL[tokens.length]; for (int i=0; i * When exceptions are processed within web applications, different unrelated parts of the webapp can end up calling * {@link HttpServletResponse#getOutputStream()}. This fundamentally doesn't work with the notion that the application * needs to process "Content-Encoding:gzip" on its own. Such app has to maintain a GZIP output stream on its own, * since {@link HttpServletResponse} doesn't know that its output is written through a compressed stream. * *

* Another place this break-down can be seen is when a servlet throws an exception that the container handles. * It tries to render an error page, but of course it wouldn't know that "Content-Encoding:gzip" is set, so it * will fail to write in the correct format. * *

* The only way to properly fix this is to make {@link HttpServletResponse} smart enough that it returns * the compression-transparent stream from {@link HttpServletResponse#getOutputStream()} (and it would also * have to process the exception thrown from the app.) This filter does exactly that. * * @author Kohsuke Kawaguchi */ public class CompressionFilter implements Filter { private ServletContext context; public void init(FilterConfig filterConfig) throws ServletException { context = filterConfig.getServletContext(); } public void doFilter(ServletRequest _req, ServletResponse _rsp, FilterChain filterChain) throws IOException, ServletException { _req.setAttribute(CompressionFilter.class.getName(),true); CompressionServletResponse rsp = new CompressionServletResponse(((HttpServletResponse) _rsp)); try { filterChain.doFilter(_req, rsp); } catch (IOException e) { if (DISABLED) throw e; reportException(e,(HttpServletRequest)_req,rsp); } catch (ServletException e) { if (DISABLED) throw e; reportException(e,(HttpServletRequest)_req,rsp); } catch (RuntimeException e) { if (DISABLED) throw e; reportException(e,(HttpServletRequest)_req,rsp); } catch (Error e) { if (DISABLED) throw e; reportException(e,(HttpServletRequest)_req,rsp); } } private void reportException(Throwable e, HttpServletRequest req, HttpServletResponse rsp) throws IOException, ServletException { getUncaughtExceptionHandler(context).reportException(e, context, req, rsp); } public void destroy() { } public static void setUncaughtExceptionHandler(ServletContext context, UncaughtExceptionHandler handler) { context.setAttribute(UncaughtExceptionHandler.class.getName(),handler); } public static UncaughtExceptionHandler getUncaughtExceptionHandler(ServletContext context) { UncaughtExceptionHandler h = (UncaughtExceptionHandler) context.getAttribute(UncaughtExceptionHandler.class.getName()); if (h==null) h=UncaughtExceptionHandler.DEFAULT; return h; } /** * Is this request already wrapped into {@link CompressionFilter}? */ public static boolean has(ServletRequest req) { return req.getAttribute(CompressionFilter.class.getName())!=null; } public static boolean DISABLED = Boolean.getBoolean(CompressionFilter.class.getName()+".disabled"); } ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/compression/UncaughtExceptionHandler.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/compression/UncaughtExceptionHan0000664000175000017500000000415512414640747033347 0ustar ebourgebourgpackage org.kohsuke.stapler.compression; import org.kohsuke.stapler.AttributeKey; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.text.MessageFormat; import java.util.Date; import static org.kohsuke.stapler.Stapler.escape; /** * Handles an exception caught by {@link CompressionFilter}. * * See {@link CompressionFilter} javadoc for why this exception needs to be handled * by us and can't just be handled by the servlet container like it does all others. * * @author Kohsuke Kawaguchi */ public interface UncaughtExceptionHandler { /** * Called to render the exception as an HTTP response. */ void reportException(Throwable e, ServletContext context, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException; UncaughtExceptionHandler DEFAULT = new UncaughtExceptionHandler() { public void reportException(Throwable e, ServletContext context, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); pw.close(); rsp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); rsp.setContentType("text/html"); PrintWriter w = rsp.getWriter(); String message = e.getMessage(); w.print(MessageFormat.format("Error {0}\n" + "

Status Code: {0}

Exception: {1}
Stacktrace:
{2}


\n" + "Generated by Stapler at {3}", HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message != null ? escape(message) : "?", escape(sw.toString()), new Date().toString() )); w.close(); } }; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/TruncatedInputStream.java0000664000175000017500000000477612414640747032000 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; /** * {@link InputStream} decorator that chops off the underlying stream at the specified length * * @author Kohsuke Kawaguchi */ final class TruncatedInputStream extends FilterInputStream { private long len; public TruncatedInputStream(InputStream in, long len) { super(in); this.len = len; } @Override public int read() throws IOException { if(len<=0) return -1; len--; return super.read(); } @Override public int read(byte[] b, int off, int l) throws IOException { int toRead = (int) Math.min(l, len); if (toRead <= 0) { return -1; } int r = super.read(b, off, toRead); if(r>0) len -= r; return r; } @Override public int available() throws IOException { return (int)Math.min(super.available(),len); } @Override public long skip(long n) throws IOException { long r = super.skip(Math.min(len, n)); len -= r; return r; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/StaplerResponse.java0000664000175000017500000002230112414640747030764 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import net.sf.json.JsonConfig; import org.kohsuke.stapler.export.Flavor; import javax.annotation.Nonnull; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; import java.net.URL; import java.net.URLConnection; import org.kohsuke.stapler.export.Model; import org.kohsuke.stapler.export.NamedPathPruner; /** * Defines additional operations made available by Stapler. * * @see Stapler#getCurrentResponse() * @author Kohsuke Kawaguchi */ public interface StaplerResponse extends HttpServletResponse { /** * Evaluates the url against the given object and * forwards the request to the result. * *

* This can be used for example inside an action method * to forward a request to a JSP. * * @param it * the URL is evaluated against this object. Must not be null. * @param url * the relative URL (e.g., "foo" or "foo/bar") to resolve * against the "it" object. * @param request * Request to be forwarded. */ void forward(Object it, String url, StaplerRequest request) throws ServletException, IOException; /** * Redirects the browser to where it came from (the referer.) */ void forwardToPreviousPage(StaplerRequest request) throws ServletException, IOException; /** * Works like {@link #sendRedirect(String)} except that this method * escapes the URL. */ void sendRedirect2(@Nonnull String url) throws IOException; /** * Works like {@link #sendRedirect2(String)} but allows the caller to specify the HTTP status code. */ void sendRedirect(int statusCore, @Nonnull String url) throws IOException; /** * Serves a static resource. * *

* This method sets content type, HTTP status code, sends the complete data * and closes the response. This method also handles cache-control HTTP headers * like "If-Modified-Since" and others. */ void serveFile(StaplerRequest request, URL res) throws ServletException, IOException; void serveFile(StaplerRequest request, URL res, long expiration) throws ServletException, IOException; /** * Works like {@link #serveFile(StaplerRequest, URL)} but chooses the locale specific * version of the resource if it's available. The convention of "locale specific version" * is the same as that of property files. * So Japanese resource for foo.html would be named foo_ja.html. */ void serveLocalizedFile(StaplerRequest request, URL res) throws ServletException, IOException; /** * Works like {@link #serveFile(StaplerRequest, URL, long)} but chooses the locale * specific version of the resource if it's available. * * See {@link #serveLocalizedFile(StaplerRequest, URL)} for more details. */ void serveLocalizedFile(StaplerRequest request, URL res, long expiration) throws ServletException, IOException; /** * Serves a static resource. * *

* This method works like {@link #serveFile(StaplerRequest, URL)} but this version * allows the caller to fetch data from anywhere. * * @param data * {@link InputStream} that contains the data of the static resource. * @param lastModified * The timestamp when the resource was last modified. See {@link URLConnection#getLastModified()} * for the meaning of the value. 0 if unknown, in which case "If-Modified-Since" handling * will not be performed. * @param expiration * The number of milliseconds until the resource will "expire". * Until it expires the browser will be allowed to cache it * and serve it without checking back with the server. * After it expires, the client will send conditional GET to * check if the resource is actually modified or not. * If 0, it will immediately expire. * @param contentLength * if the length of the input stream is known in advance, specify that value * so that HTTP keep-alive works. Otherwise specify -1 to indicate that the length is unknown. * @param fileName * file name of this resource. Used to determine the MIME type. * Since the only important portion is the file extension, this could be just a file name, * or a full path name, or even a pseudo file name that doesn't actually exist. * It supports both '/' and '\\' as the path separator. * * If this string starts with "mime-type:", like "mime-type:foo/bar", then "foo/bar" will * be used as a MIME type without consulting the servlet container. */ void serveFile(StaplerRequest req, InputStream data, long lastModified, long expiration, long contentLength, String fileName) throws ServletException, IOException; /** * @Deprecated use form with long contentLength */ void serveFile(StaplerRequest req, InputStream data, long lastModified, long expiration, int contentLength, String fileName) throws ServletException, IOException; /** * Serves a static resource. * * Expiration date is set to the value that forces browser to do conditional GET * for all resources. * * @see #serveFile(StaplerRequest, InputStream, long, long, int, String) */ void serveFile(StaplerRequest req, InputStream data, long lastModified, long contentLength, String fileName) throws ServletException, IOException; /** * @Deprecated use form with long contentLength */ void serveFile(StaplerRequest req, InputStream data, long lastModified, int contentLength, String fileName) throws ServletException, IOException; /** * Serves the exposed bean in the specified flavor. * *

* This method performs the complete output from the header to the response body. * If the flavor is JSON, this method also supports JSONP via the {@code jsonp} query parameter. * *

The {@code depth} parameter may be used to specify a recursion depth * as in {@link Model#writeTo(Object,int,DataWriter)}. * *

As of 1.146, the {@code tree} parameter may be used to control the output * in detail; see {@link NamedPathPruner#NamedPathPruner(String)} for details. */ void serveExposedBean(StaplerRequest req, Object exposedBean, Flavor flavor) throws ServletException,IOException; /** * Works like {@link #getOutputStream()} but tries to send the response * with gzip compression if the client supports it. * *

* This method is useful for sending out a large text content. * * @param req * Used to determine whether the client supports compression */ OutputStream getCompressedOutputStream(HttpServletRequest req) throws IOException; /** * Works like {@link #getCompressedOutputStream(HttpServletRequest)} but this * method is for {@link #getWriter()}. */ Writer getCompressedWriter(HttpServletRequest req) throws IOException; /** * Performs the reverse proxy to the given URL. * * @return * The status code of the response. */ int reverseProxyTo(URL url, StaplerRequest req) throws IOException; /** * The JsonConfig to be used when serializing java beans from js bound methods to JSON. * Setting this to null will make the default config to be used. * * @param config the config */ void setJsonConfig(JsonConfig config); /** * The JsonConfig to be used when serializing java beans to JSON previously set by {@link #setJsonConfig(JsonConfig)}. * Will return the default config if nothing has previously been set. * * @return the config */ JsonConfig getJsonConfig(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/DataBoundSetter.java0000664000175000017500000000264012414640747030667 0ustar ebourgebourgpackage org.kohsuke.stapler; import net.sf.json.JSONObject; import javax.annotation.PostConstruct; import java.beans.Introspector; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; /** * Designates a setter method or a field used to databind JSON values into objects in methods like * {@link StaplerRequest#bindJSON(Class, JSONObject)} and * {@link StaplerRequest#bindParameters(Class, String)}. * *

* Stapler will first invoke {@link DataBoundConstructor}-annotated constructor, and if there's any * remaining properties in JSON, it'll try to find a matching {@link DataBoundSetter}-annotated setter * method or a field. * *

* The setter method is discovered through {@link Introspector}, so setter method name must match * the property name (such as setFoo for the foo property), and it needs to be public. * *

* The field is discovered through simple reflection, so its name must match the property name, but * its access modifier can be anything. * *

* To create a method to be called after all the setter injections are complete, annotate a method * with {@link PostConstruct}. * * @author Kohsuke Kawaguchi */ @Retention(RUNTIME) @Target({METHOD,FIELD}) @Documented public @interface DataBoundSetter { } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/0000775000175000017500000000000012414640747026767 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/errors/0000775000175000017500000000000012414640747030303 5ustar ebourgebourg././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/errors/NoHomeDirError.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/errors/NoHomeDirError.0000664000175000017500000000361412414640747033146 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.errors; import java.io.File; /** * Model object used to display the error top page if * we couldn't create the home directory. * *

* index.jelly would display a nice friendly error page. * * @author Kohsuke Kawaguchi */ public class NoHomeDirError extends ErrorObject { public final File home; public NoHomeDirError(File home) { this.home = home; } @Override public String getMessage() { return "Unable to create home directory: "+home; } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/errors/ErrorObject.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/errors/ErrorObject.jav0000664000175000017500000000315512414640747033231 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.errors; /** * Root class of the stapler error objects. * * @author Kohsuke Kawaguchi */ public abstract class ErrorObject { /** * Gets the error message. */ public abstract String getMessage(); } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/AbstractWebAppMain.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/AbstractWebAppMain.jav0000664000175000017500000002022412414640747033140 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework; import org.jvnet.localizer.LocaleProvider; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.framework.errors.NoHomeDirError; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import java.io.File; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; /** * Entry point for web applications. * *

* Applications that use stapler can use this as the base class, * and then register that as the servlet context listener. * * @param * The type of the root object instance * @author Kohsuke Kawaguchi */ public abstract class AbstractWebAppMain implements ServletContextListener { protected final Class rootType; private static final String APP = "app"; protected ServletContext context; /** * Once the home directory is determined, this value is set to that directory. */ protected File home; protected AbstractWebAppMain(Class rootType) { this.rootType = rootType; } /** * Returns the application name, like "Hudson" or "Torricelli". * * The method should always return the same value. The name * should only contain alpha-numeric character. */ protected abstract String getApplicationName(); /** * If the root application object is loaded asynchronously, * override this method to return the place holder object * to serve the request in the mean time. * * @return * null to synchronously load the application object. */ protected Object createPlaceHolderForAsyncLoad() { return null; } /** * Creates the root application object. */ protected abstract Object createApplication() throws Exception; public void contextInitialized(ServletContextEvent event) { try { context = event.getServletContext(); installLocaleProvider(); if (!checkEnvironment()) return; Object ph = createPlaceHolderForAsyncLoad(); if(ph!=null) { // asynchronous load context.setAttribute(APP,ph); new Thread(getApplicationName()+" initialization thread") { public void run() { setApplicationObject(); } }.start(); } else { setApplicationObject(); } } catch (Error e) { LOGGER.log(Level.SEVERE, "Failed to initialize "+getApplicationName(),e); throw e; } catch (RuntimeException e) { LOGGER.log(Level.SEVERE, "Failed to initialize "+getApplicationName(),e); throw e; } } /** * Sets the root application object. */ protected void setApplicationObject() { try { context.setAttribute(APP,createApplication()); } catch (Error e) { LOGGER.log(Level.SEVERE, "Failed to initialize "+getApplicationName(),e); throw e; } catch (RuntimeException e) { LOGGER.log(Level.SEVERE, "Failed to initialize "+getApplicationName(),e); throw e; } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to initialize "+getApplicationName(),e); throw new Error(e); } } /** * Performs pre start-up environment check. * * @return * false if a check fails. Webapp will fail to boot in this case. */ protected boolean checkEnvironment() { home = getHomeDir().getAbsoluteFile(); home.mkdirs(); LOGGER.info(getApplicationName()+" home directory: "+home); // check that home exists (as mkdirs could have failed silently), otherwise throw a meaningful error if (!home.exists()) { context.setAttribute(APP,new NoHomeDirError(home)); return false; } return true; } /** * Install {@link LocaleProvider} that uses the current request to determine the language. */ private void installLocaleProvider() { LocaleProvider.setProvider(new LocaleProvider() { public Locale get() { Locale locale=null; StaplerRequest req = Stapler.getCurrentRequest(); if(req!=null) locale = req.getLocale(); if(locale==null) locale = Locale.getDefault(); return locale; } }); } /** * Determines the home directory for the application. * * People makes configuration mistakes, so we are trying to be nice * with those by doing {@link String#trim()}. */ protected File getHomeDir() { // check JNDI for the home directory first String varName = getApplicationName().toUpperCase() + "_HOME"; try { InitialContext iniCtxt = new InitialContext(); Context env = (Context) iniCtxt.lookup("java:comp/env"); String value = (String) env.lookup(varName); if(value!=null && value.trim().length()>0) return new File(value.trim()); // look at one more place. See HUDSON-1314 value = (String) iniCtxt.lookup(varName); if(value!=null && value.trim().length()>0) return new File(value.trim()); } catch (NamingException e) { // ignore } // finally check the system property String sysProp = System.getProperty(varName); if(sysProp!=null) return new File(sysProp.trim()); // look at the env var next String env = System.getenv(varName); if(env!=null) return new File(env.trim()).getAbsoluteFile(); return getDefaultHomeDir(); } /** * If no home directory is configured, this method is called * to determine the default location, which is "~/.appname". * * Override this method to change that behavior. */ protected File getDefaultHomeDir() { return new File(new File(System.getProperty("user.home")),'.'+getApplicationName().toLowerCase()); } public void contextDestroyed(ServletContextEvent event) { Object o = event.getServletContext().getAttribute(APP); if(rootType.isInstance(o)) { cleanUp(rootType.cast(o)); } } /** * Called during the destructino of the web app to perform * any clean up act on the application object. */ protected void cleanUp(T app) {} private static final Logger LOGGER = Logger.getLogger(AbstractWebAppMain.class.getName()); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/io/0000775000175000017500000000000012414640747027376 5ustar ebourgebourg././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/io/LineEndNormalizingWriter.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/io/LineEndNormalizingW0000664000175000017500000000703712414640747033207 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.io; import java.io.FilterWriter; import java.io.Writer; import java.io.IOException; /** * Finds the lone LF and converts that to CR+LF. * *

* Internet Explorer's XmlHttpRequest.responseText seems to * normalize the line end, and if we only send LF without CR, it will * not recognize that as a new line. To work around this problem, * we use this filter to always convert LF to CR+LF. * * @author Kohsuke Kawaguchi */ public /*for now, until Hudson migration completes*/ class LineEndNormalizingWriter extends FilterWriter { private boolean seenCR; public LineEndNormalizingWriter(Writer out) { super(out); } public void write(char cbuf[]) throws IOException { write(cbuf, 0, cbuf.length); } public void write(String str) throws IOException { write(str,0,str.length()); } public void write(int c) throws IOException { if(!seenCR && c==LF) super.write("\r\n"); else super.write(c); seenCR = (c==CR); } public void write(char cbuf[], int off, int len) throws IOException { int end = off+len; int writeBegin = off; for( int i=off; i * The write operation is atomic when used for overwriting; * it either leaves the original file intact, or it completely rewrites it with new contents. * * @author Kohsuke Kawaguchi */ public class AtomicFileWriter extends Writer { private final Writer core; private final File tmpFile; private final File destFile; public AtomicFileWriter(File f) throws IOException { tmpFile = File.createTempFile("atomic",null,f.getParentFile()); destFile = f; core = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tmpFile),"UTF-8")); } public void write(int c) throws IOException { core.write(c); } public void write(String str, int off, int len) throws IOException { core.write(str,off,len); } public void write(char cbuf[], int off, int len) throws IOException { core.write(cbuf,off,len); } public void flush() throws IOException { core.flush(); } public void close() throws IOException { core.close(); } public void commit() throws IOException { close(); if(destFile.exists() && !destFile.delete()) throw new IOException("Unable to delete "+destFile); tmpFile.renameTo(destFile); } /** * Until the data is committed, this file captures * the written content. */ public File getTemporaryFile() { return tmpFile; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/io/LargeText.java0000664000175000017500000004176712414640747032157 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Copyright (c) 2012, Martin Schroeder, Intel Mobile Communications GmbH * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.io; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.CountingOutputStream; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import javax.servlet.http.HttpServletResponse; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.RandomAccessFile; import java.io.Reader; import java.io.Writer; import java.nio.charset.Charset; import com.jcraft.jzlib.GZIPInputStream; /** * Represents a large text data. * *

* This class defines methods for handling progressive text update. * *

Usage

*

* * @author Kohsuke Kawaguchi */ public class LargeText { /** * Represents the data source of this text. */ private interface Source { Session open() throws IOException; long length(); boolean exists(); } private final Source source; protected final Charset charset; private volatile boolean completed; public LargeText(File file, boolean completed) { this(file,Charset.defaultCharset(),completed); } /** * @since 1.196 * * @param transparentGunzip if set to true, this class will detect if the * given file is compressed with GZIP. If so, it will transparently * uncompress its content during read-access. Do note that the underlying * file is not altered and remains compressed. */ public LargeText(File file, boolean completed, boolean transparentGunzip) { this(file, Charset.defaultCharset(), completed, transparentGunzip); } public LargeText(final File file, Charset charset, boolean completed) { this(file, charset, completed, false); } /** * @since 1.196 * * @param transparentGunzip if set to true, this class will detect if the * given file is compressed with GZIP. If so, it will transparently * uncompress its content during read-access. Do note that the underlying * file is not altered and remains compressed. */ public LargeText(final File file, Charset charset, boolean completed, boolean transparentGunzip) { this.charset = charset; if (transparentGunzip && GzipAwareSession.isGzipStream(file)) { this.source = new Source() { public Session open() throws IOException { return new GzipAwareSession(file); } public long length() { return GzipAwareSession.getGzipStreamSize(file); } public boolean exists() { return file.exists(); } }; } else { this.source = new Source() { public Session open() throws IOException { return new FileSession(file); } public long length() { return file.length(); } public boolean exists() { return file.exists(); } }; } this.completed = completed; } public LargeText(ByteBuffer memory, boolean completed) { this(memory,Charset.defaultCharset(),completed); } public LargeText(final ByteBuffer memory, Charset charset, boolean completed) { this.charset = charset; this.source = new Source() { public Session open() throws IOException { return new BufferSession(memory); } public long length() { return memory.length(); } public boolean exists() { return true; } }; this.completed = completed; } public void markAsComplete() { completed = true; } public boolean isComplete() { return completed; } public long length() { return source.length(); } /** * Returns {@link Reader} for reading the raw bytes. */ public Reader readAll() throws IOException { return new InputStreamReader(new InputStream() { final Session session = source.open(); public int read() throws IOException { byte[] buf = new byte[1]; int n = session.read(buf); if(n==1) return buf[0]; else return -1; // EOF } public int read(byte[] buf, int off, int len) throws IOException { return session.read(buf,off,len); } public void close() throws IOException { session.close(); } },charset); } public long writeLogTo(long start, Writer w) throws IOException { return writeLogTo(start, new WriterOutputStream(w, charset)); } /** * Writes the tail portion of the file to the {@link OutputStream}. * * @param start * The byte offset in the input file where the write operation starts. * * @return * if the file is still being written, this method writes the file * until the last newline character and returns the offset to start * the next write operation. */ public long writeLogTo(long start, OutputStream out) throws IOException { CountingOutputStream os = new CountingOutputStream(out); Session f = source.open(); f.skip(start); if(completed) { // write everything till EOF byte[] buf = new byte[1024]; int sz; while((sz=f.read(buf))>=0) os.write(buf,0,sz); } else { ByteBuf buf = new ByteBuf(null,f); HeadMark head = new HeadMark(buf); TailMark tail = new TailMark(buf); buf = null; int readLines = 0; while(tail.moveToNextLine(f) && readLines++ < MAX_LINES_READ) { head.moveTo(tail,os); } head.finish(os); } f.close(); os.flush(); return os.getCount()+start; } /** * Implements the progressive text handling. * This method is used as a "web method" with progressiveText.jelly. */ public void doProgressText(StaplerRequest req, StaplerResponse rsp) throws IOException { setContentType(rsp); rsp.setStatus(HttpServletResponse.SC_OK); if(!source.exists()) { // file doesn't exist yet rsp.addHeader("X-Text-Size","0"); rsp.addHeader("X-More-Data","true"); return; } long start = 0; String s = req.getParameter("start"); if(s!=null) start = Long.parseLong(s); if(source.length() < start ) start = 0; // text rolled over CharSpool spool = new CharSpool(); long r = writeLogTo(start,spool); rsp.addHeader("X-Text-Size",String.valueOf(r)); if(!completed) rsp.addHeader("X-More-Data","true"); Writer w = createWriter(req, rsp, r - start); spool.writeTo(new LineEndNormalizingWriter(w)); w.close(); } protected void setContentType(StaplerResponse rsp) { rsp.setContentType("text/plain;charset=UTF-8"); } protected Writer createWriter(StaplerRequest req, StaplerResponse rsp, long size) throws IOException { // when sending big text, try compression. don't bother if it's small if(size >4096) return rsp.getCompressedWriter(req); else return rsp.getWriter(); } /** * Points to a byte in the buffer. */ private static class Mark { protected ByteBuf buf; protected int pos; public Mark(ByteBuf buf) { this.buf = buf; } } /** * Points to the start of the region that's not committed * to the output yet. */ private static final class HeadMark extends Mark { public HeadMark(ByteBuf buf) { super(buf); } /** * Moves this mark to 'that' mark, and writes the data * in between to {@link OutputStream} if necessary. */ void moveTo(Mark that, OutputStream os) throws IOException { while(this.buf!=that.buf) { os.write(buf.buf,0,buf.size); buf = buf.next; pos = 0; } this.pos = that.pos; } void finish(OutputStream os) throws IOException { os.write(buf.buf,0,pos); } } /** * Points to the end of the region. */ private static final class TailMark extends Mark { public TailMark(ByteBuf buf) { super(buf); } boolean moveToNextLine(Session f) throws IOException { while(true) { while(pos==buf.size) { if(!buf.isFull()) { // read until EOF return false; } else { // read into the next buffer buf = new ByteBuf(buf,f); pos = 0; } } byte b = buf.buf[pos++]; if(b=='\r' || b=='\n') return true; } } } /** * Variable length byte buffer implemented as a linked list of fixed length buffer. */ private static final class ByteBuf { private final byte[] buf = new byte[1024]; private int size = 0; private ByteBuf next; public ByteBuf(ByteBuf previous, Session f) throws IOException { if(previous!=null) { assert previous.next==null; previous.next = this; } while(!this.isFull()) { int chunk = f.read(buf, size, buf.length - size); if(chunk==-1) return; size+= chunk; } } public boolean isFull() { return buf.length==size; } } /** * Represents the read session of the {@link Source}. * Methods generally follow the contracts of {@link InputStream}. */ private interface Session { void close() throws IOException; void skip(long start) throws IOException; int read(byte[] buf) throws IOException; int read(byte[] buf, int offset, int length) throws IOException; } /** * {@link Session} implementation over {@link RandomAccessFile}. */ private static final class FileSession implements Session { private final RandomAccessFile file; public FileSession(File file) throws IOException { this.file = new RandomAccessFile(file,"r"); } public void close() throws IOException { file.close(); } public void skip(long start) throws IOException { file.seek(file.getFilePointer()+start); } public int read(byte[] buf) throws IOException { return file.read(buf); } public int read(byte[] buf, int offset, int length) throws IOException { return file.read(buf,offset,length); } } /** * {@link Session} implementation over {@link GZIPInputStream}. *

* Always use {@link GzipAwareSession#isGzipStream(File)} to check if you * really deal with a GZIPed file before you invoke this class. Otherwise, * {@link GZIPInputStream} might throw an exception. */ private static final class GzipAwareSession implements Session { private final GZIPInputStream gz; public GzipAwareSession(File file) throws IOException { this.gz = new GZIPInputStream(new FileInputStream(file)); } public void close() throws IOException { gz.close(); } public void skip(long start) throws IOException { while (start > 0) { start -= gz.skip(start); } } public int read(byte[] buf) throws IOException { return gz.read(buf); } public int read(byte[] buf, int offset, int length) throws IOException { return gz.read(buf,offset,length); } /** * Checks the first two bytes of the target file and return true if * they equal the GZIP magic number. * @param file * @return true, if the first two bytes are the GZIP magic number. */ public static boolean isGzipStream(File file) { DataInputStream in = null; try { in = new DataInputStream(new FileInputStream(file)); return in.readShort()==0x1F8B; } catch (IOException ex) { return false; } finally { IOUtils.closeQuietly(in); } } /** * Returns the uncompressed size of the file in a quick, but unreliable * manner. It will not report the correct size if: *

    *
  1. The compressed size is larger than 232 bytes.
  2. *
  3. The file is broken or truncated.
  4. *
  5. The file has not been generated by a standard-conformant compressor.
  6. *
  7. It is a multi-volume GZIP stream.
  8. *
*

* The advantage of this approach is, that it only reads the first 2 * and last 4 bytes of the target file. If the first 2 bytes are not * the GZIP magic number, the raw length of the file is returned. * * @see #isGzipStream(File) * @param file * @return the size of the uncompressed file content. */ public static long getGzipStreamSize(File file) { if (!isGzipStream(file)) { return file.length(); } RandomAccessFile raf = null; try { raf = new RandomAccessFile(file, "r"); if (raf.length() <= 4) { raf.close(); return file.length(); } raf.seek(raf.length() - 4); int b4 = raf.read(); int b3 = raf.read(); int b2 = raf.read(); int b1 = raf.read(); return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4; } catch (IOException ex) { return file.length(); } finally { if (raf!=null) try { raf.close(); } catch (IOException e) { // ignore } } } } /** * {@link Session} implementation over {@link ByteBuffer}. */ private static final class BufferSession implements Session { private final InputStream in; public BufferSession(ByteBuffer buf) { this.in = buf.newInputStream(); } public void close() throws IOException { in.close(); } public void skip(long start) throws IOException { while (start>0) start -= in.skip(start); } public int read(byte[] buf) throws IOException { return in.read(buf); } public int read(byte[] buf, int offset, int length) throws IOException { return in.read(buf,offset,length); } } /** * We cap the # of lines read in one batch to avoid buffering too much in memory. */ private static final int MAX_LINES_READ = 10000; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/io/CharSpool.java0000664000175000017500000000527112414640747032140 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.io; import java.io.Writer; import java.io.IOException; import java.util.List; import java.util.LinkedList; /** * {@link Writer} that spools the output and writes to another {@link Writer} later. * * @author Kohsuke Kawaguchi */ public /*for now, until Hudson migration completes*/ final class CharSpool extends Writer { private List buf; private char[] last = new char[1024]; private int pos; public void write(char cbuf[], int off, int len) { while(len>0) { int sz = Math.min(last.length-pos,len); System.arraycopy(cbuf,off,last,pos,sz); len -= sz; off += sz; pos += sz; renew(); } } private void renew() { if(pos(); buf.add(last); last = new char[1024]; pos = 0; } public void write(int c) { renew(); last[pos++] = (char)c; } public void flush() { // noop } public void close() { // noop } public void writeTo(Writer w) throws IOException { if(buf!=null) { for (char[] cb : buf) { w.write(cb); } } w.write(last,0,pos); } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/io/WriterOutputStream.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/io/WriterOutputStream.0000664000175000017500000001073312414640747033254 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.io; import java.io.OutputStream; import java.io.Writer; import java.io.IOException; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.CoderResult; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.nio.*; import java.nio.ByteBuffer; /** * {@link OutputStream} that writes to {@link Writer} * by assuming the platform default encoding. * * @author Kohsuke Kawaguchi */ public class WriterOutputStream extends OutputStream { private final Writer writer; private final CharsetDecoder decoder; private java.nio.ByteBuffer buf = ByteBuffer.allocate(1024); private CharBuffer out = CharBuffer.allocate(1024); public WriterOutputStream(Writer out, Charset charset) { this.writer = out; decoder = charset.newDecoder(); decoder.onMalformedInput(CodingErrorAction.REPLACE); decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); } public WriterOutputStream(Writer out) { this(out,DEFAULT_CHARSET); } public void write(int b) throws IOException { if(buf.remaining()==0) decode(false); buf.put((byte)b); } public void write(byte b[], int off, int len) throws IOException { while(len>0) { if(buf.remaining()==0) decode(false); int sz = Math.min(buf.remaining(),len); buf.put(b,off,sz); off += sz; len -= sz; } } public void flush() throws IOException { decode(false); flushOutput(); writer.flush(); } private void flushOutput() throws IOException { writer.write(out.array(),0,out.position()); out.clear(); } public void close() throws IOException { decode(true); flushOutput(); writer.close(); buf.rewind(); } /** * Decodes the contents of {@link #buf} as much as possible to {@link #out}. * If necessary {@link #out} is further sent to {@link #writer}. * *

* When this method returns, the {@link #buf} is back to the 'accumulation' * mode. * * @param last * if true, tell the decoder that all the input bytes are ready. */ private void decode(boolean last) throws IOException { buf.flip(); while(true) { CoderResult r = decoder.decode(buf, out, last); if(r==CoderResult.OVERFLOW) { flushOutput(); continue; } if(r==CoderResult.UNDERFLOW) { buf.compact(); return; } // otherwise treat it as an error r.throwException(); } } private static final Charset DEFAULT_CHARSET = getDefaultCharset(); private static Charset getDefaultCharset() { try { String encoding = System.getProperty("file.encoding"); return Charset.forName(encoding); } catch (UnsupportedCharsetException e) { return Charset.forName("UTF-8"); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/framework/io/ByteBuffer.java0000664000175000017500000001000612414640747032273 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.io; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.io.IOException; import java.io.InputStream; /** * {@link ByteArrayOutputStream} re-implementation. * *

* This version allows one to read while writing is in progress. * * @author Kohsuke Kawaguchi */ // TODO: reimplement this without buffer reallocation public class ByteBuffer extends OutputStream { private byte[] buf = new byte[8192]; /** * Size of the data. */ private int size = 0; public synchronized void write(byte b[], int off, int len) throws IOException { ensureCapacity(len); System.arraycopy(b,off,buf,size,len); size+=len; } public synchronized void write(int b) throws IOException { ensureCapacity(1); buf[size++] = (byte)b; } public synchronized long length() { return size; } private void ensureCapacity(int len) { if(buf.length-size>len) return; byte[] n = new byte[Math.max(buf.length*2, size+len)]; System.arraycopy(buf,0,n,0,size); this.buf = n; } public synchronized String toString() { return new String(buf,0,size); } /** * Writes the contents of this buffer to another OutputStream. */ public synchronized void writeTo(OutputStream os) throws IOException { os.write(buf,0,size); } /** * Creates an {@link InputStream} that reads from the underlying buffer. */ public InputStream newInputStream() { return new InputStream() { private int pos = 0; public int read() throws IOException { synchronized(ByteBuffer.this) { if(pos>=size) return -1; return buf[pos++]; } } public int read(byte b[], int off, int len) throws IOException { synchronized(ByteBuffer.this) { if(size==pos) return -1; int sz = Math.min(len,size-pos); System.arraycopy(buf,pos,b,off,sz); pos+=sz; return sz; } } public int available() throws IOException { synchronized(ByteBuffer.this) { return size-pos; } } public long skip(long n) throws IOException { synchronized(ByteBuffer.this) { int diff = (int) Math.min(n,size-pos); pos+=diff; return diff; } } }; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/TokenList.java0000664000175000017500000001340612414640747027555 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.util.StringTokenizer; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; /** * Tokenized path portion of the URL. * * For example "foo/bar/zot" is treated as ["foo","bar","zot"] * * @author Kohsuke Kawaguchi */ public final class TokenList { /** * URL-decoded tokens. */ public final String[] tokens; /** * Like {@link #tokens} but before decoding. */ public final String[] rawTokens; /** * Index of the next token. */ public int idx; /** * If the request URL ends with the path separator. */ public final boolean endsWithSlash; TokenList(String url) { // to avoid a directory traversal vulnerability in Windows, treat '\\' as a path separator just like '/' StringTokenizer tknzr = new StringTokenizer(url,"/\\"); final int tokenCount = tknzr.countTokens(); tokens = new String[tokenCount]; rawTokens = new String[tokenCount]; for(int i=0; tknzr.hasMoreTokens(); i++) { rawTokens[i] = tknzr.nextToken(); tokens[i] = decode(rawTokens[i]); if (tokens[i].equals("..")) throw new IllegalArgumentException(url); } endsWithSlash = url.endsWith("/") || url.endsWith("\\"); } public boolean hasMore() { return tokens.length!=idx; } public String peek() { if(hasMore()) return tokens[idx]; else return null; } public String next() { return tokens[idx++]; } public String prev() { return tokens[--idx]; } public int nextAsInt() throws NumberFormatException { String p = peek(); if(p==null) throw new NumberFormatException(); // no more token int i = Integer.valueOf(p); idx++; return i; } public int length() { return tokens.length; } public String get(int i) { return tokens[i]; } public int countRemainingTokens() { return length()-idx; } public String toString() { StringBuilder buf = new StringBuilder(); for( int i=0; i0) buf.append('/'); if(i==idx) buf.append('!'); buf.append(tokens[i]); } return buf.toString(); } private String assembleRestOfPath(String[] tokens) { StringBuilder buf = new StringBuilder(); for( int i=idx; i0) { buf.append(new String(baos.toByteArray(),"UTF-8")); baos.reset(); } buf.append(c); } } if (baos.size()>0) buf.append(new String(baos.toByteArray(),"UTF-8")); return buf.toString(); } catch (UnsupportedEncodingException e) { throw new AssertionError(e); // UTF-8 is mandatory encoding } } private static int fromHex(char upper) { return ((upper & 0xF) + ((upper & 0x40) != 0 ? 9 : 0)); } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/CancelRequestHandlingException.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/CancelRequestHandlingException.j0000664000175000017500000000117612414640747033234 0ustar ebourgebourgpackage org.kohsuke.stapler; /** * Signals that the request dispatching to the current method is cancelled, * and that Stapler should resume the search for the next request dispatcher * and dispatch the request accordingly. * *

* This is useful in conjunction with {@link StaplerOverridable} to delegate * requests selectively to original object after examining the request, * or in a request handling method like {@code doXyz()} method to then fall * back to {@code getDynamic()} or anything else. * * @author Kohsuke Kawaguchi * @since 1.210 */ public class CancelRequestHandlingException extends RuntimeException { } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/EvaluationTrace.java0000664000175000017500000000506412414640747030730 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.util.List; import java.util.ArrayList; import java.io.PrintWriter; /** * Remebers the {@link Stapler#invoke(RequestImpl, ResponseImpl, Object)} * evaluation traces. * * @author Kohsuke Kawaguchi */ public class EvaluationTrace { private final List traces = new ArrayList(); public void trace(StaplerResponse rsp, String msg) { traces.add(msg); // Firefox Live HTTP header plugin cannot nicely render multiple headers // with the same name, so give each one unique name. rsp.addHeader(String.format("Stapler-Trace-%03d",traces.size()),msg.replace("\n","\\n").replace("\r","\\r")); } public void printHtml(PrintWriter w) { for (String trace : traces) w.println(trace.replaceAll("&","&").replaceAll("<","<")); } public static EvaluationTrace get(StaplerRequest req) { EvaluationTrace et = (EvaluationTrace) req.getAttribute(KEY); if(et==null) req.setAttribute(KEY,et=new EvaluationTrace()); return et; } /** * Used for counting trace header. */ private static final String KEY = EvaluationTrace.class.getName(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/WebApp.java0000664000175000017500000002277412414640747027027 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import net.sf.json.JSONObject; import org.kohsuke.stapler.bind.BoundObjectTable; import org.kohsuke.stapler.lang.Klass; import javax.servlet.Filter; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.Vector; import java.util.Hashtable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; /** * Object scoped to the entire webapp. Mostly used for configuring behavior of Stapler. * *

* In contrast, {@link Stapler} is a servlet, so there can be multiple instances per webapp. * * @author Kohsuke Kawaguchi * @see WebApp#get(ServletContext) * @see WebApp#getCurrent() * @see Stapler#getWebApp() */ public class WebApp { /** * Obtains the {@link WebApp} associated with the given {@link ServletContext}. */ public static WebApp get(ServletContext context) { Object o = context.getAttribute(WebApp.class.getName()); if(o==null) { synchronized (WebApp.class) { o = context.getAttribute(WebApp.class.getName()); if(o==null) { o = new WebApp(context); context.setAttribute(WebApp.class.getName(),o); } } } return (WebApp)o; } /** * {@link ServletContext} for this webapp. */ public final ServletContext context; /** * Duck-type wrappers for the given class. */ public final Map wrappers = new HashMap(); /** * MIME type -> encoding map that determines how static contents in the war file is served. */ public final Map defaultEncodingForStaticResources = new HashMap(); /** * Activated facets. * * TODO: is this really mutable? */ public final List facets = new Vector(); /** * Global {@link BindInterceptor}s. * * These are consulted after {@link StaplerRequest#getBindInterceptor()} is consulted. * Global bind interceptors are useful to register webapp-wide conversion logic local to the application. * @since 1.220 */ public final List bindInterceptors = new CopyOnWriteArrayList(); /** * MIME type mapping from extensions (like "txt" or "jpg") to MIME types ("foo/bar"). * * This overrides whatever mappings given in the servlet as far as stapler is concerned. * This is case insensitive, and should be normalized to lower case. */ public final Map mimeTypes = new Hashtable(); private volatile ClassLoader classLoader; /** * All {@link MetaClass}es. * * Note that this permanently holds a strong reference to its key, i.e. is a memory leak. */ private final Map,MetaClass> classMap = new HashMap,MetaClass>(); /** * Handles objects that are exported. */ public final BoundObjectTable boundObjectTable = new BoundObjectTable(); private final CopyOnWriteArrayList responseRenderers = new CopyOnWriteArrayList(); private CrumbIssuer crumbIssuer = CrumbIssuer.DEFAULT; /** * Provides access to {@link Stapler} servlet instances. This is useful * for sending a request over to stapler from a context outside Stapler, * such as in {@link Filter}. * * Keyed by {@link ServletConfig#getServletName()}. */ private final ConcurrentMap servlets = new ConcurrentHashMap(); public WebApp(ServletContext context) { this.context = context; // TODO: allow classloader to be given? facets.addAll(Facet.discoverExtensions(Facet.class, Thread.currentThread().getContextClassLoader(), getClass().getClassLoader())); responseRenderers.add(new HttpResponseRenderer.Default()); } /** * Returns the 'app' object, which is the user-specified object that * sits at the root of the URL hierarchy and handles the request to '/'. */ public Object getApp() { return context.getAttribute("app"); } public void setApp(Object app) { context.setAttribute("app",app); } public CrumbIssuer getCrumbIssuer() { return crumbIssuer; } public void setCrumbIssuer(CrumbIssuer crumbIssuer) { this.crumbIssuer = crumbIssuer; } public CopyOnWriteArrayList getResponseRenderers() { return responseRenderers; } public ClassLoader getClassLoader() { ClassLoader cl = classLoader; if(cl==null) cl = Thread.currentThread().getContextClassLoader(); if(cl==null) cl = Stapler.class.getClassLoader(); return cl; } /** * If the facet of the given type exists, return it. Otherwise null. */ public T getFacet(Class type) { for (Facet f : facets) if(type==f.getClass()) return type.cast(f); return null; } /** * Sets the classloader used by {@link StaplerRequest#bindJSON(Class, JSONObject)} and its sibling methods. */ public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } public MetaClass getMetaClass(Class c) { return getMetaClass(Klass.java(c)); } public MetaClass getMetaClass(Klass c) { if(c==null) return null; synchronized(classMap) { MetaClass mc = classMap.get(c); if(mc==null) { mc = new MetaClass(this,c); classMap.put(c,mc); } return mc; } } /** * Obtains a {@link MetaClass} that represents the type of the given object. * *

* This code consults all facets to handle scripting language objects correctly. */ public MetaClass getMetaClass(Object o) { return getMetaClass(getKlass(o)); } public Klass getKlass(Object o) { for (Facet f : facets) { Klass k = f.getKlass(o); if (k!=null) return k; } return Klass.java(o.getClass()); } /** * Convenience maintenance method to clear all the cached scripts for the given tearoff type. * *

* This is useful when you want to have the scripts reloaded into the live system without * the performance penalty of {@link MetaClass#NO_CACHE}. * * @see MetaClass#NO_CACHE */ public void clearScripts(Class clazz) { synchronized (classMap) { for (MetaClass v : classMap.values()) { AbstractTearOff t = v.getTearOff(clazz); if (t!=null) t.clearScripts(); } } } void addStaplerServlet(String servletName, Stapler servlet) { if (servletName==null) servletName=""; // be defensive servlets.put(servletName,servlet); } /** * Gets a reference to some {@link Stapler} servlet in this webapp. * *

* Most Stapler webapps will have one <servlet> entry in web.xml * and if that's the case, that'd be returned. In a fully general case, * a webapp can have multiple servlets and more than one of them can be * {@link Stapler}. This method returns one of those. Which one gets * returned is unspecified. * *

* This method is useful if you are in a {@link Filter} and using * Stapler to handle the current request. For example, * *

     * WebApp.get(servletContext).getSomeStapler().invoke(
     *     request,response,
     *     someJavaObject,
     *     "/path/to/dispatch/request");
     * 
*/ public Stapler getSomeStapler() { return servlets.values().iterator().next(); } /** * Gets the current {@link WebApp} that the calling thread is associated with. */ public static WebApp getCurrent() { return Stapler.getCurrent().getWebApp(); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/Function.java0000664000175000017500000003451612414640747027433 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import org.kohsuke.stapler.interceptor.Interceptor; import org.kohsuke.stapler.interceptor.InterceptorAnnotation; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; /** * Abstracts the difference between normal instance methods and * static duck-typed methods. * * @author Kohsuke Kawaguchi */ public abstract class Function { /** * Gets the method name. */ public abstract String getName(); /** * Gets the human readable name of this function. Used to assist debugging. */ public abstract String getDisplayName(); /** * Gets "className.methodName" */ public abstract String getQualifiedName(); /** * Gets the type of parameters in a single array. */ public abstract Class[] getParameterTypes(); public abstract Type[] getGenericParameterTypes(); /** * Gets the annotations on parameters. */ public abstract Annotation[][] getParameterAnnotations(); /** * Gets the list of parameter names. */ public abstract String[] getParameterNames(); /** * Return type of the method. */ public abstract Class getReturnType(); /** * Calls {@link #bindAndInvoke(Object, StaplerRequest, StaplerResponse, Object...)} and then * optionally serve the response object. * * @return * true if the request was dispatched and processed. false if the dispatch was cancelled * and the search for the next request handler should continue. An exception is thrown * if the request was dispatched but the processing failed. */ boolean bindAndInvokeAndServeResponse(Object node, RequestImpl req, ResponseImpl rsp, Object... headArgs) throws IllegalAccessException, InvocationTargetException, ServletException, IOException { try { Object r = bindAndInvoke(node, req, rsp, headArgs); if (getReturnType()!=void.class) renderResponse(req,rsp,node, r); return true; } catch (InvocationTargetException e) { // exception as an HttpResponse Throwable te = e.getTargetException(); if (te instanceof CancelRequestHandlingException) return false; if (renderResponse(req,rsp,node,te)) return true; // exception rendered the response throw e; // unprocessed exception } } static boolean renderResponse(RequestImpl req, ResponseImpl rsp, Object node, Object ret) throws IOException, ServletException { for (HttpResponseRenderer r : req.stapler.getWebApp().getResponseRenderers()) if (r.generateResponse(req,rsp,node,ret)) return true; return false; } /** * Use the given arguments as the first N arguments, * then figure out the rest of the arguments by looking at parameter annotations, * then finally call {@link #invoke}. */ Object bindAndInvoke(Object o, StaplerRequest req, StaplerResponse rsp, Object... headArgs) throws IllegalAccessException, InvocationTargetException, ServletException { Class[] types = getParameterTypes(); Annotation[][] annotations = getParameterAnnotations(); String[] parameterNames = getParameterNames(); Object[] arguments = new Object[types.length]; // fill in the first N arguments System.arraycopy(headArgs,0,arguments,0,headArgs.length); try { // find the rest of the arguments. either known types, or with annotations for( int i=headArgs.length; i PARSE_METHODS; private static final Function RETURN_NULL; static { try { RETURN_NULL = new StaticFunction(Function.class.getMethod("returnNull")); } catch (NoSuchMethodException e) { throw new AssertionError(e); // impossible } PARSE_METHODS = CacheBuilder.newBuilder().weakKeys().build(new CacheLoader() { public Function load(Class from) { // MethdFunction for invoking a static method as a static method FunctionList methods = new ClassDescriptor(from).methods.name("fromStapler"); switch (methods.size()) { case 0: return RETURN_NULL; default: throw new IllegalArgumentException("Too many 'fromStapler' methods on "+from); case 1: Method m = ((MethodFunction)methods.get(0)).m; return new MethodFunction(m) { @Override public Class[] getParameterTypes() { return m.getParameterTypes(); } @Override public Type[] getGenericParameterTypes() { return m.getGenericParameterTypes(); } @Override public Annotation[][] getParameterAnnotations() { return m.getParameterAnnotations(); } @Override public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException { return m.invoke(null,args); } }; } } }); } public static Object returnNull() { return null; } /** * Invokes the method. */ public abstract Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException; final Function wrapByInterceptors(Method m) { try { Function f = this; for (Annotation a : m.getAnnotations()) { final InterceptorAnnotation ia = a.annotationType().getAnnotation(InterceptorAnnotation.class); if (ia!=null) { f = new InterceptedFunction(f,ia); } } return f; } catch (LinkageError e) { // running in JDK 1.4 return this; } } public abstract A getAnnotation(Class annotation); private abstract static class MethodFunction extends Function { protected final Method m; private volatile String[] names; public MethodFunction(Method m) { this.m = m; } public final String getName() { return m.getName(); } public final String getDisplayName() { return m.toGenericString(); } @Override public String getQualifiedName() { return m.getDeclaringClass().getName()+'.'+getName(); } public final A getAnnotation(Class annotation) { return m.getAnnotation(annotation); } public final String[] getParameterNames() { if(names==null) names = ClassDescriptor.loadParameterNames(m); return names; } @Override public Class getReturnType() { return m.getReturnType(); } } /** * Normal instance methods. */ static final class InstanceFunction extends MethodFunction { public InstanceFunction(Method m) { super(m); } public Class[] getParameterTypes() { return m.getParameterTypes(); } @Override public Type[] getGenericParameterTypes() { return m.getGenericParameterTypes(); } public Annotation[][] getParameterAnnotations() { return m.getParameterAnnotations(); } public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException { return m.invoke(o,args); } } /** * Static methods on the wrapper type. */ static final class StaticFunction extends MethodFunction { public StaticFunction(Method m) { super(m); } public Class[] getParameterTypes() { Class[] p = m.getParameterTypes(); Class[] r = new Class[p.length-1]; System.arraycopy(p,1,r,0,r.length); return r; } @Override public Type[] getGenericParameterTypes() { Type[] p = m.getGenericParameterTypes(); Type[] r = new Type[p.length-1]; System.arraycopy(p,1,r,0,r.length); return r; } public Annotation[][] getParameterAnnotations() { Annotation[][] a = m.getParameterAnnotations(); Annotation[][] r = new Annotation[a.length-1][]; System.arraycopy(a,1,r,0,r.length); return r; } public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException { Object[] r = new Object[args.length+1]; r[0] = o; System.arraycopy(args,0,r,1,args.length); return m.invoke(null,r); } } /** * Function that's wrapped by {@link Interceptor}. */ static final class InterceptedFunction extends Function { private final Function next; private final Interceptor interceptor; public InterceptedFunction(Function next, InterceptorAnnotation ia) { this.next = next; this.interceptor = instantiate(ia); interceptor.setTarget(next); } private Interceptor instantiate(InterceptorAnnotation ia) { try { return ia.value().newInstance(); } catch (InstantiationException e) { throw (Error)new InstantiationError("Failed to instantiate interceptor for "+next.getDisplayName()).initCause(e); } catch (IllegalAccessException e) { throw (Error)new IllegalAccessError("Failed to instantiate interceptor for "+next.getDisplayName()).initCause(e); } } public String getName() { return next.getName(); } public String getDisplayName() { return next.getDisplayName(); } @Override public String getQualifiedName() { return next.getQualifiedName(); } public Class[] getParameterTypes() { return next.getParameterTypes(); } @Override public Class getReturnType() { return next.getReturnType(); } @Override public Type[] getGenericParameterTypes() { return next.getGenericParameterTypes(); } public Annotation[][] getParameterAnnotations() { return next.getParameterAnnotations(); } public String[] getParameterNames() { return next.getParameterNames(); } public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException { return interceptor.invoke(req, rsp, o, args); } public A getAnnotation(Class annotation) { return next.getAnnotation(annotation); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/ForwardToView.java0000664000175000017500000000742312414640747030405 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import javax.servlet.ServletException; import javax.servlet.RequestDispatcher; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; /** * {@link HttpResponse} that forwards to a {@link RequestDispatcher}, such as a view. * Extends from {@link RuntimeException} so that you can throw it. * * @author Kohsuke Kawaguchi */ public class ForwardToView extends RuntimeException implements HttpResponse { private final DispatcherFactory factory; private boolean optional; private final Map attributes = new HashMap(); private interface DispatcherFactory { RequestDispatcher get(StaplerRequest req) throws IOException; } public ForwardToView(final RequestDispatcher dispatcher) { this.factory = new DispatcherFactory() { public RequestDispatcher get(StaplerRequest req) { return dispatcher; } }; } public ForwardToView(final Object it, final String view) { this.factory = new DispatcherFactory() { public RequestDispatcher get(StaplerRequest req) throws IOException { return req.getView(it,view); } }; } public ForwardToView(final Class c, final String view) { this.factory = new DispatcherFactory() { public RequestDispatcher get(StaplerRequest req) throws IOException { return req.getView(c,view); } }; } /** * Forwards to the view with specified attributes exposed as a variable binding. */ public ForwardToView with(String varName, Object value) { attributes.put(varName,value); return this; } public ForwardToView with(Map attributes) { this.attributes.putAll(attributes); return this; } /** * Make this forwarding optional. Render nothing if a view doesn't exist. */ public ForwardToView optional() { optional = true; return this; } public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { for (Entry e : attributes.entrySet()) req.setAttribute(e.getKey(),e.getValue()); RequestDispatcher rd = factory.get(req); if (rd==null && optional) return; rd.forward(req, rsp); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/Optional.java0000664000175000017500000000371612414640747027431 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; /** * Represents a T value or no value at all. Used to work around the lack of null value in the computing map. * * @author Kohsuke Kawaguchi */ final class Optional { private final T value; Optional(T value) { this.value = value; } public T get() { return value; } private static Optional NONE = new Optional(null); public static Optional none() { return NONE; } public static Optional create(T value) { if (value==null) return NONE; // cache return new Optional(value); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/StaplerFallback.java0000664000175000017500000000423212414640747030670 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; /** * An object can fall back to another object for a part of its UI processing, * by implementing this interface and designating another object from * {@link #getStaplerFallback()}. * *

* Compared to {@link StaplerProxy}, stapler handles this interface at the very end, * whereas {@link StaplerProxy} is handled at the very beginning. * * @author Kohsuke Kawaguchi * @see StaplerProxy */ public interface StaplerFallback { /** * Returns the object that is further searched for processing web requests. * * @return * If null or {@code this} is returned, stapler behaves as if the object * didn't implement this interface (which means the request processing * failes with 404.) */ Object getStaplerFallback(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/ClassDescriptor.java0000664000175000017500000003060612414640747030746 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import org.apache.commons.io.IOUtils; import org.kohsuke.asm5.ClassReader; import org.kohsuke.asm5.ClassVisitor; import org.kohsuke.asm5.Label; import org.kohsuke.asm5.MethodVisitor; import org.kohsuke.asm5.Type; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.TreeMap; import java.util.logging.Logger; import static java.util.logging.Level.FINE; import static java.util.logging.Level.WARNING; import static org.kohsuke.asm5.Opcodes.ASM5; /** * Reflection information of a {@link Class}. * * @author Kohsuke Kawaguchi */ public final class ClassDescriptor { public final Class clazz; public final FunctionList methods; public final Field[] fields; /** * @param clazz * The class to build a descriptor around. * @param wrappers * Optional wrapper duck-typing classes. * Static methods on this class that has the first parameter * as 'clazz' will be handled as if it's instance methods on * 'clazz'. Useful for adding view/controller methods on * model classes. */ public ClassDescriptor(Class clazz, Class... wrappers) { this.clazz = clazz; this.fields = clazz.getFields(); // instance methods List functions = new ArrayList(); for (Method m : clazz.getMethods()) { functions.add(new Function.InstanceFunction(m).wrapByInterceptors(m)); } if(wrappers!=null) { for (Class w : wrappers) { for (Method m : w.getMethods()) { if(!Modifier.isStatic(m.getModifiers())) continue; Class[] p = m.getParameterTypes(); if(p.length==0) continue; if(p[0].isAssignableFrom(clazz)) continue; functions.add(new Function.StaticFunction(m).wrapByInterceptors(m)); } } } this.methods = new FunctionList(functions); } /** * Loads the list of parameter names of the given method, by using a stapler-specific way of getting it. * *

* This is not the best place to expose this, but for now this would do. */ public static String[] loadParameterNames(Method m) { CapturedParameterNames cpn = m.getAnnotation(CapturedParameterNames.class); if(cpn!=null) return cpn.value(); // debug information, if present, is more trustworthy try { String[] n = ASM.loadParametersFromAsm(m); if (n!=null) return n; } catch (LinkageError e) { LOGGER.log(FINE, "Incompatible ASM", e); } catch (IOException e) { LOGGER.log(WARNING, "Failed to load a class file", e); } // otherwise check the .stapler file Class c = m.getDeclaringClass(); URL url = c.getClassLoader().getResource( c.getName().replace('.', '/').replace('$','/') + '/' + m.getName() + ".stapler"); if(url!=null) { try { return IOUtils.toString(url.openStream()).split(","); } catch (IOException e) { LOGGER.log(WARNING, "Failed to load "+url,e); return EMPTY_ARRAY; } } // couldn't find it return EMPTY_ARRAY; } /** * Loads the list of parameter names of the given method, by using a stapler-specific way of getting it. * *

* This is not the best place to expose this, but for now this would do. */ public static String[] loadParameterNames(Constructor m) { CapturedParameterNames cpn = m.getAnnotation(CapturedParameterNames.class); if(cpn!=null) return cpn.value(); // debug information, if present, is more trustworthy try { String[] n = ASM.loadParametersFromAsm(m); if (n!=null) return n; } catch (LinkageError e) { LOGGER.log(FINE, "Incompatible ASM", e); } catch (IOException e) { LOGGER.log(WARNING, "Failed to load a class file", e); } // couldn't find it return EMPTY_ARRAY; } /** * Determines the constructor parameter names. * *

* First, try to load names from the debug information. Otherwise * if there's the .stapler file, load it as a property file and determines the constructor parameter names. * Otherwise, look for {@link CapturedParameterNames} annotation. */ public String[] loadConstructorParamNames() { Constructor[] ctrs = clazz.getConstructors(); // which constructor was data bound? Constructor dbc = null; for (Constructor c : ctrs) { if (c.getAnnotation(DataBoundConstructor.class) != null) { dbc = c; break; } } if (dbc==null) throw new NoStaplerConstructorException("There's no @DataBoundConstructor on any constructor of " + clazz); String[] names = ClassDescriptor.loadParameterNames(dbc); if (names.length==dbc.getParameterTypes().length) return names; String resourceName = clazz.getName().replace('.', '/').replace('$','/') + ".stapler"; ClassLoader cl = clazz.getClassLoader(); if(cl==null) throw new NoStaplerConstructorException(clazz+" is a built-in type"); InputStream s = cl.getResourceAsStream(resourceName); if (s != null) {// load the property file and figure out parameter names try { Properties p = new Properties(); p.load(s); s.close(); String v = p.getProperty("constructor"); if (v.length() == 0) return new String[0]; return v.split(","); } catch (IOException e) { throw new IllegalArgumentException("Unable to load " + resourceName, e); } } // no debug info and no stapler file throw new NoStaplerConstructorException( "Unable to find " + resourceName + ". " + "Run 'mvn clean compile' once to run the annotation processor."); } /** * Isolate the ASM dependency to its own class, as otherwise this seems to cause linkage error on the whole {@link ClassDescriptor}. */ private static class ASM { /** * Try to load parameter names from the debug info by using ASM. */ private static String[] loadParametersFromAsm(final Method m) throws IOException { final String[] paramNames = new String[m.getParameterTypes().length]; if (paramNames.length==0) return paramNames; Class c = m.getDeclaringClass(); URL clazz = c.getClassLoader().getResource(c.getName().replace('.', '/') + ".class"); if (clazz==null) return null; final TreeMap localVars = new TreeMap(); ClassReader r = new ClassReader(clazz.openStream()); r.accept(new ClassVisitor(ASM5) { final String md = Type.getMethodDescriptor(m); // First localVariable is "this" for non-static method final int limit = (m.getModifiers() & Modifier.STATIC) != 0 ? 0 : 1; @Override public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, String[] exceptions) { if (methodName.equals(m.getName()) && desc.equals(md)) return new MethodVisitor(ASM5) { @Override public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { if (index >= limit) localVars.put(index, name); } }; else return null; // ignore this method } }, 0); // Indexes may not be sequential, but first set of local variables are method params int i = 0; for (String s : localVars.values()) { paramNames[i] = s; if (++i == paramNames.length) return paramNames; } return null; // Not enough data found to fill array } /** * Try to load parameter names from the debug info by using ASM. */ private static String[] loadParametersFromAsm(final Constructor m) throws IOException { final String[] paramNames = new String[m.getParameterTypes().length]; if (paramNames.length==0) return paramNames; Class c = m.getDeclaringClass(); URL clazz = c.getClassLoader().getResource(c.getName().replace('.', '/') + ".class"); if (clazz==null) return null; final TreeMap localVars = new TreeMap(); InputStream is = clazz.openStream(); try { ClassReader r = new ClassReader(is); r.accept(new ClassVisitor(ASM5) { final String md = getConstructorDescriptor(m); public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, String[] exceptions) { if (methodName.equals("") && desc.equals(md)) return new MethodVisitor(ASM5) { @Override public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { if (index>0) // 0 is 'this' localVars.put(index, name); } }; else return null; // ignore this method } }, 0); } finally { is.close(); } // Indexes may not be sequential, but first set of local variables are method params int i = 0; for (String s : localVars.values()) { paramNames[i] = s; if (++i == paramNames.length) return paramNames; } return null; // Not enough data found to fill array } private static String getConstructorDescriptor(Constructor c) { StringBuilder buf = new StringBuilder("("); for (Class p : c.getParameterTypes()) buf.append(Type.getDescriptor(p)); return buf.append(")V").toString(); } } private static final Logger LOGGER = Logger.getLogger(ClassDescriptor.class.getName()); private static final String[] EMPTY_ARRAY = new String[0]; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/AbstractTearOff.java0000664000175000017500000001060012414640747030644 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.net.URL; import java.util.Collection; /** * Partial default implementation of tear-off class, for convenience of derived classes. * * @param * ClassLoader tear-off. * @author Kohsuke Kawaguchi */ public abstract class AbstractTearOff extends CachingScriptLoader { protected final MetaClass owner; protected final CLT classLoader; protected AbstractTearOff(MetaClass owner, Class cltClass) { this.owner = owner; if(owner.classLoader!=null) classLoader = owner.classLoader.loadTearOff(cltClass); else classLoader = null; } protected final WebApp getWebApp() { return owner.webApp; } /** * The file extension of this kind of scripts, such as ".jelly" */ protected abstract String getDefaultScriptExtension(); /** * Checks if the file name is allowed as a script of this type. * * This is necessary to have multiple facets co-exist peacefully * without them trying to load each other's scripts. */ protected boolean hasAllowedExtension(String name) { return name.endsWith(getDefaultScriptExtension()); } /** * Loads the script just from the target class without considering inherited scripts * from its base types. */ public S resolveScript(String name) throws E { if (name.lastIndexOf('.')<=name.lastIndexOf('/')) // no file extension provided name += getDefaultScriptExtension(); if (!hasAllowedExtension(name)) // for multiple Facets to co-exist peacefully, we need to be able to determine // which Facet is responsible for a given view just from the file name return null; URL res = getResource(name); if(res==null) { // look for 'defaults' file int dot = name.lastIndexOf('.'); // foo/bar.groovy -> foo/bar.default.groovy // but don't do foo.bar/test -> foo.default.bar/test // as of 2010/9, this behaviour is considered deprecated, but left here for backward compatibility. // we need a better way to refer to the resource of the same name in the base type. if(name.lastIndexOf('/'))owner.baseClass.loadTearOff(getClass())).findScript(name); return null; } /** * Compiles a script into the compiled form. */ protected abstract S parseScript(URL res) throws E; protected URL getResource(String name) { return owner.klass.getResource(name); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/AnnotationHandler.java0000664000175000017500000001133612414640747031251 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import org.apache.commons.beanutils.Converter; import javax.servlet.ServletException; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * Handles stapler parameter annotations by determining what values to inject for a method call. * * @author Kohsuke Kawaguchi * @see InjectedParameter */ public abstract class AnnotationHandler { /** * * @param request * Current request being processed. Normally the parameter injection grabs some value from here and returns it. * Never null. * @param a * The annotation object attached on the parameter for which this handler is configured. Never null * @param type * The type of the parameter. Any value returned from this method must be assignable to this type. * Never null. * @param parameterName * Name of the parameter. */ public abstract Object parse(StaplerRequest request, T a, Class type, String parameterName) throws ServletException; /** * Helper method for {@link #parse(StaplerRequest, Annotation, Class, String)} to convert to the right type * from String. */ protected final Object convert(Class targetType, String value) { Converter converter = Stapler.lookupConverter(targetType); if (converter==null) throw new IllegalArgumentException("Unable to convert to "+targetType); return converter.convert(targetType,value); } static Object handle(StaplerRequest request, Annotation[] annotations, String parameterName, Class targetType) throws ServletException { for (Annotation a : annotations) { Class at = a.annotationType(); AnnotationHandler h = HANDLERS.get(at); if (h==null) { InjectedParameter ip = at.getAnnotation(InjectedParameter.class); if (ip!=null) { try { h = ip.value().newInstance(); } catch (InstantiationException e) { throw new ServletException("Failed to instantiate parameter injector for "+at,e); } catch (IllegalAccessException e) { throw new ServletException("Failed to instantiate parameter injector for "+at,e); } } else { h = NOT_HANDLER; } AnnotationHandler prev = HANDLERS.putIfAbsent(at, h); if (prev!=null) h=prev; } if (h==NOT_HANDLER) continue; return h.parse(request,a,targetType,parameterName); } return null; // probably we should report an error } private static final ConcurrentMap,AnnotationHandler> HANDLERS = new ConcurrentHashMap, AnnotationHandler>(); private static final AnnotationHandler NOT_HANDLER = new AnnotationHandler() { @Override public Object parse(StaplerRequest request, Annotation a, Class type, String parameterName) throws ServletException { return null; } }; static { // synchronize with CaptureParameterNameTransformation.HANDLER_ANN } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/Ancestor.java0000664000175000017500000000730512414640747027420 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import javax.servlet.http.HttpServletRequest; /** * Information about ancestor of the "it" node. * * @author Kohsuke Kawaguchi */ public interface Ancestor { /** * Gets the model object of the application. */ Object getObject(); /** * Gets the URL to this ancestor. * *

* The returned string represents the portion of the request URL * that matches this object. It starts with * {@link HttpServletRequest#getContextPath() context path}, * and it ends without '/'. So, for example, if your web app * is deployed as "mywebapp" and this ancestor object is * obtained from the app root object by getFoo().getBar(3), * then this string will be /mywebapp/foo/bar/3 * *

* Any ASCII-unsafe characters are escaped. * * @return * never null. */ String getUrl(); /** * Gets the remaining URL after this ancestor. * *

* The returned string represents the portion of the request URL * that follows this ancestor. It starts and ends without '/'. * So, for example, if the request URL is "foo/bar/3" and this ancestor object is * obtained from the app root object by getFoo(), * then this string will be bar/3 */ String getRestOfUrl(); /** * Of the tokens that constitute {@link #getRestOfUrl()}, * return the n-th token. So in the example described in {@link #getRestOfUrl()}, * {@code getNextToken(0).equals("bar")} and * {@code getNextToken(1).equals("3")} */ String getNextToken(int n); /** * Gets the complete URL to this ancestor. * *

* This method works like {@link #getUrl()} except it contains * the host name and the port number. */ String getFullUrl(); /** * Gets the relative path from the current object to this ancestor. * *

* The returned string looks like "../.." (ends without '/') * * @return * never null. */ String getRelativePath(); /** * Gets the previous ancestor, or null if none (meaning * this is the root object.) */ Ancestor getPrev(); /** * Gets the next ancestor, or null if none (meaning * this is the 'it' object. */ Ancestor getNext(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/DataBoundConstructor.java0000664000175000017500000000502212414640747031743 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import net.sf.json.JSONObject; import java.lang.annotation.Documented; import static java.lang.annotation.ElementType.CONSTRUCTOR; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Target; /** * Designates the constructor to be created * from methods like * {@link StaplerRequest#bindJSON(Class, JSONObject)} and * {@link StaplerRequest#bindParameters(Class, String)}. * *

* Stapler will invoke the designated constructor by using arguments from the corresponding * {@link JSONObject} (in case of {@link StaplerRequest#bindJSON(Class, JSONObject)}) or request parameters * (in case of {@link StaplerRequest#bindParameters(Class, String)}). * *

* The matching is done by using the constructor parameter name. Since this information is not available * at the runtime, annotation processing runs during the compilation to capture them in separate "*.stapler" files. * * *

* This replaces "@stapler-constructor" annotation. * * @author Kohsuke Kawaguchi */ @Retention(RUNTIME) @Target(CONSTRUCTOR) @Documented public @interface DataBoundConstructor { } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/HttpResponses.java0000664000175000017500000002054612414640747030465 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY; /** * Factory for {@link HttpResponse}. * * @author Kohsuke Kawaguchi */ public class HttpResponses { public static abstract class HttpResponseException extends RuntimeException implements HttpResponse { public HttpResponseException() { } public HttpResponseException(String message) { super(message); } public HttpResponseException(String message, Throwable cause) { super(message, cause); } public HttpResponseException(Throwable cause) { super(cause); } } public static HttpResponseException ok() { return status(HttpServletResponse.SC_OK); } public static HttpResponseException notFound() { return status(HttpServletResponse.SC_NOT_FOUND); } public static HttpResponseException forbidden() { return status(HttpServletResponse.SC_FORBIDDEN); } public static HttpResponseException status(final int code) { return new HttpResponseException() { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.setStatus(code); } }; } /** * Sends an error with a stack trace. * @see #errorWithoutStack */ @SuppressWarnings({"ThrowableInstanceNeverThrown"}) public static HttpResponseException error(int code, String errorMessage) { return error(code,new Exception(errorMessage)); } public static HttpResponseException error(Throwable cause) { return error(500,cause); } public static HttpResponseException error(final int code, final Throwable cause) { return new HttpResponseException(cause) { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.setStatus(code); rsp.setContentType("text/plain;charset=UTF-8"); PrintWriter w = new PrintWriter(rsp.getWriter()); cause.printStackTrace(w); w.close(); } }; } /** * Sends an error without a stack trace. * @since 1.215 * @see #error(int, String) */ public static HttpResponseException errorWithoutStack(final int code, final String errorMessage) { return new HttpResponseException() { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.sendError(code, errorMessage); } }; } public static HttpResponseException redirectViaContextPath(String relative) { return redirectViaContextPath(SC_MOVED_TEMPORARILY,relative); } /** * @param relative * The path relative to the context path. The context path + this value * is sent to the user. */ public static HttpResponseException redirectViaContextPath(final int statusCode, final String relative) { return new HttpResponseException() { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { StringBuilder sb = new StringBuilder(req.getContextPath()); if (!relative.startsWith("/")) sb.append('/'); sb.append(relative); rsp.sendRedirect(statusCode,sb.toString()); } }; } /** * @param url * The URL to redirect to. If relative, relative to the page currently being served. */ public static HttpRedirect redirectTo(String url) { return new HttpRedirect(url); } public static HttpRedirect redirectTo(int statusCode, String url) { return new HttpRedirect(statusCode,url); } /** * Redirect to "." */ public static HttpResponse redirectToDot() { return HttpRedirect.DOT; } /** * Redirect to the context root */ public static HttpResponseException redirectToContextRoot() { return redirectViaContextPath(""); } /** * Redirects the user back to where he came from. */ public static HttpResponseException forwardToPreviousPage() { return FORWARD_TO_PREVIOUS_PAGE; } private static final HttpResponseException FORWARD_TO_PREVIOUS_PAGE = new HttpResponseException() { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.forwardToPreviousPage(req); } }; /** * Serves a static resource specified by the URL. * Short for {@code staticResource(resource,0)} */ public static HttpResponse staticResource(URL resource) { return staticResource(resource,0); } /** * Serves a static resource specified by the URL. * * @param resource * The static resource to be served. * @param expiration * The number of milliseconds until the resource will "expire". * Until it expires the browser will be allowed to cache it * and serve it without checking back with the server. * After it expires, the client will send conditional GET to * check if the resource is actually modified or not. * If 0, it will immediately expire. */ public static HttpResponse staticResource(final URL resource, final long expiration) { return new HttpResponse() { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.serveFile(req,resource,expiration); } }; } /** * Serves the literal HTML. */ public static HttpResponse html(final String literalHtml) { return new HttpResponse() { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.setContentType("text/html;charset=UTF-8"); rsp.getWriter().println(literalHtml); } }; } /** * Serves the plain text. */ public static HttpResponse plainText(final String plainText) { return new HttpResponse() { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.setContentType("text/plain;charset=UTF-8"); rsp.getWriter().println(plainText); } }; } public static ForwardToView forwardToView(Object it, String view) { return new ForwardToView(it,view); } public static ForwardToView forwardToView(Class clazz, String view) { return new ForwardToView(clazz,view); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/ReflectionUtils.java0000664000175000017500000000403312414640747030750 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.util.HashMap; import java.util.Map; /** * @author Kohsuke Kawaguchi */ public class ReflectionUtils { /** * Given the primitive type, returns the VM default value for that type in a boxed form. * For reference types, return null. */ public static Object getVmDefaultValueFor(Class type) { return defaultPrimitiveValue.get(type); } private static final Map defaultPrimitiveValue = new HashMap(); static { defaultPrimitiveValue.put(boolean.class,false); defaultPrimitiveValue.put(int.class,0); defaultPrimitiveValue.put(long.class,0L); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/ScriptLoadException.java0000664000175000017500000000331712414640747031564 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; /** * Indicates a failure to load a script. * * @author Kohsuke Kawaguchi */ public class ScriptLoadException extends RuntimeException { public ScriptLoadException(String message, Throwable cause) { super(message, cause); } public ScriptLoadException(Throwable cause) { super(cause); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/RequestImpl.java0000664000175000017500000010356612414640747030122 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONException; import net.sf.json.JSONNull; import net.sf.json.JSONObject; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.Converter; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.jvnet.tiger_types.Lister; import org.kohsuke.stapler.bind.BoundObjectTable; import org.kohsuke.stapler.lang.Klass; import org.kohsuke.stapler.lang.MethodRef; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.logging.Logger; import static java.util.logging.Level.WARNING; import static javax.servlet.http.HttpServletResponse.*; /** * {@link StaplerRequest} implementation. * * @author Kohsuke Kawaguchi */ public class RequestImpl extends HttpServletRequestWrapper implements StaplerRequest { /** * Tokenized URLs and consumed tokens. * This object is modified by {@link Stapler} as we parse through the URL. */ public final TokenList tokens; /** * Ancesotr nodes traversed so far. * This object is modified by {@link Stapler} as we parse through the URL. */ public final List ancestors; private final List ancestorsView; public final Stapler stapler; private final String originalRequestURI; /** * Cached result of {@link #getSubmittedForm()} */ private JSONObject structuredForm; /** * If the request is "multipart/form-data", parsed result goes here. * * @see #parseMultipartFormData() */ private Map parsedFormData; private BindInterceptor bindInterceptor = BindInterceptor.NOOP; public RequestImpl(Stapler stapler, HttpServletRequest request, List ancestors, TokenList tokens) { super(request); this.stapler = stapler; this.ancestors = ancestors; this.ancestorsView = Collections.unmodifiableList(ancestors); this.tokens = tokens; this.originalRequestURI = request.getRequestURI(); } public boolean isJavaScriptProxyCall() { String ct = getContentType(); return ct!=null && ct.startsWith("application/x-stapler-method-invocation"); } public BoundObjectTable getBoundObjectTable() { return stapler.getWebApp().boundObjectTable; } public String createJavaScriptProxy(Object toBeExported) { return getBoundObjectTable().bind(toBeExported).getProxyScript(); } public Stapler getStapler() { return stapler; } public WebApp getWebApp() { return stapler.getWebApp(); } public String getRestOfPath() { return tokens.assembleRestOfPath(); } public String getOriginalRestOfPath() { return tokens.assembleOriginalRestOfPath(); } public ServletContext getServletContext() { return stapler.getServletContext(); } public String getRequestURIWithQueryString() { String s = getRequestURI(); String q = getQueryString(); if (q!=null) s+='?'+q; return s; } public StringBuffer getRequestURLWithQueryString() { StringBuffer s = getRequestURL(); String q = getQueryString(); if (q!=null) s.append('?').append(q); return s; } public RequestDispatcher getView(Object it,String viewName) throws IOException { return getView(Klass.java(it.getClass()),it,viewName); } public RequestDispatcher getView(Class clazz, String viewName) throws IOException { return getView(Klass.java(clazz),null,viewName); } public RequestDispatcher getView(Klass clazz, String viewName) throws IOException { return getView(clazz,null,viewName); } public RequestDispatcher getView(Klass clazz, Object it, String viewName) throws IOException { for( Facet f : stapler.getWebApp().facets ) { RequestDispatcher rd = f.createRequestDispatcher(this,clazz,it,viewName); if(rd!=null) return rd; } return null; } public String getRootPath() { StringBuffer buf = super.getRequestURL(); int idx = 0; for( int i=0; i<3; i++ ) idx += buf.substring(idx).indexOf("/")+1; buf.setLength(idx-1); buf.append(super.getContextPath()); return buf.toString(); } public String getReferer() { return getHeader("Referer"); } public List getAncestors() { return ancestorsView; } public Ancestor findAncestor(Class type) { for( int i = ancestors.size()-1; i>=0; i-- ) { AncestorImpl a = ancestors.get(i); Object o = a.getObject(); if (type.isInstance(o)) return a; } return null; } public T findAncestorObject(Class type) { Ancestor a = findAncestor(type); if(a==null) return null; return type.cast(a.getObject()); } public Ancestor findAncestor(Object anc) { for( int i = ancestors.size()-1; i>=0; i-- ) { AncestorImpl a = ancestors.get(i); Object o = a.getObject(); if (o==anc) return a; } return null; } public boolean hasParameter(String name) { return getParameter(name)!=null; } public String getOriginalRequestURI() { return originalRequestURI; } public boolean checkIfModified(long lastModified, StaplerResponse rsp) { return checkIfModified(lastModified,rsp,0); } public boolean checkIfModified(long lastModified, StaplerResponse rsp, long expiration) { if(lastModified<=0) return false; // send out Last-Modified, or check If-Modified-Since String since = getHeader("If-Modified-Since"); SimpleDateFormat format = Stapler.HTTP_DATE_FORMAT.get(); if(since!=null) { try { long ims = format.parse(since).getTime(); if(lastModified List bindParametersToList(Class type, String prefix) { List r = new ArrayList(); int len = Integer.MAX_VALUE; Enumeration e = getParameterNames(); while(e.hasMoreElements()) { String name = (String)e.nextElement(); if(name.startsWith(prefix)) len = Math.min(len,getParameterValues(name).length); } if(len==Integer.MAX_VALUE) return r; // nothing try { new ClassDescriptor(type).loadConstructorParamNames(); // use the designated constructor for databinding for( int i=0; i T bindParameters(Class type, String prefix) { return bindParameters(type,prefix,0); } public T bindParameters(Class type, String prefix, int index) { String[] names = new ClassDescriptor(type).loadConstructorParamNames(); // the actual arguments to invoke the constructor with. Object[] args = new Object[names.length]; // constructor Constructor c = findConstructor(type, names.length); Class[] types = c.getParameterTypes(); // convert parameters for( int i=0; i T bindJSON(Class type, JSONObject src) { return type.cast(bindJSON(type, type, src)); } public Object bindJSON(Type type, Class erasure, Object json) { return new TypePair(type,erasure).convertJSON(json); } public void bindJSON(Object bean, JSONObject src) { try { for( String key : (Set)src.keySet() ) { TypePair type = getPropertyType(bean, key); if(type==null) continue; fill(bean,key, type.convertJSON(src.get(key))); } } catch (IllegalAccessException e) { IllegalAccessError x = new IllegalAccessError(e.getMessage()); x.initCause(e); throw x; } catch (InvocationTargetException x) { Throwable e = x.getTargetException(); if(e instanceof RuntimeException) throw (RuntimeException)e; if(e instanceof Error) throw (Error)e; throw new RuntimeException(x); } } public List bindJSONToList(Class type, Object src) { ArrayList r = new ArrayList(); if (src instanceof JSONObject) { JSONObject j = (JSONObject) src; r.add(bindJSON(type,j)); } if (src instanceof JSONArray) { JSONArray a = (JSONArray) src; for (Object o : a) { if (o instanceof JSONObject) { JSONObject j = (JSONObject) o; r.add(bindJSON(type,j)); } } } return r; } private T invokeConstructor(Constructor c, Object[] args) { try { return c.newInstance(args); } catch (InstantiationException e) { InstantiationError x = new InstantiationError(e.getMessage()); x.initCause(e); throw x; } catch (IllegalAccessException e) { IllegalAccessError x = new IllegalAccessError(e.getMessage()); x.initCause(e); throw x; } catch (InvocationTargetException e) { Throwable x = e.getTargetException(); if(x instanceof Error) throw (Error)x; if(x instanceof RuntimeException) throw (RuntimeException)x; throw new IllegalArgumentException(x); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Failed to invoke "+c+" with "+ Arrays.asList(args),e); } } private Constructor findConstructor(Class type, int length) { Constructor[] ctrs = type.getConstructors(); // one with DataBoundConstructor is the most reliable for (Constructor c : ctrs) { if(c.getAnnotation(DataBoundConstructor.class)!=null) { if(c.getParameterTypes().length!=length) throw new IllegalArgumentException(c+" has @DataBoundConstructor but it doesn't match with your .stapler file. Try clean rebuild"); return c; } } // if not, maybe this was from @stapler-constructor, // so look for the constructor with the expected argument length. // this is not very reliable. for (Constructor c : ctrs) { if(c.getParameterTypes().length==length) return c; } throw new IllegalArgumentException(type+" does not have a constructor with "+length+" arguments"); } private static void fill(Object bean, String key, Object value) { StringTokenizer tokens = new StringTokenizer(key); while(tokens.hasMoreTokens()) { String token = tokens.nextToken(); boolean last = !tokens.hasMoreTokens(); // is this the last token? try { if(last) { copyProperty(bean,token,value); } else { bean = BeanUtils.getProperty(bean,token); } } catch (IllegalAccessException x) { throw new IllegalAccessError(x.getMessage()); } catch (InvocationTargetException x) { Throwable e = x.getTargetException(); if(e instanceof RuntimeException) throw (RuntimeException)e; if(e instanceof Error) throw (Error)e; throw new RuntimeException(x); } catch (NoSuchMethodException e) { // ignore if there's no such property } } } /** * Information about the type. */ private final class TypePair { final Type genericType; /** * Erasure of {@link #genericType} */ final Class type; TypePair(Type genericType, Class type) { this.genericType = genericType; this.type = type; } TypePair(Field f) { this(f.getGenericType(),f.getType()); } /** * Converts the given JSON object (either {@link JSONObject}, {@link JSONArray}, or other primitive types * in JSON, to the type represented by the 'this' object. */ public Object convertJSON(Object o) { Object r = bindInterceptor.onConvert(genericType, type, o); if (r!= BindInterceptor.DEFAULT) return r; // taken over by the interceptor for (BindInterceptor i : getWebApp().bindInterceptors) { r = i.onConvert(genericType, type, o); if (r!= BindInterceptor.DEFAULT) return r; // taken over by the interceptor } if(o==null || o instanceof JSONNull) { // this method returns null if the type is not primitive, which works. return ReflectionUtils.getVmDefaultValueFor(type); } if (type==JSONArray.class) { if (o instanceof JSONArray) return o; JSONArray a = new JSONArray(); a.add(o); return a; } Lister l = Lister.create(type,genericType); if (o instanceof JSONObject) { JSONObject j = (JSONObject) o; if (j.isNullObject()) // another flavor of null. json-lib sucks. return ReflectionUtils.getVmDefaultValueFor(type); if(l==null) {// single value conversion try { Class actualType = type; if(j.has("stapler-class")) { // sub-type is specified in JSON. // note that this can come from malicious clients, so we need to make sure we don't have security issues. ClassLoader cl = stapler.getWebApp().getClassLoader(); String className = j.getString("stapler-class"); try { Class subType = cl.loadClass(className); if(!actualType.isAssignableFrom(subType)) throw new IllegalArgumentException("Specified type "+subType+" is not assignable to the expected "+actualType); actualType = (Class)subType; // I'm being lazy here } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Class "+className+" is specified in JSON, but no such class found in "+cl,e); } } return instantiate(actualType, j); } catch (IllegalArgumentException e) { throw new IllegalArgumentException("Failed to instantiate "+type+" from "+j,e); } } else {// collection conversion if(j.has("stapler-class-bag")) { // this object is a hash from class names to their parameters // build them into a collection via Lister ClassLoader cl = stapler.getWebApp().getClassLoader(); for (Map.Entry e : (Set>)j.entrySet()) { Object v = e.getValue(); String className = e.getKey().replace('-','.'); // decode JSON-safe class name escaping try { Class itemType = cl.loadClass(className); if (v instanceof JSONObject) { l.add(bindJSON(itemType, (JSONObject) v)); } if (v instanceof JSONArray) { for(Object i : bindJSONToList(itemType, (JSONArray) v)) l.add(i); } } catch (ClassNotFoundException e1) { // ignore unrecognized element } } } else if (Enum.class.isAssignableFrom(l.itemType)) { // this is a hash of element names as enum constant names for (Map.Entry e : (Set>)j.entrySet()) { Object v = e.getValue(); if (v==null || (v instanceof Boolean && !(Boolean)v)) continue; // skip if the value is null or false l.add(Enum.valueOf(l.itemType,e.getKey())); } } else { // only one value given to the collection l.add(new TypePair(l.itemGenericType,l.itemType).convertJSON(j)); } return l.toCollection(); } } if (o instanceof JSONArray) { JSONArray a = (JSONArray) o; TypePair itemType = new TypePair(l.itemGenericType,l.itemType); for (Object item : a) l.add(itemType.convertJSON(item)); return l.toCollection(); } if(Enum.class.isAssignableFrom(type)) return Enum.valueOf(type,o.toString()); if (l==null) {// single value conversion Converter converter = Stapler.lookupConverter(type); if (converter==null) throw new IllegalArgumentException("Unable to convert to "+type); return converter.convert(type,o); } else {// single value in a collection Converter converter = Stapler.lookupConverter(l.itemType); if (converter==null) throw new IllegalArgumentException("Unable to convert to "+type); l.add(converter.convert(type,o)); return l.toCollection(); } } } /** * Called after the actual type of the binding is figured out. */ private Object instantiate(Class actualType, JSONObject j) { Object r = bindInterceptor.instantiate(actualType,j); if (r!=BindInterceptor.DEFAULT) return r; for (BindInterceptor bi : getWebApp().bindInterceptors) { r = bi.instantiate(actualType,j); if (r!=BindInterceptor.DEFAULT) return r; } if (actualType==JSONObject.class || actualType==JSON.class) return actualType.cast(j); String[] names = new ClassDescriptor(actualType).loadConstructorParamNames(); // the actual arguments to invoke the constructor with. Object[] args = new Object[names.length]; // constructor Constructor c = findConstructor(actualType, names.length); Class[] types = c.getParameterTypes(); Type[] genTypes = c.getGenericParameterTypes(); // convert parameters for( int i=0; i T injectSetters(T r, JSONObject j, Collection exclusions) { // try to assign rest of the properties OUTER: for (String key : (Set)j.keySet()) { if (!exclusions.contains(key)) { try { // try field injection first for (Class c=r.getClass(); c!=null; c=c.getSuperclass()) { try { Field f = c.getDeclaredField(key); if (f.getAnnotation(DataBoundSetter.class)!=null) { f.setAccessible(true); f.set(r, bindJSON(f.getGenericType(), f.getType(), j.get(key))); continue OUTER; } } catch (NoSuchFieldException e) { // recurse into parents } } PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor(r, key); if (pd==null) continue; Method wm = pd.getWriteMethod(); if (wm==null) continue; if (wm.getAnnotation(DataBoundSetter.class)==null) { LOGGER.warning("Tried to set value to "+key+" but method "+wm+" is missing @DataBoundSetter"); continue; } Class[] pt = wm.getParameterTypes(); if (pt.length!=1) { LOGGER.log(WARNING, "Setter method "+wm+" is expected to have 1 parameter"); continue; } // only invoking public methods for security reasons wm.invoke(r, bindJSON(wm.getGenericParameterTypes()[0], pt[0], j.get(key))); } catch (IllegalAccessException e) { LOGGER.log(WARNING, "Cannot access property " + key + " of " + r.getClass(), e); } catch (InvocationTargetException e) { LOGGER.log(WARNING, "Cannot access property " + key + " of " + r.getClass(), e); } catch (NoSuchMethodException e) { LOGGER.log(WARNING, "Cannot access property " + key + " of " + r.getClass(), e); } } } invokePostConstruct(getWebApp().getMetaClass(r).getPostConstructMethods(), r); return r; } /** * Invoke PostConstruct method from the base class to subtypes. */ private void invokePostConstruct(SingleLinkedList methods, Object r) { if (methods.isEmpty()) return; invokePostConstruct(methods.tail,r); try { methods.head.invoke(r); } catch (InvocationTargetException e) { throw new IllegalArgumentException("Unable to post-construct "+r,e); } catch (IllegalAccessException e) { throw (Error)new IllegalAccessError().initCause(e); } } /** * Gets the type of the field/property designate by the given name. */ private TypePair getPropertyType(Object bean, String name) throws IllegalAccessException, InvocationTargetException { try { PropertyDescriptor propDescriptor = PropertyUtils.getPropertyDescriptor(bean, name); if(propDescriptor!=null) { Method m = propDescriptor.getWriteMethod(); if(m!=null) return new TypePair(m.getGenericParameterTypes()[0], m.getParameterTypes()[0]); } } catch (NoSuchMethodException e) { // no such property } // try a field try { return new TypePair(bean.getClass().getField(name)); } catch (NoSuchFieldException e) { // no such field } return null; } /** * Sets the property/field value of the given name, by performing a value type conversion if necessary. */ private static void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException { PropertyDescriptor propDescriptor; try { propDescriptor = PropertyUtils.getPropertyDescriptor(bean, name); } catch (NoSuchMethodException e) { propDescriptor = null; } if ((propDescriptor != null) && (propDescriptor.getWriteMethod() == null)) { propDescriptor = null; } if (propDescriptor != null) { Converter converter = Stapler.lookupConverter(propDescriptor.getPropertyType()); if (converter != null) value = converter.convert(propDescriptor.getPropertyType(), value); try { PropertyUtils.setSimpleProperty(bean, name, value); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } return; } // try a field try { Field field = bean.getClass().getField(name); Converter converter = ConvertUtils.lookup(field.getType()); if (converter != null) value = converter.convert(field.getType(), value); field.set(bean,value); } catch (NoSuchFieldException e) { // no such field } } private void parseMultipartFormData() throws ServletException { if(parsedFormData!=null) return; parsedFormData = new HashMap(); ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); try { for( FileItem fi : (List)upload.parseRequest(this) ) parsedFormData.put(fi.getFieldName(),fi); } catch (FileUploadException e) { throw new ServletException(e); } } public JSONObject getSubmittedForm() throws ServletException { if(structuredForm==null) { String ct = getContentType(); String p = null; boolean isSubmission; // for error diagnosis, if something is submitted, set to true if(ct!=null && ct.startsWith("multipart/")) { isSubmission=true; parseMultipartFormData(); FileItem item = parsedFormData.get("json"); if(item!=null) { if (item.getContentType() == null && getCharacterEncoding() != null) { // JENKINS-11543: If client doesn't set charset per part, use request encoding try { p = item.getString(getCharacterEncoding()); } catch (java.io.UnsupportedEncodingException uee) { LOGGER.log(WARNING, "Request has unsupported charset, using default for 'json' parameter", uee); p = item.getString(); } } else { p = item.getString(); } } } else { p = getParameter("json"); isSubmission = !getParameterMap().isEmpty(); } if(p==null || p.length() == 0) { // no data submitted try { StaplerResponse rsp = Stapler.getCurrentResponse(); if(isSubmission) rsp.sendError(SC_BAD_REQUEST,"This page expects a form submission"); else rsp.sendError(SC_BAD_REQUEST,"Nothing is submitted"); throw new ServletException("This page expects a form submission but had only " + getParameterMap()); } catch (IOException e) { throw new ServletException(e); } } try { structuredForm = JSONObject.fromObject(p); } catch (JSONException e) { throw new ServletException("Failed to parse JSON:" + p, e); } } return structuredForm; } public FileItem getFileItem(String name) throws ServletException, IOException { parseMultipartFormData(); if(parsedFormData==null) return null; FileItem item = parsedFormData.get(name); if(item==null || item.isFormField()) return null; return item; } private static final Logger LOGGER = Logger.getLogger(RequestImpl.class.getName()); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/ResponseImpl.java0000664000175000017500000003607312414640747030266 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import net.sf.json.JsonConfig; import org.kohsuke.stapler.compression.CompressionFilter; import org.kohsuke.stapler.compression.FilterServletOutputStream; import org.kohsuke.stapler.export.ExportConfig; import org.kohsuke.stapler.export.NamedPathPruner; import org.kohsuke.stapler.export.Flavor; import org.kohsuke.stapler.export.Model; import org.kohsuke.stapler.export.ModelBuilder; import org.apache.commons.io.IOUtils; import javax.annotation.Nonnull; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.InputStream; import java.io.PrintWriter; import java.io.OutputStream; import java.io.Writer; import java.net.URL; import java.net.HttpURLConnection; import com.jcraft.jzlib.GZIPOutputStream; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.kohsuke.stapler.export.TreePruner; import org.kohsuke.stapler.export.TreePruner.ByDepth; /** * {@link StaplerResponse} implementation. * * @author Kohsuke Kawaguchi */ public class ResponseImpl extends HttpServletResponseWrapper implements StaplerResponse { private final Stapler stapler; private final HttpServletResponse response; enum OutputMode { BYTE, CHAR } private OutputMode mode=null; private Throwable origin; private JsonConfig jsonConfig; /** * {@link ServletOutputStream} or {@link PrintWriter}, set when {@link #mode} is set. */ private Object output=null; public ResponseImpl(Stapler stapler, HttpServletResponse response) { super(response); this.stapler = stapler; this.response = response; } @Override public ServletOutputStream getOutputStream() throws IOException { if(mode==OutputMode.CHAR) throw new IllegalStateException("getWriter has already been called. Its call site is in the nested exception",origin); if(mode==null) { recordOutput(super.getOutputStream()); } return (ServletOutputStream)output; } @Override public PrintWriter getWriter() throws IOException { if(mode==OutputMode.BYTE) throw new IllegalStateException("getOutputStream has already been called. Its call site is in the nested exception",origin); if(mode==null) { recordOutput(super.getWriter()); } return (PrintWriter)output; } private T recordOutput(T obj) { this.output = obj; this.mode = OutputMode.BYTE; this.origin = new Throwable(); return obj; } private T recordOutput(T obj) { this.output = obj; this.mode = OutputMode.CHAR; this.origin = new Throwable(); return obj; } public void forward(Object it, String url, StaplerRequest request) throws ServletException, IOException { stapler.invoke(request,response,it,url); } public void forwardToPreviousPage(StaplerRequest request) throws ServletException, IOException { String referer = request.getHeader("Referer"); if(referer==null) referer="."; sendRedirect(referer); } @Override public void sendRedirect(@Nonnull String url) throws IOException { // WebSphere doesn't apparently handle relative URLs, so // to be safe, always resolve relative URLs to absolute URLs by ourselves. // see http://www.nabble.com/Hudson%3A-1.262%3A-Broken-link-using-update-manager-to21067157.html if(url.startsWith("http://") || url.startsWith("https://") || url.startsWith("/")) { // absolute URLs super.sendRedirect(url); return; } // example: /foo/bar/zot + ../abc -> /foo/bar/../abc String base = Stapler.getCurrentRequest().getRequestURI(); base = base.substring(0,base.lastIndexOf('/')+1); if(!url.equals(".")) base += url; super.sendRedirect(base); } public void sendRedirect2(@Nonnull String url) throws IOException { // Tomcat doesn't encode URL (servlet spec isn't very clear on it) // so do the encoding by ourselves sendRedirect(encode(url)); } public void sendRedirect(int statusCode, @Nonnull String url) throws IOException { if (statusCode==SC_MOVED_TEMPORARILY) { sendRedirect(url); // to be safe, let the servlet container handles this default case return; } if(url.startsWith("http://") || url.startsWith("https://")) { // absolute URLs url = encode(url); } else { StaplerRequest req = Stapler.getCurrentRequest(); if (!url.startsWith("/")) { // WebSphere doesn't apparently handle relative URLs, so // to be safe, always resolve relative URLs to absolute URLs by ourselves. // see http://www.nabble.com/Hudson%3A-1.262%3A-Broken-link-using-update-manager-to21067157.html // example: /foo/bar/zot + ../abc -> /foo/bar/../abc String base = req.getRequestURI(); base = base.substring(0,base.lastIndexOf('/')+1); if(!url.equals(".")) url = base+encode(url); else url = base; assert url.startsWith("/"); } StringBuilder buf = new StringBuilder(req.getScheme()).append("://").append(req.getServerName()); if ((req.getScheme().equals("http") && req.getServerPort()!=80) || (req.getScheme().equals("https") && req.getServerPort()!=443)) buf.append(':').append(req.getServerPort()); url = buf.append(url).toString(); } setStatus(statusCode); setHeader("Location",url); getOutputStream().close(); } public void serveFile(StaplerRequest req, URL resource, long expiration) throws ServletException, IOException { if(!stapler.serveStaticResource(req,this,resource,expiration)) sendError(SC_NOT_FOUND); } public void serveFile(StaplerRequest req, URL resource) throws ServletException, IOException { serveFile(req,resource,-1); } public void serveLocalizedFile(StaplerRequest request, URL res) throws ServletException, IOException { serveLocalizedFile(request,res,-1); } public void serveLocalizedFile(StaplerRequest request, URL res, long expiration) throws ServletException, IOException { if(!stapler.serveStaticResource(request, this, stapler.selectResourceByLocale(res,request.getLocale()), expiration)) sendError(SC_NOT_FOUND); } public void serveFile(StaplerRequest req, InputStream data, long lastModified, long expiration, long contentLength, String fileName) throws ServletException, IOException { if(!stapler.serveStaticResource(req,this,data,lastModified,expiration,contentLength,fileName)) sendError(SC_NOT_FOUND); } public void serveFile(StaplerRequest req, InputStream data, long lastModified, long expiration, int contentLength, String fileName) throws ServletException, IOException { serveFile(req,data,lastModified,expiration,(long)contentLength,fileName); } public void serveFile(StaplerRequest req, InputStream data, long lastModified, long contentLength, String fileName) throws ServletException, IOException { serveFile(req,data,lastModified,-1,contentLength,fileName); } public void serveFile(StaplerRequest req, InputStream data, long lastModified, int contentLength, String fileName) throws ServletException, IOException { serveFile(req,data,lastModified,(long)contentLength,fileName); } @SuppressWarnings({"unchecked", "rawtypes"}) // API design flaw prevents this from type-checking public void serveExposedBean(StaplerRequest req, Object exposedBean, Flavor flavor) throws ServletException, IOException { String pad=null; setContentType(flavor.contentType); Writer w = getCompressedWriter(req); if(flavor== Flavor.JSON) { pad = req.getParameter("jsonp"); if(pad!=null) w.write(pad+'('); } TreePruner pruner; String tree = req.getParameter("tree"); if (tree != null) { try { pruner = new NamedPathPruner(tree); } catch (IllegalArgumentException x) { throw new ServletException("Malformed tree expression: " + x, x); } } else { int depth = 0; try { String s = req.getParameter("depth"); if (s != null) { depth = Integer.parseInt(s); } } catch (NumberFormatException e) { throw new ServletException("Depth parameter must be a number"); } pruner = new ByDepth(1 - depth); } ExportConfig config = new ExportConfig(); config.prettyPrint = req.hasParameter("pretty"); Model p = MODEL_BUILDER.get(exposedBean.getClass()); p.writeTo(exposedBean, pruner, flavor.createDataWriter(exposedBean,w,config)); if(pad!=null) w.write(')'); w.close(); } public OutputStream getCompressedOutputStream(HttpServletRequest req) throws IOException { String acceptEncoding = req.getHeader("Accept-Encoding"); if(acceptEncoding==null || acceptEncoding.indexOf("gzip")==-1) return getOutputStream(); // compression not available setHeader("Content-Encoding","gzip"); if (CompressionFilter.has(req)) return getOutputStream(); // CompressionFilter will set up compression. no need to do anything if (mode!=null) return getOutputStream(); return recordOutput(new FilterServletOutputStream(new GZIPOutputStream(super.getOutputStream()))); } public Writer getCompressedWriter(HttpServletRequest req) throws IOException { String acceptEncoding = req.getHeader("Accept-Encoding"); if(acceptEncoding==null || acceptEncoding.indexOf("gzip")==-1) return getWriter(); // compression not available setHeader("Content-Encoding","gzip"); if (CompressionFilter.has(req)) return getWriter(); // CompressionFilter will set up compression. no need to do anything if (mode!=null) return getWriter(); return recordOutput(new PrintWriter(new OutputStreamWriter(new GZIPOutputStream(super.getOutputStream()),getCharacterEncoding()))); } public int reverseProxyTo(URL url, StaplerRequest req) throws IOException { HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setDoOutput(true); Enumeration h = req.getHeaderNames(); while(h.hasMoreElements()) { String key = (String) h.nextElement(); Enumeration v = req.getHeaders(key); while (v.hasMoreElements()) { con.addRequestProperty(key,(String)v.nextElement()); } } // copy the request body con.setRequestMethod(req.getMethod()); // TODO: how to set request headers? copyAndClose(req.getInputStream(), con.getOutputStream()); // copy the response int code = con.getResponseCode(); setStatus(code,con.getResponseMessage()); Map> rspHeaders = con.getHeaderFields(); for (Entry> header : rspHeaders.entrySet()) { if(header.getKey()==null) continue; // response line for (String value : header.getValue()) { addHeader(header.getKey(),value); } } copyAndClose(con.getInputStream(), getOutputStream()); return code; } public void setJsonConfig(JsonConfig config) { jsonConfig = config; } public JsonConfig getJsonConfig() { if (jsonConfig == null) { jsonConfig = new JsonConfig(); } return jsonConfig; } private void copyAndClose(InputStream in, OutputStream out) throws IOException { IOUtils.copy(in, out); IOUtils.closeQuietly(in); IOUtils.closeQuietly(out); } /** * Escapes non-ASCII characters. */ public static @Nonnull String encode(@Nonnull String s) { try { boolean escaped = false; StringBuilder out = new StringBuilder(s.length()); ByteArrayOutputStream buf = new ByteArrayOutputStream(); OutputStreamWriter w = new OutputStreamWriter(buf,"UTF-8"); for (int i = 0; i < s.length(); i++) { int c = (int) s.charAt(i); if (c<128 && c!=' ') { out.append((char) c); } else { // 1 char -> UTF8 w.write(c); w.flush(); for (byte b : buf.toByteArray()) { out.append('%'); out.append(toDigit((b >> 4) & 0xF)); out.append(toDigit(b & 0xF)); } buf.reset(); escaped = true; } } return escaped ? out.toString() : s; } catch (IOException e) { throw new Error(e); // impossible } } private static char toDigit(int n) { char ch = Character.forDigit(n,16); if(ch>='a') ch = (char)(ch-'a'+'A'); return ch; } /*package*/ static ModelBuilder MODEL_BUILDER = new ModelBuilder(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/CrumbIssuer.java0000664000175000017500000000377612414640747030115 0ustar ebourgebourgpackage org.kohsuke.stapler; import javax.servlet.http.HttpSession; import java.util.UUID; /** * Generates a nonce value that allows us to protect against cross-site request forgery (CSRF) attacks. * *

* We send this with each JavaScript proxy and verify them when we receive a request. * * @author Kohsuke Kawaguchi * @see WebApp#getCrumbIssuer() * @see WebApp#setCrumbIssuer(CrumbIssuer) */ public abstract class CrumbIssuer { /** * Issues a crumb for the given request. */ public abstract String issueCrumb(StaplerRequest request); public final String issueCrumb() { return issueCrumb(Stapler.getCurrentRequest()); } /** * Sends the crumb value in plain text, enabling retrieval through XmlHttpRequest. */ public HttpResponse doCrumb() { return HttpResponses.plainText(issueCrumb()); } /** * Validates a crumb that was submitted along with the request. * * @param request * The request that submitted the crumb * @param submittedCrumb * The submitted crumb value to be validated. * * @throws Exception * If the crumb doesn't match and the request processing should abort. */ public void validateCrumb(StaplerRequest request, String submittedCrumb) { if (!issueCrumb(request).equals(submittedCrumb)) { throw new SecurityException("Request failed to pass the crumb test (try clearing your cookies)"); } } /** * Default crumb issuer. */ public static final CrumbIssuer DEFAULT = new CrumbIssuer() { @Override public String issueCrumb(StaplerRequest request) { HttpSession s = request.getSession(); String v = (String)s.getAttribute(ATTRIBUTE_NAME); if (v!=null) return v; v = UUID.randomUUID().toString(); s.setAttribute(ATTRIBUTE_NAME,v); return v; } }; private static final String ATTRIBUTE_NAME = CrumbIssuer.class.getName(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/SingleLinkedList.java0000664000175000017500000000317112414640747031043 0ustar ebourgebourgpackage org.kohsuke.stapler; import java.util.AbstractList; import java.util.Iterator; /** * Single linked list which allows sharing of the suffix. * * @author Kohsuke Kawaguchi * @since 1.220 */ public class SingleLinkedList extends AbstractList { public final T head; public final SingleLinkedList tail; public SingleLinkedList(T head, SingleLinkedList tail) { this.head = head; this.tail = tail; } /** * Creates a new list by adding a new element as the head. */ public SingleLinkedList grow(T item) { return new SingleLinkedList(item,this); } @Override public Iterator iterator() { return new Iterator() { SingleLinkedList next = SingleLinkedList.this; public boolean hasNext() { return next!=EMPTY_LIST; } public T next() { T r = next.head; next = next.tail; return r; } public void remove() { throw new UnsupportedOperationException(); } }; } @Override public T get(int index) { return null; } @Override public int size() { int sz = 0; for (SingleLinkedList head=this; head!=EMPTY_LIST; head=head.tail) sz++; return sz; } @Override public boolean isEmpty() { return this==EMPTY_LIST; } public static SingleLinkedList empty() { return EMPTY_LIST; } private static final SingleLinkedList EMPTY_LIST = new SingleLinkedList(null,null); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/bind/0000775000175000017500000000000012414640747025706 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java0000664000175000017500000002010012414640747031710 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.bind; import org.kohsuke.stapler.Ancestor; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerFallback; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import javax.servlet.http.HttpSession; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.logging.Logger; /** * Objects exported and bound by JavaScript proxies. * * TODO: think about some kind of eviction strategy, beyond the session eviction. * Maybe it's not necessary, I don't know. * * @author Kohsuke Kawaguchi */ public class BoundObjectTable implements StaplerFallback { public Table getStaplerFallback() { return resolve(false); } private Bound bind(Ref ref) { return resolve(true).add(ref); } /** * Binds an object temporarily and returns its URL. */ public Bound bind(Object o) { return bind(new StrongRef(o)); } /** * Binds an object temporarily and returns its URL. */ public Bound bindWeak(Object o) { return bind(new WeakRef(o)); } /** * Called from within the request handling of a bound object, to release the object explicitly. */ public void releaseMe() { Ancestor eot = Stapler.getCurrentRequest().findAncestor(BoundObjectTable.class); if (eot==null) throw new IllegalStateException("The thread is not handling a request to a abound object"); String id = eot.getNextToken(0); resolve(false).release(id); // resolve(false) can't fail because we are processing this request now. } /** * Obtains a {@link Table} associated with this session. */ private Table resolve(boolean createIfNotExist) { HttpSession session = Stapler.getCurrentRequest().getSession(createIfNotExist); if (session==null) return null; Table t = (Table) session.getAttribute(Table.class.getName()); if (t==null) { if (createIfNotExist) session.setAttribute(Table.class.getName(), t=new Table()); else return null; } return t; } /** * Explicit call to create the table if one doesn't exist yet. */ public Table getTable() { return resolve(true); } /** * Per-session table that remembers all the bound instances. */ public static class Table { private final Map entries = new HashMap(); private boolean logging; private synchronized Bound add(Ref ref) { final Object target = ref.get(); if (target instanceof WithWellKnownURL) { WithWellKnownURL w = (WithWellKnownURL) target; String url = w.getWellKnownUrl(); if (!url.startsWith("/")) { LOGGER.warning("WithWellKnownURL.getWellKnownUrl must start with a slash. But we got " + url + " from "+w); } return new WellKnownObjectHandle(url, w); } final String id = UUID.randomUUID().toString(); entries.put(id,ref); if (logging) LOGGER.info(String.format("%s binding %s for %s", toString(), target, id)); return new Bound() { public void release() { Table.this.release(id); } public String getURL() { return Stapler.getCurrentRequest().getContextPath()+PREFIX+id; } public Object getTarget() { return target; } public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.sendRedirect2(getURL()); } }; } public Object getDynamic(String id) { return resolve(id); } private synchronized Ref release(String id) { return entries.remove(id); } private synchronized Object resolve(String id) { Ref e = entries.get(id); if (e==null) { if (logging) LOGGER.info(toString()+" doesn't have binding for "+id); return null; } Object v = e.get(); if (v==null) { if (logging) LOGGER.warning(toString() + " had binding for " + id + " but it got garbage collected"); entries.remove(id); // reference is already garbage collected. } return v; } public HttpResponse doEnableLogging() { if (DEBUG_LOGGING) { this.logging = true; return HttpResponses.plainText("Logging enabled for this session: "+toString()); } else { return HttpResponses.forbidden(); } } } private static final class WellKnownObjectHandle extends Bound { private final String url; private final Object target; public WellKnownObjectHandle(String url, Object target) { this.url = url; this.target = target; } /** * Objects with well-known URLs cannot be released, as their URL bindings are controlled * implicitly by the application. */ public void release() { } public String getURL() { return Stapler.getCurrentRequest().getContextPath()+url; } @Override public Object getTarget() { return target; } public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.sendRedirect2(getURL()); } } /** * Reference that resolves to an object. */ interface Ref { Object get(); } private static class StrongRef implements Ref { private final Object o; StrongRef(Object o) { this.o = o; } public Object get() { return o; } } private static class WeakRef extends WeakReference implements Ref { private WeakRef(Object referent) { super(referent); } } public static final String PREFIX = "/$stapler/bound/"; /** * True to activate debug logging of session fragments. */ public static boolean DEBUG_LOGGING = Boolean.getBoolean(BoundObjectTable.class.getName()+".debugLog"); private static final Logger LOGGER = Logger.getLogger(BoundObjectTable.class.getName()); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/bind/Bound.java0000664000175000017500000000743112414640747027625 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.bind; import org.kohsuke.stapler.ClassDescriptor; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.MetaClass; import org.kohsuke.stapler.WebApp; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Collections; /** * Handles to the object bound via {@link BoundObjectTable}. * * As {@link HttpResponse}, this object generates a redirect to the URL that it points to. * * @author Kohsuke Kawaguchi * @see MetaClass#buildDispatchers(ClassDescriptor) */ public abstract class Bound implements HttpResponse { /** * Explicitly unbind this object. The referenced object * won't be bound to URL anymore. */ public abstract void release(); /** * The URL where the object is bound to. This method * starts with '/' and thus always absolute within the current web server. */ public abstract String getURL(); /** * Gets the bound object. */ public abstract Object getTarget(); /** * Returns a JavaScript expression which evaluates to a JavaScript proxy that * talks back to the bound object that this handle represents. */ public final String getProxyScript() { StringBuilder buf = new StringBuilder("makeStaplerProxy('").append(getURL()).append("','").append( WebApp.getCurrent().getCrumbIssuer().issueCrumb() ).append("',["); boolean first=true; for (Method m : getTarget().getClass().getMethods()) { Collection names; if (m.getName().startsWith("js")) { names = Collections.singleton(camelize(m.getName().substring(2))); } else { JavaScriptMethod a = m.getAnnotation(JavaScriptMethod.class); if (a!=null) { names = Arrays.asList(a.name()); if (names.isEmpty()) names = Collections.singleton(m.getName()); } else continue; } for (String n : names) { if (first) first = false; else buf.append(','); buf.append('\'').append(n).append('\''); } } buf.append("])"); return buf.toString(); } private static String camelize(String name) { return Character.toLowerCase(name.charAt(0))+name.substring(1); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/bind/package-info.java0000664000175000017500000000275012414640747031101 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ /** * Subsystem for exposing arbitrary objects on per-session basis to the URL space. */ package org.kohsuke.stapler.bind;stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/bind/JavaScriptMethod.java0000664000175000017500000000434612414640747031767 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.bind; import java.lang.annotation.Documented; import static java.lang.annotation.ElementType.METHOD; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Target; /** * Indicates that the method is exposed to client-side JavaScript proxies * and is callable as a method from them. * *

* This annotation is assumed to be implicit on every public methods * that start with 'js', like 'jsFoo' or 'jsBar', but you can use this annotation * on those methods to assign different names. * * @author Kohsuke Kawaguchi */ @Retention(RUNTIME) @Target(METHOD) @Documented public @interface JavaScriptMethod { /** * JavaScript method name assigned to this method. * *

* If unspecified, defaults to the method name. */ String[] name() default {}; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/bind/WithWellKnownURL.java0000664000175000017500000000407312414640747031714 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.bind; /** * Marker interface for objects that have known URLs. * * If objects that implement this interface are exported, the well-known URLs * are used instead of assigning temporary URLs to objects. In this way, the application * can reduce memory consumption. This also enables objects to have "identities" * that outlive their GC life (for example, instance of the JPA-bound "User" class can * come and go, but they represent the single identity that's pointed by its primary key.) * * @author Kohsuke Kawaguchi */ public interface WithWellKnownURL { /** * @return a URL appended to the context path, such as {@code /myWidget} */ String getWellKnownUrl(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/HttpResponse.java0000664000175000017500000000417612414640747030303 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import javax.servlet.ServletException; import java.io.IOException; /** * Object that represents the HTTP response, which is defined as a capability to produce the response. * *

* doXyz(...) method could return an object of this type or throw an exception of this type, and if it does so, * the object is asked to produce HTTP response. * *

* This is useful to make doXyz look like a real function, and decouple it further from HTTP. * * @author Kohsuke Kawaguchi */ public interface HttpResponse { /** * @param node * The object whose "doXyz" method created this object. */ void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/InjectedParameter.java0000664000175000017500000000126512414640747031227 0ustar ebourgebourgpackage org.kohsuke.stapler; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Used on annotations to indicate that it signals a parameter injection in web-bound "doXyz" methods. * * @author Kohsuke Kawaguchi */ @Retention(RUNTIME) @Target(ANNOTATION_TYPE) @Documented public @interface InjectedParameter { /** * Code that computes the actual value to inject. * * One instance of this is created lazily and reused concurrently. */ Class value(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/lang/0000775000175000017500000000000012414640747025713 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/lang/KlassNavigator.java0000664000175000017500000000770312414640747031515 0ustar ebourgebourgpackage org.kohsuke.stapler.lang; import org.kohsuke.stapler.MetaClassLoader; import java.lang.reflect.Method; import java.net.URL; import java.util.AbstractList; import java.util.ArrayList; import java.util.List; /** * Strategy pattern to provide navigation across class-like objects in other languages of JVM. * *

* Implementations should be stateless and typically a singleton. * * @author Kohsuke Kawaguchi */ public abstract class KlassNavigator { /** * Loads the resources associated with this class. * *

* In stapler, the convention is that the "associated" resources live in the directory named after * the fully qualified class name (as opposed to the behavior of {@link Class#getResource(String)}, * that looks for resources in the same package as the class.) * *

* But other languages can choose their own conventions if it makes more sense to do so. * For example, stapler-jruby uses camelized class name. * *

* Implementation must consult {@link MetaClassLoader#debugLoader} if it's available. Implementation * must not look for resources in the base type. That operation is performed by the caller when * needed. * * @return * non-null if the resource is found. Otherwise null. */ public abstract URL getResource(C clazz, String resourceName); /** * Lists up all the ancestor classes, from specific to general, without any duplicate. * * This is used to look up a resource. */ public abstract Iterable> getAncestors(C clazz); /** * Gets the super class. * * @return * Can be null. */ public abstract Klass getSuperClass(C clazz); /** * For backward compatibility, map the given class to the closest Java equivalent. * In the worst case, this is Object.class */ public abstract Class toJavaClass(C clazz); /** * List methods of this class, regardless of access modifier. * * This list excludes methods from super classes. * @since 1.220 */ public abstract List getDeclaredMethods(C clazz); public static final KlassNavigator JAVA = new KlassNavigator() { @Override public URL getResource(Class clazz, String resourceName) { ClassLoader cl = clazz.getClassLoader(); if (cl==null) return null; String fullName; if (resourceName.startsWith("/")) fullName = resourceName.substring(1); else fullName = clazz.getName().replace('.','/').replace('$','/')+'/'+resourceName; if (MetaClassLoader.debugLoader!=null) { URL res = MetaClassLoader.debugLoader.loader.getResource(fullName); if (res!=null) return res; } return cl.getResource(fullName); } @Override public Klass getSuperClass(Class clazz) { return Klass.java(clazz.getSuperclass()); } @Override public Iterable> getAncestors(Class clazz) { // TODO: shall we support interfaces? List> r = new ArrayList>(); for (; clazz!=null; clazz=clazz.getSuperclass()) { r.add(Klass.java(clazz)); } return r; } @Override public Class toJavaClass(Class clazz) { return clazz; } @Override public List getDeclaredMethods(Class clazz) { final Method[] methods = clazz.getDeclaredMethods(); return new AbstractList() { @Override public MethodRef get(int index) { return MethodRef.wrap(methods[index]); } @Override public int size() { return methods.length; } }; } }; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/lang/Klass.java0000664000175000017500000000371712414640747027643 0ustar ebourgebourgpackage org.kohsuke.stapler.lang; import java.net.URL; import java.util.List; /** * Abstraction of class-like object, agnostic to languages. * *

* To support other JVM languages that use their own specific types to represent a class * (such as JRuby and Jython), we now use this object instead of {@link Class}. This allows * us to reuse much of the logic of class traversal/resource lookup across different languages. * * This is a convenient tuple so that we can pass around a single argument instead of two. * * @author Kohsuke Kawaguchi */ public class Klass { public final C clazz; public final KlassNavigator navigator; public Klass(C clazz, KlassNavigator navigator) { this.clazz = clazz; this.navigator = navigator; } public URL getResource(String resourceName) { return navigator.getResource(clazz,resourceName); } public Iterable> getAncestors() { return navigator.getAncestors(clazz); } public Klass getSuperClass() { return navigator.getSuperClass(clazz); } public Class toJavaClass() { return navigator.toJavaClass(clazz); } /** * @since 1.220 */ public List getDeclaredMethods() { return navigator.getDeclaredMethods(clazz); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Klass that = (Klass) o; return clazz.equals(that.clazz) && navigator.equals(that.navigator); } @Override public int hashCode() { return 31 * clazz.hashCode() + navigator.hashCode(); } @Override public String toString() { return clazz.toString(); } /** * Creates {@link Klass} from a Java {@link Class}. */ public static Klass java(Class c) { return c == null ? null : new Klass(c, KlassNavigator.JAVA); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/lang/MethodRef.java0000664000175000017500000000204512414640747030434 0ustar ebourgebourgpackage org.kohsuke.stapler.lang; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author Kohsuke Kawaguchi * @since 1.220 */ public abstract class MethodRef { public abstract T getAnnotation(Class type); public boolean hasAnnotation(Class type) { return getAnnotation(type)!=null; } public abstract Object invoke(Object _this, Object... args) throws InvocationTargetException, IllegalAccessException; public static MethodRef wrap(final Method m) { m.setAccessible(true); return new MethodRef() { @Override public T getAnnotation(Class type) { return m.getAnnotation(type); } @Override public Object invoke(Object _this, Object... args) throws InvocationTargetException, IllegalAccessException { return m.invoke(_this,args); } }; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/Stapler.java0000664000175000017500000013621012414640747027252 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import net.sf.json.JSONObject; import org.apache.commons.beanutils.ConversionException; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.ConvertUtilsBean; import org.apache.commons.beanutils.Converter; import org.apache.commons.beanutils.converters.DoubleConverter; import org.apache.commons.beanutils.converters.FloatConverter; import org.apache.commons.beanutils.converters.IntegerConverter; import org.apache.commons.fileupload.FileItem; import org.apache.commons.io.IOUtils; import org.kohsuke.stapler.bind.BoundObjectTable; import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.DataInputStream; import java.io.EOFException; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.net.JarURLConnection; import java.net.MalformedURLException; import java.net.SocketException; import java.net.URL; import java.net.URLConnection; import java.net.URLDecoder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.Stack; import java.util.TimeZone; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import static javax.servlet.http.HttpServletResponse.*; import static org.kohsuke.stapler.Dispatcher.*; /** * Maps an HTTP request to a method call / JSP invocation against a model object * by evaluating the request URL in a EL-ish way. * *

* This servlet should be used as the default servlet. * * @author Kohsuke Kawaguchi */ public class Stapler extends HttpServlet { private /*final*/ ServletContext context; private /*final*/ WebApp webApp; /** * All the resources that exist in {@link ServletContext#getResource(String)}, * as a cache. * * If this field is null, no cache. */ private volatile Map resourcePaths; /** * Temporarily updates the thread name to reflect the request being processed. * On by default for convenience, but for webapps that use filters, use * {@link DiagnosticThreadNameFilter} as the first filter and switch this off. */ private boolean diagnosticThreadName = true; public @Override void init(ServletConfig servletConfig) throws ServletException { super.init(servletConfig); this.context = servletConfig.getServletContext(); this.webApp = WebApp.get(context); String defaultEncodings = servletConfig.getInitParameter("default-encodings"); if(defaultEncodings!=null) { for(String t : defaultEncodings.split(";")) { t=t.trim(); int idx=t.indexOf('='); if(idx<0) throw new ServletException("Invalid format: "+t); webApp.defaultEncodingForStaticResources.put(t.substring(0,idx),t.substring(idx+1)); } } buildResourcePaths(); webApp.addStaplerServlet(servletConfig.getServletName(),this); String v = servletConfig.getInitParameter("diagnosticThreadName"); if (v!=null) diagnosticThreadName = Boolean.parseBoolean(v); } /** * Rebuild the internal cache for static resources. */ public void buildResourcePaths() { try { if (Boolean.getBoolean(Stapler.class.getName()+".noResourcePathCache")) { resourcePaths = null; return; } Map paths = new HashMap(); Stack q = new Stack(); q.push("/"); while (!q.isEmpty()) { String dir = q.pop(); Set children = context.getResourcePaths(dir); if (children!=null) { for (String child : children) { if (child.endsWith("/")) q.push(child); else { URL v = context.getResource(child); if (v==null) { resourcePaths = null; return; // this can't happen. abort with no cache } paths.put(child, v); } } } } resourcePaths = Collections.unmodifiableMap(paths); } catch (MalformedURLException e) { resourcePaths = null; // abort } } public WebApp getWebApp() { return webApp; } /*package*/ void setWebApp(WebApp webApp) { this.webApp = webApp; } protected @Override void service(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { Thread t = Thread.currentThread(); final String oldName = t.getName(); try { if (diagnosticThreadName) t.setName("Handling "+req.getMethod()+' '+req.getRequestURI()+" : "+oldName); String servletPath = getServletPath(req); if(LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Processing request for "+servletPath); if (servletPath.startsWith(BoundObjectTable.PREFIX)) { // serving exported objects invoke( req, rsp, webApp.boundObjectTable, servletPath.substring(BoundObjectTable.PREFIX.length())); return; } boolean staticLink = false; if(servletPath.startsWith("/static/")) { // skip "/static/..../ portion int idx = servletPath.indexOf('/',8); if (idx != -1) { servletPath=servletPath.substring(idx); staticLink = true; } } String lowerPath = servletPath.toLowerCase(Locale.ENGLISH); if(servletPath.length()!=0 && !lowerPath.startsWith("/web-inf") && !lowerPath.startsWith("/meta-inf")) { // getResource requires '/' prefix (and resin insists on that, too) but servletPath can be empty string (JENKINS-879) // so make sure servletPath is at least length 1 before calling getResource() // WEB-INF and META-INF are by convention hidden and not supposed to be rendered to clients (JENKINS-7457/JENKINS-11538) // also note that Windows allows "/WEB-INF./" to refer to refer to this directory. // here we also reject that (by rejecting /WEB-INF*) OpenConnection con = openResourcePathByLocale(req,servletPath); if(con!=null) { long expires = MetaClass.NO_CACHE ? 0 : 24L * 60 * 60 * 1000; /*1 day*/ if(staticLink) expires*=365; // static resources are unique, so we can set a long expiration date if(serveStaticResource(req, new ResponseImpl(this, rsp), con, expires)) return; // done } } Object root = webApp.getApp(); if(root==null) throw new ServletException("there's no \"app\" attribute in the application context."); // consider reusing this ArrayList. invoke( req, rsp, root, servletPath); } finally { t.setName(oldName); } } /** * Tomcat and GlassFish returns a fresh {@link InputStream} every time * {@link URLConnection#getInputStream()} is invoked in their {@code org.apache.naming.resources.DirContextURLConnection}. * *

* All the other {@link URLConnection}s in JDK don't do this --- they return the same {@link InputStream}, * even the one for the file:// URLs. * *

* In Tomcat (and most likely in GlassFish, although this is not verified), resource look up on * {@link ServletContext#getResource(String)} successfully returns non-existent URL, and * the failure can be only detected by {@link IOException} from {@link URLConnection#getInputStream()}. * *

* Therefore, for the whole thing to work without resource leak, once we open {@link InputStream} * for the sake of really making sure that the resource exists, we need to hang on to that stream. * *

* Hence the need for this tuple. */ private static final class OpenConnection { final URLConnection connection; final InputStream stream; private OpenConnection(URLConnection connection, InputStream stream) { this.connection = connection; this.stream = stream; } private OpenConnection(URLConnection connection) throws IOException { this(connection,connection.getInputStream()); } private void close() throws IOException { stream.close(); } /** * Can't just use {@code connection.getLastModified()} because * of a file descriptor leak in {@code JarURLConnection}. * See http://sourceforge.net/p/freemarker/bugs/189/ */ public long getLastModified() { if (connection instanceof JarURLConnection) { // There is a bug in sun's jar url connection that causes file handle leaks when calling getLastModified() // Since the time stamps of jar file contents can't vary independent from the jar file timestamp, just use // the jar file timestamp URL jarURL = ((JarURLConnection) connection).getJarFileURL(); if (jarURL.getProtocol().equals("file")) { // Return the last modified time of the underlying file - saves some opening and closing return new File(jarURL.getFile()).lastModified(); } else { // Use the URL mechanism URLConnection jarConn = null; try { jarConn = jarURL.openConnection(); return jarConn.getLastModified(); } catch (IOException e) { return -1; } finally { if (jarConn != null) { try { IOUtils.closeQuietly(jarConn.getInputStream()); } catch (IOException e) { // ignore this error } } } } } else { return connection.getLastModified(); } } } /** * Logic for performing locale driven resource selection. * * Different subtypes provide different meanings for the 'path' parameter. */ private abstract class LocaleDrivenResourceSelector { /** * The 'path' is divided into the base part and the extension, and the locale-specific * suffix is inserted to the base portion. {@link #map(String)} is used to convert * the combined path into {@link URL}, until we find one that works. * *

* The syntax of the locale specific resource is the same as property file localization. * So Japanese resource for foo.html would be named foo_ja.html. * * @param path * path/URL-like string that represents the path of the base resource, * say "foo/bar/index.html" or "file:///a/b/c/d/efg.png" * @param locale * The preferred locale * @param fallback * The {@link URL} representation of the {@code path} parameter * Used as a fallback. */ OpenConnection open(String path, Locale locale, URL fallback) throws IOException { String s = path; int idx = s.lastIndexOf('.'); if(idx<0) // no file extension, so no locale switch available return openURL(fallback); String base = s.substring(0,idx); String ext = s.substring(idx); if(ext.indexOf('/')>=0) // the '.' we found was not an extension separator return openURL(fallback); OpenConnection con; // try locale specific resources first. con = openURL(map(base + '_' + locale.getLanguage() + '_' + locale.getCountry() + '_' + locale.getVariant() + ext)); if(con!=null) return con; con = openURL(map(base+'_'+ locale.getLanguage()+'_'+ locale.getCountry()+ext)); if(con!=null) return con; con = openURL(map(base+'_'+ locale.getLanguage()+ext)); if(con!=null) return con; // default return openURL(fallback); } /** * Maps the 'path' into {@link URL}. */ abstract URL map(String path) throws IOException; } private final LocaleDrivenResourceSelector resourcePathLocaleSelector = new LocaleDrivenResourceSelector() { @Override URL map(String path) throws IOException { return getResource(path); } }; private OpenConnection openResourcePathByLocale(HttpServletRequest req,String resourcePath) throws IOException { URL url = getResource(resourcePath); if(url==null) return null; // hopefully HotSpot would be able to inline all the virtual calls in here return resourcePathLocaleSelector.open(resourcePath,req.getLocale(),url); } /** * {@link LocaleDrivenResourceSelector} that uses a complete URL as 'path' */ private final LocaleDrivenResourceSelector urlLocaleSelector = new LocaleDrivenResourceSelector() { @Override URL map(String url) throws IOException { return new URL(url); } }; OpenConnection selectResourceByLocale(URL url, Locale locale) throws IOException { // hopefully HotSpot would be able to inline all the virtual calls in here return urlLocaleSelector.open(url.toString(),locale,url); } /** * Serves the specified {@link URLConnection} as a static resource. */ boolean serveStaticResource(HttpServletRequest req, StaplerResponse rsp, OpenConnection con, long expiration) throws IOException { if (con == null) return false; try { return serveStaticResource(req, rsp, con.stream, con.getLastModified(), expiration, con.connection.getContentLength(), con.connection.getURL().toString()); } finally { con.close(); } } /** * Serves the specified {@link URL} as a static resource. */ boolean serveStaticResource(HttpServletRequest req, StaplerResponse rsp, URL url, long expiration) throws IOException { return serveStaticResource(req,rsp,openURL(url),expiration); } /** * Opens URL, with error handling to absorb container differences. *

* This method returns null if the resource pointed by URL doesn't exist. The initial attempt was to * distinguish "resource exists but failed to load" vs "resource doesn't exist", but as more reports * from the field come in, we discovered that it's impossible to make such a distinction and work with * many environments both at the same time. */ private OpenConnection openURL(URL url) { if(url==null) return null; // jetty reports directories as URLs, which isn't what this is intended for, // so check and reject. File f = toFile(url); if(f!=null && f.isDirectory()) return null; try { // in normal protocol handlers like http/file, openConnection doesn't actually open a connection // (that's deferred until URLConnection.connect()), so this method doesn't result in an error, // even if URL points to something that doesn't exist. // // but we've heard a report from http://github.com/adreghiciu that some URLS backed by custom // protocol handlers can throw an exception as early as here. So treat this IOException // as "the resource pointed by URL is missing". URLConnection con = url.openConnection(); OpenConnection c = new OpenConnection(con); // Some URLs backed by custom broken protocol handler can return null from getInputStream(), // so let's be defensive here. An example of that is an OSGi container --- unfortunately // we don't have more details than that. if(c.stream==null) return null; return c; } catch (IOException e) { // Tomcat only reports a missing resource error here, from URLConnection.getInputStream() return null; } } /** * Serves the specified {@link InputStream} as a static resource. * * @param contentLength * if the length of the input stream is known in advance, specify that value * so that HTTP keep-alive works. Otherwise specify -1 to indicate that the length is unknown. * @param expiration * The number of milliseconds until the resource will "expire". * Until it expires the browser will be allowed to cache it * and serve it without checking back with the server. * After it expires, the client will send conditional GET to * check if the resource is actually modified or not. * If 0, it will immediately expire. * @param fileName * file name of this resource. Used to determine the MIME type. * Since the only important portion is the file extension, this could be just a file name, * or a full path name, or even a pseudo file name that doesn't actually exist. * It supports both '/' and '\\' as the path separator. * @return false * if the resource doesn't exist. */ boolean serveStaticResource(HttpServletRequest req, StaplerResponse rsp, InputStream in, long lastModified, long expiration, long contentLength, String fileName) throws IOException { try { {// send out Last-Modified, or check If-Modified-Since if(lastModified!=0) { String since = req.getHeader("If-Modified-Since"); SimpleDateFormat format = HTTP_DATE_FORMAT.get(); if(since!=null) { try { long ims = format.parse(since).getTime(); if(lastModified 0 && (thisSkip = dis.skipBytes((int)Math.min(toSkip, Integer.MAX_VALUE))) > 0) toSkip -= thisSkip; if (toSkip > 0) throw new IOException( "skipBytes failure (" + toSkip + " of " + s + " bytes unskipped)"); in = new TruncatedInputStream(in,e-s); contentLength = Math.min(e-s,contentLength); } // if the Range header doesn't look like what we can handle, // pretend as if we didn't understand it, instead of doing a proper error reporting } } if (out == null) { if(contentLength!=-1) rsp.setHeader("Content-Length", Long.toString(contentLength)); out = rsp.getOutputStream(); } byte[] buf = new byte[1024]; int len; while((len=in.read(buf))>0) out.write(buf,0,len); out.close(); return true; } finally { in.close(); } } /** * Strings like "5-300", "0-900", or "100-" */ private static final Pattern RANGE_SPEC = Pattern.compile("([\\d]+)-([\\d]*)"); private String getMimeType(String fileName) { if(fileName.startsWith("mime-type:")) return fileName.substring("mime-type:".length()); int idx = fileName.lastIndexOf('/'); fileName = fileName.substring(idx+1); idx = fileName.lastIndexOf('\\'); fileName = fileName.substring(idx+1); String extension = fileName.substring(fileName.lastIndexOf('.')+1); String mimeType = webApp.mimeTypes.get(extension); if(mimeType==null) mimeType = getServletContext().getMimeType(fileName); if(mimeType==null) mimeType="application/octet-stream"; if(webApp.defaultEncodingForStaticResources.containsKey(mimeType)) mimeType += ";charset="+webApp.defaultEncodingForStaticResources.get(mimeType); return mimeType; } /** * If the URL is "file://", return its file representation. * * See http://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html */ /*package for test*/ File toFile(URL url) { String urlstr = url.toExternalForm(); if(!urlstr.startsWith("file:")) return null; // File(String) does fs.normalize, which is really forgiving in fixing up // malformed stuff. I couldn't make the other URL.toURI() or File(URI) work // in all the cases that we test try { return new File(URLDecoder.decode(urlstr.substring(5),"UTF-8")); } catch (UnsupportedEncodingException x) { throw new AssertionError(x); } } /** * Performs stapler processing on the given root object and request URL. */ public void invoke(HttpServletRequest req, HttpServletResponse rsp, Object root, String url) throws IOException, ServletException { RequestImpl sreq = new RequestImpl(this, req, new ArrayList(), new TokenList(url)); RequestImpl oreq = CURRENT_REQUEST.get(); CURRENT_REQUEST.set(sreq); ResponseImpl srsp = new ResponseImpl(this, rsp); ResponseImpl orsp = CURRENT_RESPONSE.get(); CURRENT_RESPONSE.set(srsp); try { invoke(sreq,srsp,root); } finally { CURRENT_REQUEST.set(oreq); CURRENT_RESPONSE.set(orsp); } } /** * Try to dispatch the request against the given node, and if there's no route to deliver a request, return false. * *

* If a route to deliver a request is found but it failed to handle the request, the request is considered * handled and the method returns true. * * @see #invoke(RequestImpl, ResponseImpl, Object) */ boolean tryInvoke(RequestImpl req, ResponseImpl rsp, Object node ) throws IOException, ServletException { if(traceable()) traceEval(req,rsp,node); if(node instanceof StaplerProxy) { if(traceable()) traceEval(req,rsp,node,"((StaplerProxy)",").getTarget()"); Object n = null; try { n = ((StaplerProxy)node).getTarget(); } catch (RuntimeException e) { if (Function.renderResponse(req,rsp,node,e)) return true; // let the exception serve the request and we are done else throw e; // unprocessed exception } if(n==node || n==null) { // if the proxy returns itself, assume that it doesn't want to proxy. // if null, no one will handle the request } else { // recursion helps debugging by leaving the trace in the stack. invoke(req,rsp,n); return true; } } // adds this node to ancestor list AncestorImpl a = new AncestorImpl(req, node); // try overrides if (node instanceof StaplerOverridable) { StaplerOverridable o = (StaplerOverridable) node; Collection list = o.getOverrides(); if (list!=null) { int count = 0; for (Object subject : list) { if (subject==null) continue; if(traceable()) traceEval(req,rsp,node,"((StaplerOverridable)",").getOverrides()["+(count++)+']'); if (tryInvoke(req,rsp,subject)) return true; } } } MetaClass metaClass = webApp.getMetaClass(node); if(!req.tokens.hasMore()) { String servletPath = getServletPath(req); if(!servletPath.endsWith("/")) { // if we are serving the index page, we demand that the URL be '/some/dir/' not '/some/dir' // so that relative links in the page will resolve correctly. Apache does the same thing. String target = req.getContextPath() + servletPath + '/'; if(req.getQueryString()!=null) target += '?' + req.getQueryString(); if(LOGGER.isLoggable(Level.FINER)) LOGGER.finer("Redirecting to "+target); rsp.sendRedirect2(target); return true; } if(req.getMethod().equals("DELETE")) { if(node instanceof HttpDeletable) { ((HttpDeletable)node).delete(req,rsp); return true; } } for (Facet f : webApp.facets) { if(f.handleIndexRequest(req,rsp,node,metaClass)) return true; } URL indexHtml = getSideFileURL(node,"index.html"); if(indexHtml!=null && serveStaticResource(req,rsp,indexHtml,0)) return true; // done } try { for( Dispatcher d : metaClass.dispatchers ) { if(d.dispatch(req,rsp,node)) { if(LOGGER.isLoggable(Level.FINER)) LOGGER.finer("Handled by "+d); return true; } } } catch (IllegalAccessException e) { // this should never really happen if (!isSocketException(e)) { getServletContext().log("Error while serving "+req.getRequestURL(),e); } throw new ServletException(e); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause == null) { // ??? getServletContext().log("Error while serving " + req.getRequestURL(), e); throw new ServletException(); } // allow the exception from the dispatch to be handled. This is handy to throw HttpResponse as an exception // from the getXyz method. for (HttpResponseRenderer r : webApp.getResponseRenderers()) if (r.generateResponse(req,rsp,node,cause)) return true; StringBuffer url = req.getRequestURL(); if (cause instanceof IOException) { if (!isSocketException(e)) { getServletContext().log("Error while serving " + url, e); } throw (IOException) cause; } if (cause instanceof ServletException) { if (!isSocketException(e)) { getServletContext().log("Error while serving " + url, e); } throw (ServletException) cause; } for (Class c = cause.getClass(); c != null; c = c.getSuperclass()) { if (c == Object.class) { if (!isSocketException(e)) { getServletContext().log("Error while serving " + url, e); } } else if (c.getName().equals("org.acegisecurity.AccessDeniedException")) { // [HUDSON-4834] A stack trace is too noisy for this; could just need to log in. // (Could consider doing this for all AcegiSecurityException's.) getServletContext().log("While serving " + url + ": " + cause); break; } } throw new ServletException(cause); } if(node instanceof StaplerFallback) { if(traceable()) traceEval(req,rsp,node,"((StaplerFallback)",").getStaplerFallback()"); Object n; try { n = ((StaplerFallback)node).getStaplerFallback(); } catch (RuntimeException e) { if (Function.renderResponse(req,rsp,node,e)) return true; // let the exception serve the request and we are done else throw e; // unprocessed exception } if(n!=node && n!=null) { // delegate to the fallback object invoke(req,rsp,n); return true; } } return false; } /** * Used to detect exceptions thrown when writing content that seem to be due merely to a closed socket. * @param x an exception that got caught * @return true if this looks like a closed stream, false for some real problem * @since 1.222 */ public static boolean isSocketException(Throwable x) { // JENKINS-10524 if (x == null) { return false; } if (x instanceof SocketException) { return true; } if (String.valueOf(x.getMessage()).equals("Broken pipe")) { // TBD I18N return true; } // JENKINS-20074: various things that Jetty and other components could throw if (x instanceof EOFException) { return true; } if (x instanceof IOException && "Closed".equals(x.getMessage())) { // org.eclipse.jetty.server.HttpOutput.print return true; } if (x instanceof IOException && "finished".equals(x.getMessage())) { //com.jcraft.jzlib.DeflaterOutputStream.write return true; } return isSocketException(x.getCause()); } /** * Try to dispatch the request against the given node, and if it fails, report an error to the client. */ void invoke(RequestImpl req, ResponseImpl rsp, Object node ) throws IOException, ServletException { if(node==null) { // node is null if(!Dispatcher.isTraceEnabled(req)) { rsp.sendError(SC_NOT_FOUND); } else { // show error page rsp.setStatus(SC_NOT_FOUND); rsp.setContentType("text/html;charset=UTF-8"); PrintWriter w = rsp.getWriter(); w.println(""); w.println("

404 Not Found

"); w.println("

Stapler processed this HTTP request as follows, but couldn't find the resource to consume the request"); w.println("

");
                EvaluationTrace.get(req).printHtml(w);
                w.println("-> unexpected null!");
                w.println("
"); w.println("

If this 404 is unexpected, double check the last part of the trace to see if it should have evaluated to null."); w.println(""); } return; } if (tryInvoke(req,rsp,node)) return; // done // we really run out of options. if(!Dispatcher.isTraceEnabled(req)) { rsp.sendError(SC_NOT_FOUND); } else { // show error page rsp.setStatus(SC_NOT_FOUND); rsp.setContentType("text/html;charset=UTF-8"); PrintWriter w = rsp.getWriter(); w.println(""); w.println("

404 Not Found

"); w.println("

Stapler processed this HTTP request as follows, but couldn't find the resource to consume the request"); w.println("

");
            EvaluationTrace.get(req).printHtml(w);
            w.printf("-> No matching rule was found on <%s> for \"%s\"\n",node,req.tokens.assembleOriginalRestOfPath());
            w.println("
"); w.printf("

<%s> has the following URL mappings, in the order of preference:",node); w.println("

    "); MetaClass metaClass = webApp.getMetaClass(node); for (Dispatcher d : metaClass.dispatchers) { w.println("
  1. "); w.println(d.toString()); } w.println("
"); w.println(""); } } public void forward(RequestDispatcher dispatcher, StaplerRequest req, HttpServletResponse rsp) throws ServletException, IOException { dispatcher.forward(req,new ResponseImpl(this,rsp)); } private URL getSideFileURL(Object node,String fileName) throws MalformedURLException { for( Class c = node.getClass(); c!=Object.class; c=c.getSuperclass() ) { String name = "/WEB-INF/side-files/"+c.getName().replace('.','/')+'/'+fileName; URL url = getResource(name); if(url!=null) return url; } return null; } /** * {@link ServletContext#getResource(String)} with caching. */ private URL getResource(String name) throws MalformedURLException { if (resourcePaths!=null) return resourcePaths.get(name); else return context.getResource(name); } /** * Gets the URL (e.g., "/WEB-INF/side-files/fully/qualified/class/name/jspName") * from a class and the JSP name. */ public static String getViewURL(Class clazz,String jspName) { return "/WEB-INF/side-files/"+clazz.getName().replace('.','/')+'/'+jspName; } /** * Sets the specified object as the root of the web application. * *

* This method should be invoked from your implementation of * {@link ServletContextListener#contextInitialized(ServletContextEvent)}. * *

* This is just a convenience method to invoke * servletContext.setAttribute("app",rootApp). * *

* The root object is bound to the URL '/' and used to resolve * all the requests to this web application. */ public static void setRoot( ServletContextEvent event, Object rootApp ) { event.getServletContext().setAttribute("app",rootApp); } /** * Sets the classloader used by {@link StaplerRequest#bindJSON(Class, JSONObject)} and its sibling methods. * * @deprecated * Use {@link WebApp#setClassLoader(ClassLoader)} */ public static void setClassLoader( ServletContext context, ClassLoader classLoader ) { WebApp.get(context).setClassLoader(classLoader); } /** * @deprecated * Use {@link WebApp#getClassLoader()} */ public static ClassLoader getClassLoader( ServletContext context ) { return WebApp.get(context).getClassLoader(); } /** * @deprecated * Use {@link WebApp#getClassLoader()} */ public ClassLoader getClassLoader() { return webApp.getClassLoader(); } /** * Gets the current {@link StaplerRequest} that the calling thread is associated with. */ public static StaplerRequest getCurrentRequest() { return CURRENT_REQUEST.get(); } /** * Gets the current {@link StaplerResponse} that the calling thread is associated with. */ public static StaplerResponse getCurrentResponse() { return CURRENT_RESPONSE.get(); } /** * Gets the current {@link Stapler} that the calling thread is associated with. */ public static Stapler getCurrent() { return CURRENT_REQUEST.get().getStapler(); } /** * HTTP date format. Notice that {@link SimpleDateFormat} is thread unsafe. */ static final ThreadLocal HTTP_DATE_FORMAT = new ThreadLocal() { protected @Override SimpleDateFormat initialValue() { // RFC1945 section 3.3 Date/Time Formats states that timezones must be in GMT SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); format.setTimeZone(TimeZone.getTimeZone("GMT")); return format; } }; /*package*/ static ThreadLocal CURRENT_REQUEST = new ThreadLocal(); /*package*/ static ThreadLocal CURRENT_RESPONSE = new ThreadLocal(); private static final Logger LOGGER = Logger.getLogger(Stapler.class.getName()); /** * Extensions that look like text files. */ private static final Set TEXT_FILES = new HashSet(Arrays.asList( "css","js","html","txt","java","htm","c","cpp","h","rb","pl","py","xml" )); /** * Get raw servlet path (decoded in TokenList). */ private String getServletPath(HttpServletRequest req) { return canonicalPath(req.getRequestURI().substring(req.getContextPath().length())); } /** * Some web containers (e.g., Winstone) leaves ".." and "." in the request URL, * which is a security risk. Fix that by normalizing them. */ static String canonicalPath(String path) { List r = new ArrayList(Arrays.asList(path.split("/+"))); for (int i=0; i0) { r.remove(i-1); i--; } } else { i++; } } StringBuilder buf = new StringBuilder(); if (path.startsWith("/")) buf.append('/'); boolean first = true; for (String token : r) { if (!first) buf.append('/'); else first = false; buf.append(token); } // translation: if (path.endsWith("/") && !buf.endsWith("/")) if (path.endsWith("/") && (buf.length()==0 || buf.charAt(buf.length()-1)!='/')) buf.append('/'); return buf.toString(); } /** * This is the {@link Converter} registry that Stapler uses, primarily * for form-to-JSON binding in {@link StaplerRequest#bindJSON(Class, JSONObject)} * and its family of methods. */ public static final ConvertUtilsBean CONVERT_UTILS = new ConvertUtilsBean(); public static Converter lookupConverter(Class type) { Converter c = CONVERT_UTILS.lookup(type); if (c!=null) return c; // fall back to compatibility behavior c = ConvertUtils.lookup(type); if (c!=null) return c; // look for the associated converter try { if(type.getClassLoader()==null) return null; Class cl = type.getClassLoader().loadClass(type.getName() + "$StaplerConverterImpl"); c = (Converter)cl.newInstance(); CONVERT_UTILS.register(c,type); return c; } catch (ClassNotFoundException e) { // fall through } catch (IllegalAccessException e) { IllegalAccessError x = new IllegalAccessError(); x.initCause(e); throw x; } catch (InstantiationException e) { InstantiationError x = new InstantiationError(); x.initCause(e); throw x; } // bean utils doesn't check the super type, so converters that apply to multiple types // need to be handled outside its semantics if (Enum.class.isAssignableFrom(type)) { // enum return ENUM_CONVERTER; } return null; } static { CONVERT_UTILS.register(new Converter() { public Object convert(Class type, Object value) { if(value==null) return null; try { return new URL(value.toString()); } catch (MalformedURLException e) { throw new ConversionException(e); } } }, URL.class); CONVERT_UTILS.register(new Converter() { public FileItem convert(Class type, Object value) { if(value==null) return null; try { return Stapler.getCurrentRequest().getFileItem(value.toString()); } catch (ServletException e) { throw new ConversionException(e); } catch (IOException e) { throw new ConversionException(e); } } }, FileItem.class); // mapping for boxed types should map null to null, instead of null to zero. CONVERT_UTILS.register(new IntegerConverter(null),Integer.class); CONVERT_UTILS.register(new FloatConverter(null),Float.class); CONVERT_UTILS.register(new DoubleConverter(null),Double.class); } private static final Converter ENUM_CONVERTER = new Converter() { public Object convert(Class type, Object value) { return Enum.valueOf(type,value.toString()); } }; /** * Escapes HTML/XML unsafe characters for the PCDATA section. * This method does not handle whitespace-preserving escape, nor attribute escapes. */ public static String escape(String v) { StringBuffer buf = new StringBuffer(v.length()+64); for( int i=0; i') buf.append(">"); else if(ch=='&') buf.append("&"); else buf.append(ch); } return buf.toString(); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/HttpRedirect.java0000664000175000017500000000566012414640747030245 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import javax.annotation.Nonnull; import javax.servlet.ServletException; import java.io.IOException; import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY; /** * {@link HttpResponse} that dose HTTP 302 redirect. * Extends from {@link RuntimeException} so that you can throw it. * * @author Kohsuke Kawaguchi */ public final class HttpRedirect extends RuntimeException implements HttpResponse { private final int statusCode; private final String url; public HttpRedirect(@Nonnull String url) { this(SC_MOVED_TEMPORARILY,url); } public HttpRedirect(int statusCode, @Nonnull String url) { this.statusCode = statusCode; if (url == null) { throw new NullPointerException(); } this.url = url; } public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.sendRedirect(statusCode,url); } /** * @param relative * The path relative to the context path. The context path + this value * is sent to the user. * @deprecated * Use {@link HttpResponses#redirectViaContextPath(String)}. */ public static HttpResponse fromContextPath(final String relative) { return HttpResponses.redirectViaContextPath(relative); } /** * Redirect to "." */ public static HttpRedirect DOT = new HttpRedirect("."); /** * Redirect to the context root */ public static HttpResponse CONTEXT_ROOT = fromContextPath(""); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/NameBasedDispatcher.java0000664000175000017500000000510012414640747031457 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import javax.servlet.ServletException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; /** * @author Kohsuke Kawaguchi */ abstract class NameBasedDispatcher extends Dispatcher { protected final String name; private final int argCount; protected NameBasedDispatcher(String name, int argCount) { this.name = name; this.argCount = argCount; } protected NameBasedDispatcher(String name) { this(name,0); } public final boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException, IllegalAccessException, InvocationTargetException { if(!req.tokens.hasMore() || !req.tokens.peek().equals(name)) return false; if(req.tokens.countRemainingTokens()<=argCount) return false; req.tokens.next(); boolean b = doDispatch(req, rsp, node); if (!b) req.tokens.prev(); // cancel the next effect return b; } protected abstract boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException, IllegalAccessException, InvocationTargetException; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/Header.java0000664000175000017500000000535712414640747027037 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import org.kohsuke.stapler.Header.HandlerImpl; import javax.servlet.ServletException; import static java.lang.annotation.ElementType.PARAMETER; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Target; import java.lang.annotation.Documented; /** * Indicates that this parameter is bound from HTTP header. * * @author Kohsuke Kawaguchi */ @Retention(RUNTIME) @Target(PARAMETER) @Documented @InjectedParameter(HandlerImpl.class) public @interface Header { /** * HTTP header name. */ String value(); /** * If true, request without this header will be rejected. */ boolean required() default false; class HandlerImpl extends AnnotationHandler

{ public Object parse(StaplerRequest request, Header a, Class type, String parameterName) throws ServletException { String name = a.value(); if(name.length()==0) name=parameterName; if(name==null) throw new IllegalArgumentException("Parameter name unavailable neither in the code nor in annotation"); String value = request.getHeader(name); if(a.required() && value==null) throw new ServletException("Required HTTP header "+name+" is missing"); return convert(type,value); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java0000664000175000017500000004320712414640747030626 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.fileupload.FileItem; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Type; import java.util.Calendar; import java.util.Date; import java.util.List; import net.sf.json.JSONObject; import net.sf.json.JSONArray; import org.kohsuke.stapler.bind.BoundObjectTable; import org.kohsuke.stapler.lang.Klass; /** * Defines additional parameters/operations made available by Stapler. * * @see Stapler#getCurrentRequest() * @author Kohsuke Kawaguchi */ public interface StaplerRequest extends HttpServletRequest { /** * Gets the {@link Stapler} instance that this belongs to. */ Stapler getStapler(); /** * Short for {@code getStapler().getWebApp()} */ WebApp getWebApp(); /** * Returns the additional URL portion that wasn't used by the stapler, * excluding the query string. * *

* For example, if the requested URL is "foo/bar/zot/abc?def=ghi" and * "foo/bar" portion matched bar.jsp, this method returns * "/zot/abc". * *

* If this method is invoked from getters or {@link StaplerProxy#getTarget()} * during the object traversal, this method returns the path portion * that is not yet processed. * * @return * can be empty string, but never null. */ String getRestOfPath(); /** * Returns the same thing as {@link #getRestOfPath()} but in the pre-decoded form, * so all "%HH"s as present in the request URL is intact. */ String getOriginalRestOfPath(); /** * Returns the {@link ServletContext} object given to the stapler * dispatcher servlet. */ ServletContext getServletContext(); /** * {@link #getRequestURI()} plus additional query string part, if it exists. */ String getRequestURIWithQueryString(); /** * {@link #getRequestURL()} plus additional query string part, if it exists. */ StringBuffer getRequestURLWithQueryString(); /** * Gets the {@link RequestDispatcher} that represents a specific view * for the given object. * * This support both JSP and Jelly. * * @param viewName * If this name is relative name like "foo.jsp" or "bar/zot.jelly", * then the corresponding "side file" is searched by this name. *

* For Jelly, this also accepts absolute path name that starts * with '/', such as "/foo/bar/zot.jelly". In this case, * it.getClass().getClassLoader() is searched for this script. * * @return null * if neither JSP nor Jelly is not found by the given name. */ RequestDispatcher getView(Object it,String viewName) throws IOException; /** * Convenience method to call {@link #getView(Klass, String)} with {@link Class}. */ RequestDispatcher getView(Class clazz,String viewName) throws IOException; /** * Gets the {@link RequestDispatcher} that represents a specific view * for the given class. * *

* Unlike {@link #getView(Object, String)}, calling this request dispatcher * doesn't set the "it" variable, so * {@code getView(it.getClass(),viewName)} and {@code getView(it,viewName)} * aren't the same thing. */ RequestDispatcher getView(Klass clazz, String viewName) throws IOException; /** * Gets the part of the request URL from protocol up to the context path. * So typically it's something like http://foobar:8080/something */ String getRootPath(); /** * Gets the referer header (like "http://foobar.com/zot") or null. * * This is just a convenience method. */ String getReferer(); /** * Returns a list of ancestor objects that lead to the "it" object. * The returned list contains {@link Ancestor} objects sorted in the * order from root to the "it" object. * *

* For example, if the URL was "foo/bar/zot" and the "it" object * was determined as root.getFoo().getBar("zot"), * then this list will contain the following 3 objects in this order: *

    *
  1. the root object *
  2. root.getFoo() object *
  3. root.getFoo().getBar("zot") object (the "it" object) *
*

* * * @return * list of {@link Ancestor}s. Can be empty, but always non-null. */ List getAncestors(); /** * Finds the nearest ancestor that has the object of the given type, or null if not found. */ Ancestor findAncestor(Class type); /** * Short for {@code findAncestor(type).getObject()}, with proper handling for null de-reference. * This version is also type safe. */ T findAncestorObject(Class type); /** * Finds the nearest ancestor whose {@link Ancestor#getObject()} matches the given object. */ Ancestor findAncestor(Object o); /** * Short for {@code getParameter(name)!=null} */ boolean hasParameter(String name); /** * Gets the {@link HttpServletRequest#getRequestURI() request URI} * of the original request, so that you can access the value even from * JSP. */ String getOriginalRequestURI(); /** * Checks "If-Modified-Since" header and returns false * if the resource needs to be served. * *

* This method can behave in three ways. * *

    *
  1. If timestampOfResource is 0 or negative, * this method just returns false. * *
  2. If "If-Modified-Since" header is sent and if it's bigger than * timestampOfResource, then this method sets * {@link HttpServletResponse#SC_NOT_MODIFIED} as the response code * and returns true. * *
  3. Otherwise, "Last-Modified" header is added with timestampOfResource value, * and this method returns false. *
* *

* This method sends out the "Expires" header to force browser * to re-validate all the time. * * @param timestampOfResource * The time stamp of the resource. * @param rsp * This object is updated accordingly to simplify processing. * * @return * false to indicate that the caller has to serve the actual resource. * true to indicate that the caller should just quit processing right there * (and send back {@link HttpServletResponse#SC_NOT_MODIFIED}. */ boolean checkIfModified(long timestampOfResource, StaplerResponse rsp); /** * @see #checkIfModified(long, StaplerResponse) */ boolean checkIfModified(Date timestampOfResource, StaplerResponse rsp); /** * @see #checkIfModified(long, StaplerResponse) */ boolean checkIfModified(Calendar timestampOfResource, StaplerResponse rsp); /** * @param expiration * The number of milliseconds until the resource will "expire". * Until it expires the browser will be allowed to cache it * and serve it without checking back with the server. * After it expires, the client will send conditional GET to * check if the resource is actually modified or not. * If 0, it will immediately expire. * * @see #checkIfModified(long, StaplerResponse) */ boolean checkIfModified(long timestampOfResource, StaplerResponse rsp, long expiration); /** * Binds form parameters to a bean by using introspection. * * For example, if there's a parameter called 'foo' that has value 'abc', * then bean.setFoo('abc') will be invoked. This will be repeated * for all parameters. Parameters that do not have corresponding setters will * be simply ignored. * *

* Values are converted into the right type. See {@link ConvertUtils#convert(String, Class)}. * * @see BeanUtils#setProperty(Object, String, Object) * * @param bean * The object which will be filled out. */ void bindParameters( Object bean ); /** * Binds form parameters to a bean by using introspection. * * This method works like {@link #bindParameters(Object)}, but it performs a * pre-processing on property names. Namely, only property names that start * with the given prefix will be used for binding, and only the portion of the * property name after the prefix is used. * * So for example, if the prefix is "foo.", then property name "foo.bar" with value * "zot" will invoke bean.setBar("zot"). * * * @deprecated * Instead of using prefix to group object among form parameter names, * use structured form submission and {@link #bindJSON(Class, JSONObject)}. */ void bindParameters( Object bean, String prefix ); /** * Binds collection form parameters to beans by using introspection or * constructor parameters injection. * *

* This method works like {@link #bindParameters(Object,String)} and * {@link #bindParameters(Class, String)}, but it assumes * that form parameters have multiple-values, and use individual values to * fill in multiple beans. * *

* For example, if getParameterValues("foo")=={"abc","def"} * and getParameterValues("bar")=={"5","3"}, then this method will * return two objects (the first with "abc" and "5", the second with * "def" and "3".) * * @param type * Type of the bean to be created. This class must have the default no-arg * constructor. * * @param prefix * See {@link #bindParameters(Object, String)} for details. * * @return * Can be empty but never null. * * * @deprecated * Instead of using prefix to group object among form parameter names, * use structured form submission and {@link #bindJSON(Class, JSONObject)}. */ List bindParametersToList( Class type, String prefix ); /** * Instantiates a new object by injecting constructor parameters from the form parameters. * *

* The given class must have a constructor annotated with '@stapler-constructor', * and must be processed by the maven-stapler-plugin, so that the parameter names * of the constructor is available at runtime. * *

* The prefix is used to control the form parameter name. For example, * if the prefix is "foo." and if the constructor is define as * Foo(String a, String b), then the constructor will be invoked * as new Foo(getParameter("foo.a"),getParameter("foo.b")). * * @deprecated * Instead of using prefix to group object among form parameter names, * use structured form submission and {@link #bindJSON(Class, JSONObject)}. */ T bindParameters( Class type, String prefix ); /** * Works like {@link #bindParameters(Class, String)} but uses n-th value * of all the parameters. * *

* This is useful for creating multiple instances from repeated form fields. * * * @deprecated * Instead of using prefix to group object among form parameter names, * use structured form submission and {@link #bindJSON(Class, JSONObject)}. */ T bindParameters( Class type, String prefix, int index ); /** * Data-bind from a {@link JSONObject} to the given target type, * by using introspection or constructor parameters injection. * *

* For example, if you have a constructor that looks like the following: * *

     * class Foo {
     *   @{@link DataBoundConstructor}
     *   public Foo(Integer x, String y, boolean z, Bar bar) { ... }
     * }
     *
     * class Bar {
     *   @{@link DataBoundConstructor}
     *   public Bar(int x, int y) {}
     * }
     * 
* * ... and if JSONObject looks like * *
{ y:"text", z:true, bar:{x:1,y:2}}
* * then, this method returns * *
new Foo(null,"text",true,new Bar(1,2))
* *

Sub-typing

*

* In the above example, a new instance of Bar was created, * but you can also create a subtype of Bar by having the 'stapler-class' property in * JSON like this: * *

     * class BarEx extends Bar {
     *   @{@link DataBoundConstructor}
     *   public BarEx(int a, int b, int c) {}
     * }
     *
     * { y:"text", z:true, bar: { stapler-class:"p.k.g.BarEx", a:1, b:2, c:3 } }
     * 
* *

* The type that shows up in the constructor (Bar in this case) * can be an interface or an abstract class. */ T bindJSON(Class type, JSONObject src); /** * Data-bind from one of the JSON object types ({@link JSONObject}, {@link JSONArray}, * {@link String}, {@link Integer}, and so on) to the expected type given as an argument. * * @param genericType * The generic type of the 'erasure' parameter. * @param erasure * The expected type to convert the JSON argument to. * @param json * One of the JSON value type. */ T bindJSON(Type genericType, Class erasure, Object json); /** * Data-binds from {@link JSONObject} to the given object. * *

* This method is bit like {@link #bindJSON(Class, JSONObject)}, except that this method * populates an existing object, instead of creating a new instance. * *

* This method is also bit like {@link #bindParameters(Object, String)}, in that it * populates an existing object from a form submission, except that this method * obtains data from {@link JSONObject} thus more structured, whereas {@link #bindParameters(Object, String)} * uses the map structure of the form submission. */ void bindJSON( Object bean, JSONObject src ); /** * Data-bind from either {@link JSONObject} or {@link JSONArray} to a list, * by using {@link #bindJSON(Class, JSONObject)} as the lower-level mechanism. * *

* If the source is {@link JSONObject}, the returned list will contain * a single item. If it is {@link JSONArray}, each item will be bound. * If it is null, then the list will be empty. */ List bindJSONToList(Class type, Object src); /** * Gets the {@link BindInterceptor} set for this request. * * @see WebApp#bindInterceptors */ BindInterceptor getBindInterceptor(); /** * @deprecated * Typo. Use {@link #setBindInterceptpr(BindInterceptor)} */ BindInterceptor setBindListener(BindInterceptor bindListener); BindInterceptor setBindInterceptpr(BindInterceptor bindListener); /** * Gets the content of the structured form submission. * * @see Structured Form Submission */ JSONObject getSubmittedForm() throws ServletException; /** * Obtains a commons-fileupload object that represents an uploaded file. * * @return * null if a file of the given form field name doesn't exist. * This includes the case where the name corresponds to a simple * form field (like textbox, checkbox, etc.) */ FileItem getFileItem(String name) throws ServletException, IOException; /** * Returns true if this request represents a server method call to a JavaScript proxy object. */ boolean isJavaScriptProxyCall(); /** * Short cut for obtaining {@link BoundObjectTable} associated with this webapp. */ BoundObjectTable getBoundObjectTable(); /** * Exports the given Java object as a JavaScript proxy and returns a JavaScript expression to create * a proxy on the client side. * * Short cut for {@code getBoundObjectTable().bind(toBeExported).getProxyScript()} */ String createJavaScriptProxy(Object toBeExported); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/LimitedTo.java0000664000175000017500000000577012414640747027540 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import org.kohsuke.stapler.interceptor.Interceptor; import org.kohsuke.stapler.interceptor.InterceptorAnnotation; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; /** * Declares that methods are only available for requests that * have the specified role(s). * *

* This annotation should be placed on methods that need to be * secured (iow protected from anonymous users.) * * @author Kohsuke Kawaguchi */ @Retention(RUNTIME) @Target({METHOD,FIELD}) @InterceptorAnnotation(LimitedTo.Processor.class) public @interface LimitedTo { /** * The name of role. * the method can be invoked only if the user belongs * to this role. */ String value(); public static class Processor extends Interceptor { private String role; @Override public void setTarget(Function target) { role = target.getAnnotation(LimitedTo.class).value(); super.setTarget(target); } @Override public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException { if(request.isUserInRole(role)) return target.invoke(request, response, instance, arguments); else throw new IllegalAccessException("Needs to be in role "+role); } } } ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/CaptureParameterNameTransformation.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/CaptureParameterNameTransformati0000664000175000017500000001032112414640747033351 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import org.codehaus.groovy.ast.ASTNode; import org.codehaus.groovy.ast.AnnotatedNode; import org.codehaus.groovy.ast.AnnotationNode; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.expr.ConstantExpression; import org.codehaus.groovy.ast.expr.ListExpression; import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.transform.ASTTransformation; import org.codehaus.groovy.transform.GroovyASTTransformation; import org.kohsuke.MetaInfServices; import java.util.Collections; import java.util.List; import java.util.Set; /** * Groovy AST transformation that capture necessary parameter names. * * @author Kohsuke Kawaguchi */ @MetaInfServices @GroovyASTTransformation public class CaptureParameterNameTransformation implements ASTTransformation { public void visit(ASTNode[] nodes, SourceUnit source) { handleClasses(source.getAST().getClasses()); } private void handleClasses(List classNodes) { for (ClassNode c : classNodes) handleMethods(c.getMethods()); } // set of annotation class names to capture private static final Set CONSTRUCTOR_ANN = Collections.singleton(DataBoundConstructor.class.getName()); private static final Set INJECTED_PARAMETER_ANN = Collections.singleton(InjectedParameter.class.getName()); private void handleMethods(List methods) { for (MethodNode m : methods) // copy the array as we'll modify them if(hasAnnotation(m,CONSTRUCTOR_ANN) || hasInjectionAnnotation(m)) write(m); } private boolean hasInjectionAnnotation(MethodNode m) { for (Parameter p : m.getParameters()) if(hasInjectedParameterAnnotation(p)) return true; return false; } private boolean hasAnnotation(AnnotatedNode target, Set annotationTypeNames) { for (AnnotationNode a : target.getAnnotations()) if(annotationTypeNames.contains(a.getClassNode().getName())) return true; return false; } private boolean hasInjectedParameterAnnotation(Parameter p) { for (AnnotationNode a : p.getAnnotations()) { if (hasAnnotation(a.getClassNode(), INJECTED_PARAMETER_ANN)) return true; } return false; } /** * Captures the parameter names as annotations on the class. */ private void write(MethodNode c) { ListExpression v = new ListExpression(); for( Parameter p : c.getParameters() ) v.addExpression(new ConstantExpression(p.getName())); AnnotationNode a = new AnnotationNode(new ClassNode(CapturedParameterNames.class)); a.addMember("value",v); c.addAnnotation(a); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/AttributeKey.java0000664000175000017500000000645512414640747030263 0ustar ebourgebourgpackage org.kohsuke.stapler; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.util.UUID; /** * Type-safe attribute accessor. * *

* Servlet API has a bag of stuff in several scopes (such as request, session, ...) * but the API is not type-safe. * * This object provides a convenient type-safe access to to such bags, as well * as providing uniform API regardless of the actual scope. * *

* Each instance of {@link AttributeKey} gets an unique attribute name, which means * in the most typical case, these instances should be used as a singleton. * * @author Kohsuke Kawaguchi */ public abstract class AttributeKey { protected final String name; public AttributeKey() { name = UUID.randomUUID().toString(); } public AttributeKey(String name) { this.name = name; } public abstract T get(HttpServletRequest req); public abstract void set(HttpServletRequest req, T value); public abstract void remove(HttpServletRequest req); public final T get() { return get(Stapler.getCurrentRequest()); } public final void set(T value) { set(Stapler.getCurrentRequest(),value); } public final void remove() { remove(Stapler.getCurrentRequest()); } /** * Creates a new request-scoped {@link AttributeKey}. */ public static AttributeKey requestScoped() { return new AttributeKey() { public T get(HttpServletRequest req) { return (T)req.getAttribute(name); } public void set(HttpServletRequest req, T value) { req.setAttribute(name, value); } public void remove(HttpServletRequest req) { req.removeAttribute(name); } }; } /** * Creates a new session-scoped {@link AttributeKey}. */ public static AttributeKey sessionScoped() { return new AttributeKey() { public T get(HttpServletRequest req) { HttpSession s = req.getSession(false); if (s==null) return null; return (T)s.getAttribute(name); } public void set(HttpServletRequest req, T value) { req.getSession().setAttribute(name, value); } public void remove(HttpServletRequest req) { HttpSession s = req.getSession(false); if (s!=null) s.removeAttribute(name); } }; } /** * Creates a new {@link ServletContext}-scoped {@link AttributeKey}. */ public static AttributeKey appScoped() { return new AttributeKey() { public T get(HttpServletRequest req) { return (T) getContext(req).getAttribute(name); } public void set(HttpServletRequest req, T value) { getContext(req).setAttribute(name, value); } public void remove(HttpServletRequest req) { getContext(req).removeAttribute(name); } private ServletContext getContext(HttpServletRequest req) { return ((StaplerRequest)req).getServletContext(); } }; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/BindInterceptor.java0000664000175000017500000000353112414640747030732 0ustar ebourgebourgpackage org.kohsuke.stapler; import net.sf.json.JSONObject; import java.lang.reflect.Type; /** * Intercepts (and receives callbacks) about the JSON->object binding process. * * @author Kohsuke Kawaguchi * @see StaplerRequest#setBindInterceptpr(BindInterceptor) * @see WebApp#bindInterceptors */ public class BindInterceptor { /** * Called for each object conversion, after the expected type is determined. * * @param targetType * Type that the converted object must be assignable to. * @param targetTypeErasure * Erasure of the {@code targetType} parameter. * @param jsonSource * JSON object to be mapped to Java object. * @return * {@link #DEFAULT} to indicate that the default conversion process should proceed. * Any other values (including null) will override the process. */ public Object onConvert(Type targetType, Class targetTypeErasure, Object jsonSource) { return DEFAULT; } /** * Called for each object conversion, after the actual subtype to instantiate is determined. * * @param actualType * The type to instnatiate * @param json * JSON object to be mapped to Java object. * @return * {@link #DEFAULT} to indicate that the default conversion process should proceed. * Any other values (including null) will override the process. */ public Object instantiate(Class actualType, JSONObject json) { return DEFAULT; } /** * Indicates that the conversion should proceed as it normally does, * and that the listener isn't replacing the process. */ public static final Object DEFAULT = new Object(); /** * Default {@link BindInterceptor} that does nothing. */ public static final BindInterceptor NOOP = new BindInterceptor(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/package-info.java0000664000175000017500000000303512414640747030162 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ /** * Stapler URL->Object mapping framework. The main entry points are {@link Stapler}, * {@link StaplerRequest}, and {@link StaplerResponse}. */ package org.kohsuke.stapler;stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/interceptor/0000775000175000017500000000000012414640747027330 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/interceptor/RequirePOST.java0000664000175000017500000000403412414640747032316 0ustar ebourgebourgpackage org.kohsuke.stapler.interceptor; import java.io.IOException; import java.io.PrintWriter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.kohsuke.stapler.HttpResponses; /** * Requires the request to be a POST. * * @author Kohsuke Kawaguchi * @since 1.180 */ @Retention(RUNTIME) @Target({METHOD,FIELD}) @InterceptorAnnotation(RequirePOST.Processor.class) public @interface RequirePOST { public static class Processor extends Interceptor { @Override public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException { if (!request.getMethod().equals("POST")) { throw new InvocationTargetException(new HttpResponses.HttpResponseException() { public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { rsp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); rsp.addHeader("Allow", "POST"); rsp.setContentType("text/html"); PrintWriter w = rsp.getWriter(); w.println("POST required"); w.println("POST is required for " + target.getQualifiedName() + "
"); w.println("

"); w.println(""); } }); } return target.invoke(request, response, instance, arguments); } } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/interceptor/JsonOutputFilter.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/interceptor/JsonOutputFilter.jav0000664000175000017500000001131012414640747033326 0ustar ebourgebourg/* * Copyright (c) 2013, Robert Sandell * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.interceptor; import net.sf.json.JsonConfig; import net.sf.json.util.PropertyFilter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.bind.JavaScriptMethod; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; import java.util.Set; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.util.Arrays; import java.util.HashSet; /** * Annotation for filtering the JSON data returned from a {@link JavaScriptMethod} annotated method. * Put this annotation on your js proxied method and provide the properties you want filtered. * * @author Robert Sandell <sandell.robert@gmail.com> */ @Retention(RUNTIME) @Target({METHOD, FIELD}) @InterceptorAnnotation(JsonOutputFilter.Processor.class) public @interface JsonOutputFilter { /** * White-list of properties to include in the output. */ String[] includes() default {}; /** * Black-list of properties to exclude from the output. */ String[] excludes() default {}; /** * If transient fields should be ignored. Default true. * * @see JsonConfig#isIgnoreTransientFields() */ boolean ignoreTransient() default true; /** * If {@link JsonConfig#DEFAULT_EXCLUDES} should be ignored. Default false * * @see JsonConfig#isIgnoreDefaultExcludes() */ boolean ignoreDefaultExcludes() default false; public static class Processor extends Interceptor { @Override public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException { JsonOutputFilter annotation = target.getAnnotation((JsonOutputFilter.class)); if (annotation != null) { JsonConfig config = new JsonConfig(); config.setJsonPropertyFilter(new FilterPropertyFilter(annotation.includes(), annotation.excludes())); config.setIgnoreTransientFields(annotation.ignoreTransient()); config.setIgnoreDefaultExcludes(annotation.ignoreDefaultExcludes()); response.setJsonConfig(config); } return target.invoke(request, response, instance, arguments); } } /** * Json Property filter for handling the include and exclude. */ static class FilterPropertyFilter implements PropertyFilter { private Set includes; private Set excludes; public FilterPropertyFilter(String[] includes, String[] excludes) { this(new HashSet(Arrays.asList(includes)), new HashSet(Arrays.asList(excludes))); } public FilterPropertyFilter(Set includes, Set excludes) { this.includes = includes; this.excludes = excludes; } public boolean apply(Object source, String name, Object value) { if (excludes.contains(name)) { return true; } else if (!includes.isEmpty()) { return !includes.contains(name); } else { return false; } } } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/interceptor/InterceptorAnnotation.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/interceptor/InterceptorAnnotatio0000664000175000017500000000162012414640747033425 0ustar ebourgebourgpackage org.kohsuke.stapler.interceptor; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; /** * Marks the annotation as an interceptor annotation, * which executes before/after the method invocation of domain objects happen * as a part of the request processing. * *

* This mechanism is useful for performing declarative processing/check on domain objects, * such as checking HTTP headers, performing the access control, etc. * * @author Kohsuke Kawaguchi * @see Interceptor * @see RequirePOST */ @Target(ANNOTATION_TYPE) @Retention(RUNTIME) @Documented public @interface InterceptorAnnotation { /** * Actual interceptor logic. Must have a default constructor. */ Class value(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/interceptor/Interceptor.java0000664000175000017500000000326512414640747032477 0ustar ebourgebourgpackage org.kohsuke.stapler.interceptor; import org.kohsuke.stapler.Function; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import java.lang.reflect.InvocationTargetException; import org.kohsuke.stapler.HttpResponses; /** * Intercepts the domain method call from Stapler. * * @author Kohsuke Kawaguchi * @see InterceptorAnnotation */ public abstract class Interceptor { protected Function target; /** * Called by Stapler to set up the target of the interceptor. * This function object represents a method on which your annotation is placed. * * This happens once before this instance takes any calls. */ public void setTarget(Function target) { this.target = target; } /** * Intercepts the call. * *

* The minimal no-op interceptor would do {@code target.invoke(request,response,instance,arguments)}, * but the implementation is free to do additional pre/post processing. * * @param request * The current request we are processing. * @param response * The current response object. * @param instance * The domain object instance whose method we are about to invoke. * @param arguments * Arguments of the method call. * * @return * Return value from the method. * @throws InvocationTargetException if you want to send e.g. something from {@link HttpResponses} */ public abstract Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/interceptor/RespondSuccess.java0000664000175000017500000000254112414640747033140 0ustar ebourgebourgpackage org.kohsuke.stapler.interceptor; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Used on the web-bound doXyz method to indicate that the successful return of the method should * result in HTTP 200 Success status. * * @author Kohsuke Kawaguchi * @see HttpResponses#ok() */ @Retention(RUNTIME) @Target({METHOD,FIELD}) @InterceptorAnnotation(RespondSuccess.Processor.class) public @interface RespondSuccess { public static class Processor extends Interceptor { @Override public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException { target.invoke(request, response, instance, arguments); // TODO does this actually do anything? // Function.bindAndInvokeAndServeResponse ignores return value if the method is declared to return void. // And it seems Stapler will send a 200 by default anyway. return HttpResponses.ok(); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/TearOffSupport.java0000664000175000017500000000623312414640747030564 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; /** * Allows "tear-off" objects to be linked to the parent object. * *

* This mechanism is used to avoid static linking optional packages, * so that stapler can work even when the optional dependencies are missing. * * @author Kohsuke Kawaguchi */ public abstract class TearOffSupport { private volatile Map tearOffs; public final T getTearOff(Class t) { Map m = tearOffs; if(m==null) return null; return (T)m.get(t); } public final T loadTearOff(Class t) { T o = getTearOff(t); if(o==null) { try { o = t.getConstructor(getClass()).newInstance(this); setTearOff(t,o); } catch (InstantiationException e) { throw new InstantiationError(e.getMessage()); } catch (IllegalAccessException e) { throw new IllegalAccessError(e.getMessage()); } catch (InvocationTargetException e) { Throwable ex = e.getTargetException(); if(ex instanceof RuntimeException) throw (RuntimeException)ex; if(ex instanceof Error) throw (Error)ex; throw new Error(e); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } return o; } public synchronized void setTearOff(Class type, T instance) { Map m = tearOffs; Map r = m!=null ? new HashMap(tearOffs) : new HashMap(); r.put(type,instance); tearOffs = r; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/MetaClass.java0000664000175000017500000005133412414640747027517 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import net.sf.json.JSONArray; import org.apache.commons.io.IOUtils; import org.kohsuke.stapler.bind.JavaScriptMethod; import org.kohsuke.stapler.lang.Klass; import org.kohsuke.stapler.lang.MethodRef; import javax.annotation.PostConstruct; import javax.servlet.ServletException; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import static javax.servlet.http.HttpServletResponse.*; /** * Created one instance each for a {@link Klass}, * that retains some useful cache about a class and its views. * * @author Kohsuke Kawaguchi * @see WebApp#getMetaClass(Klass) */ public class MetaClass extends TearOffSupport { /** * This meta class wraps this class * * @deprecated as of 1.177 * Use {@link #klass}. If you really want the Java class representation, use {@code klass.toJavaClass()}. */ public final Class clazz; public final Klass klass; /** * {@link MetaClassLoader} that wraps {@code clazz.getClassLoader()}. * Null if the class is loaded by the bootstrap classloader. */ public final MetaClassLoader classLoader; public final List dispatchers = new ArrayList(); /** * Base metaclass. * Note that baseClass.clazz==clazz.getSuperClass() */ public final MetaClass baseClass; /** * {@link WebApp} that owns this meta class. */ public final WebApp webApp; /** * If there's a method annotated with @PostConstruct, that {@link MethodRef} object, linked * to the list of the base class. */ private volatile SingleLinkedList postConstructMethods; /*package*/ MetaClass(WebApp webApp, Klass klass) { this.clazz = klass.toJavaClass(); this.klass = klass; this.webApp = webApp; this.baseClass = webApp.getMetaClass(klass.getSuperClass()); this.classLoader = MetaClassLoader.get(clazz.getClassLoader()); buildDispatchers(); } /** * Build {@link #dispatchers}. * *

* This is the meat of URL dispatching. It looks at the class * via reflection and figures out what URLs are handled by who. */ /*package*/ void buildDispatchers() { this.dispatchers.clear(); ClassDescriptor node = new ClassDescriptor(clazz,null/*TODO:support wrappers*/); // check action .do(...) for( final Function f : node.methods.prefix("do") ) { WebMethod a = f.getAnnotation(WebMethod.class); String[] names; if(a!=null && a.name().length>0) names=a.name(); else names=new String[]{camelize(f.getName().substring(2))}; // 'doFoo' -> 'foo' for (String name : names) { dispatchers.add(new NameBasedDispatcher(name,0) { public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException, InvocationTargetException, ServletException, IOException { if(traceable()) trace(req,rsp,"-> <%s>.%s(...)",node,f.getName()); return f.bindAndInvokeAndServeResponse(node, req, rsp); } public String toString() { return f.getQualifiedName()+"(...) for url=/"+name+"/..."; } }); } } // JavaScript proxy method invocations for js // reacts only to a specific content type for( final Function f : node.methods.prefix("js") ) { String name = camelize(f.getName().substring(2)); // jsXyz -> xyz dispatchers.add(new JavaScriptProxyMethodDispatcher(name, f)); } // JavaScript proxy method with @JavaScriptMethod // reacts only to a specific content type for( final Function f : node.methods.annotated(JavaScriptMethod.class) ) { JavaScriptMethod a = f.getAnnotation(JavaScriptMethod.class); String[] names; if(a!=null && a.name().length>0) names=a.name(); else names=new String[]{f.getName()}; for (String name : names) dispatchers.add(new JavaScriptProxyMethodDispatcher(name,f)); } for (Facet f : webApp.facets) f.buildViewDispatchers(this, dispatchers); // check action .doIndex(...) for( final Function f : node.methods.name("doIndex") ) { dispatchers.add(new Dispatcher() { public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException, InvocationTargetException, ServletException, IOException { if(req.tokens.hasMore()) return false; // applicable only when there's no more token if(traceable()) trace(req,rsp,"-> <%s>.doIndex(...)",node); return f.bindAndInvokeAndServeResponse(node,req,rsp); } public String toString() { return f.getQualifiedName()+"(StaplerRequest,StaplerResponse) for url=/"; } }); } // check public properties of the form NODE.TOKEN for (final Field f : node.fields) { dispatchers.add(new NameBasedDispatcher(f.getName()) { final String role = getProtectedRole(f); public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException, IllegalAccessException { if(role!=null && !req.isUserInRole(role)) throw new IllegalAccessException("Needs to be in role "+role); if(traceable()) traceEval(req,rsp,node,f.getName()); req.getStapler().invoke(req, rsp, f.get(node)); return true; } public String toString() { return String.format("%1$s.%2$s for url=/%2$s/...",f.getDeclaringClass().getName(),f.getName()); } }); } FunctionList getMethods = node.methods.prefix("get"); // check public selector methods of the form NODE.getTOKEN() for( final Function f : getMethods.signature() ) { if(f.getName().length()<=3) continue; WebMethod a = f.getAnnotation(WebMethod.class); String[] names; if(a!=null && a.name().length>0) names=a.name(); else names=new String[]{camelize(f.getName().substring(3))}; // 'getFoo' -> 'foo' for (String name : names) { dispatchers.add(new NameBasedDispatcher(name) { public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException, IllegalAccessException, InvocationTargetException { if(traceable()) traceEval(req,rsp,node,f.getName()+"()"); req.getStapler().invoke(req,rsp, f.invoke(req, rsp, node)); return true; } public String toString() { return String.format("%1$s() for url=/%2$s/...",f.getQualifiedName(),name); } }); } } // check public selector methods of the form static NODE.getTOKEN(StaplerRequest) for( final Function f : getMethods.signature(StaplerRequest.class) ) { if(f.getName().length()<=3) continue; String name = camelize(f.getName().substring(3)); // 'getFoo' -> 'foo' dispatchers.add(new NameBasedDispatcher(name) { public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException, IllegalAccessException, InvocationTargetException { if(traceable()) traceEval(req,rsp,node,f.getName()+"(...)"); req.getStapler().invoke(req,rsp, f.invoke(req, rsp, node, req)); return true; } public String toString() { return String.format("%1$s(StaplerRequest) for url=/%2$s/...",f.getQualifiedName(),name); } }); } // check public selector methods .get(String) for( final Function f : getMethods.signature(String.class) ) { if(f.getName().length()<=3) continue; String name = camelize(f.getName().substring(3)); // 'getFoo' -> 'foo' dispatchers.add(new NameBasedDispatcher(name,1) { public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException, IllegalAccessException, InvocationTargetException { String token = req.tokens.next(); if(traceable()) traceEval(req,rsp,node,f.getName()+"(\""+token+"\")"); req.getStapler().invoke(req,rsp, f.invoke(req, rsp, node,token)); return true; } public String toString() { return String.format("%1$s(String) for url=/%2$s/TOKEN/...",f.getQualifiedName(),name); } }); } // check public selector methods .get(int) for( final Function f : getMethods.signature(int.class) ) { if(f.getName().length()<=3) continue; String name = camelize(f.getName().substring(3)); // 'getFoo' -> 'foo' dispatchers.add(new NameBasedDispatcher(name,1) { public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException, IllegalAccessException, InvocationTargetException { int idx = req.tokens.nextAsInt(); if(traceable()) traceEval(req,rsp,node,f.getName()+"("+idx+")"); req.getStapler().invoke(req,rsp, f.invoke(req, rsp, node,idx)); return true; } public String toString() { return String.format("%1$s(int) for url=/%2$s/N/...",f.getQualifiedName(),name); } }); } if(node.clazz.isArray()) { dispatchers.add(new Dispatcher() { public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException { if(!req.tokens.hasMore()) return false; try { int index = req.tokens.nextAsInt(); if(traceable()) traceEval(req,rsp,node,"((Object[])",")["+index+"]"); req.getStapler().invoke(req,rsp, ((Object[]) node)[index]); return true; } catch (NumberFormatException e) { return false; // try next } } public String toString() { return "Array look-up for url=/N/..."; } }); } if(List.class.isAssignableFrom(node.clazz)) { dispatchers.add(new Dispatcher() { public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException { if(!req.tokens.hasMore()) return false; try { int index = req.tokens.nextAsInt(); if(traceable()) traceEval(req,rsp,node,"((List)",").get("+index+")"); List list = (List) node; if (0<=index && index IndexOutOfRange [0,%d)",list.size()); rsp.sendError(SC_NOT_FOUND); } return true; } catch (NumberFormatException e) { return false; // try next } } public String toString() { return "List.get(int) look-up for url=/N/..."; } }); } if(Map.class.isAssignableFrom(node.clazz)) { dispatchers.add(new Dispatcher() { public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException { if(!req.tokens.hasMore()) return false; try { String key = req.tokens.peek(); if(traceable()) traceEval(req,rsp,"((Map)",").get(\""+key+"\")"); Object item = ((Map)node).get(key); if(item!=null) { req.tokens.next(); req.getStapler().invoke(req,rsp,item); return true; } else { // otherwise just fall through if(traceable()) trace(req,rsp,"Map.get(\""+key+"\")==null. Back tracking."); return false; } } catch (NumberFormatException e) { return false; // try next } } public String toString() { return "Map.get(String) look-up for url=/TOKEN/..."; } }); } // TODO: check if we can route to static resources // which directory shall we look up a resource from? for (Facet f : webApp.facets) f.buildFallbackDispatchers(this, dispatchers); // check action .doDynamic(...) for( final Function f : node.methods.name("doDynamic") ) { dispatchers.add(new Dispatcher() { public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException, InvocationTargetException, ServletException, IOException { if(traceable()) trace(req,rsp,"-> <%s>.doDynamic(...)",node); return f.bindAndInvokeAndServeResponse(node,req,rsp); } public String toString() { return String.format("%s(StaplerRequest,StaplerResponse) for any URL",f.getQualifiedName()); } }); } // check public selector methods .getDynamic(,...) for( final Function f : getMethods.signatureStartsWith(String.class).name("getDynamic")) { dispatchers.add(new Dispatcher() { public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException, InvocationTargetException, IOException, ServletException { if(!req.tokens.hasMore()) return false; String token = req.tokens.next(); if(traceable()) traceEval(req,rsp,node,"getDynamic(\""+token+"\",...)"); Object target = f.bindAndInvoke(node, req,rsp, token); if(target!=null) { req.getStapler().invoke(req,rsp, target); return true; } else { if(traceable()) // indent: "-> evaluate( trace(req,rsp," %s.getDynamic(\"%s\",...)==null. Back tracking.",node,token); req.tokens.prev(); // cancel the next effect return false; } } public String toString() { return String.format("%s(String,StaplerRequest,StaplerResponse) for url=/TOKEN/...",f.getQualifiedName()); } }); } } /** * Returns all the methods in the ancestory chain annotated with {@link PostConstruct} * from those defined in the derived type toward those defined in the base type. * * Normally invocation requires visiting the list in the reverse order. * @since 1.220 */ public SingleLinkedList getPostConstructMethods() { if (postConstructMethods ==null) { SingleLinkedList l = baseClass==null ? SingleLinkedList.empty() : baseClass.getPostConstructMethods(); for (MethodRef mr : klass.getDeclaredMethods()) { if (mr.hasAnnotation(PostConstruct.class)) { l = l.grow(mr); } } postConstructMethods = l; } return postConstructMethods; } private String getProtectedRole(Field f) { try { LimitedTo a = f.getAnnotation(LimitedTo.class); return (a!=null)?a.value():null; } catch (LinkageError e) { return null; // running in JDK 1.4 } } private static String camelize(String name) { return Character.toLowerCase(name.charAt(0))+name.substring(1); } private static class JavaScriptProxyMethodDispatcher extends NameBasedDispatcher { private final Function f; public JavaScriptProxyMethodDispatcher(String name, Function f) { super(name, 0); this.f = f; } public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IllegalAccessException, InvocationTargetException, ServletException, IOException { if (!req.isJavaScriptProxyCall()) return false; req.stapler.getWebApp().getCrumbIssuer().validateCrumb(req,req.getHeader("Crumb")); if(traceable()) trace(req,rsp,"-> <%s>.%s(...)",node, f.getName()); JSONArray jsargs = JSONArray.fromObject(IOUtils.toString(req.getReader())); Object[] args = new Object[jsargs.size()]; Class[] types = f.getParameterTypes(); Type[] genericTypes = f.getGenericParameterTypes(); if (args.length != types.length) { throw new IllegalArgumentException("argument count mismatch between " + jsargs + " and " + Arrays.toString(genericTypes)); } for (int i=0; i * If the designated override objects does not have a handler for the request, * the host object (the one that's implementing {@link StaplerOverridable}) will handle the request. * *

* In override objects, {@link CancelRequestHandlingException} is an useful mechanism to programmatically * inspect a request and then selecctively return the request back to the original object (that implements * {@link StaplerOverridable}. * * @author Kohsuke Kawaguchi * @see CancelRequestHandlingException */ public interface StaplerOverridable { /** * Returns a list of overridables. * Override objects are tried in their iteration order. * * @return can be null, which is treated as the same thing as returning an empty collection. */ Collection getOverrides(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/CachingScriptLoader.java0000664000175000017500000000521012414640747031503 0ustar ebourgebourgpackage org.kohsuke.stapler; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import java.net.URL; /** * Convenient base class for caching loaded scripts. * @author Kohsuke Kawaguchi */ public abstract class CachingScriptLoader { /** * Compiled scripts of this class. * Access needs to be synchronized. * *

* Jelly leaks memory (because Scripts hold on to Tag) * which usually holds on to JellyContext that was last used to run it, * which often holds on to some big/heavy objects.) * * So it's important to allow Scripts to be garbage collected. * This is not an ideal fix, but it works. * * {@link Optional} is used as Google Collection doesn't allow null values in a map. */ private final LoadingCache> scripts = CacheBuilder.newBuilder().softValues().build(new CacheLoader>() { public Optional load(String from) { try { return Optional.create(loadScript(from)); } catch (RuntimeException e) { throw e; // pass through } catch (Exception e) { throw new ScriptLoadException(e); } } }); /** * Locates the view script of the given name. * * @param name * if this is a relative path, such as "foo.jelly" or "foo/bar.groovy", * then it is assumed to be relative to this class, so * "org/acme/MyClass/foo.jelly" or "org/acme/MyClass/foo/bar.groovy" * will be searched. *

* If the extension is omitted, the default extension will be appended. * This is useful for some loaders that support loading multiple file extension types * (such as Jelly support.) *

* If this starts with "/", then it is assumed to be absolute, * and that name is searched from the classloader. This is useful * to do mix-in. * @return null if none was found. */ public S findScript(String name) throws E { if (MetaClass.NO_CACHE) return loadScript(name); else return scripts.getUnchecked(name).get(); } /** * Cache-less version of the {@link #findScript(String)} that provides the actual logic. */ protected abstract S loadScript(String name) throws E; /** * Discards the cached script. */ public synchronized void clearScripts() { scripts.invalidateAll(); } protected abstract URL getResource(String name); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/Dispatcher.java0000664000175000017500000001230712414640747027726 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import javax.servlet.ServletException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; import java.util.logging.Logger; /** * Controls the dispatching of incoming HTTP requests. * * @author Kohsuke Kawaguchi */ public abstract class Dispatcher { /** * Tries to handle the given request and returns true * if it succeeds. Otherwise false. * *

* We have a few known strategies for handling requests * (for example, one is to try to treat the request as JSP invocation, * another might be try getXXX(), etc) So we use a list of * {@link Dispatcher} and try them one by one until someone * returns true. */ public abstract boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException, IllegalAccessException, InvocationTargetException; /** * Diagnostic string that explains this dispatch rule. */ public abstract String toString(); public static boolean traceable() { return TRACE || TRACE_PER_REQUEST || LOGGER.isLoggable(Level.FINE); } public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object node) { trace(req,rsp,String.format("-> evaluate(%s%s,\"%s\")", node==null?"null":'<'+node.toString()+'>', node==null?"":" :"+node.getClass().getName(), ((RequestImpl)req).tokens.assembleOriginalRestOfPath())); } public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object node, String prefix, String suffix) { trace(req,rsp,String.format("-> evaluate(%s<%s>%s,\"%s\")", prefix,node,suffix, ((RequestImpl)req).tokens.assembleOriginalRestOfPath())); } public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object node, String expression) { trace(req,rsp,String.format("-> evaluate(<%s>.%s,\"%s\")", node,expression, ((RequestImpl)req).tokens.assembleOriginalRestOfPath())); } public static void trace(StaplerRequest req, StaplerResponse rsp, String msg, Object... args) { trace(req,rsp,String.format(msg,args)); } public static void trace(StaplerRequest req, StaplerResponse rsp, String msg) { if(isTraceEnabled(req)) EvaluationTrace.get(req).trace(rsp,msg); if(LOGGER.isLoggable(Level.FINE)) LOGGER.fine(msg); } /** * Checks if tracing is enabled for the given request. Tracing can be * enabled globally with the "stapler.trace=true" system property. Tracing * can be enabled per-request by setting "stapler.trace.per-request=true" * and sending an "X-Stapler-Trace" header set to "true" with the request. */ public static boolean isTraceEnabled(StaplerRequest req) { if (TRACE) return true; if (TRACE_PER_REQUEST && "true".equals(req.getHeader("X-Stapler-Trace"))) return true; return false; } /** * This flag will activate the evaluation trace. * It adds the evaluation process as HTTP headers, * and when the evaluation failed, special diagnostic 404 page will be rendered. * Useful for developer assistance. */ public static boolean TRACE = Boolean.getBoolean("stapler.trace"); /** * This flag will activate the per-request evaluation trace for requests * that have X-Stapler-Trace set to "true". * It adds the evaluation process as HTTP headers, * and when the evaluation failed, special diagnostic 404 page will be rendered. * Useful for developer assistance. */ public static boolean TRACE_PER_REQUEST = Boolean.getBoolean("stapler.trace.per-request"); private static final Logger LOGGER = Logger.getLogger(Dispatcher.class.getName()); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/0000775000175000017500000000000012414640747026313 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/Range.java0000664000175000017500000000252712414640747030220 0ustar ebourgebourgpackage org.kohsuke.stapler.export; import com.google.common.collect.Iterators; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; /** * Specifies the range in a collection. * * @author Kohsuke Kawaguchi */ public class Range { public final int min; public final int max; public Range(int min, int max) { this.min = min; this.max = max; } public List apply(T[] a) { return apply(Arrays.asList(a)); } public List apply(List s) { if (max0) s = s.subList(min,s.size()); return s; } public Iterable apply(final Collection s) { if (s instanceof List) { return apply((List) s); } else { return new Iterable() { public Iterator iterator() { Iterator itr = s.iterator(); if (max0) Iterators.advance(itr,min); return itr; } }; } } /** * Range that includes natural numbers. */ public static final Range ALL = new Range(0,Integer.MAX_VALUE); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/FieldProperty.java0000664000175000017500000000422512414640747031751 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import java.lang.reflect.Field; import java.lang.reflect.Type; import java.io.IOException; /** * {@link Property} based on {@link Field}. * @author Kohsuke Kawaguchi */ class FieldProperty extends Property { private final Field field; public FieldProperty(Model owner, Field field, Exported exported) { super(owner,field.getName(), exported); this.field = field; } public Type getGenericType() { return field.getGenericType(); } public Class getType() { return field.getType(); } public String getJavadoc() { return parent.getJavadoc().getProperty(field.getName()); } protected Object getValue(Object object) throws IllegalAccessException { return field.get(object); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/XmlChars.java0000664000175000017500000002602412414640747030703 0ustar ebourgebourg/* * $Id: XmlChars.java,v 1.1.1.1 2000/11/23 01:53:35 edwingo Exp $ * * The Apache Software License, Version 1.1 * * * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Crimson" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR * ITS 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. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999, Sun Microsystems, Inc., * http://www.sun.com. For more information on the Apache Software * Foundation, please see . */ package org.kohsuke.stapler.export; /** * Methods in this class are used to determine whether characters may * appear in certain roles in XML documents. Such methods are used * both to parse and to create such documents. * * @author David Brownell */ class XmlChars { // can't construct instances private XmlChars () { } public static boolean isNameStart (char c) { return isLetter(c) || c == '_' || c == ':'; } /** * Returns true if the character is allowed to be a non-initial * character in names according to the XML recommendation. * @see #isLetter */ public static boolean isNameChar (char c) { // [4] NameChar ::= Letter | Digit | '.' | '_' | ':' // | CombiningChar | Extender if (isLetter2 (c)) return true; else if (c == '>') return false; else if (c == '.' || c == '-' || c == '_' || c == ':' || isExtender (c)) return true; else return false; } /* * NOTE: java.lang.Character.getType() values are: * * UNASSIGNED = 0, * * UPPERCASE_LETTER = 1, // Lu * LOWERCASE_LETTER = 2, // Ll * TITLECASE_LETTER = 3, // Lt * MODIFIER_LETTER = 4, // Lm * OTHER_LETTER = 5, // Lo * NON_SPACING_MARK = 6, // Mn * ENCLOSING_MARK = 7, // Me * COMBINING_SPACING_MARK = 8, // Mc * DECIMAL_DIGIT_NUMBER = 9, // Nd * LETTER_NUMBER = 10, // Nl * OTHER_NUMBER = 11, // No * SPACE_SEPARATOR = 12, // Zs * LINE_SEPARATOR = 13, // Zl * PARAGRAPH_SEPARATOR = 14, // Zp * CONTROL = 15, // Cc * FORMAT = 16, // Cf * // 17 reserved for proposed Ci category * PRIVATE_USE = 18, // Co * SURROGATE = 19, // Cs * DASH_PUNCTUATION = 20, // Pd * START_PUNCTUATION = 21, // Ps * END_PUNCTUATION = 22, // Pe * CONNECTOR_PUNCTUATION = 23, // Pc * OTHER_PUNCTUATION = 24, // Po * MATH_SYMBOL = 25, // Sm * CURRENCY_SYMBOL = 26, // Sc * MODIFIER_SYMBOL = 27, // Sk * OTHER_SYMBOL = 28; // So */ /** * Returns true if the character is an XML "letter". XML Names must * start with Letters or a few other characters, but other characters * in names must only satisfy the isNameChar predicate. * * @see #isNameChar */ public static boolean isLetter (char c) { // [84] Letter ::= BaseChar | Ideographic // [85] BaseChar ::= ... too much to repeat // [86] Ideographic ::= ... too much to repeat // // Optimize the typical case. // if (c >= 'a' && c <= 'z') return true; if (c == '/') return false; if (c >= 'A' && c <= 'Z') return true; // // Since the tables are too ridiculous to use in code, // we're using the footnotes here to drive this test. // switch (Character.getType (c)) { // app. B footnote says these are 'name start' // chars' ... case Character.LOWERCASE_LETTER: // Ll case Character.UPPERCASE_LETTER: // Lu case Character.OTHER_LETTER: // Lo case Character.TITLECASE_LETTER: // Lt case Character.LETTER_NUMBER: // Nl // OK, here we just have some exceptions to check... return !isCompatibilityChar (c) // per "5.14 of Unicode", rule out some combiners && !(c >= 0x20dd && c <= 0x20e0); default: // check for some exceptions: these are "alphabetic" return ((c >= 0x02bb && c <= 0x02c1) || c == 0x0559 || c == 0x06e5 || c == 0x06e6); } } // // XML 1.0 discourages "compatibility" characters in names; these // were defined to permit passing through some information stored in // older non-Unicode character sets. These always have alternative // representations in Unicode, e.g. using combining chars. // private static boolean isCompatibilityChar (char c) { // the numerous comparisions here seem unavoidable, // but the switch can reduce the number which must // actually be executed. switch ((c >> 8) & 0x0ff) { case 0x00: // ISO Latin/1 has a few compatibility characters return c == 0x00aa || c == 0x00b5 || c == 0x00ba; case 0x01: // as do Latin Extended A and (parts of) B return (c >= 0x0132 && c <= 0x0133) || (c >= 0x013f && c <= 0x0140) || c == 0x0149 || c == 0x017f || (c >= 0x01c4 && c <= 0x01cc) || (c >= 0x01f1 && c <= 0x01f3) ; case 0x02: // some spacing modifiers return (c >= 0x02b0 && c <= 0x02b8) || (c >= 0x02e0 && c <= 0x02e4); case 0x03: return c == 0x037a; // Greek case 0x05: return c == 0x0587; // Armenian case 0x0e: return c >= 0x0edc && c <= 0x0edd; // Laotian case 0x11: // big chunks of Hangul Jamo are all "compatibility" return c == 0x1101 || c == 0x1104 || c == 0x1108 || c == 0x110a || c == 0x110d || (c >= 0x1113 && c <= 0x113b) || c == 0x113d || c == 0x113f || (c >= 0x1141 && c <= 0x114b) || c == 0x114d || c == 0x114f || (c >= 0x1151 && c <= 0x1153) || (c >= 0x1156 && c <= 0x1158) || c == 0x1162 || c == 0x1164 || c == 0x1166 || c == 0x1168 || (c >= 0x116a && c <= 0x116c) || (c >= 0x116f && c <= 0x1171) || c == 0x1174 || (c >= 0x1176 && c <= 0x119d) || (c >= 0x119f && c <= 0x11a2) || (c >= 0x11a9 && c <= 0x11aa) || (c >= 0x11ac && c <= 0x11ad) || (c >= 0x11b0 && c <= 0x11b6) || c == 0x11b9 || c == 0x11bb || (c >= 0x11c3 && c <= 0x11ea) || (c >= 0x11ec && c <= 0x11ef) || (c >= 0x11f1 && c <= 0x11f8) ; case 0x20: return c == 0x207f; // superscript case 0x21: return // various letterlike symbols c == 0x2102 || c == 0x2107 || (c >= 0x210a && c <= 0x2113) || c == 0x2115 || (c >= 0x2118 && c <= 0x211d) || c == 0x2124 || c == 0x2128 || (c >= 0x212c && c <= 0x212d) || (c >= 0x212f && c <= 0x2138) // most Roman numerals (less 1K, 5K, 10K) || (c >= 0x2160 && c <= 0x217f) ; case 0x30: // some Hiragana return c >= 0x309b && c <= 0x309c; case 0x31: // all Hangul Compatibility Jamo return c >= 0x3131 && c <= 0x318e; case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: // the whole "compatibility" area is for that purpose! return true; default: // most of Unicode isn't flagged as being for compatibility return false; } } // guts of isNameChar/isNCNameChar private static boolean isLetter2 (char c) { // [84] Letter ::= BaseChar | Ideographic // [85] BaseChar ::= ... too much to repeat // [86] Ideographic ::= ... too much to repeat // [87] CombiningChar ::= ... too much to repeat // // Optimize the typical case. // if (c >= 'a' && c <= 'z') return true; if (c == '>') return false; if (c >= 'A' && c <= 'Z') return true; // // Since the tables are too ridiculous to use in code, // we're using the footnotes here to drive this test. // switch (Character.getType (c)) { // app. B footnote says these are 'name start' // chars' ... case Character.LOWERCASE_LETTER: // Ll case Character.UPPERCASE_LETTER: // Lu case Character.OTHER_LETTER: // Lo case Character.TITLECASE_LETTER: // Lt case Character.LETTER_NUMBER: // Nl // ... and these are name characters 'other // than name start characters' case Character.COMBINING_SPACING_MARK: // Mc case Character.ENCLOSING_MARK: // Me case Character.NON_SPACING_MARK: // Mn case Character.MODIFIER_LETTER: // Lm case Character.DECIMAL_DIGIT_NUMBER: // Nd // OK, here we just have some exceptions to check... return !isCompatibilityChar (c) // per "5.14 of Unicode", rule out some combiners && !(c >= 0x20dd && c <= 0x20e0); default: // added a character ... return c == 0x0387; } } private static boolean isExtender (char c) { // [89] Extender ::= ... return c == 0x00b7 || c == 0x02d0 || c == 0x02d1 || c == 0x0387 || c == 0x0640 || c == 0x0e46 || c == 0x0ec6 || c == 0x3005 || (c >= 0x3031 && c <= 0x3035) || (c >= 0x309d && c <= 0x309e) || (c >= 0x30fc && c <= 0x30fe) ; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/Flavor.java0000664000175000017500000000607112414640747030413 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import org.kohsuke.stapler.StaplerResponse; import java.io.IOException; import java.io.Writer; /** * Export flavor. * * @author Kohsuke Kawaguchi */ public enum Flavor { JSON("application/json;charset=UTF-8") { public DataWriter createDataWriter(Object bean, Writer w, ExportConfig config) throws IOException { return new JSONDataWriter(w,config); } }, PYTHON("text/x-python;charset=UTF-8") { public DataWriter createDataWriter(Object bean, Writer w, ExportConfig config) throws IOException { return new PythonDataWriter(w,config); } }, RUBY("text/x-ruby;charset=UTF-8") { public DataWriter createDataWriter(Object bean, Writer w, ExportConfig config) throws IOException { return new RubyDataWriter(w,config); } }, XML("application/xml;charset=UTF-8") { public DataWriter createDataWriter(Object bean, Writer w, ExportConfig config) throws IOException { // TODO: support pretty printing return new XMLDataWriter(bean,w); } }; /** * Content-type of this flavor, including charset "UTF-8". */ public final String contentType; Flavor(String contentType) { this.contentType = contentType; } public DataWriter createDataWriter(Object bean, StaplerResponse rsp) throws IOException { return createDataWriter(bean,rsp.getWriter()); } public DataWriter createDataWriter(Object bean, Writer w) throws IOException { return createDataWriter(bean,w,new ExportConfig()); } public abstract DataWriter createDataWriter(Object bean, Writer w, ExportConfig config) throws IOException; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/SchemaGenerator.java0000664000175000017500000001451712414640747032235 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import com.sun.xml.txw2.TXW; import com.sun.xml.txw2.output.ResultFactory; import java.beans.Introspector; import org.kohsuke.stapler.export.XSD.ComplexType; import org.kohsuke.stapler.export.XSD.ContentModel; import org.kohsuke.stapler.export.XSD.Element; import org.kohsuke.stapler.export.XSD.Schema; import org.kohsuke.stapler.export.XSD.Annotated; import javax.xml.namespace.QName; import javax.xml.transform.Result; import java.util.Calendar; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Stack; /** * Generates XML Schema that describes the XML representation of exported beans. * * @author Kohsuke Kawaguchi */ public class SchemaGenerator { private final Stack queue = new Stack(); private final Set written = new HashSet(); /** * Enumerations to be generated. */ private final Set enums = new HashSet(); private final ModelBuilder builder; private final Model top; public SchemaGenerator(Model m) { this.builder = m.parent; this.top = m; } /** * Generates the complete schema to the specified result. */ public void generateSchema(Result r) { Schema s = TXW.create(Schema.class, ResultFactory.createSerializer(r)); s._namespace(XSD.URI,"xsd"); queue.clear(); written.clear(); // element decl for the root element s.element().name(Introspector.decapitalize(top.type.getSimpleName())).type(getXmlTypeName(top.type)); // write all beans while(!queue.isEmpty()) writeBean(s, (Model) queue.pop()); // then enums for (Class e : enums) writeEnum(s,e); s.commit(); } private void writeEnum(Schema s, Class e) { XSD.Restriction facets = s.simpleType().name(getXmlToken(e)).restriction().base(XSD.Types.STRING); for (Object constant : e.getEnumConstants()) { facets.enumeration().value(constant.toString()); } } private void writeBean(Schema s, Model m) { ComplexType ct = s.complexType().name(getXmlToken(m.type)); final ContentModel cm; if(m.superModel==null) cm = ct.sequence(); else { addToQueue(m.superModel); cm = ct.complexContent().extension().base(getXmlTypeName(m.superModel.type)).sequence(); } for (Property p : m.getProperties()) { Class t = p.getType(); final boolean isCollection; final Class itemType; if(t.isArray()) { isCollection = true; itemType = t.getComponentType(); } else if(Collection.class.isAssignableFrom(t)) { isCollection = true; itemType = TypeUtil.erasure( TypeUtil.getTypeArgument(TypeUtil.getBaseClass(p.getGenericType(),Collection.class),0)); } else { isCollection = false; itemType = t; } Element e = cm.element() .name(isCollection?XMLDataWriter.toSingular(p.name):p.name) .type(getXmlTypeName(itemType)); if(!t.isPrimitive()) e.minOccurs(0); if(isCollection) e.maxOccurs("unbounded"); annotate(e,p.getJavadoc()); } } /** * Annotates the schema element by javadoc, if that exists. */ private void annotate(Annotated e, String javadoc) { if(javadoc==null) return; e.annotation().documentation(javadoc); } /** * Adds the schema for the XML representation of the given class. */ public void add(Class c) { addToQueue(builder.get(c)); } private void addToQueue(Model m) { if (written.add(m)) queue.push(m); } public QName getXmlTypeName(Class t) { if(Property.STRING_TYPES.contains(t)) return XSD.Types.STRING; if(t==Boolean.class || t==boolean.class) return XSD.Types.BOOLEAN; if(t==Integer.class || t==int.class) return XSD.Types.INT; if(t==Long.class || t==long.class) return XSD.Types.LONG; if(Map.class.isAssignableFrom(t)) return XSD.Types.ANYTYPE; if(Calendar.class.isAssignableFrom(t)) return XSD.Types.LONG; if(Enum.class.isAssignableFrom(t)) { enums.add(t); return new QName(getXmlToken(t)); } // otherwise bean try { addToQueue(builder.get(t)); } catch (IllegalArgumentException e) { // not an exposed bean by itself return XSD.Types.ANYTYPE; } return new QName(getXmlToken(t)); } private String getXmlToken(Class t) { return t.getName().replace('$','-'); } private String getXmlElementName(Class type) { return getXmlToken(type); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/XMLDataWriter.java0000664000175000017500000001032612414640747031607 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerResponse; import java.util.Stack; import java.io.Writer; import java.io.IOException; import java.beans.Introspector; /** * Writes XML. * * @author Kohsuke Kawaguchi */ final class XMLDataWriter implements DataWriter { private String name; private final Stack objectNames = new Stack(); private final Stack arrayState = new Stack(); private final Writer out; public boolean isArray; XMLDataWriter(Object bean, Writer out) throws IOException { Class c=bean.getClass(); while (c.isAnonymousClass()) c = c.getSuperclass(); name = Introspector.decapitalize(c.getSimpleName()); this.out = out; } XMLDataWriter(Object bean, StaplerResponse rsp) throws IOException { this(bean,rsp.getWriter()); } public void name(String name) { this.name = name; } public void valuePrimitive(Object v) throws IOException { value(v.toString()); } public void value(String v) throws IOException { String n = adjustName(); out.write('<'+n+'>'); out.write(Stapler.escape(v)); out.write("'); } public void valueNull() { // use absence to indicate null. } public void startArray() { // use repeated element to display array // this means nested arrays are not supported isArray = true; } public void endArray() { isArray = false; } public void startObject() throws IOException { objectNames.push(name); out.write('<'+adjustName()+'>'); arrayState.push(isArray); isArray = false; } public void endObject() throws IOException { name = objectNames.pop(); isArray = arrayState.pop(); out.write("'); } /** * Returns the name to be used as an element name * by considering {@link #isArray} */ private String adjustName() { String escaped = makeXmlName(name); if(isArray) return toSingular(escaped); return escaped; } /*package*/ static String toSingular(String name) { return name.replaceFirst("ies$", "y").replaceFirst("s$", ""); } /*package*/ static String makeXmlName(String name) { if (name.length()==0) name="_"; if (!XmlChars.isNameStart(name.charAt(0))) { if (name.length()>1 && XmlChars.isNameStart(name.charAt(1))) name = name.substring(1); else name = '_'+name; } int i=1; while (i * If the value is 1, the property will be * visible only when the current model object is exposed as the * top-level object. *

* If the value is 2, in addition to above, the property will still * be visible if the current model object is exposed as the 2nd-level * object. *

* And the rest goes in the same way. If the value is N, the object * is exposed as the Nth level object. * *

* The default value of this property is determined by * {@link ExportedBean#defaultVisibility()}. * *

* So bigger the number, more important the property is. */ int visibility() default 0; /** * Name of the exposed property. *

* This token is used as the XML element name or the JSON property name. * The default is to use the Java property name. */ String name() default ""; /** * Visibility adjustment for traversing this property. * *

* If true, visiting this property won't increase the depth count, * so the referenced object is exported as if it were a part of this * object. * *

* This flag can be used to selectively expand the subree to be * returned to the client. */ boolean inline() default false; /** * If a string value "key/value" is given, produce a map in more verbose following form: * "[{key:KEY1, value:VALUE1}, {key:KEY2, value:VALUE2}, ...] * (whereas normally it produces more compact {KEY1:VALUE1, KEY2:VALUE2, ...} * *

* So for example, if you say "name/value", you might see something like * "[{name:"kohsuke", value:"abc"], ...} * *

* The verboose form is useful/necessary when you use complex data structure as a key, * or if the string representation of the key can contain letters that are unsafe in some flavours * (such as XML, which prohibits a number of characters to be used as tag names.) * */ String verboseMap() default ""; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/TreePruner.java0000664000175000017500000000504412414640747031254 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; /** * Controls the portion of the object graph to be written to {@link DataWriter}. * * @author Kohsuke Kawaguchi * @see Model#writeTo(Object, TreePruner, DataWriter) */ public abstract class TreePruner { /** * Called before Hudson writes a new property. * * @return * null if this property shouldn't be written. Otherwise the returned {@link TreePruner} object * will be consulted to determine properties of the child object in turn. */ public abstract TreePruner accept(Object node, Property prop); public Range getRange() { return Range.ALL; } public static class ByDepth extends TreePruner { final int n; private ByDepth next; public ByDepth(int n) { this.n = n; } private ByDepth next() { if (next==null) next = new ByDepth(n+1); return next; } @Override public TreePruner accept(Object node, Property prop) { if (prop.visibility < n) return null; // not visible if (prop.inline) return this; return next(); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/ExportConfig.java0000664000175000017500000000042112414640747031562 0ustar ebourgebourgpackage org.kohsuke.stapler.export; /** * Controls the output behaviour. * * @author Kohsuke Kawaguchi */ public class ExportConfig { /** * If true, output will be indented to make it easier for humans to understand. */ public boolean prettyPrint; } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/NotExportableException.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/NotExportableException.ja0000664000175000017500000000474712414640747033310 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; /** * Signals an error that the class didn't have {@link ExportedBean}. * * @author Kohsuke Kawaguchi * @see Model */ public class NotExportableException extends IllegalArgumentException { private final Class type; public NotExportableException(Class type) { this(type+" doesn't have @"+ ExportedBean.class.getSimpleName(),type); } public NotExportableException(Class type, Class propertyOwner, String property) { this(type + " doesn't have @" + ExportedBean.class.getSimpleName() + " so cannot write " + propertyOwner.getName() + '.' + property, type); } public NotExportableException(String s, Class type) { super(s); this.type = type; } public NotExportableException(String message, Throwable cause, Class type) { super(message, cause); this.type = type; } public NotExportableException(Throwable cause, Class type) { super(cause); this.type = type; } /** * Gets the type that didn't have {@link ExportedBean} */ public Class getType() { return type; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/RubyDataWriter.java0000664000175000017500000000462512414640747032075 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import java.io.IOException; import java.io.Writer; /** * Writes out the format that can be eval-ed from Ruby. * *

* Ruby uses a similar list and map literal syntax as JavaScript. * The only differences are null vs nil and * key:value vs key => value. * * @author Kohsuke Kawaguchi, Jim Meyer */ final class RubyDataWriter extends JSONDataWriter { public RubyDataWriter(Writer out, ExportConfig config) throws IOException { super(out,config); } @Override public void name(String name) throws IOException { comma(); out.write('"'+name+"\" => "); needComma = false; } public void valueNull() throws IOException { data("nil"); } @Override public void startObject() throws IOException { comma(); out.write("OpenStruct.new({"); needComma=false; } @Override public void endObject() throws IOException { out.write("})"); needComma=true; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/package-info.java0000664000175000017500000000312112414640747031477 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ /** * Mechanism for writing out a graph of model objects in a machine readable format. *

* Annotation driven. */ @XmlNamespace(XSD.URI) package org.kohsuke.stapler.export; import com.sun.xml.txw2.annotation.XmlNamespace;stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/Model.java0000664000175000017500000001565612414640747030233 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import org.kohsuke.stapler.export.TreePruner.ByDepth; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; /** * Writes all the property of one {@link ExportedBean} to {@link DataWriter}. * * @author Kohsuke Kawaguchi */ public class Model { /** * The class being modeled. */ public final Class type; /** * {@link Model} for the super class. */ public final Model superModel; private final Property[] properties; /*package*/ final ModelBuilder parent; /*package*/ final int defaultVisibility; /** * Lazily loaded "*.javadoc" file for this model. */ private volatile Properties javadoc; /*package*/ Model(ModelBuilder parent, Class type, @CheckForNull Class propertyOwner, @Nullable String property) throws NotExportableException { this.parent = parent; this.type = type; ExportedBean eb = type.getAnnotation(ExportedBean.class); if (eb == null) { throw propertyOwner != null ? new NotExportableException(type, propertyOwner, property) : new NotExportableException(type); } this.defaultVisibility = eb.defaultVisibility(); Class sc = type.getSuperclass(); if(sc!=null && sc.getAnnotation(ExportedBean.class)!=null) superModel = parent.get(sc); else superModel = null; List properties = new ArrayList(); // Use reflection to find out what properties are exposed. for( Field f : type.getFields() ) { if(f.getDeclaringClass()!=type) continue; Exported exported = f.getAnnotation(Exported.class); if(exported !=null) properties.add(new FieldProperty(this,f, exported)); } for( Method m : type.getMethods() ) { if(m.getDeclaringClass()!=type) continue; Exported exported = m.getAnnotation(Exported.class); if(exported !=null) properties.add(new MethodProperty(this,m, exported)); } this.properties = properties.toArray(new Property[properties.size()]); Arrays.sort(this.properties); parent.models.put(type,this); } /** * Gets all the exported properties. */ public List getProperties() { return Collections.unmodifiableList(Arrays.asList(properties)); } /** * Loads the javadoc list and returns it as {@link Properties}. * * @return always non-null. */ /*package*/ Properties getJavadoc() { if(javadoc!=null) return javadoc; synchronized(this) { if(javadoc!=null) return javadoc; // load Properties p = new Properties(); InputStream is = type.getClassLoader().getResourceAsStream(type.getName().replace('$', '/').replace('.', '/') + ".javadoc"); if(is!=null) { try { try { p.load(is); } finally { is.close(); } } catch (IOException e) { throw new RuntimeException("Unable to load javadoc for "+type,e); } } javadoc = p; return javadoc; } } /** * Writes the property values of the given object to the writer. */ public void writeTo(T object, DataWriter writer) throws IOException { writeTo(object,0,writer); } /** * Writes the property values of the given object to the writer. * * @param pruner * Controls which portion of the object graph will be sent to the writer. */ public void writeTo(T object, TreePruner pruner, DataWriter writer) throws IOException { writer.startObject(); writeNestedObjectTo(object, pruner, writer, Collections.emptySet()); writer.endObject(); } /** * Writes the property values of the given object to the writer. * * @param baseVisibility * This parameters controls how much data we'd be writing, * by adding bias to the sub tree cutting. * A property with {@link Exported#visibility() visibility} X will be written * if the current depth Y and baseVisibility Z satisfies X+Z>Y. * * 0 is the normal value. Positive value means writing bigger tree, * and negative value means writing smaller trees. * * @deprecated as of 1.139 */ public void writeTo(T object, int baseVisibility, DataWriter writer) throws IOException { writeTo(object,new ByDepth(1-baseVisibility),writer); } void writeNestedObjectTo(T object, TreePruner pruner, DataWriter writer, Set blacklist) throws IOException { if (superModel != null) { Set superBlacklist = new HashSet(blacklist); for (Property p : properties) { superBlacklist.add(p.name); } superModel.writeNestedObjectTo(object, pruner, writer, superBlacklist); } for (Property p : properties) { if (!blacklist.contains(p.name)) { p.writeTo(object,pruner,writer); } } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/XSD.java0000664000175000017500000000726112414640747027622 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import com.sun.xml.txw2.TypedXmlWriter; import com.sun.xml.txw2.annotation.XmlAttribute; import com.sun.xml.txw2.annotation.XmlElement; import javax.xml.namespace.QName; /** * TXW interfaces to generate schema. * * @author Kohsuke Kawaguchi */ public interface XSD { public static final String URI = "http://www.w3.org/2001/XMLSchema"; @XmlElement("schema") public interface Schema extends TypedXmlWriter { Element element(); ComplexType complexType(); SimpleType simpleType(); } public interface Element extends Annotated { @XmlAttribute Element name(String v); @XmlAttribute Element type(QName t); @XmlAttribute Element minOccurs(int i); @XmlAttribute Element maxOccurs(String v); } public interface ComplexType extends TypedXmlWriter { @XmlAttribute ComplexType name(String v); ContentModel sequence(); ComplexContent complexContent(); } public interface ComplexContent extends TypedXmlWriter { Restriction extension(); } public interface ContentModel extends TypedXmlWriter { Element element(); } public interface SimpleType extends TypedXmlWriter { @XmlAttribute SimpleType name(String v); Restriction restriction(); } public interface Restriction extends TypedXmlWriter { @XmlAttribute Restriction base(QName t); // for simple type Enumeration enumeration(); // for complex type ContentModel sequence(); } public interface Enumeration extends TypedXmlWriter { @XmlAttribute void value(String v); } public interface Annotated extends TypedXmlWriter { Annotation annotation(); } public interface Annotation extends TypedXmlWriter { void documentation(String value); } public abstract class Types { public static final QName STRING = t("string"); public static final QName BOOLEAN = t("boolean"); public static final QName INT = t("int"); public static final QName LONG = t("long"); public static final QName ANYTYPE = t("anyType"); private static QName t(String name) { return new QName(XSD.URI, name); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/MethodProperty.java0000664000175000017500000000505212414640747032145 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import java.beans.Introspector; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.io.IOException; /** * {@link Property} based on {@link Method}. * @author Kohsuke Kawaguchi */ final class MethodProperty extends Property { private final Method method; MethodProperty(Model owner, Method m, Exported exported) { super(owner,buildName(m.getName()), exported); this.method = m; } private static String buildName(String name) { if(name.startsWith("get")) name = name.substring(3); else if(name.startsWith("is")) name = name.substring(2); return Introspector.decapitalize(name); } public Type getGenericType() { return method.getGenericReturnType(); } public Class getType() { return method.getReturnType(); } public String getJavadoc() { return parent.getJavadoc().getProperty(method.getName()+"()"); } protected Object getValue(Object object) throws IllegalAccessException, InvocationTargetException { return method.invoke(object); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/Property.java0000664000175000017500000002116212414640747031004 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import org.kohsuke.stapler.export.TreePruner.ByDepth; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; import java.lang.reflect.Array; import java.net.URL; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * Exposes one {@link Exported exposed property} of {@link ExportedBean} to * {@link DataWriter}. * * @author Kohsuke Kawaguchi */ public abstract class Property implements Comparable { /** * Name of the property. */ public final String name; final ModelBuilder owner; /** * Visibility depth level of this property. * * @see Exported#visibility() */ public final int visibility; /** * Model to which this property belongs to. * Never null. */ public final Model parent; /** * @see Exported#inline() */ public final boolean inline; private String[] verboseMap; Property(Model parent, String name, Exported exported) { this.parent = parent; this.owner = parent.parent; this.name = exported.name().length()>1 ? exported.name() : name; int v = exported.visibility(); if(v==0) v = parent.defaultVisibility; this.visibility = v; this.inline = exported.inline(); String[] s = exported.verboseMap().split("/"); if (s.length<2) this.verboseMap = null; else this.verboseMap = s; } public int compareTo(Property that) { return this.name.compareTo(that.name); } public abstract Type getGenericType(); public abstract Class getType(); /** * Gets the associated javadoc, if any, or null. */ public abstract String getJavadoc(); /** * Writes one property of the given object to {@link DataWriter}. * * @param pruner * Determines how to prune the object graph tree. */ public void writeTo(Object object, TreePruner pruner, DataWriter writer) throws IOException { TreePruner child = pruner.accept(object, this); if (child==null) return; try { writer.name(name); writeValue(getValue(object),child,writer); } catch (IllegalAccessException e) { IOException x = new IOException("Failed to write " + name); x.initCause(e); throw x; } catch (InvocationTargetException e) { IOException x = new IOException("Failed to write " + name); x.initCause(e); throw x; } } /** * @deprecated as of 1.139 */ public void writeTo(Object object, int depth, DataWriter writer) throws IOException { writeTo(object,new ByDepth(depth),writer); } /** * Writes one value of the property to {@link DataWriter}. */ private void writeValue(Object value, TreePruner pruner, DataWriter writer) throws IOException { writeValue(value,pruner,writer,false); } /** * Writes one value of the property to {@link DataWriter}. */ private void writeValue(Object value, TreePruner pruner, DataWriter writer, boolean skipIfFail) throws IOException { if(value==null) { writer.valueNull(); return; } if(value instanceof CustomExportedBean) { writeValue(((CustomExportedBean)value).toExportedObject(),pruner,writer); return; } Class c = value.getClass(); if(STRING_TYPES.contains(c)) { writer.value(value.toString()); return; } if(PRIMITIVE_TYPES.contains(c)) { writer.valuePrimitive(value); return; } if(c.getComponentType()!=null) { // array Range r = pruner.getRange(); writer.startArray(); if (value instanceof Object[]) { // typical case for (Object item : r.apply((Object[]) value)) { writeValue(item,pruner,writer,true); } } else { // more generic case int len = Math.min(r.max,Array.getLength(value)); for (int i=r.min; i) value).entrySet()) { writer.startObject(); writer.name(verboseMap[0]); writeValue(e.getKey(),pruner,writer); writer.name(verboseMap[1]); writeValue(e.getValue(),pruner,writer); writer.endObject(); } writer.endArray(); } else {// compact form writer.startObject(); for (Map.Entry e : ((Map) value).entrySet()) { writer.name(e.getKey().toString()); writeValue(e.getValue(),pruner,writer); } writer.endObject(); } return; } if(value instanceof Date) { writer.valuePrimitive(((Date) value).getTime()); return; } if(value instanceof Calendar) { writer.valuePrimitive(((Calendar) value).getTimeInMillis()); return; } if(value instanceof Enum) { writer.value(value.toString()); return; } // otherwise handle it as a bean writer.startObject(); Model model = null; try { model = owner.get(c, parent.type, name); } catch (NotExportableException e) { if (skipIfFail) { Logger.getLogger(Property.class.getName()).log(Level.FINE, e.getMessage()); } else { throw e; } // otherwise ignore this error by writing empty object } if(model!=null) model.writeNestedObjectTo(value, pruner, writer, Collections.emptySet()); writer.endObject(); } /** * Gets the value of this property from the bean. */ protected abstract Object getValue(Object bean) throws IllegalAccessException, InvocationTargetException; /*package*/ static final Set STRING_TYPES = new HashSet(Arrays.asList( String.class, URL.class )); /*package*/ static final Set PRIMITIVE_TYPES = new HashSet(Arrays.asList( Integer.class, Long.class, Boolean.class, Short.class, Character.class, Float.class, Double.class )); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/PythonDataWriter.java0000664000175000017500000000435012414640747032430 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import org.kohsuke.stapler.StaplerResponse; import java.io.Writer; import java.io.IOException; /** * Writes out the format that can be eval-ed from Python. * *

* Python uses the same list and map literal syntax as JavaScript. * The only difference is null vs None. * * @author Kohsuke Kawaguchi */ final class PythonDataWriter extends JSONDataWriter { public PythonDataWriter(Writer out, ExportConfig config) throws IOException { super(out, config); } @Override public void valueNull() throws IOException { data("None"); } public void valuePrimitive(Object v) throws IOException { if(v instanceof Boolean) { if((Boolean)v) data("True"); else data("False"); return; } super.valuePrimitive(v); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/DataWriter.java0000664000175000017500000000423012414640747031223 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import java.io.IOException; /** * Receives the event callback on the model data to be exposed. * *

* The call sequence is: * *

 * EVENTS := startObject PROPERTY* endObject
 * PROPERTY := name VALUE
 * VALUE := valuePrimitive
 *        | value
 *        | valueNull
 *        | startArray VALUE* endArray
 *        | EVENTS
 * 
* * @author Kohsuke Kawaguchi */ public interface DataWriter { void name(String name) throws IOException; void valuePrimitive(Object v) throws IOException; void value(String v) throws IOException; void valueNull() throws IOException; void startArray() throws IOException; void endArray() throws IOException; void startObject() throws IOException; void endObject() throws IOException; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/NamedPathPruner.java0000664000175000017500000001512512414640747032217 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import java.util.Map; import java.util.TreeMap; import java.util.regex.Pattern; /** * Tree pruner which operates according to a textual description of what tree leaves should be included. */ public final class NamedPathPruner extends TreePruner { static class Tree { final Map children = new TreeMap(); Range range = Range.ALL; public @Override String toString() {return children.toString();} } // Simple recursive descent parser: static Tree parse(String spec) throws IllegalArgumentException { Reader r = new Reader(spec); Tree t = new Tree(); list(r, t); r.expect(Token.EOF); return t; } private static void list(Reader r, Tree t) throws IllegalArgumentException { node(r, t); if (r.accept(Token.COMMA)) { list(r, t); } } private static void node(Reader r, Tree t) throws IllegalArgumentException { Object actual = r.peek(); if (actual instanceof Token) { throw new IllegalArgumentException("expected name at " + r.pos); } r.advance(); Tree subtree = new Tree(); t.children.put((String) actual, subtree); if (r.accept(Token.LBRACE)) { list(r, subtree); r.expect(Token.RBRACE); } if (r.accept(Token.QLBRACE)) { subtree.range = parseRange(r); r.expect(Token.QRBRACE); } } static Range parseRange(Reader r) { int min; if (r.accept(Token.COMMA)) { return new Range(0, r.expectNumber()); // {,M} } else { min = r.expectNumber(); if (r.peek()==Token.QRBRACE) return new Range(min,min+1); // {N} r.expect(Token.COMMA); if (r.peek()==Token.QRBRACE) return new Range(min,Integer.MAX_VALUE); // {N,} else return new Range(min,r.expectNumber()); // {N,M} } } private enum Token {COMMA /* , */, LBRACE /* [ */, RBRACE /* ] */, QLBRACE /* { */, QRBRACE /* } */, EOF} private static class Reader { private final String text; int pos, next; Reader(String text) { this.text = text; pos = 0; } Object peek() { if (pos == text.length()) { return Token.EOF; } switch (text.charAt(pos)) { case ',': next = pos + 1; return Token.COMMA; case '[': next = pos + 1; return Token.LBRACE; case ']': next = pos + 1; return Token.RBRACE; case '{': next = pos + 1; return Token.QLBRACE; case '}': next = pos + 1; return Token.QRBRACE; default: next = text.length(); for (char c : new char[] {',', '[', ']', '{', '}'}) { int x = text.indexOf(c, pos); if (x != -1 && x < next) { next = x; } } return text.substring(pos, next); } } void advance() { pos = next; } void expect(Token tok) throws IllegalArgumentException { Object actual = peek(); if (actual != tok) { throw new IllegalArgumentException("expected " + tok + " at " + pos); } advance(); } int expectNumber() { Object t = peek(); if (!(t instanceof String) || !Pattern.matches("[0-9]+$", (String) t)) { throw new IllegalArgumentException("expected number at " + pos); } advance(); return Integer.parseInt((String) t); } boolean accept(Token tok) { if (peek() == tok) { advance(); return true; } else { return false; } } } private final Tree tree; /** * Constructs a pruner by parsing a textual specification. * This lists the properties which should be included at each level of the hierarchy. * Properties are separated by commas and nested objects are inside square braces. * For example, {@code a,b[c,d]} will emit the top-level property {@code a} but * none of its children, and the top-level property {@code b} and only those * of its children named {@code c} and {@code d}. * @param spec textual specification of tree * @throws IllegalArgumentException if the syntax is incorrect */ public NamedPathPruner(String spec) throws IllegalArgumentException { this(parse(spec)); } private NamedPathPruner(Tree tree) { this.tree = tree; } public @Override TreePruner accept(Object node, Property prop) { Tree subtree = tree.children.get(prop.name); if (subtree==null) subtree=tree.children.get("*"); return subtree != null ? new NamedPathPruner(subtree) : null; } public @Override Range getRange() { return tree.range; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/ExportedBean.java0000664000175000017500000000500312414640747031534 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import org.jvnet.hudson.annotation_indexer.Indexed; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Documented; import java.lang.annotation.Inherited; import java.lang.annotation.Target; import java.lang.annotation.ElementType; /** * Indicates that the class has {@link Exported} annotations * on its properties to indicate which properties are written * as values to the remote XML/JSON API. * *

* This annotation inherits, so it only needs to be placed on the base class. * * @author Kohsuke Kawaguchi * @see Exported */ @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Target(ElementType.TYPE) @Indexed public @interface ExportedBean { /** * Controls the default visibility of all {@link Exported} properties * of this class (and its descendants.) * *

* A big default visibility value usually indicates that the bean * is always exposed as a descendant of another bean. In such case, * unless the default visibility is set no property will be exposed. */ int defaultVisibility() default 1; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/ModelBuilder.java0000664000175000017500000000463012414640747031530 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.annotation.CheckForNull; import javax.annotation.Nullable; /** * Creates and maintains {@link Model}s, that are used to write out * the value representation of {@link ExportedBean exposed beans}. * @author Kohsuke Kawaguchi */ public class ModelBuilder { /** * Instantiated {@link Model}s. * Registration happens in {@link Model#Model(ModelBuilder,Class)} so that cyclic references * are handled correctly. */ /*package*/ final Map models = new ConcurrentHashMap(); public Model get(Class type) throws NotExportableException { return get(type, null, null); } public Model get(Class type, @CheckForNull Class propertyOwner, @Nullable String property) throws NotExportableException { Model m = models.get(type); if(m==null) { m = new Model(this, type, propertyOwner, property); } return m; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/TypeUtil.java0000664000175000017500000004542412414640747030746 0ustar ebourgebourg/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package org.kohsuke.stapler.export; import java.lang.reflect.Type; import java.lang.reflect.ParameterizedType; import java.lang.reflect.GenericArrayType; import java.lang.reflect.WildcardType; import java.lang.reflect.TypeVariable; import java.lang.reflect.Array; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.MalformedParameterizedTypeException; import java.util.Arrays; /** * Type arithmetic code. Taken from the JAXB RI. * * @author Kohsuke Kawaguchi */ public class TypeUtil { abstract static class TypeVisitor { public final T visit( Type t, P param ) { assert t!=null; if (t instanceof Class) return onClass((Class)t,param); if (t instanceof ParameterizedType) return onParameterizdType( (ParameterizedType)t,param); if(t instanceof GenericArrayType) return onGenericArray((GenericArrayType)t,param); if(t instanceof WildcardType) return onWildcard((WildcardType)t,param); if(t instanceof TypeVariable) return onVariable((TypeVariable)t,param); // covered all the cases assert false; throw new IllegalArgumentException(); } protected abstract T onClass(Class c, P param); protected abstract T onParameterizdType(ParameterizedType p, P param); protected abstract T onGenericArray(GenericArrayType g, P param); protected abstract T onVariable(TypeVariable v, P param); protected abstract T onWildcard(WildcardType w, P param); } /** * Implements the logic for {@link #erasure(Type)}. */ private static final TypeVisitor eraser = new TypeVisitor() { public Class onClass(Class c,Void _) { return c; } public Class onParameterizdType(ParameterizedType p,Void _) { // TODO: why getRawType returns Type? not Class? return visit(p.getRawType(),null); } public Class onGenericArray(GenericArrayType g,Void _) { return Array.newInstance( visit(g.getGenericComponentType(),null), 0 ).getClass(); } public Class onVariable(TypeVariable v,Void _) { return visit(v.getBounds()[0],null); } public Class onWildcard(WildcardType w,Void _) { return visit(w.getUpperBounds()[0],null); } }; /** * Returns the runtime representation of the given type. * * This corresponds to the notion of the erasure in JSR-14. */ public static Class erasure(Type t) { return eraser.visit(t,null); } private static final TypeVisitor baseClassFinder = new TypeVisitor() { public Type onClass(Class c, Class sup) { // t is a raw type if(sup==c) return sup; Type r; Type sc = c.getGenericSuperclass(); if(sc!=null) { r = visit(sc,sup); if(r!=null) return r; } for( Type i : c.getGenericInterfaces() ) { r = visit(i,sup); if(r!=null) return r; } return null; } public Type onParameterizdType(ParameterizedType p, Class sup) { Class raw = (Class) p.getRawType(); if(raw==sup) { // p is of the form sup<...> return p; } else { // recursively visit super class/interfaces Type r = raw.getGenericSuperclass(); if(r!=null) r = visit(bind(r,raw,p),sup); if(r!=null) return r; for( Type i : raw.getGenericInterfaces() ) { r = visit(bind(i,raw,p),sup); if(r!=null) return r; } return null; } } public Type onGenericArray(GenericArrayType g, Class sup) { // not clear what I should do here return null; } public Type onVariable(TypeVariable v, Class sup) { return visit(v.getBounds()[0],sup); } public Type onWildcard(WildcardType w, Class sup) { // not clear what I should do here return null; } /** * Replaces the type variables in {@code t} by its actual arguments. * * @param decl * provides a list of type variables. See {@link GenericDeclaration#getTypeParameters()} * @param args * actual arguments. See {@link ParameterizedType#getActualTypeArguments()} */ private Type bind( Type t, GenericDeclaration decl, ParameterizedType args ) { return binder.visit(t,new BinderArg(decl,args.getActualTypeArguments())); } }; private static final TypeVisitor binder = new TypeVisitor() { public Type onClass(Class c, BinderArg args) { return c; } public Type onParameterizdType(ParameterizedType p, BinderArg args) { Type[] params = p.getActualTypeArguments(); boolean different = false; for( int i=0; i)p.getRawType(), params, newOwner ); } public Type onGenericArray(GenericArrayType g, BinderArg types) { Type c = visit(g.getGenericComponentType(),types); if(c==g.getGenericComponentType()) return g; return new GenericArrayTypeImpl(c); } public Type onVariable(TypeVariable v, BinderArg types) { return types.replace(v); } public Type onWildcard(WildcardType w, BinderArg types) { // TODO: this is probably still incorrect // bind( "? extends T" ) with T= "? extends Foo" should be "? extends Foo", // not "? extends (? extends Foo)" Type[] lb = w.getLowerBounds(); Type[] ub = w.getUpperBounds(); boolean diff = false; for( int i=0; i * For example, given the following *


     * interface Foo<T> extends List<List<T>> {}
     * interface Bar extends Foo<String> {}
     * 
* This method works like this: *

     * getBaseClass( Bar, List ) = List<List<String>
     * getBaseClass( Bar, Foo  ) = Foo<String>
     * getBaseClass( Foo<? extends Number>, Collection ) = Collection<List<? extends Number>>
     * getBaseClass( ArrayList<? extends BigInteger>, List ) = List<? extends BigInteger>
     * 
* * @param type * The type that derives from {@code baseType} * @param baseType * The class whose parameterization we are interested in. * @return * The use of {@code baseType} in {@code type}. * or null if the type is not assignable to the base type. */ public static Type getBaseClass(Type type, Class baseType) { return baseClassFinder.visit(type,baseType); } static class ParameterizedTypeImpl implements ParameterizedType { private Type[] actualTypeArguments; private Class rawType; private Type ownerType; ParameterizedTypeImpl(Class rawType, Type[] actualTypeArguments, Type ownerType) { this.actualTypeArguments = actualTypeArguments; this.rawType = rawType; if (ownerType != null) { this.ownerType = ownerType; } else { this.ownerType = rawType.getDeclaringClass(); } validateConstructorArguments(); } private void validateConstructorArguments() { TypeVariable/**/[] formals = rawType.getTypeParameters(); // check correct arity of actual type args if (formals.length != actualTypeArguments.length) { throw new MalformedParameterizedTypeException(); } for (int i = 0; i < actualTypeArguments.length; i++) { // check actuals against formals' bounds } } public Type[] getActualTypeArguments() { return actualTypeArguments.clone(); } public Class getRawType() { return rawType; } public Type getOwnerType() { return ownerType; } /* * From the JavaDoc for java.lang.reflect.ParameterizedType * "Instances of classes that implement this interface must * implement an equals() method that equates any two instances * that share the same generic type declaration and have equal * type parameters." */ @Override public boolean equals(Object o) { if (o instanceof ParameterizedType) { // Check that information is equivalent ParameterizedType that = (ParameterizedType) o; if (this == that) return true; Type thatOwner = that.getOwnerType(); Type thatRawType = that.getRawType(); if (false) { // Debugging boolean ownerEquality = (ownerType == null ? thatOwner == null : ownerType.equals(thatOwner)); boolean rawEquality = (rawType == null ? thatRawType == null : rawType.equals(thatRawType)); boolean typeArgEquality = Arrays.equals(actualTypeArguments, // avoid clone that.getActualTypeArguments()); for (Type t : actualTypeArguments) { System.out.printf("\t\t%s%s%n", t, t.getClass()); } System.out.printf("\towner %s\traw %s\ttypeArg %s%n", ownerEquality, rawEquality, typeArgEquality); return ownerEquality && rawEquality && typeArgEquality; } return (ownerType == null ? thatOwner == null : ownerType.equals(thatOwner)) && (rawType == null ? thatRawType == null : rawType.equals(thatRawType)) && Arrays.equals(actualTypeArguments, // avoid clone that.getActualTypeArguments()); } else return false; } @Override public int hashCode() { return Arrays.hashCode(actualTypeArguments) ^ (ownerType == null ? 0 : ownerType.hashCode()) ^ (rawType == null ? 0 : rawType.hashCode()); } public String toString() { StringBuilder sb = new StringBuilder(); if (ownerType != null) { if (ownerType instanceof Class) sb.append(((Class) ownerType).getName()); else sb.append(ownerType.toString()); sb.append("."); if (ownerType instanceof ParameterizedTypeImpl) { // Find simple name of nested type by removing the // shared prefix with owner. sb.append(rawType.getName().replace(((ParameterizedTypeImpl) ownerType).rawType.getName() + "$", "")); } else sb.append(rawType.getName()); } else sb.append(rawType.getName()); if (actualTypeArguments != null && actualTypeArguments.length > 0) { sb.append("<"); boolean first = true; for (Type t : actualTypeArguments) { if (!first) sb.append(", "); if (t instanceof Class) sb.append(((Class) t).getName()); else sb.append(t.toString()); first = false; } sb.append(">"); } return sb.toString(); } } static final class GenericArrayTypeImpl implements GenericArrayType { private Type genericComponentType; GenericArrayTypeImpl(Type ct) { assert ct!=null; genericComponentType = ct; } /** * Returns a Type object representing the component type * of this array. * * @return a Type object representing the component type * of this array * @since 1.5 */ public Type getGenericComponentType() { return genericComponentType; // return cached component type } public String toString() { Type componentType = getGenericComponentType(); StringBuilder sb = new StringBuilder(); if (componentType instanceof Class) sb.append(((Class) componentType).getName()); else sb.append(componentType.toString()); sb.append("[]"); return sb.toString(); } @Override public boolean equals(Object o) { if (o instanceof GenericArrayType) { GenericArrayType that = (GenericArrayType) o; Type thatComponentType = that.getGenericComponentType(); return genericComponentType.equals(thatComponentType); } else return false; } @Override public int hashCode() { return genericComponentType.hashCode(); } } static final class WildcardTypeImpl implements WildcardType { private final Type[] ub; private final Type[] lb; public WildcardTypeImpl(Type[] ub, Type[] lb) { this.ub = ub; this.lb = lb; } public Type[] getUpperBounds() { return ub; } public Type[] getLowerBounds() { return lb; } public int hashCode() { return Arrays.hashCode(lb) ^ Arrays.hashCode(ub); } public boolean equals(Object obj) { if (obj instanceof WildcardType) { WildcardType that = (WildcardType) obj; return Arrays.equals(that.getLowerBounds(),lb) && Arrays.equals(that.getUpperBounds(),ub); } return false; } } public static Type getTypeArgument(Type type, int i) { if (type instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) type; return fix(p.getActualTypeArguments()[i]); } else throw new IllegalArgumentException(); } /** * JDK 5.0 has a bug of createing {@link GenericArrayType} where it shouldn't. * fix that manually to work around the problem. * * See bug 6202725. */ private static Type fix(Type t) { if(!(t instanceof GenericArrayType)) return t; GenericArrayType gat = (GenericArrayType) t; if(gat.getGenericComponentType() instanceof Class) { Class c = (Class) gat.getGenericComponentType(); return Array.newInstance(c,0).getClass(); } return t; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/CustomExportedBean.java0000664000175000017500000000331712414640747032735 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; /** * Interface that an exposed bean can implement, to do the equivalent * of writeReplace in Java serialization. * @author Kohsuke Kawaguchi */ public interface CustomExportedBean { /** * The returned object will be introspected and written as JSON/XML. */ Object toExportedObject(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/export/JSONDataWriter.java0000664000175000017500000001042712414640747031722 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.export; import java.io.IOException; import java.io.Writer; /** * JSON writer. * * @author Kohsuke Kawaguchi */ class JSONDataWriter implements DataWriter { protected boolean needComma; protected final Writer out; private int indent; JSONDataWriter(Writer out, ExportConfig config) throws IOException { this.out = out; indent = config.prettyPrint ? 0 : -1; } public void name(String name) throws IOException { comma(); if (indent<0) out.write('"'+name+"\":"); else out.write('"'+name+"\" : "); needComma = false; } protected void data(String v) throws IOException { comma(); out.write(v); } protected void comma() throws IOException { if(needComma) { out.write(','); indent(); } needComma = true; } /** * Prints indentation. */ private void indent() throws IOException { if (indent>=0) { out.write('\n'); for (int i=indent*2; i>0; ) { int len = Math.min(i,INDENT.length); out.write(INDENT,0,len); i-=len; } } } private void inc() { if (indent<0) return; // no indentation indent++; } private void dec() { if (indent<0) return; indent--; } public void valuePrimitive(Object v) throws IOException { data(v.toString()); } public void value(String v) throws IOException { StringBuilder buf = new StringBuilder(v.length()); buf.append('\"'); for( int i=0; i { private final Function[] functions; public FunctionList(Function... functions) { this.functions = functions; } public FunctionList(Collection functions) { this.functions = functions.toArray(new Function[0]); } private FunctionList filter(Filter f) { List r = new ArrayList(); for (Function m : functions) if (f.keep(m)) r.add(m); return new FunctionList(r.toArray(new Function[0])); } @Override public Function get(int index) { return functions[index]; } public int size() { return functions.length; } //public int length() { // return functions.length; //} // //public Method get(int i) { // return functions[i]; //} public interface Filter { boolean keep(Function m); } /** * Returns {@link Function}s that start with the given prefix. */ public FunctionList prefix(final String prefix) { return filter(new Filter() { public boolean keep(Function m) { return m.getName().startsWith(prefix); } }); } /** * Returns {@link Function}s that are annotated with the given annotation. */ public FunctionList annotated(final Class ann) { return filter(new Filter() { public boolean keep(Function m) { return m.getAnnotation(ann)!=null; } }); } /** * Returns {@link Function}s that have the given name. */ public FunctionList name(final String name) { return filter(new Filter() { public boolean keep(Function m) { return m.getName().equals(name); } }); } /** * Returns {@link Function}s that has the given type parameters */ public FunctionList signature(final Class... args) { return filter(new Filter() { public boolean keep(Function m) { return Arrays.equals(m.getParameterTypes(),args); } }); } /** * Returns {@link Function}s that has the parameters * that start with given types (but can have additional parameters.) */ public FunctionList signatureStartsWith(final Class... args) { return filter(new Filter() { public boolean keep(Function m) { Class[] params = m.getParameterTypes(); if(params.length { public Object parse(StaplerRequest request, AncestorInPath a, Class type, String parameterName) throws ServletException { return request.findAncestorObject(type); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/AncestorImpl.java0000664000175000017500000000764712414640747030253 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.util.List; /** * @author Kohsuke Kawaguchi */ class AncestorImpl implements Ancestor { private final List owner; private final int listIndex; private final Object object; private final String[] tokens; private final int index; private final String contextPath; /** * True if the request URL had '/' in the end. */ private final boolean endsWithSlash; AncestorImpl(RequestImpl req, Object object) { this.owner = req.ancestors; listIndex = owner.size(); owner.add(this); this.object = object; this.tokens = req.tokens.rawTokens; this.index = req.tokens.idx; this.endsWithSlash = req.tokens.endsWithSlash; this.contextPath = req.getContextPath(); } public Object getObject() { return object; } public String getUrl() { StringBuilder buf = new StringBuilder(contextPath); for( int i=0; i0) buf.append('/'); buf.append(tokens[i]); } return buf.toString(); } public String getFullUrl() { StringBuilder buf = new StringBuilder(); StaplerRequest req = Stapler.getCurrentRequest(); buf.append(req.getScheme()); buf.append("://"); buf.append(req.getServerName()); if(req.getServerPort()!=80) buf.append(':').append(req.getServerPort()); buf.append(getUrl()); return buf.toString(); } public String getRelativePath() { StringBuilder buf = new StringBuilder(); for( int i=index+(endsWithSlash?0:1); i0) buf.append('/'); buf.append(".."); } if(buf.length()==0) buf.append('.'); return buf.toString(); } public String getNextToken(int n) { return tokens[index+n]; } public Ancestor getPrev() { if(listIndex==0) return null; else return owner.get(listIndex-1); } public Ancestor getNext() { if(listIndex==owner.size()-1) return null; else return owner.get(listIndex+1); } @Override public String toString() { return object.toString(); } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/0000775000175000017500000000000012414640747026031 5ustar ebourgebourg././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/WebMethodAnnotationProcessor.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/WebMethodAnnotationProces0000664000175000017500000000540412414640747033044 0ustar ebourgebourg/* * Copyright (c) 2013, Jesse Glick * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * 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 HOLDER 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. */ package org.kohsuke.stapler.jsr269; import java.util.Set; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.WebMethod; @SupportedSourceVersion(SourceVersion.RELEASE_6) @SupportedAnnotationTypes("org.kohsuke.stapler.WebMethod") @MetaInfServices(Processor.class) public class WebMethodAnnotationProcessor extends AbstractProcessorImpl { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { for (Element e : roundEnv.getElementsAnnotatedWith(WebMethod.class)) { if (e instanceof ExecutableElement) {// defensive against broken code ExecutableElement method = (ExecutableElement) e; String name = method.getSimpleName().toString(); if (!name.startsWith("do")) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@WebMethod cannot be used on " + name + "; name must start with 'do'", e); } } } return true; } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/ConstructorProcessor.java0000664000175000017500000000677412414640747033137 0ustar ebourgebourgpackage org.kohsuke.stapler.jsr269; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.DataBoundConstructor; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.util.ElementScanner6; import java.io.IOException; import java.util.Properties; import java.util.Set; import javax.lang.model.element.Modifier; import javax.tools.Diagnostic; /** * @author Kohsuke Kawaguchi */ @SuppressWarnings({"Since15"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) @SupportedAnnotationTypes("*") @MetaInfServices(Processor.class) public class ConstructorProcessor extends AbstractProcessorImpl { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { try { ElementScanner6 scanner = new ElementScanner6() { @Override public Void visitExecutable(ExecutableElement e, Void aVoid) { if(e.getAnnotation(DataBoundConstructor.class)!=null) { write(e); } else { String javadoc = getJavadoc(e); if(javadoc!=null && javadoc.contains("@stapler-constructor")) { write(e); } } return super.visitExecutable(e, aVoid); } }; for (Element e : roundEnv.getRootElements()) { if (e.getKind() == ElementKind.PACKAGE) { // JENKINS-11739 continue; } scanner.scan(e, null); } return false; } catch (RuntimeException e) { // javac sucks at reporting errors in annotation processors e.printStackTrace(); throw e; } catch (Error e) { e.printStackTrace(); throw e; } } private void write(ExecutableElement c) { if (!c.getModifiers().contains(Modifier.PUBLIC)) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@DataBoundConstructor must be applied to a public constructor", c); return; } if (c.getEnclosingElement().getModifiers().contains(Modifier.ABSTRACT)) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@DataBoundConstructor may not be used on an abstract class (only on concrete subclasses)", c); return; } try { StringBuilder buf = new StringBuilder(); for( VariableElement p : c.getParameters() ) { if(buf.length()>0) buf.append(','); buf.append(p.getSimpleName()); } TypeElement t = (TypeElement) c.getEnclosingElement(); String name = t.getQualifiedName().toString().replace('.', '/') + ".stapler"; notice("Generating " + name, c); Properties p = new Properties(); p.put("constructor",buf.toString()); writePropertyFile(p, name); } catch (IOException x) { error(x); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/PoormansMultimap.java0000664000175000017500000000160412414640747032204 0ustar ebourgebourgpackage org.kohsuke.stapler.jsr269; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Very simple multi-map implmentation. * *

* We historically used Google Collections, but there have been multiple reports that * certain versions of Maven (and IDEs such as IntelliJ) fail to correctly compute * classpath for annotation processors and cause a NoClassDefFoundError. * * To work around this problem, we are now using this class. * * @author Kohsuke Kawaguchi */ class PoormansMultimap { private final HashMap> store = new HashMap>(); public void put(K k, V v) { List l = store.get(k); if (l==null) store.put(k,l=new ArrayList()); l.add(v); } public Map> asMap() { return (Map)store; } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/AbstractProcessorImpl.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/AbstractProcessorImpl.jav0000664000175000017500000000627112414640747033026 0ustar ebourgebourg/* * Copyright (c) 2011, CloudBees, 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: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jsr269; import javax.annotation.processing.AbstractProcessor; import javax.lang.model.element.Element; import javax.tools.FileObject; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Properties; import static javax.tools.Diagnostic.Kind.*; import static javax.tools.StandardLocation.*; /** * @author Kohsuke Kawaguchi */ @SuppressWarnings({"Since15"}) abstract class AbstractProcessorImpl extends AbstractProcessor { protected String toString(Throwable t) { StringWriter w = new StringWriter(); t.printStackTrace(new PrintWriter(w)); return w.toString(); } protected void error(Throwable t) { error(toString(t)); } protected void error(String msg) { processingEnv.getMessager().printMessage(ERROR, msg); } protected String getJavadoc(Element md) { return processingEnv.getElementUtils().getDocComment(md); } protected void notice(String msg, Element location) { // IntelliJ flags this as an error. So disabling it for now. // See http://youtrack.jetbrains.net/issue/IDEA-71822 // processingEnv.getMessager().printMessage(NOTE, msg, location); } protected void writePropertyFile(Properties p, String name) throws IOException { FileObject f = createResource(name); OutputStream os = f.openOutputStream(); try { p.store(os,null); } finally { os.close(); } } protected FileObject getResource(String name) throws IOException { return processingEnv.getFiler().getResource(CLASS_OUTPUT, "", name); } protected FileObject createResource(String name) throws IOException { return processingEnv.getFiler().createResource(CLASS_OUTPUT, "", name); } } ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/RequirePOSTAnnotationProcessor.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/RequirePOSTAnnotationProc0000664000175000017500000001123512414640747032757 0ustar ebourgebourg/* * Copyright (c) 2013, Jesse Glick * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * 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 HOLDER 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. */ package org.kohsuke.stapler.jsr269; import java.util.Set; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.interceptor.RequirePOST; @SupportedSourceVersion(SourceVersion.RELEASE_6) @SupportedAnnotationTypes("org.kohsuke.stapler.interceptor.RequirePOST") @MetaInfServices(Processor.class) public class RequirePOSTAnnotationProcessor extends AbstractProcessorImpl { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { for (Element e : roundEnv.getElementsAnnotatedWith(RequirePOST.class)) { if (e.getKind() != ElementKind.METHOD) { continue; // defensive against broken code } ExecutableElement method = (ExecutableElement) e; if (method.getModifiers().contains(Modifier.ABSTRACT)) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@RequirePOST is meaningless on an abstract method", e); } } for (Element e : roundEnv.getRootElements()) { if (e.getKind() != ElementKind.CLASS) { continue; } for (Element e2 : ((TypeElement) e).getEnclosedElements()) { if (e2.getKind() != ElementKind.METHOD) { continue; } ExecutableElement method = (ExecutableElement) e2; if (method.getAnnotation(RequirePOST.class) != null) { continue; } if (method.getModifiers().contains(Modifier.ABSTRACT)) { continue; } checkForOverrides((ExecutableElement) e2); } } return true; } private void checkForOverrides(ExecutableElement concrete) { checkForOverrides(concrete, ((TypeElement) concrete.getEnclosingElement()).getSuperclass()); } private void checkForOverrides(ExecutableElement concrete, TypeMirror superclass) { TypeElement superclassE = (TypeElement) processingEnv.getTypeUtils().asElement(superclass); if (superclassE == null) { return; } for (Element e : superclassE.getEnclosedElements()) { if (e.getKind() != ElementKind.METHOD) { continue; } ExecutableElement method = (ExecutableElement) e; if (processingEnv.getElementUtils().overrides(concrete, method, superclassE)) { if (method.getAnnotation(RequirePOST.class) != null) { processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "@RequirePOST ignored unless also specified on an overriding method", concrete); } return; } } checkForOverrides(concrete, superclassE.getSuperclass()); } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/ExportedBeanAnnotationProcessor.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/ExportedBeanAnnotationPro0000664000175000017500000001452212414640747033054 0ustar ebourgebourgpackage org.kohsuke.stapler.jsr269; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.export.Exported; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.FileObject; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Collection; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.TreeSet; /** * @author Kohsuke Kawaguchi */ @SuppressWarnings({"Since15"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) @SupportedAnnotationTypes("org.kohsuke.stapler.export.Exported") @MetaInfServices(Processor.class) public class ExportedBeanAnnotationProcessor extends AbstractProcessorImpl { private Set exposedBeanNames; @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { try { if (roundEnv.processingOver()) { FileObject beans = createResource(STAPLER_BEAN_FILE); PrintWriter w = new PrintWriter(new OutputStreamWriter(beans.openOutputStream(), "UTF-8")); for (String beanName : exposedBeanNames) { w.println(beanName); } w.close(); return false; } // collect all exposed properties PoormansMultimap props = new PoormansMultimap(); for (Element exported : roundEnv.getElementsAnnotatedWith(Exported.class)) { Element type = exported.getEnclosingElement(); if (type.getKind().isClass() || type.getKind().isInterface()) { props.put((TypeElement)type, exported); } } if (exposedBeanNames == null) { scanExisting(); } for (Entry> e : props.asMap().entrySet()) { exposedBeanNames.add(e.getKey().getQualifiedName().toString()); final Properties javadocs = new Properties(); for (Element md : e.getValue()) { switch (md.getKind()) { case FIELD: case METHOD: String javadoc = getJavadoc(md); if(javadoc!=null) javadocs.put(md.getSimpleName().toString(), javadoc); break; default: throw new AssertionError("Unexpected element type: "+md); } // TODO: possibly a proper method signature generation, but it's too tedious // way too tedious. //private String getSignature(MethodDeclaration m) { // final StringBuilder buf = new StringBuilder(m.getSimpleName()); // buf.append('('); // boolean first=true; // for (ParameterDeclaration p : m.getParameters()) { // if(first) first = false; // else buf.append(','); // p.getType().accept(new SimpleTypeVisitor() { // public void visitPrimitiveType(PrimitiveType pt) { // buf.append(pt.getKind().toString().toLowerCase()); // } // public void visitDeclaredType(DeclaredType dt) { // buf.append(dt.getDeclaration().getQualifiedName()); // } // // public void visitArrayType(ArrayType at) { // at.getComponentType().accept(this); // buf.append("[]"); // } // // public void visitTypeVariable(TypeVariable tv) { // // // TODO // super.visitTypeVariable(typeVariable); // } // // public void visitVoidType(VoidType voidType) { // // TODO // super.visitVoidType(voidType); // } // }); // } // buf.append(')'); // // TODO // return null; //} } String javadocFile = e.getKey().getQualifiedName().toString().replace('.', '/') + ".javadoc"; notice("Generating "+ javadocFile, e.getKey()); writePropertyFile(javadocs, javadocFile); } } catch (IOException x) { error(x); } catch (RuntimeException e) { // javac sucks at reporting errors in annotation processors e.printStackTrace(); throw e; } catch (Error e) { e.printStackTrace(); throw e; } return false; } private void scanExisting() throws IOException { exposedBeanNames = new TreeSet(); try { FileObject beans = getResource(STAPLER_BEAN_FILE); BufferedReader in = new BufferedReader(new InputStreamReader(beans.openInputStream(),"UTF-8")); String line; while((line=in.readLine())!=null) exposedBeanNames.add(line.trim()); in.close(); } catch (FileNotFoundException e) { // no existing file, which is fine } } static final String STAPLER_BEAN_FILE = "META-INF/exposed.stapler-beans"; } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessor.javastapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationP0000664000175000017500000000560712414640747033105 0ustar ebourgebourgpackage org.kohsuke.stapler.jsr269; import org.apache.commons.io.IOUtils; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.QueryParameter; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.tools.FileObject; import java.io.IOException; import java.io.OutputStream; import java.util.HashSet; import java.util.Set; /** * @author Kohsuke Kawaguchi */ @SuppressWarnings({"Since15"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) @SupportedAnnotationTypes("org.kohsuke.stapler.QueryParameter") @MetaInfServices(Processor.class) public class QueryParameterAnnotationProcessor extends AbstractProcessorImpl { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { try { Set params = roundEnv.getElementsAnnotatedWith(QueryParameter.class); Set methods = new HashSet(); for (Element p : params) { // at least in JDK7u3, if some of the annotation types doesn't resolve, they end up showing up // in the result from the getElementsAnnotatedWith method. This check rejects those bogus matches if (p.getAnnotation(QueryParameter.class)!=null) methods.add((ExecutableElement)p.getEnclosingElement()); } for (ExecutableElement m : methods) { write(m); } } catch (IOException e) { error(e); } catch (RuntimeException e) { // javac sucks at reporting errors in annotation processors e.printStackTrace(); throw e; } catch (Error e) { e.printStackTrace(); throw e; } return false; } /** * @param m * Method whose parameter has {@link QueryParameter} */ private void write(ExecutableElement m) throws IOException { StringBuffer buf = new StringBuffer(); for( VariableElement p : m.getParameters() ) { if(buf.length()>0) buf.append(','); buf.append(p.getSimpleName()); } TypeElement t = (TypeElement)m.getEnclosingElement(); FileObject f = createResource(t.getQualifiedName().toString().replace('.', '/') + "/" + m.getSimpleName() + ".stapler"); notice("Generating " + f, m); OutputStream os = f.openOutputStream(); try { IOUtils.write(buf, os, "UTF-8"); } finally { os.close(); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/QueryParameter.java0000664000175000017500000000624212414640747030607 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import org.kohsuke.stapler.QueryParameter.HandlerImpl; import javax.servlet.ServletException; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.annotation.Documented; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Indicates that this parameter is injected from HTTP query parameter. * * @author Kohsuke Kawaguchi */ @Retention(RUNTIME) @Target(PARAMETER) @Documented @InjectedParameter(HandlerImpl.class) public @interface QueryParameter { /** * query parameter name. By default, name of the parameter. */ String value() default ""; /** * If true, request without this header will be rejected. */ boolean required() default false; /** * If true, and the actual value of this parameter is "", * null is passed instead. This is useful to unify the treatment of * the absence of the value vs the empty value. */ boolean fixEmpty() default false; class HandlerImpl extends AnnotationHandler { public Object parse(StaplerRequest request, QueryParameter a, Class type, String parameterName) throws ServletException { String name = a.value(); if(name.length()==0) name=parameterName; if(name==null) throw new IllegalArgumentException("Parameter name unavailable neither in the code nor in annotation"); String value = request.getParameter(name); if(a.required() && value==null) throw new ServletException("Required Query parameter "+name+" is missing"); if(a.fixEmpty() && value!=null && value.length()==0) value = null; return convert(type,value); } } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/WebMethod.java0000664000175000017500000000464612414640747027525 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; import java.lang.annotation.Documented; import static java.lang.annotation.ElementType.METHOD; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Target; /** * Indicates that the method is bound to HTTP and used to * serve the HTTP request. * *

* This annotation is assumed to be implicit on every public methods * that start with 'do', like 'doFoo' or 'doBar', but you can use this annotation * on methods starting with {@code do} to assign different names. * * @author Kohsuke Kawaguchi */ @Retention(RUNTIME) @Target(METHOD) @Documented public @interface WebMethod { /** * URL names assigned to this method. * *

* Normally, for doXyz method, the name is xyz, * but you can use this to assign multiple names or non-default names. * Often useful for using names that contain non-identifier characters. * *

* The same applies to getXyz methods. */ String[] name(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/DiagnosticThreadNameFilter.java0000664000175000017500000000225512414640747033024 0ustar ebourgebourgpackage org.kohsuke.stapler; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * {@link Filter} that sets the thread name to reflect the current request being processed. * * @author Kohsuke Kawaguchi */ public class DiagnosticThreadNameFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest req, ServletResponse rsp, FilterChain chain) throws IOException, ServletException { Thread t = Thread.currentThread(); final String oldName = t.getName(); try { HttpServletRequest hreq = (HttpServletRequest) req; t.setName("Handling " + hreq.getMethod() + ' ' + hreq.getRequestURI() + " from "+hreq.getRemoteAddr()+" : " + oldName); chain.doFilter(req, rsp); } finally { t.setName(oldName); } } @Override public void destroy() { } } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/StaplerProxy.java0000664000175000017500000000454512414640747030321 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler; /** * If an object delegates all its UI processing to another object, * it can implement this interface and return the designated object * from the {@link #getTarget()} method. * *

* Compared to {@link StaplerFallback}, stapler handles this interface at the very beginning, * whereas {@link StaplerFallback} is handled at the very end. * *

* By returning {@code this} from the {@link #getTarget()} method, * {@link StaplerProxy} can be also used just as an interception hook (for example * to perform authorization.) * * @author Kohsuke Kawaguchi * @see StaplerFallback */ public interface StaplerProxy { /** * Returns the object that is responsible for processing web requests. * * @return * If null is returned, it generates 404. * If {@code this} object is returned, no further * {@link StaplerProxy} look-up is done and {@code this} object * processes the request. */ Object getTarget(); } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/config/0000775000175000017500000000000012414640747026237 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/config/ConfigurationLoader.java0000664000175000017500000001256212414640747033046 0ustar ebourgebourgpackage org.kohsuke.stapler.config; import com.google.common.base.Function; import org.apache.commons.beanutils.ConvertUtils; import java.beans.Introspector; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Comparator; import java.util.Map; import java.util.Properties; import java.util.TreeMap; import static org.kohsuke.stapler.config.Configuration.UNSPECIFIED; /** * Provides a type-safe access to the configuration of the application. * *

* Often web applications need to load configuration from outside. T * *

* Typical usage would be {@code MyConfig config=ConfigurationLoad.from(...).as(MyConfig.class)} * where the MyConfig interface defines a bunch of methods named after * the property name: * *

 * interface MyConfig {
 *     File rootDir();
 *     int retryCount();
 *     String domainName();
 *     ...
 * }
 * 
* *

* Method calls translate to respective property lookup. For example, {@code config.rootDir()} would * be equivalent to {@code new File(properties.get("rootDir"))}. * *

* The method name can include common prefixes, such as "get", "is", and "has", and those portions * will be excluded from the property name. Thus the {@code rootDir()} could have been named {@code getRootDir()}. * * * @author Kohsuke Kawaguchi */ public class ConfigurationLoader { private final Function source; /** * The caller should use one of the fromXyz methods. */ private ConfigurationLoader(Function source) { this.source = source; } private static Properties load(File f) throws IOException { Properties config = new Properties(); FileInputStream in = new FileInputStream(f); try { config.load(in); return config; } finally { in.close(); } } /** * Loads the configuration from the specified property file. */ public static ConfigurationLoader from(File configPropertyFile) throws IOException { return from(load(configPropertyFile)); } /** * Loads the configuration from the specified {@link Properties} object. */ public static ConfigurationLoader from(final Properties props) throws IOException { return new ConfigurationLoader(new Function() { public String apply(String from) { return props.getProperty(from); } }); } public static ConfigurationLoader from(final Map props) throws IOException { return new ConfigurationLoader(new Function() { public String apply(String from) { return props.get(from); } }); } /** * Creates {@link ConfigurationLoader} that uses all the system properties as the source. */ public static ConfigurationLoader fromSystemProperties() throws IOException { return from(System.getProperties()); } /** * Creates {@link ConfigurationLoader} that uses environment variables as the source. * * Since environment variables are often by convention all caps, while system properties * and other properties tend to be camel cased, this method creates a case-insensitive configuration * (that allows retrievals by both "path" and "PATH" to fill this gap. */ public static ConfigurationLoader fromEnvironmentVariables() throws IOException { TreeMap m = new TreeMap(new Comparator() { public int compare(String o1, String o2) { return o1.compareToIgnoreCase(o2); } }); m.putAll(System.getenv()); return from(m); } /** * Creates a type-safe proxy that reads from the source specified by one of the fromXyz methods. */ public T as(Class type) { return type.cast(Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) return method.invoke(this, args); Configuration cn = method.getAnnotation(Configuration.class); Class r = method.getReturnType(); String key = getKey(method,cn); String v = source.apply(key); if (v==null && cn!=null && !cn.defaultValue().equals(UNSPECIFIED)) v = cn.defaultValue(); if (v==null) return null; // TODO: check how the primitive types are handled here return ConvertUtils.convert(v,r); } private String getKey(Method method, Configuration c) { if (c!=null && !c.name().equals(UNSPECIFIED)) return c.name(); // name override String n = method.getName(); for (String p : GETTER_PREFIX) { if (n.startsWith(p)) return Introspector.decapitalize(n.substring(p.length())); } return n; } })); } private static final String[] GETTER_PREFIX = {"get","has","is"}; } stapler-stapler-parent-1.231/core/src/main/java/org/kohsuke/stapler/config/Configuration.java0000664000175000017500000000136412414640747031715 0ustar ebourgebourgpackage org.kohsuke.stapler.config; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; /** * Customizes how the property retrieval is handled. * * @author Kohsuke Kawaguchi * @see ConfigurationLoader */ @Retention(RUNTIME) @Target(METHOD) @Documented public @interface Configuration { /** * Name of the property. */ String name() default UNSPECIFIED; /** * Default value to be applied if the actual configuration source doesn't specify this property. */ String defaultValue() default UNSPECIFIED; static String UNSPECIFIED = "\u0000"; } stapler-stapler-parent-1.231/core/src/main/resources/0000775000175000017500000000000012414640747022151 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/resources/org/0000775000175000017500000000000012414640747022740 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/0000775000175000017500000000000012414640747024411 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/0000775000175000017500000000000012414640747026063 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/0000775000175000017500000000000012414640747030060 5ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/errors/0000775000175000017500000000000012414640747031374 5ustar ebourgebourg././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/errors/ErrorObject/stapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/errors/ErrorObjec0000775000175000017500000000000012414640747033351 5ustar ebourgebourg././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/errors/ErrorObject/index.default.jellystapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/errors/ErrorObjec0000664000175000017500000000013112414640747033346 0ustar ebourgebourg

Error

${it.message}

stapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/prototype/0000775000175000017500000000000012414640747032125 5ustar ebourgebourg././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/prototype/prototype.jsstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/prototype/prototy0000664000175000017500000036626412414640747033611 0ustar ebourgebourg/* Prototype JavaScript framework, version 1.6.0.2 * (c) 2005-2008 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. * For details, see the Prototype web site: http://www.prototypejs.org/ * *--------------------------------------------------------------------------*/ var Prototype = { Version: '1.6.0.2', Browser: { IE: !!(window.attachEvent && !window.opera), Opera: !!window.opera, WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) }, BrowserFeatures: { XPath: !!document.evaluate, ElementExtensions: !!window.HTMLElement, SpecificElementExtensions: document.createElement('div').__proto__ && document.createElement('div').__proto__ !== document.createElement('form').__proto__ }, ScriptFragment: ']*>([\\S\\s]*?)<\/script>', JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, emptyFunction: function() { }, K: function(x) { return x } }; if (Prototype.Browser.MobileSafari) Prototype.BrowserFeatures.SpecificElementExtensions = false; /* Based on Alex Arnell's inheritance implementation. */ var Class = { create: function() { var parent = null, properties = $A(arguments); if (Object.isFunction(properties[0])) parent = properties.shift(); function klass() { this.initialize.apply(this, arguments); } Object.extend(klass, Class.Methods); klass.superclass = parent; klass.subclasses = []; if (parent) { var subclass = function() { }; subclass.prototype = parent.prototype; klass.prototype = new subclass; parent.subclasses.push(klass); } for (var i = 0; i < properties.length; i++) klass.addMethods(properties[i]); if (!klass.prototype.initialize) klass.prototype.initialize = Prototype.emptyFunction; klass.prototype.constructor = klass; return klass; } }; Class.Methods = { addMethods: function(source) { var ancestor = this.superclass && this.superclass.prototype; var properties = Object.keys(source); if (!Object.keys({ toString: true }).length) properties.push("toString", "valueOf"); for (var i = 0, length = properties.length; i < length; i++) { var property = properties[i], value = source[property]; if (ancestor && Object.isFunction(value) && value.argumentNames().first() == "$super") { var method = value, value = Object.extend((function(m) { return function() { return ancestor[m].apply(this, arguments) }; })(property).wrap(method), { valueOf: function() { return method }, toString: function() { return method.toString() } }); } this.prototype[property] = value; } return this; } }; var Abstract = { }; 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.isUndefined(object)) return 'undefined'; if (object === null) return 'null'; return object.inspect ? object.inspect() : String(object); } 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.isElement(object)) return; var results = []; for (var property in object) { var value = Object.toJSON(object[property]); if (!Object.isUndefined(value)) results.push(property.toJSON() + ': ' + value); } return '{' + results.join(', ') + '}'; }, toQueryString: function(object) { return $H(object).toQueryString(); }, toHTML: function(object) { return object && object.toHTML ? object.toHTML() : String.interpret(object); }, 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); }, isElement: function(object) { return object && object.nodeType == 1; }, isArray: function(object) { return object != null && typeof object == "object" && 'splice' in object && 'join' in object; }, isHash: function(object) { return object instanceof Hash; }, isFunction: function(object) { return typeof object == "function"; }, isString: function(object) { return typeof object == "string"; }, isNumber: function(object) { return typeof object == "number"; }, isUndefined: function(object) { return typeof object == "undefined"; } }); Object.extend(Function.prototype, { argumentNames: function() { var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); return names.length == 1 && !names[0] ? [] : names; }, bind: function() { if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; var __method = this, args = $A(arguments), object = args.shift(); return function() { return __method.apply(object, args.concat($A(arguments))); } }, bindAsEventListener: function() { var __method = this, args = $A(arguments), object = args.shift(); return function(event) { return __method.apply(object, [event || window.event].concat(args)); } }, curry: function() { if (!arguments.length) return this; var __method = this, args = $A(arguments); return function() { return __method.apply(this, args.concat($A(arguments))); } }, delay: function() { var __method = this, args = $A(arguments), timeout = args.shift() * 1000; return window.setTimeout(function() { return __method.apply(__method, args); }, timeout); }, wrap: function(wrapper) { var __method = this; return function() { return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); } }, methodize: function() { if (this._methodized) return this._methodized; var __method = this; return this._methodized = function() { return __method.apply(null, [this].concat($A(arguments))); }; } }); Function.prototype.defer = Function.prototype.delay.curry(0.01); Date.prototype.toJSON = function() { return '"' + this.getUTCFullYear() + '-' + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + this.getUTCDate().toPaddedString(2) + 'T' + this.getUTCHours().toPaddedString(2) + ':' + this.getUTCMinutes().toPaddedString(2) + ':' + this.getUTCSeconds().toPaddedString(2) + 'Z"'; }; 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; } }; RegExp.prototype.match = RegExp.prototype.test; RegExp.escape = function(str) { return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); }; /*--------------------------------------------------------------------------*/ var PeriodicalExecuter = Class.create({ 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); }, execute: function() { this.callback(this); }, stop: function() { if (!this.timer) return; clearInterval(this.timer); this.timer = null; }, onTimerEvent: function() { if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; this.execute(); } 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 = Object.isUndefined(count) ? 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 String(this); }, truncate: function(length, truncation) { length = length || 30; truncation = Object.isUndefined(truncation) ? '...' : truncation; return this.length > length ? this.slice(0, length - truncation.length) + truncation : String(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 = new Element('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 (!Object.isArray(hash[key])) 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) { return count < 1 ? '' : new Array(count + 1).join(this); }, 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}'); }, isJSON: function() { var str = this; if (str.blank()) return false; str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); }, evalJSON: function(sanitize) { var json = this.unfilterJSON(); try { if (!sanitize || json.isJSON()) 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); }, interpolate: function(object, pattern) { return new Template(this, pattern).evaluate(object); } }); 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 (Object.isFunction(replacement)) 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({ initialize: function(template, pattern) { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { if (Object.isFunction(object.toTemplateReplacements)) object = object.toTemplateReplacements(); return this.template.gsub(this.pattern, function(match) { if (object == null) return ''; var before = match[1] || ''; if (before == '\\') return match[2]; var ctx = object, expr = match[3]; var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; match = pattern.exec(expr); if (match == null) return before; while (match != null) { var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; ctx = ctx[comp]; if (null == ctx || '' == match[3]) break; expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); match = pattern.exec(expr); } return before + String.interpret(ctx); }); } }); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; var $break = { }; var Enumerable = { each: function(iterator, context) { var index = 0; iterator = iterator.bind(context); try { this._each(function(value) { iterator(value, index++); }); } catch (e) { if (e != $break) throw e; } return this; }, eachSlice: function(number, iterator, context) { iterator = iterator ? iterator.bind(context) : Prototype.K; var index = -number, slices = [], array = this.toArray(); while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.collect(iterator, context); }, all: function(iterator, context) { iterator = iterator ? iterator.bind(context) : Prototype.K; var result = true; this.each(function(value, index) { result = result && !!iterator(value, index); if (!result) throw $break; }); return result; }, any: function(iterator, context) { iterator = iterator ? iterator.bind(context) : Prototype.K; var result = false; this.each(function(value, index) { if (result = !!iterator(value, index)) throw $break; }); return result; }, collect: function(iterator, context) { iterator = iterator ? iterator.bind(context) : Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator(value, index)); }); return results; }, detect: function(iterator, context) { iterator = iterator.bind(context); var result; this.each(function(value, index) { if (iterator(value, index)) { result = value; throw $break; } }); return result; }, findAll: function(iterator, context) { iterator = iterator.bind(context); var results = []; this.each(function(value, index) { if (iterator(value, index)) results.push(value); }); return results; }, grep: function(filter, iterator, context) { iterator = iterator ? iterator.bind(context) : Prototype.K; var results = []; if (Object.isString(filter)) filter = new RegExp(filter); this.each(function(value, index) { if (filter.match(value)) results.push(iterator(value, index)); }); return results; }, include: function(object) { if (Object.isFunction(this.indexOf)) if (this.indexOf(object) != -1) return true; var found = false; this.each(function(value) { if (value == object) { found = true; throw $break; } }); return found; }, inGroupsOf: function(number, fillWith) { fillWith = Object.isUndefined(fillWith) ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); }, inject: function(memo, iterator, context) { iterator = iterator.bind(context); 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, context) { iterator = iterator ? iterator.bind(context) : Prototype.K; var result; this.each(function(value, index) { value = iterator(value, index); if (result == null || value >= result) result = value; }); return result; }, min: function(iterator, context) { iterator = iterator ? iterator.bind(context) : Prototype.K; var result; this.each(function(value, index) { value = iterator(value, index); if (result == null || value < result) result = value; }); return result; }, partition: function(iterator, context) { iterator = iterator ? iterator.bind(context) : Prototype.K; var trues = [], falses = []; this.each(function(value, index) { (iterator(value, index) ? trues : falses).push(value); }); return [trues, falses]; }, pluck: function(property) { var results = []; this.each(function(value) { results.push(value[property]); }); return results; }, reject: function(iterator, context) { iterator = iterator.bind(context); var results = []; this.each(function(value, index) { if (!iterator(value, index)) results.push(value); }); return results; }, sortBy: function(iterator, context) { iterator = iterator.bind(context); 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 (Object.isFunction(args.last())) 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, filter: Enumerable.findAll, member: Enumerable.include, entries: Enumerable.toArray, every: Enumerable.all, some: Enumerable.any }); function $A(iterable) { if (!iterable) return []; if (iterable.toArray) return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; } if (Prototype.Browser.WebKit) { $A = function(iterable) { if (!iterable) return []; if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && iterable.toArray) return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; }; } Array.from = $A; 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(Object.isArray(value) ? value.flatten() : [value]); }); }, without: function() { var values = $A(arguments); return this.select(function(value) { return !values.include(value); }); }, 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; }); }, intersect: function(array) { return this.uniq().findAll(function(item) { return array.detect(function(value) { return item === value }); }); }, 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 (!Object.isUndefined(value)) results.push(value); }); return '[' + results.join(', ') + ']'; } }); // use native browser JS 1.6 implementation if available if (Object.isFunction(Array.prototype.forEach)) Array.prototype._each = Array.prototype.forEach; if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { i || (i = 0); var length = this.length; if (i < 0) i = length + i; for (; i < length; i++) if (this[i] === item) return i; return -1; }; if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; var n = this.slice(0, i).reverse().indexOf(item); return (n < 0) ? n : i - n - 1; }; Array.prototype.toArray = Array.prototype.clone; function $w(string) { if (!Object.isString(string)) return []; 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 (Object.isArray(arguments[i])) { for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) array.push(arguments[i][j]); } else { array.push(arguments[i]); } } return array; }; } 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'; } }); $w('abs round ceil floor').each(function(method){ Number.prototype[method] = Math[method].methodize(); }); function $H(object) { return new Hash(object); }; var Hash = Class.create(Enumerable, (function() { function toQueryPair(key, value) { if (Object.isUndefined(value)) return key; return key + '=' + encodeURIComponent(String.interpret(value)); } return { initialize: function(object) { this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); }, _each: function(iterator) { for (var key in this._object) { var value = this._object[key], pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } }, set: function(key, value) { return this._object[key] = value; }, get: function(key) { return this._object[key]; }, unset: function(key) { var value = this._object[key]; delete this._object[key]; return value; }, toObject: function() { return Object.clone(this._object); }, keys: function() { return this.pluck('key'); }, values: function() { return this.pluck('value'); }, index: function(value) { var match = this.detect(function(pair) { return pair.value === value; }); return match && match.key; }, merge: function(object) { return this.clone().update(object); }, update: function(object) { return new Hash(object).inject(this, function(result, pair) { result.set(pair.key, pair.value); return result; }); }, toQueryString: function() { return this.map(function(pair) { var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object') { if (Object.isArray(values)) return values.map(toQueryPair.curry(key)).join('&'); } return toQueryPair(key, values); }).join('&'); }, inspect: function() { return '#'; }, toJSON: function() { return Object.toJSON(this.toObject()); }, clone: function() { return new Hash(this); } } })()); Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; Hash.from = $H; var ObjectRange = Class.create(Enumerable, { 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 (Object.isFunction(responder[callback])) { 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 = Class.create({ initialize: function(options) { this.options = { method: 'post', asynchronous: true, contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', parameters: '', evalJSON: true, evalJS: true }; Object.extend(this.options, options || { }); this.options.method = this.options.method.toLowerCase(); if (Object.isString(this.options.parameters)) this.options.parameters = this.options.parameters.toQueryParams(); else if (Object.isHash(this.options.parameters)) this.options.parameters = this.options.parameters.toObject(); } }); Ajax.Request = Class.create(Ajax.Base, { _complete: false, initialize: function($super, url, options) { $super(options); this.transport = Ajax.getTransport(); 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 = Object.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 { var response = new Ajax.Response(this); if (this.options.onCreate) this.options.onCreate(response); Ajax.Responders.dispatch('onCreate', this, response); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); 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 (Object.isFunction(extras.push)) 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() { var status = this.getStatus(); return !status || (status >= 200 && status < 300); }, getStatus: function() { try { return this.transport.status || 0; } catch (e) { return 0 } }, respondToReadyState: function(readyState) { var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); if (state == 'Complete') { try { this._complete = true; (this.options['on' + response.status] || this.options['on' + (this.success() ? 'Success' : 'Failure')] || Prototype.emptyFunction)(response, response.headerJSON); } catch (e) { this.dispatchException(e); } var contentType = response.getHeader('Content-type'); if (this.options.evalJS == 'force' || (this.options.evalJS && this.isSameOrigin() && contentType && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) this.evalResponse(); } try { (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); } catch (e) { this.dispatchException(e); } if (state == 'Complete') { // avoid memory leak in MSIE: clean up this.transport.onreadystatechange = Prototype.emptyFunction; } }, isSameOrigin: function() { var m = this.url.match(/^\s*https?:\/\/[^\/]*/); return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ protocol: location.protocol, domain: document.domain, port: location.port ? ':' + location.port : '' })); }, getHeader: function(name) { try { return this.transport.getResponseHeader(name) || 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.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; Ajax.Response = Class.create({ initialize: function(request){ this.request = request; var transport = this.transport = request.transport, readyState = this.readyState = transport.readyState; if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { this.status = this.getStatus(); this.statusText = this.getStatusText(); this.responseText = String.interpret(transport.responseText); this.headerJSON = this._getHeaderJSON(); } if(readyState == 4) { var xml = transport.responseXML; this.responseXML = Object.isUndefined(xml) ? null : xml; this.responseJSON = this._getResponseJSON(); } }, status: 0, statusText: '', getStatus: Ajax.Request.prototype.getStatus, getStatusText: function() { try { return this.transport.statusText || ''; } catch (e) { return '' } }, getHeader: Ajax.Request.prototype.getHeader, getAllHeaders: function() { try { return this.getAllResponseHeaders(); } catch (e) { return null } }, getResponseHeader: function(name) { return this.transport.getResponseHeader(name); }, getAllResponseHeaders: function() { return this.transport.getAllResponseHeaders(); }, _getHeaderJSON: function() { var json = this.getHeader('X-JSON'); if (!json) return null; json = decodeURIComponent(escape(json)); try { return json.evalJSON(this.request.options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } }, _getResponseJSON: function() { var options = this.request.options; if (!options.evalJSON || (options.evalJSON != 'force' && !(this.getHeader('Content-type') || '').include('application/json')) || this.responseText.blank()) return null; try { return this.responseText.evalJSON(options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } } }); Ajax.Updater = Class.create(Ajax.Request, { initialize: function($super, container, url, options) { this.container = { success: (container.success || container), failure: (container.failure || (container.success ? null : container)) }; options = Object.clone(options); var onComplete = options.onComplete; options.onComplete = (function(response, json) { this.updateContent(response.responseText); if (Object.isFunction(onComplete)) onComplete(response, json); }).bind(this); $super(url, options); }, updateContent: function(responseText) { var receiver = this.container[this.success() ? 'success' : 'failure'], options = this.options; if (!options.evalScripts) responseText = responseText.stripScripts(); if (receiver = $(receiver)) { if (options.insertion) { if (Object.isString(options.insertion)) { var insertion = { }; insertion[options.insertion] = responseText; receiver.insert(insertion); } else options.insertion(receiver, responseText); } else receiver.update(responseText); } } }); Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { initialize: function($super, container, url, options) { $super(options); this.onComplete = this.options.onComplete; this.frequency = (this.options.frequency || 2); this.decay = (this.options.decay || 1); this.updater = { }; this.container = container; this.url = url; this.start(); }, start: function() { this.options.onComplete = this.updateComplete.bind(this); this.onTimerEvent(); }, stop: function() { this.updater.options.onComplete = undefined; clearTimeout(this.timer); (this.onComplete || Prototype.emptyFunction).apply(this, arguments); }, updateComplete: function(response) { if (this.options.decay) { this.decay = (response.responseText == this.lastText ? this.decay * this.options.decay : 1); this.lastText = response.responseText; } this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); }, onTimerEvent: function() { this.updater = new Ajax.Updater(this.container, this.url, this.options); } }); function $(element) { if (arguments.length > 1) { for (var i = 0, elements = [], length = arguments.length; i < length; i++) elements.push($(arguments[i])); return elements; } if (Object.isString(element)) element = document.getElementById(element); return Element.extend(element); } if (Prototype.BrowserFeatures.XPath) { document._getElementsByXPath = function(expression, parentElement) { var results = []; var query = document.evaluate(expression, $(parentElement) || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0, length = query.snapshotLength; i < length; i++) results.push(Element.extend(query.snapshotItem(i))); return results; }; } /*--------------------------------------------------------------------------*/ if (!window.Node) var Node = { }; if (!Node.ELEMENT_NODE) { // DOM level 2 ECMAScript Language Binding Object.extend(Node, { ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12 }); } (function() { var element = this.Element; this.Element = function(tagName, attributes) { attributes = attributes || { }; tagName = tagName.toLowerCase(); var cache = Element.cache; if (Prototype.Browser.IE && attributes.name) { tagName = '<' + tagName + ' name="' + attributes.name + '">'; delete attributes.name; return Element.writeAttribute(document.createElement(tagName), attributes); } if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); }; Object.extend(this.Element, element || { }); }).call(window); Element.cache = { }; Element.Methods = { visible: function(element) { return $(element).style.display != 'none'; }, toggle: function(element) { element = $(element); Element[Element.visible(element) ? 'hide' : 'show'](element); return element; }, hide: function(element) { $(element).style.display = 'none'; return element; }, show: function(element) { $(element).style.display = ''; return element; }, remove: function(element) { element = $(element); element.parentNode.removeChild(element); return element; }, update: function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) return element.update().insert(content); content = Object.toHTML(content); element.innerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }, replace: function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); else if (!Object.isElement(content)) { content = Object.toHTML(content); var range = element.ownerDocument.createRange(); range.selectNode(element); content.evalScripts.bind(content).defer(); content = range.createContextualFragment(content.stripScripts()); } element.parentNode.replaceChild(content, element); return element; }, insert: function(element, insertions) { element = $(element); if (Object.isString(insertions) || Object.isNumber(insertions) || Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) insertions = {bottom:insertions}; var content, insert, tagName, childNodes; for (var position in insertions) { content = insertions[position]; position = position.toLowerCase(); insert = Element._insertionTranslations[position]; if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { insert(element, content); continue; } content = Object.toHTML(content); tagName = ((position == 'before' || position == 'after') ? element.parentNode : element).tagName.toUpperCase(); childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); if (position == 'top' || position == 'after') childNodes.reverse(); childNodes.each(insert.curry(element)); content.evalScripts.bind(content).defer(); } return element; }, wrap: function(element, wrapper, attributes) { element = $(element); if (Object.isElement(wrapper)) $(wrapper).writeAttribute(attributes || { }); else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); else wrapper = new Element('div', wrapper); if (element.parentNode) element.parentNode.replaceChild(wrapper, element); wrapper.appendChild(element); return wrapper; }, inspect: function(element) { element = $(element); var result = '<' + element.tagName.toLowerCase(); $H({'id': 'id', 'className': 'class'}).each(function(pair) { var property = pair.first(), attribute = pair.last(); var value = (element[property] || '').toString(); if (value) result += ' ' + attribute + '=' + value.inspect(true); }); return result + '>'; }, recursivelyCollect: function(element, property) { element = $(element); var elements = []; while (element = element[property]) if (element.nodeType == 1) elements.push(Element.extend(element)); return elements; }, ancestors: function(element) { return $(element).recursivelyCollect('parentNode'); }, descendants: function(element) { return $(element).select("*"); }, firstDescendant: function(element) { element = $(element).firstChild; while (element && element.nodeType != 1) element = element.nextSibling; return $(element); }, immediateDescendants: function(element) { if (!(element = $(element).firstChild)) return []; while (element && element.nodeType != 1) element = element.nextSibling; if (element) return [element].concat($(element).nextSiblings()); return []; }, previousSiblings: function(element) { return $(element).recursivelyCollect('previousSibling'); }, nextSiblings: function(element) { return $(element).recursivelyCollect('nextSibling'); }, siblings: function(element) { element = $(element); return element.previousSiblings().reverse().concat(element.nextSiblings()); }, match: function(element, selector) { if (Object.isString(selector)) selector = new Selector(selector); return selector.match($(element)); }, up: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(element.parentNode); var ancestors = element.ancestors(); return Object.isNumber(expression) ? ancestors[expression] : Selector.findElement(ancestors, expression, index); }, down: function(element, expression, index) { element = $(element); if (arguments.length == 1) return element.firstDescendant(); return Object.isNumber(expression) ? element.descendants()[expression] : element.select(expression)[index || 0]; }, previous: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); var previousSiblings = element.previousSiblings(); return Object.isNumber(expression) ? previousSiblings[expression] : Selector.findElement(previousSiblings, expression, index); }, next: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); var nextSiblings = element.nextSiblings(); return Object.isNumber(expression) ? nextSiblings[expression] : Selector.findElement(nextSiblings, expression, index); }, select: function() { var args = $A(arguments), element = $(args.shift()); return Selector.findChildElements(element, args); }, adjacent: function() { var args = $A(arguments), element = $(args.shift()); return Selector.findChildElements(element.parentNode, args).without(element); }, identify: function(element) { element = $(element); var id = element.readAttribute('id'), self = arguments.callee; if (id) return id; do { id = 'anonymous_element_' + self.counter++ } while ($(id)); element.writeAttribute('id', id); return id; }, readAttribute: function(element, name) { element = $(element); if (Prototype.Browser.IE) { var t = Element._attributeTranslations.read; if (t.values[name]) return t.values[name](element, name); if (t.names[name]) name = t.names[name]; if (name.include(':')) { return (!element.attributes || !element.attributes[name]) ? null : element.attributes[name].value; } } return element.getAttribute(name); }, writeAttribute: function(element, name, value) { element = $(element); var attributes = { }, t = Element._attributeTranslations.write; if (typeof name == 'object') attributes = name; else attributes[name] = Object.isUndefined(value) ? true : value; for (var attr in attributes) { name = t.names[attr] || attr; value = attributes[attr]; if (t.values[attr]) name = t.values[attr](element, value); if (value === false || value === null) element.removeAttribute(name); else if (value === true) element.setAttribute(name, name); else element.setAttribute(name, value); } return element; }, getHeight: function(element) { return $(element).getDimensions().height; }, getWidth: function(element) { return $(element).getDimensions().width; }, classNames: function(element) { return new Element.ClassNames(element); }, hasClassName: function(element, className) { if (!(element = $(element))) return; var elementClassName = element.className; return (elementClassName.length > 0 && (elementClassName == className || new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); }, addClassName: function(element, className) { if (!(element = $(element))) return; if (!element.hasClassName(className)) element.className += (element.className ? ' ' : '') + className; return element; }, removeClassName: function(element, className) { if (!(element = $(element))) return; element.className = element.className.replace( new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); return element; }, toggleClassName: function(element, className) { if (!(element = $(element))) return; return element[element.hasClassName(className) ? 'removeClassName' : 'addClassName'](className); }, // removes whitespace-only text node children cleanWhitespace: function(element) { element = $(element); var node = element.firstChild; while (node) { var nextNode = node.nextSibling; if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) element.removeChild(node); node = nextNode; } return element; }, empty: function(element) { return $(element).innerHTML.blank(); }, descendantOf: function(element, ancestor) { element = $(element), ancestor = $(ancestor); var originalAncestor = ancestor; if (element.compareDocumentPosition) return (element.compareDocumentPosition(ancestor) & 8) === 8; if (element.sourceIndex && !Prototype.Browser.Opera) { var e = element.sourceIndex, a = ancestor.sourceIndex, nextAncestor = ancestor.nextSibling; if (!nextAncestor) { do { ancestor = ancestor.parentNode; } while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); } if (nextAncestor && nextAncestor.sourceIndex) return (e > a && e < nextAncestor.sourceIndex); } while (element = element.parentNode) if (element == originalAncestor) return true; return false; }, scrollTo: function(element) { element = $(element); var pos = element.cumulativeOffset(); window.scrollTo(pos[0], pos[1]); return element; }, getStyle: function(element, style) { element = $(element); style = style == 'float' ? 'cssFloat' : style.camelize(); var value = element.style[style]; if (!value) { var css = document.defaultView.getComputedStyle(element, null); value = css ? css[style] : null; } if (style == 'opacity') return value ? parseFloat(value) : 1.0; return value == 'auto' ? null : value; }, getOpacity: function(element) { return $(element).getStyle('opacity'); }, setStyle: function(element, styles) { element = $(element); var elementStyle = element.style, match; if (Object.isString(styles)) { element.style.cssText += ';' + styles; return styles.include('opacity') ? element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; } for (var property in styles) if (property == 'opacity') element.setOpacity(styles[property]); else elementStyle[(property == 'float' || property == 'cssFloat') ? (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : property] = styles[property]; return element; }, setOpacity: function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }, getDimensions: function(element) { element = $(element); var display = $(element).getStyle('display'); if (display != 'none' && display != null) // Safari bug return {width: element.offsetWidth, height: element.offsetHeight}; // All *Width and *Height properties give 0 on elements with display none, // so enable the element temporarily var els = element.style; var originalVisibility = els.visibility; var originalPosition = els.position; var originalDisplay = els.display; els.visibility = 'hidden'; els.position = 'absolute'; els.display = 'block'; var originalWidth = element.clientWidth; var originalHeight = element.clientHeight; els.display = originalDisplay; els.position = originalPosition; els.visibility = originalVisibility; return {width: originalWidth, height: originalHeight}; }, makePositioned: function(element) { element = $(element); var pos = Element.getStyle(element, 'position'); if (pos == 'static' || !pos) { element._madePositioned = true; element.style.position = 'relative'; // Opera returns the offset relative to the positioning context, when an // element is position relative but top and left have not been defined if (window.opera) { element.style.top = 0; element.style.left = 0; } } return element; }, undoPositioned: function(element) { element = $(element); if (element._madePositioned) { element._madePositioned = undefined; element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = ''; } return element; }, makeClipping: function(element) { element = $(element); if (element._overflow) return element; element._overflow = Element.getStyle(element, 'overflow') || 'auto'; if (element._overflow !== 'hidden') element.style.overflow = 'hidden'; return element; }, undoClipping: function(element) { element = $(element); if (!element._overflow) return element; element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; element._overflow = null; return element; }, cumulativeOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }, positionedOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { if (element.tagName == 'BODY') break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); return Element._returnOffset(valueL, valueT); }, absolutize: function(element) { element = $(element); if (element.getStyle('position') == 'absolute') return; // Position.prepare(); // To be done manually by Scripty when it needs it. var offsets = element.positionedOffset(); var top = offsets[1]; var left = offsets[0]; var width = element.clientWidth; var height = element.clientHeight; element._originalLeft = left - parseFloat(element.style.left || 0); element._originalTop = top - parseFloat(element.style.top || 0); element._originalWidth = element.style.width; element._originalHeight = element.style.height; element.style.position = 'absolute'; element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.width = width + 'px'; element.style.height = height + 'px'; return element; }, relativize: function(element) { element = $(element); if (element.getStyle('position') == 'relative') return; // Position.prepare(); // To be done manually by Scripty when it needs it. element.style.position = 'relative'; var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.height = element._originalHeight; element.style.width = element._originalWidth; return element; }, cumulativeScrollOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return Element._returnOffset(valueL, valueT); }, getOffsetParent: function(element) { if (element.offsetParent) return $(element.offsetParent); if (element == document.body) return $(element); while ((element = element.parentNode) && element != document.body) if (Element.getStyle(element, 'position') != 'static') return $(element); return $(document.body); }, viewportOffset: function(forElement) { var valueT = 0, valueL = 0; var element = forElement; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; // Safari fix if (element.offsetParent == document.body && Element.getStyle(element, 'position') == 'absolute') break; } while (element = element.offsetParent); element = forElement; do { if (!Prototype.Browser.Opera || element.tagName == 'BODY') { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return Element._returnOffset(valueL, valueT); }, clonePosition: function(element, source) { var options = Object.extend({ setLeft: true, setTop: true, setWidth: true, setHeight: true, offsetTop: 0, offsetLeft: 0 }, arguments[2] || { }); // find page position of source source = $(source); var p = source.viewportOffset(); // find coordinate system to use element = $(element); var delta = [0, 0]; var parent = null; // delta [0,0] will do fine with position: fixed elements, // position:absolute needs offsetParent deltas if (Element.getStyle(element, 'position') == 'absolute') { parent = element.getOffsetParent(); delta = parent.viewportOffset(); } // correct by body offsets (fixes Safari) if (parent == document.body) { delta[0] -= document.body.offsetLeft; delta[1] -= document.body.offsetTop; } // set position if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; if (options.setWidth) element.style.width = source.offsetWidth + 'px'; if (options.setHeight) element.style.height = source.offsetHeight + 'px'; return element; } }; Element.Methods.identify.counter = 1; Object.extend(Element.Methods, { getElementsBySelector: Element.Methods.select, childElements: Element.Methods.immediateDescendants }); Element._attributeTranslations = { write: { names: { className: 'class', htmlFor: 'for' }, values: { } } }; if (Prototype.Browser.Opera) { Element.Methods.getStyle = Element.Methods.getStyle.wrap( function(proceed, element, style) { switch (style) { case 'left': case 'top': case 'right': case 'bottom': if (proceed(element, 'position') === 'static') return null; case 'height': case 'width': // returns '0px' for hidden elements; we want it to return null if (!Element.visible(element)) return null; // returns the border-box dimensions rather than the content-box // dimensions, so we subtract padding and borders from the value var dim = parseInt(proceed(element, style), 10); if (dim !== element['offset' + style.capitalize()]) return dim + 'px'; var properties; if (style === 'height') { properties = ['border-top-width', 'padding-top', 'padding-bottom', 'border-bottom-width']; } else { properties = ['border-left-width', 'padding-left', 'padding-right', 'border-right-width']; } return properties.inject(dim, function(memo, property) { var val = proceed(element, property); return val === null ? memo : memo - parseInt(val, 10); }) + 'px'; default: return proceed(element, style); } } ); Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( function(proceed, element, attribute) { if (attribute === 'title') return element.title; return proceed(element, attribute); } ); } else if (Prototype.Browser.IE) { // IE doesn't report offsets correctly for static elements, so we change them // to "relative" to get the values, then change them back. Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( function(proceed, element) { element = $(element); var position = element.getStyle('position'); if (position !== 'static') return proceed(element); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); $w('positionedOffset viewportOffset').each(function(method) { Element.Methods[method] = Element.Methods[method].wrap( function(proceed, element) { element = $(element); var position = element.getStyle('position'); if (position !== 'static') return proceed(element); // Trigger hasLayout on the offset parent so that IE6 reports // accurate offsetTop and offsetLeft values for position: fixed. var offsetParent = element.getOffsetParent(); if (offsetParent && offsetParent.getStyle('position') === 'fixed') offsetParent.setStyle({ zoom: 1 }); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); }); Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); var value = element.style[style]; if (!value && element.currentStyle) value = element.currentStyle[style]; if (style == 'opacity') { if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) if (value[1]) return parseFloat(value[1]) / 100; return 1.0; } if (value == 'auto') { if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) return element['offset' + style.capitalize()] + 'px'; return null; } return value; }; Element.Methods.setOpacity = function(element, value) { function stripAlpha(filter){ return filter.replace(/alpha\([^\)]*\)/gi,''); } element = $(element); var currentStyle = element.currentStyle; if ((currentStyle && !currentStyle.hasLayout) || (!currentStyle && element.style.zoom == 'normal')) element.style.zoom = 1; var filter = element.getStyle('filter'), style = element.style; if (value == 1 || value === '') { (filter = stripAlpha(filter)) ? style.filter = filter : style.removeAttribute('filter'); return element; } else if (value < 0.00001) value = 0; style.filter = stripAlpha(filter) + 'alpha(opacity=' + (value * 100) + ')'; return element; }; Element._attributeTranslations = { read: { names: { 'class': 'className', 'for': 'htmlFor' }, values: { _getAttr: function(element, attribute) { return element.getAttribute(attribute, 2); }, _getAttrNode: function(element, attribute) { var node = element.getAttributeNode(attribute); return node ? node.value : ""; }, _getEv: function(element, attribute) { attribute = element.getAttribute(attribute); return attribute ? attribute.toString().slice(23, -2) : null; }, _flag: function(element, attribute) { return $(element).hasAttribute(attribute) ? attribute : null; }, style: function(element) { return element.style.cssText.toLowerCase(); }, title: function(element) { return element.title; } } } }; Element._attributeTranslations.write = { names: Object.extend({ cellpadding: 'cellPadding', cellspacing: 'cellSpacing' }, Element._attributeTranslations.read.names), values: { checked: function(element, value) { element.checked = !!value; }, style: function(element, value) { element.style.cssText = value ? value : ''; } } }; Element._attributeTranslations.has = {}; $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + 'encType maxLength readOnly longDesc').each(function(attr) { Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; Element._attributeTranslations.has[attr.toLowerCase()] = attr; }); (function(v) { Object.extend(v, { href: v._getAttr, src: v._getAttr, type: v._getAttr, action: v._getAttrNode, disabled: v._flag, checked: v._flag, readonly: v._flag, multiple: v._flag, onload: v._getEv, onunload: v._getEv, onclick: v._getEv, ondblclick: v._getEv, onmousedown: v._getEv, onmouseup: v._getEv, onmouseover: v._getEv, onmousemove: v._getEv, onmouseout: v._getEv, onfocus: v._getEv, onblur: v._getEv, onkeypress: v._getEv, onkeydown: v._getEv, onkeyup: v._getEv, onsubmit: v._getEv, onreset: v._getEv, onselect: v._getEv, onchange: v._getEv }); })(Element._attributeTranslations.read.values); } else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1) ? 0.999999 : (value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }; } else if (Prototype.Browser.WebKit) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; if (value == 1) if(element.tagName == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch (e) { } return element; }; // Safari returns margins on body which is incorrect if the child is absolutely // positioned. For performance reasons, redefine Element#cumulativeOffset for // KHTML/WebKit only. Element.Methods.cumulativeOffset = function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body) if (Element.getStyle(element, 'position') == 'absolute') break; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }; } if (Prototype.Browser.IE || Prototype.Browser.Opera) { // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements Element.Methods.update = function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) return element.update().insert(content); content = Object.toHTML(content); var tagName = element.tagName.toUpperCase(); if (tagName in Element._insertionTranslations.tags) { $A(element.childNodes).each(function(node) { element.removeChild(node) }); Element._getContentFromAnonymousElement(tagName, content.stripScripts()) .each(function(node) { element.appendChild(node) }); } else element.innerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }; } if ('outerHTML' in document.createElement('div')) { Element.Methods.replace = function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { element.parentNode.replaceChild(content, element); return element; } content = Object.toHTML(content); var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); if (Element._insertionTranslations.tags[tagName]) { var nextSibling = element.next(); var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); parent.removeChild(element); if (nextSibling) fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); else fragments.each(function(node) { parent.appendChild(node) }); } else element.outerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }; } Element._returnOffset = function(l, t) { var result = [l, t]; result.left = l; result.top = t; return result; }; Element._getContentFromAnonymousElement = function(tagName, html) { var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; if (t) { div.innerHTML = t[0] + html + t[1]; t[2].times(function() { div = div.firstChild }); } else div.innerHTML = html; return $A(div.childNodes); }; Element._insertionTranslations = { before: function(element, node) { element.parentNode.insertBefore(node, element); }, top: function(element, node) { element.insertBefore(node, element.firstChild); }, bottom: function(element, node) { element.appendChild(node); }, after: function(element, node) { element.parentNode.insertBefore(node, element.nextSibling); }, tags: { TABLE: ['', '
', 1], TBODY: ['', '
', 2], TR: ['', '
', 3], TD: ['
', '
', 4], SELECT: ['', 1] } }; (function() { Object.extend(this.tags, { THEAD: this.tags.TBODY, TFOOT: this.tags.TBODY, TH: this.tags.TD }); }).call(Element._insertionTranslations); Element.Methods.Simulated = { hasAttribute: function(element, attribute) { attribute = Element._attributeTranslations.has[attribute] || attribute; var node = $(element).getAttributeNode(attribute); return node && node.specified; } }; Element.Methods.ByTag = { }; Object.extend(Element, Element.Methods); if (!Prototype.BrowserFeatures.ElementExtensions && document.createElement('div').__proto__) { window.HTMLElement = { }; window.HTMLElement.prototype = document.createElement('div').__proto__; Prototype.BrowserFeatures.ElementExtensions = true; } Element.extend = (function() { if (Prototype.BrowserFeatures.SpecificElementExtensions) return Prototype.K; var Methods = { }, ByTag = Element.Methods.ByTag; var extend = Object.extend(function(element) { if (!element || element._extendedByPrototype || element.nodeType != 1 || element == window) return element; var methods = Object.clone(Methods), tagName = element.tagName, property, value; // extend methods for specific tags if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); for (property in methods) { value = methods[property]; if (Object.isFunction(value) && !(property in element)) element[property] = value.methodize(); } element._extendedByPrototype = Prototype.emptyFunction; return element; }, { refresh: function() { // extend methods for all tags (Safari doesn't need this) if (!Prototype.BrowserFeatures.ElementExtensions) { Object.extend(Methods, Element.Methods); Object.extend(Methods, Element.Methods.Simulated); } } }); extend.refresh(); return extend; })(); Element.hasAttribute = function(element, attribute) { if (element.hasAttribute) return element.hasAttribute(attribute); return Element.Methods.Simulated.hasAttribute(element, attribute); }; Element.addMethods = function(methods) { var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; if (!methods) { Object.extend(Form, Form.Methods); Object.extend(Form.Element, Form.Element.Methods); Object.extend(Element.Methods.ByTag, { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), "TEXTAREA": Object.clone(Form.Element.Methods) }); } if (arguments.length == 2) { var tagName = methods; methods = arguments[1]; } if (!tagName) Object.extend(Element.Methods, methods || { }); else { if (Object.isArray(tagName)) tagName.each(extend); else extend(tagName); } function extend(tagName) { tagName = tagName.toUpperCase(); if (!Element.Methods.ByTag[tagName]) Element.Methods.ByTag[tagName] = { }; Object.extend(Element.Methods.ByTag[tagName], methods); } function copy(methods, destination, onlyIfAbsent) { onlyIfAbsent = onlyIfAbsent || false; for (var property in methods) { var value = methods[property]; if (!Object.isFunction(value)) continue; if (!onlyIfAbsent || !(property in destination)) destination[property] = value.methodize(); } } function findDOMClass(tagName) { var klass; var trans = { "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": "FrameSet", "IFRAME": "IFrame" }; if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName.capitalize() + 'Element'; if (window[klass]) return window[klass]; window[klass] = { }; window[klass].prototype = document.createElement(tagName).__proto__; return window[klass]; } if (F.ElementExtensions) { copy(Element.Methods, HTMLElement.prototype); copy(Element.Methods.Simulated, HTMLElement.prototype, true); } if (F.SpecificElementExtensions) { for (var tag in Element.Methods.ByTag) { var klass = findDOMClass(tag); if (Object.isUndefined(klass)) continue; copy(T[tag], klass.prototype); } } Object.extend(Element, Element.Methods); delete Element.ByTag; if (Element.extend.refresh) Element.extend.refresh(); Element.cache = { }; }; document.viewport = { getDimensions: function() { var dimensions = { }; var B = Prototype.Browser; $w('width height').each(function(d) { var D = d.capitalize(); dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] : (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D]; }); return dimensions; }, getWidth: function() { return this.getDimensions().width; }, getHeight: function() { return this.getDimensions().height; }, getScrollOffsets: function() { return Element._returnOffset( window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; /* Portions of the Selector class are derived from Jack Slocum’s DomQuery, * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style * license. Please see http://www.yui-ext.com/ for more information. */ var Selector = Class.create({ initialize: function(expression) { this.expression = expression.strip(); this.compileMatcher(); }, shouldUseXPath: function() { if (!Prototype.BrowserFeatures.XPath) return false; var e = this.expression; // Safari 3 chokes on :*-of-type and :empty if (Prototype.Browser.WebKit && (e.include("-of-type") || e.include(":empty"))) return false; // XPath can't do namespaced attributes, nor can it read // the "checked" property from DOM nodes if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) return false; return true; }, compileMatcher: function() { if (this.shouldUseXPath()) return this.compileXPathMatcher(); var e = this.expression, ps = Selector.patterns, h = Selector.handlers, c = Selector.criteria, le, p, m; if (Selector._cache[e]) { this.matcher = Selector._cache[e]; return; } this.matcher = ["this.matcher = function(root) {", "var r = root, h = Selector.handlers, c = false, n;"]; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in ps) { p = ps[i]; if (m = e.match(p)) { this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : new Template(c[i]).evaluate(m)); e = e.replace(m[0], ''); break; } } } this.matcher.push("return h.unique(n);\n}"); eval(this.matcher.join('\n')); Selector._cache[this.expression] = this.matcher; }, compileXPathMatcher: function() { var e = this.expression, ps = Selector.patterns, x = Selector.xpath, le, m; if (Selector._cache[e]) { this.xpath = Selector._cache[e]; return; } this.matcher = ['.//*']; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in ps) { if (m = e.match(ps[i])) { this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m)); e = e.replace(m[0], ''); break; } } } this.xpath = this.matcher.join(''); Selector._cache[this.expression] = this.xpath; }, findElements: function(root) { root = root || document; if (this.xpath) return document._getElementsByXPath(this.xpath, root); return this.matcher(root); }, match: function(element) { this.tokens = []; var e = this.expression, ps = Selector.patterns, as = Selector.assertions; var le, p, m; while (e && le !== e && (/\S/).test(e)) { le = e; for (var i in ps) { p = ps[i]; if (m = e.match(p)) { // use the Selector.assertions methods unless the selector // is too complex. if (as[i]) { this.tokens.push([i, Object.clone(m)]); e = e.replace(m[0], ''); } else { // reluctantly do a document-wide search // and look for a match in the array return this.findElements(document).include(element); } } } } var match = true, name, matches; for (var i = 0, token; token = this.tokens[i]; i++) { name = token[0], matches = token[1]; if (!Selector.assertions[name](element, matches)) { match = false; break; } } return match; }, toString: function() { return this.expression; }, inspect: function() { return "#"; } }); Object.extend(Selector, { _cache: { }, xpath: { descendant: "//*", child: "/*", adjacent: "/following-sibling::*[1]", laterSibling: '/following-sibling::*', tagName: function(m) { if (m[1] == '*') return ''; return "[local-name()='" + m[1].toLowerCase() + "' or local-name()='" + m[1].toUpperCase() + "']"; }, className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", id: "[@id='#{1}']", attrPresence: function(m) { m[1] = m[1].toLowerCase(); return new Template("[@#{1}]").evaluate(m); }, attr: function(m) { m[1] = m[1].toLowerCase(); m[3] = m[5] || m[6]; return new Template(Selector.xpath.operators[m[2]]).evaluate(m); }, pseudo: function(m) { var h = Selector.xpath.pseudos[m[1]]; if (!h) return ''; if (Object.isFunction(h)) return h(m); return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); }, operators: { '=': "[@#{1}='#{3}']", '!=': "[@#{1}!='#{3}']", '^=': "[starts-with(@#{1}, '#{3}')]", '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", '*=': "[contains(@#{1}, '#{3}')]", '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" }, pseudos: { 'first-child': '[not(preceding-sibling::*)]', 'last-child': '[not(following-sibling::*)]', 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", 'checked': "[@checked]", 'disabled': "[@disabled]", 'enabled': "[not(@disabled)]", 'not': function(m) { var e = m[6], p = Selector.patterns, x = Selector.xpath, le, v; var exclusion = []; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in p) { if (m = e.match(p[i])) { v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); exclusion.push("(" + v.substring(1, v.length - 1) + ")"); e = e.replace(m[0], ''); break; } } } return "[not(" + exclusion.join(" and ") + ")]"; }, 'nth-child': function(m) { return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); }, 'nth-last-child': function(m) { return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); }, 'nth-of-type': function(m) { return Selector.xpath.pseudos.nth("position() ", m); }, 'nth-last-of-type': function(m) { return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); }, 'first-of-type': function(m) { m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); }, 'last-of-type': function(m) { m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); }, 'only-of-type': function(m) { var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); }, nth: function(fragment, m) { var mm, formula = m[6], predicate; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; if (mm = formula.match(/^(\d+)$/)) // digit only return '[' + fragment + "= " + mm[1] + ']'; if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b if (mm[1] == "-") mm[1] = -1; var a = mm[1] ? Number(mm[1]) : 1; var b = mm[2] ? Number(mm[2]) : 0; predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + "((#{fragment} - #{b}) div #{a} >= 0)]"; return new Template(predicate).evaluate({ fragment: fragment, a: a, b: b }); } } } }, criteria: { tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', className: 'n = h.className(n, r, "#{1}", c); c = false;', id: 'n = h.id(n, r, "#{1}", c); c = false;', attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', attr: function(m) { m[3] = (m[5] || m[6]); return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); }, pseudo: function(m) { if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); }, descendant: 'c = "descendant";', child: 'c = "child";', adjacent: 'c = "adjacent";', laterSibling: 'c = "laterSibling";' }, patterns: { // combinators must be listed first // (and descendant needs to be last combinator) laterSibling: /^\s*~\s*/, child: /^\s*>\s*/, adjacent: /^\s*\+\s*/, descendant: /^\s/, // selectors follow tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, id: /^#([\w\-\*]+)(\b|$)/, className: /^\.([\w\-\*]+)(\b|$)/, pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, attrPresence: /^\[([\w]+)\]/, attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ }, // for Selector.match and Element#match assertions: { tagName: function(element, matches) { return matches[1].toUpperCase() == element.tagName.toUpperCase(); }, className: function(element, matches) { return Element.hasClassName(element, matches[1]); }, id: function(element, matches) { return element.id === matches[1]; }, attrPresence: function(element, matches) { return Element.hasAttribute(element, matches[1]); }, attr: function(element, matches) { var nodeValue = Element.readAttribute(element, matches[1]); return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); } }, handlers: { // UTILITY FUNCTIONS // joins two collections concat: function(a, b) { for (var i = 0, node; node = b[i]; i++) a.push(node); return a; }, // marks an array of nodes for counting mark: function(nodes) { var _true = Prototype.emptyFunction; for (var i = 0, node; node = nodes[i]; i++) node._countedByPrototype = _true; return nodes; }, unmark: function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node._countedByPrototype = undefined; return nodes; }, // mark each child node with its position (for nth calls) // "ofType" flag indicates whether we're indexing for nth-of-type // rather than nth-child index: function(parentNode, reverse, ofType) { parentNode._countedByPrototype = Prototype.emptyFunction; if (reverse) { for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { var node = nodes[i]; if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; } } else { for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; } }, // filters out duplicates and extends all nodes unique: function(nodes) { if (nodes.length == 0) return nodes; var results = [], n; for (var i = 0, l = nodes.length; i < l; i++) if (!(n = nodes[i])._countedByPrototype) { n._countedByPrototype = Prototype.emptyFunction; results.push(Element.extend(n)); } return Selector.handlers.unmark(results); }, // COMBINATOR FUNCTIONS descendant: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) h.concat(results, node.getElementsByTagName('*')); return results; }, child: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) { for (var j = 0, child; child = node.childNodes[j]; j++) if (child.nodeType == 1 && child.tagName != '!') results.push(child); } return results; }, adjacent: function(nodes) { for (var i = 0, results = [], node; node = nodes[i]; i++) { var next = this.nextElementSibling(node); if (next) results.push(next); } return results; }, laterSibling: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) h.concat(results, Element.nextSiblings(node)); return results; }, nextElementSibling: function(node) { while (node = node.nextSibling) if (node.nodeType == 1) return node; return null; }, previousElementSibling: function(node) { while (node = node.previousSibling) if (node.nodeType == 1) return node; return null; }, // TOKEN FUNCTIONS tagName: function(nodes, root, tagName, combinator) { var uTagName = tagName.toUpperCase(); var results = [], h = Selector.handlers; if (nodes) { if (combinator) { // fastlane for ordinary descendant combinators if (combinator == "descendant") { for (var i = 0, node; node = nodes[i]; i++) h.concat(results, node.getElementsByTagName(tagName)); return results; } else nodes = this[combinator](nodes); if (tagName == "*") return nodes; } for (var i = 0, node; node = nodes[i]; i++) if (node.tagName.toUpperCase() === uTagName) results.push(node); return results; } else return root.getElementsByTagName(tagName); }, id: function(nodes, root, id, combinator) { var targetNode = $(id), h = Selector.handlers; if (!targetNode) return []; if (!nodes && root == document) return [targetNode]; if (nodes) { if (combinator) { if (combinator == 'child') { for (var i = 0, node; node = nodes[i]; i++) if (targetNode.parentNode == node) return [targetNode]; } else if (combinator == 'descendant') { for (var i = 0, node; node = nodes[i]; i++) if (Element.descendantOf(targetNode, node)) return [targetNode]; } else if (combinator == 'adjacent') { for (var i = 0, node; node = nodes[i]; i++) if (Selector.handlers.previousElementSibling(targetNode) == node) return [targetNode]; } else nodes = h[combinator](nodes); } for (var i = 0, node; node = nodes[i]; i++) if (node == targetNode) return [targetNode]; return []; } return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; }, className: function(nodes, root, className, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); return Selector.handlers.byClassName(nodes, root, className); }, byClassName: function(nodes, root, className) { if (!nodes) nodes = Selector.handlers.descendant([root]); var needle = ' ' + className + ' '; for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { nodeClassName = node.className; if (nodeClassName.length == 0) continue; if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) results.push(node); } return results; }, attrPresence: function(nodes, root, attr, combinator) { if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); var results = []; for (var i = 0, node; node = nodes[i]; i++) if (Element.hasAttribute(node, attr)) results.push(node); return results; }, attr: function(nodes, root, attr, value, operator, combinator) { if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); var handler = Selector.operators[operator], results = []; for (var i = 0, node; node = nodes[i]; i++) { var nodeValue = Element.readAttribute(node, attr); if (nodeValue === null) continue; if (handler(nodeValue, value)) results.push(node); } return results; }, pseudo: function(nodes, name, value, root, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); if (!nodes) nodes = root.getElementsByTagName("*"); return Selector.pseudos[name](nodes, value, root); } }, pseudos: { 'first-child': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.previousElementSibling(node)) continue; results.push(node); } return results; }, 'last-child': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.nextElementSibling(node)) continue; results.push(node); } return results; }, 'only-child': function(nodes, value, root) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) results.push(node); return results; }, 'nth-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root); }, 'nth-last-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true); }, 'nth-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, false, true); }, 'nth-last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true, true); }, 'first-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, false, true); }, 'last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, true, true); }, 'only-of-type': function(nodes, formula, root) { var p = Selector.pseudos; return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); }, // handles the an+b logic getIndices: function(a, b, total) { if (a == 0) return b > 0 ? [b] : []; return $R(1, total).inject([], function(memo, i) { if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); return memo; }); }, // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type nth: function(nodes, formula, root, reverse, ofType) { if (nodes.length == 0) return []; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; var h = Selector.handlers, results = [], indexed = [], m; h.mark(nodes); for (var i = 0, node; node = nodes[i]; i++) { if (!node.parentNode._countedByPrototype) { h.index(node.parentNode, reverse, ofType); indexed.push(node.parentNode); } } if (formula.match(/^\d+$/)) { // just a number formula = Number(formula); for (var i = 0, node; node = nodes[i]; i++) if (node.nodeIndex == formula) results.push(node); } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b if (m[1] == "-") m[1] = -1; var a = m[1] ? Number(m[1]) : 1; var b = m[2] ? Number(m[2]) : 0; var indices = Selector.pseudos.getIndices(a, b, nodes.length); for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { for (var j = 0; j < l; j++) if (node.nodeIndex == indices[j]) results.push(node); } } h.unmark(nodes); h.unmark(indexed); return results; }, 'empty': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { // IE treats comments as element nodes if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; results.push(node); } return results; }, 'not': function(nodes, selector, root) { var h = Selector.handlers, selectorType, m; var exclusions = new Selector(selector).findElements(root); h.mark(exclusions); for (var i = 0, results = [], node; node = nodes[i]; i++) if (!node._countedByPrototype) results.push(node); h.unmark(exclusions); return results; }, 'enabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (!node.disabled) results.push(node); return results; }, 'disabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (node.disabled) results.push(node); return results; }, 'checked': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (node.checked) results.push(node); return results; } }, operators: { '=': function(nv, v) { return nv == v; }, '!=': function(nv, v) { return nv != v; }, '^=': function(nv, v) { return nv.startsWith(v); }, '$=': function(nv, v) { return nv.endsWith(v); }, '*=': function(nv, v) { return nv.include(v); }, '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } }, split: function(expression) { var expressions = []; expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { expressions.push(m[1].strip()); }); return expressions; }, matchElements: function(elements, expression) { var matches = $$(expression), h = Selector.handlers; h.mark(matches); for (var i = 0, results = [], element; element = elements[i]; i++) if (element._countedByPrototype) results.push(element); h.unmark(matches); return results; }, findElement: function(elements, expression, index) { if (Object.isNumber(expression)) { index = expression; expression = false; } return Selector.matchElements(elements, expression || '*')[index || 0]; }, findChildElements: function(element, expressions) { expressions = Selector.split(expressions.join(',')); var results = [], h = Selector.handlers; for (var i = 0, l = expressions.length, selector; i < l; i++) { selector = new Selector(expressions[i].strip()); h.concat(results, selector.findElements(element)); } return (l > 1) ? h.unique(results) : results; } }); if (Prototype.Browser.IE) { Object.extend(Selector.handlers, { // IE returns comment nodes on getElementsByTagName("*"). // Filter them out. concat: function(a, b) { for (var i = 0, node; node = b[i]; i++) if (node.tagName !== "!") a.push(node); return a; }, // IE improperly serializes _countedByPrototype in (inner|outer)HTML. unmark: function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node.removeAttribute('_countedByPrototype'); return nodes; } }); } function $$() { return Selector.findChildElements(document, $A(arguments)); } var Form = { reset: function(form) { $(form).reset(); return form; }, serializeElements: function(elements, options) { if (typeof options != 'object') options = { hash: !!options }; else if (Object.isUndefined(options.hash)) options.hash = true; var key, value, submitted = false, submit = options.submit; var data = elements.inject({ }, function(result, element) { if (!element.disabled && element.name) { key = element.name; value = $(element).getValue(); if (value != null && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true)))) { if (key in result) { // a key is already present; construct an array of values if (!Object.isArray(result[key])) result[key] = [result[key]]; result[key].push(value); } else result[key] = value; } } return result; }); return options.hash ? data : Object.toQueryString(data); } }; Form.Methods = { serialize: function(form, options) { return Form.serializeElements(Form.getElements(form), options); }, getElements: function(form) { return $A($(form).getElementsByTagName('*')).inject([], function(elements, child) { if (Form.Element.Serializers[child.tagName.toLowerCase()]) elements.push(Element.extend(child)); return elements; } ); }, getInputs: function(form, typeName, name) { form = $(form); var inputs = form.getElementsByTagName('input'); if (!typeName && !name) return $A(inputs).map(Element.extend); for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { var input = inputs[i]; if ((typeName && input.type != typeName) || (name && input.name != name)) continue; matchingInputs.push(Element.extend(input)); } return matchingInputs; }, disable: function(form) { form = $(form); Form.getElements(form).invoke('disable'); return form; }, enable: function(form) { form = $(form); Form.getElements(form).invoke('enable'); return form; }, findFirstElement: function(form) { var elements = $(form).getElements().findAll(function(element) { return 'hidden' != element.type && !element.disabled; }); var firstByIndex = elements.findAll(function(element) { return element.hasAttribute('tabIndex') && element.tabIndex >= 0; }).sortBy(function(element) { return element.tabIndex }).first(); return firstByIndex ? firstByIndex : elements.find(function(element) { return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); }); }, focusFirstElement: function(form) { form = $(form); form.findFirstElement().activate(); return form; }, request: function(form, options) { form = $(form), options = Object.clone(options || { }); var params = options.parameters, action = form.readAttribute('action') || ''; if (action.blank()) action = window.location.href; options.parameters = form.serialize(true); if (params) { if (Object.isString(params)) params = params.toQueryParams(); Object.extend(options.parameters, params); } if (form.hasAttribute('method') && !options.method) options.method = form.method; return new Ajax.Request(action, options); } }; /*--------------------------------------------------------------------------*/ Form.Element = { focus: function(element) { $(element).focus(); return element; }, select: function(element) { $(element).select(); return element; } }; Form.Element.Methods = { serialize: function(element) { element = $(element); if (!element.disabled && element.name) { var value = element.getValue(); if (value != undefined) { var pair = { }; pair[element.name] = value; return Object.toQueryString(pair); } } return ''; }, getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); return Form.Element.Serializers[method](element); }, setValue: function(element, value) { element = $(element); var method = element.tagName.toLowerCase(); Form.Element.Serializers[method](element, value); return element; }, clear: function(element) { $(element).value = ''; return element; }, present: function(element) { return $(element).value != ''; }, activate: function(element) { element = $(element); try { element.focus(); if (element.select && (element.tagName.toLowerCase() != 'input' || !['button', 'reset', 'submit'].include(element.type))) element.select(); } catch (e) { } return element; }, disable: function(element) { element = $(element); element.blur(); element.disabled = true; return element; }, enable: function(element) { element = $(element); element.disabled = false; return element; } }; /*--------------------------------------------------------------------------*/ var Field = Form.Element; var $F = Form.Element.Methods.getValue; /*--------------------------------------------------------------------------*/ Form.Element.Serializers = { input: function(element, value) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element, value); default: return Form.Element.Serializers.textarea(element, value); } }, inputSelector: function(element, value) { if (Object.isUndefined(value)) return element.checked ? element.value : null; else element.checked = !!value; }, textarea: function(element, value) { if (Object.isUndefined(value)) return element.value; else element.value = value; }, select: function(element, index) { if (Object.isUndefined(index)) return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); else { var opt, value, single = !Object.isArray(index); for (var i = 0, length = element.length; i < length; i++) { opt = element.options[i]; value = this.optionValue(opt); if (single) { if (value == index) { opt.selected = true; return; } } else opt.selected = index.include(value); } } }, selectOne: function(element) { var index = element.selectedIndex; return index >= 0 ? this.optionValue(element.options[index]) : null; }, selectMany: function(element) { var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; if (opt.selected) values.push(this.optionValue(opt)); } return values; }, optionValue: function(opt) { // extend element because hasAttribute may not be native return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } }; /*--------------------------------------------------------------------------*/ Abstract.TimedObserver = Class.create(PeriodicalExecuter, { initialize: function($super, element, frequency, callback) { $super(callback, frequency); this.element = $(element); this.lastValue = this.getValue(); }, execute: function() { var value = this.getValue(); if (Object.isString(this.lastValue) && Object.isString(value) ? this.lastValue != value : String(this.lastValue) != String(value)) { this.callback(this.element, value); this.lastValue = value; } } }); Form.Element.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.serialize(this.element); } }); /*--------------------------------------------------------------------------*/ Abstract.EventObserver = Class.create({ initialize: function(element, callback) { this.element = $(element); this.callback = callback; this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form') this.registerFormCallbacks(); else this.registerCallback(this.element); }, onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { this.callback(this.element, value); this.lastValue = value; } }, registerFormCallbacks: function() { Form.getElements(this.element).each(this.registerCallback, this); }, registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': Event.observe(element, 'click', this.onElementEvent.bind(this)); break; default: Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } } } }); Form.Element.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.serialize(this.element); } }); if (!window.Event) var Event = { }; Object.extend(Event, { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_RETURN: 13, KEY_ESC: 27, KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40, KEY_DELETE: 46, KEY_HOME: 36, KEY_END: 35, KEY_PAGEUP: 33, KEY_PAGEDOWN: 34, KEY_INSERT: 45, cache: { }, relatedTarget: function(event) { var element; switch(event.type) { case 'mouseover': element = event.fromElement; break; case 'mouseout': element = event.toElement; break; default: return null; } return Element.extend(element); } }); Event.Methods = (function() { var isButton; if (Prototype.Browser.IE) { var buttonMap = { 0: 1, 1: 4, 2: 2 }; isButton = function(event, code) { return event.button == buttonMap[code]; }; } else if (Prototype.Browser.WebKit) { isButton = function(event, code) { switch (code) { case 0: return event.which == 1 && !event.metaKey; case 1: return event.which == 1 && event.metaKey; default: return false; } }; } else { isButton = function(event, code) { return event.which ? (event.which === code + 1) : (event.button === code); }; } return { isLeftClick: function(event) { return isButton(event, 0) }, isMiddleClick: function(event) { return isButton(event, 1) }, isRightClick: function(event) { return isButton(event, 2) }, element: function(event) { var node = Event.extend(event).target; return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); }, findElement: function(event, expression) { var element = Event.element(event); if (!expression) return element; var elements = [element].concat(element.ancestors()); return Selector.findElement(elements, expression, 0); }, pointer: function(event) { return { x: event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)), y: event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) }; }, pointerX: function(event) { return Event.pointer(event).x }, pointerY: function(event) { return Event.pointer(event).y }, stop: function(event) { Event.extend(event); event.preventDefault(); event.stopPropagation(); event.stopped = true; } }; })(); Event.extend = (function() { var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { m[name] = Event.Methods[name].methodize(); return m; }); if (Prototype.Browser.IE) { Object.extend(methods, { stopPropagation: function() { this.cancelBubble = true }, preventDefault: function() { this.returnValue = false }, inspect: function() { return "[object Event]" } }); return function(event) { if (!event) return false; if (event._extendedByPrototype) return event; event._extendedByPrototype = Prototype.emptyFunction; var pointer = Event.pointer(event); Object.extend(event, { target: event.srcElement, relatedTarget: Event.relatedTarget(event), pageX: pointer.x, pageY: pointer.y }); return Object.extend(event, methods); }; } else { Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; Object.extend(Event.prototype, methods); return Prototype.K; } })(); Object.extend(Event, (function() { var cache = Event.cache; function getEventID(element) { if (element._prototypeEventID) return element._prototypeEventID[0]; arguments.callee.id = arguments.callee.id || 1; return element._prototypeEventID = [++arguments.callee.id]; } function getDOMEventName(eventName) { if (eventName && eventName.include(':')) return "dataavailable"; return eventName; } function getCacheForID(id) { return cache[id] = cache[id] || { }; } function getWrappersForEventName(id, eventName) { var c = getCacheForID(id); return c[eventName] = c[eventName] || []; } function createWrapper(element, eventName, handler) { var id = getEventID(element); var c = getWrappersForEventName(id, eventName); if (c.pluck("handler").include(handler)) return false; var wrapper = function(event) { if (!Event || !Event.extend || (event.eventName && event.eventName != eventName)) return false; Event.extend(event); handler.call(element, event); }; wrapper.handler = handler; c.push(wrapper); return wrapper; } function findWrapper(id, eventName, handler) { var c = getWrappersForEventName(id, eventName); return c.find(function(wrapper) { return wrapper.handler == handler }); } function destroyWrapper(id, eventName, handler) { var c = getCacheForID(id); if (!c[eventName]) return false; c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); } function destroyCache() { for (var id in cache) for (var eventName in cache[id]) cache[id][eventName] = null; } if (window.attachEvent) { window.attachEvent("onunload", destroyCache); } return { observe: function(element, eventName, handler) { element = $(element); var name = getDOMEventName(eventName); var wrapper = createWrapper(element, eventName, handler); if (!wrapper) return element; if (element.addEventListener) { element.addEventListener(name, wrapper, false); } else { element.attachEvent("on" + name, wrapper); } return element; }, stopObserving: function(element, eventName, handler) { element = $(element); var id = getEventID(element), name = getDOMEventName(eventName); if (!handler && eventName) { getWrappersForEventName(id, eventName).each(function(wrapper) { element.stopObserving(eventName, wrapper.handler); }); return element; } else if (!eventName) { Object.keys(getCacheForID(id)).each(function(eventName) { element.stopObserving(eventName); }); return element; } var wrapper = findWrapper(id, eventName, handler); if (!wrapper) return element; if (element.removeEventListener) { element.removeEventListener(name, wrapper, false); } else { element.detachEvent("on" + name, wrapper); } destroyWrapper(id, eventName, handler); return element; }, fire: function(element, eventName, memo) { element = $(element); if (element == document && document.createEvent && !element.dispatchEvent) element = document.documentElement; var event; if (document.createEvent) { event = document.createEvent("HTMLEvents"); event.initEvent("dataavailable", true, true); } else { event = document.createEventObject(); event.eventType = "ondataavailable"; } event.eventName = eventName; event.memo = memo || { }; if (document.createEvent) { element.dispatchEvent(event); } else { element.fireEvent(event.eventType, event); } return Event.extend(event); } }; })()); Object.extend(Event, Event.Methods); Element.addMethods({ fire: Event.fire, observe: Event.observe, stopObserving: Event.stopObserving }); Object.extend(document, { fire: Element.Methods.fire.methodize(), observe: Element.Methods.observe.methodize(), stopObserving: Element.Methods.stopObserving.methodize(), loaded: false }); (function() { /* Support for the DOMContentLoaded event is based on work by Dan Webb, Matthias Miller, Dean Edwards and John Resig. */ var timer; function fireContentLoadedEvent() { if (document.loaded) return; if (timer) window.clearInterval(timer); document.fire("dom:loaded"); document.loaded = true; } if (document.addEventListener) { if (Prototype.Browser.WebKit) { timer = window.setInterval(function() { if (/loaded|complete/.test(document.readyState)) fireContentLoadedEvent(); }, 0); Event.observe(window, "load", fireContentLoadedEvent); } else { document.addEventListener("DOMContentLoaded", fireContentLoadedEvent, false); } } else { document.write(" ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/io/LargeText/spinner.gifstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/io/LargeText/spin0000664000175000017500000000300612414640747033261 0ustar ebourgebourgGIF89aŽrrrcccRRRBBB111!!!! NETSCAPE2.0!,v $B(BB##(N"EZQCm@ ={$Ce)@e{!!,a $A"@"* 1&*:D.+`r4Bh 5X YA% Sfb'\L "]SWB]}(!!,G $q(4b3 Z4 0´*G2RQP&R‘6Rx)U( 2̋6u!,o $A(⁈{.B"D(Q,Dc'H$B8)ȑ 9L>OPUdXh) %_v# '3wz)#!!,_ $ HYG0CKdHF`J8 AX!b$0D 7)/azSSV p$!!,] $BHb1ڢD®0B 0 v+#BٌbݤFaaA&.X0@30.} Q+> R!!,c $PxB +*-kd+P )!L ?'IpJGjPh`Bb14"`Q# } No "tI+ZI!!,\ $P`H* Apx80a V  AU DA 8 %B Be PDY00!!,\ $$I>Q] (d2!8 r^e,)D?!х0 ԅiH0^@$gck0 _TL"q(!! ,d $dI`ӬBB 7m B7:0(P!X鲪 @@Ra KjD(2E {$ft5C%!;././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/io/LargeText/taglibstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/io/LargeText/tagl0000664000175000017500000000000012414640747033226 0ustar ebourgebourgstapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/framework/io/LargeText.js0000664000175000017500000000627012414640747032731 0ustar ebourgebourg// // Auto-scroll support for progressive log output. // See http://radio.javaranch.com/pascarello/2006/08/17/1155837038219.html // // @include org.kohsuke.stapler.framework.prototype.prototype function AutoScroller(scrollContainer) { // get the height of the viewport. // See http://www.howtocreate.co.uk/tutorials/javascript/browserwindow function getViewportHeight() { if (typeof( window.innerWidth ) == 'number') { //Non-IE return window.innerHeight; } else if (document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight )) { //IE 6+ in 'standards compliant mode' return document.documentElement.clientHeight; } else if (document.body && ( document.body.clientWidth || document.body.clientHeight )) { //IE 4 compatible return document.body.clientHeight; } return null; } return { bottomThreshold : 25, scrollContainer: scrollContainer, getCurrentHeight : function() { var scrollDiv = $(this.scrollContainer); if (scrollDiv.scrollHeight > 0) return scrollDiv.scrollHeight; else if (objDiv.offsetHeight > 0) return scrollDiv.offsetHeight; return null; // huh? }, // return true if we are in the "stick to bottom" mode isSticking : function() { var scrollDiv = $(this.scrollContainer); var currentHeight = this.getCurrentHeight(); // when used with the BODY tag, the height needs to be the viewport height, instead of // the element height. //var height = ((scrollDiv.style.pixelHeight) ? scrollDiv.style.pixelHeight : scrollDiv.offsetHeight); var height = getViewportHeight(); var diff = currentHeight - scrollDiv.scrollTop - height; // window.alert("currentHeight=" + currentHeight + ",scrollTop=" + scrollDiv.scrollTop + ",height=" + height); return diff < this.bottomThreshold; }, scrollToBottom : function() { var scrollDiv = $(this.scrollContainer); scrollDiv.scrollTop = this.getCurrentHeight(); } }; } // fetches the latest update from the server function fetchNext(e,spinner,href, scroller) { new Ajax.Request(href, { method: "post", parameters: "start=" + e.fetchedBytes, onComplete: function(rsp, _) { // append text and do autoscroll if applicable var stickToBottom = scroller.isSticking(); var text = rsp.responseText; if (text != "") { e.appendChild(document.createTextNode(text)); if (stickToBottom) scroller.scrollToBottom(); } e.fetchedBytes = rsp.getResponseHeader("X-Text-Size"); if (rsp.getResponseHeader("X-More-Data") == "true") setTimeout(function() { fetchNext(e,spinner,href,scroller); }, 1000); else // completed loading if(spinner!=null) spinner.style.display = "none"; } }); } stapler-stapler-parent-1.231/core/src/main/resources/org/kohsuke/stapler/bind.js0000664000175000017500000000517112414640747027341 0ustar ebourgebourg// bind tag takes care of the dependency as an adjunct function makeStaplerProxy(url,crumb,methods) { if (url.substring(url.length - 1) !== '/') url+='/'; var proxy = {}; var stringify; if (Object.toJSON) // needs to use Prototype.js if it's present. See commit comment for discussion stringify = Object.toJSON; // from prototype else if (typeof(JSON)=="object" && JSON.stringify) stringify = JSON.stringify; // standard var genMethod = function(methodName) { proxy[methodName] = function() { var args = arguments; // the final argument can be a callback that receives the return value var callback = (function(){ if (args.length==0) return null; var tail = args[args.length-1]; return (typeof(tail)=='function') ? tail : null; })(); // 'arguments' is not an array so we convert it into an array var a = []; for (var i=0; i * Alternatively, you can define the following: *
     * public Item getItem(String id) {
     *     return items.get(id);
     * }
     * 
* ..., which works in the same way. */ public Map getItems() { return items; } /** * Define an action method that handles requests to "/hello" * (and below, like "/hello/foo/bar") * *

* Action methods are useful to perform some operations in Java. */ public void doHello( StaplerRequest request, StaplerResponse response ) throws IOException, ServletException { System.out.println("Hello operation"); request.setAttribute("systemTime",new Long(System.currentTimeMillis())); // it can generate the response by itself, just like // servlets can do so. Or you can redirect the client. // Basically, you can do anything that a servlet can do. // the following code shows how you can forward it to // another object. It's almost like a relative URL where '.' // corresponds to 'this' object. response.forward(this,"helloJSP",request); } } stapler-stapler-parent-1.231/core/maven-example/src/main/java/example/Book.java0000664000175000017500000000165012414640747027011 0ustar ebourgebourgpackage example; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import java.io.IOException; /** * A book in the bookstore. * *

* In this example we define a few side JSP files to * define views of this object. See * /resources/WEB-INF/side-files/example/Book/*.jsp * * @author Kohsuke Kawaguchi */ public class Book extends Item { private String isbn; public Book(String isbn, String title) { super(isbn,title); this.isbn = isbn; } public String getIsbn() { return isbn; } /** * Defines an action to delete this book from the store. */ public void doDelete( StaplerRequest request, StaplerResponse response ) throws IOException, ServletException { BookStore.theStore.getItems().remove(getSku()); response.sendRedirect(request.getContextPath()+'/'); } } stapler-stapler-parent-1.231/core/maven-example/src/main/java/example/WebAppMain.java0000664000175000017500000000111412414640747030075 0ustar ebourgebourgpackage example; import org.kohsuke.stapler.Stapler; import javax.servlet.ServletContextListener; import javax.servlet.ServletContextEvent; /** * This class is invoked by the container at the beginning * and at the end. * * @author Kohsuke Kawaguchi */ public class WebAppMain implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { // BookStore.theStore is the singleton instance of the application Stapler.setRoot(event,BookStore.theStore); } public void contextDestroyed(ServletContextEvent event) { } } stapler-stapler-parent-1.231/core/maven-example/src/main/java/example/Track.java0000664000175000017500000000056612414640747027170 0ustar ebourgebourgpackage example; /** * A track of a CD. * * @author Kohsuke Kawaguchi */ public class Track { private String name; private int length; public Track(String name, int length) { this.name = name; this.length = length; } public String getName() { return name; } public int getLength() { return length; } } stapler-stapler-parent-1.231/core/maven-example/src/main/java/example/Item.java0000664000175000017500000000121712414640747027014 0ustar ebourgebourgpackage example; /** * Item in the bookstore. * * This example shows the power of the polymorphic behavior that * Stapler enables. * * We have two kinds of Item in this system -- Book and CD. * They are both accessible by the same form of URL "/items/[sku]", * but their index.jsp are different. * * @author Kohsuke Kawaguchi */ public abstract class Item { private final String sku; private final String title; protected Item(String sku,String title) { this.sku = sku; this.title = title; } public String getSku() { return sku; } public String getTitle() { return title; } } stapler-stapler-parent-1.231/core/maven-example/src/main/java/example/CD.java0000664000175000017500000000064112414640747026404 0ustar ebourgebourgpackage example; /** * @author Kohsuke Kawaguchi */ public class CD extends Item { private final Track[] tracks; public CD(String sku, String title, Track[] tracks ) { super(sku,title); this.tracks = tracks; } /** * Allocates the sub directory "track/[num]" to * the corresponding Track object. */ public Track[] getTracks() { return tracks; } } stapler-stapler-parent-1.231/core/maven-example/src/main/webapp/0000775000175000017500000000000012414640747024154 5ustar ebourgebourgstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/help/0000775000175000017500000000000012414640747025104 5ustar ebourgebourgstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/help/help.html0000664000175000017500000000034112414640747026720 0ustar ebourgebourg Resources can be placed normally, and they can be accessed normally. This is often useful for site-wide resources (such as images) and other static resources (like documentations) stapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/0000775000175000017500000000000012414640747025203 5ustar ebourgebourgstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/0000775000175000017500000000000012414640747027227 5ustar ebourgebourgstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/0000775000175000017500000000000012414640747030662 5ustar ebourgebourgstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/CD/0000775000175000017500000000000012414640747031150 5ustar ebourgebourg././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/CD/index.jspstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/CD/index.0000664000175000017500000000166212414640747032265 0ustar ebourgebourg<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@taglib prefix="st" uri="http://stapler.dev.java.net/" %> <%-- "index.jsp" is used to serve the URL of the object itself. In this example, this JSP is used to serve "/items/[id]/" --%> CD ${it.title} <%-- "it" variable is set to the target CD object by the Stapler. --%> Name: ${it.title}
SKU: ${it.sku}

Track list

  1. ${t.name}
<%-- st:include tag lets you include another side JSP from the inheritance hierarchy of the "it" object. Here, we are referring to the footer.jsp defined for the Item class, allowing CD and Book to share some JSPs. --%> ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/stapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore0000775000175000017500000000000012414640747032512 5ustar ebourgebourg././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/index.jspstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore0000664000175000017500000000136712414640747032523 0ustar ebourgebourg<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- This side JSP for example.BookStore is used to serve the URL "/" --%> Book Store <%-- side files can include static resources. --%>

Inventory

${i.value.title}

Others

<%-- this jumps to another side file "count.jsp" --%> count inventory

invoke action method

<%-- resources files are served normally. --%> regular resources

././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/helloJSP.jspstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore0000664000175000017500000000021412414640747032511 0ustar ebourgebourg<%@ page contentType="text/html;charset=UTF-8" language="java" %> Current system time is ${systemTime} ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/count.jspstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore0000664000175000017500000000027212414640747032515 0ustar ebourgebourg<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <%-- An example of another side JSP. --%> # of items: ${fn:length(it.items)} ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/logo.pngstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore0000664000175000017500000000232712414640747032520 0ustar ebourgebourgPNG  IHDR+jgAMA aIDATx^Z"1 *ɉII ծ_k< e7?c5GH0G`J@a 0HX/ʒj_lEՆ'b5Thu^|~zjO Lgv#A EI SH FSN0r +HD$x :+BL$@䛮 uVԖA$6e&ah$F .H@OwS>*Iv>gf9nsӁu٠*6~r<{$SHnvu|K#|:NEIp]QSx&@>k.4 Jpnjo$v n##xtcO;: IFk]3 1 @bHy_NVTx.uڙ  :!V 5eF+F怌bmFHb1k ?ׁ_R}@Eϥ9p8V.X50o X)[t1Q$^* ={Dy+4S @!hֈWĈAAz#7 3rb{M>7B~Uׯ Ox8jjUTzc$3𢻱,@꯻ Vbn˓P ZA#%|ŔXrIzc4Z)aUkG~Ay )v bDB/WtyWzcF[K`;;$͕b#"AAPl(4.(@zcF[q*)f*C_ܭJ?6^Rh#_E8Vۦjօ fpw eI:7ƁӞT!x _<~\=b r@fFcXtzHFLRmmr pPԏ})"=VjnSlk mW qփ{)[R(qO|v1߰I 4e#NmH_4 ϡ}b&HODWF,xx#UE-M>k }$4g.j_[`,2eVfkimF]$"`A7 A ,8Q H-Xn`6HEjrߞPMIENDB`stapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Book/0000775000175000017500000000000012414640747031554 5ustar ebourgebourg././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Book/index.jspstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Book/inde0000664000175000017500000000127212414640747032420 0ustar ebourgebourg<%@taglib prefix="st" uri="http://stapler.dev.java.net/" %> <%-- "index.jsp" is used to serve the URL of the object itself. In this example, this JSP is used to serve "/items/[id]/" --%> Book ${it.title} <%-- "it" variable is set to the target Book object by the Stapler. --%> Name: ${it.title}
ISBN: ${it.isbn}
<%-- st:include tag lets you include another side JSP from the inheritance hierarchy of the "it" object. Here, we are referring to the footer.jsp defined for the Item class, allowing CD and Book to share some JSPs. --%> stapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Item/0000775000175000017500000000000012414640747031560 5ustar ebourgebourg././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Item/footer.jspstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Item/foot0000664000175000017500000000007312414640747032452 0ustar ebourgebourg
Common footer for ${it.title}
stapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Track/0000775000175000017500000000000012414640747031726 5ustar ebourgebourg././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Track/index.jspstapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/side-files/example/Track/ind0000664000175000017500000000040412414640747032421 0ustar ebourgebourg Track ${it.name} Name: ${it.name}
<%-- because of the way we organize URL, going back to the parent CD objcet is as easy as this --%> back stapler-stapler-parent-1.231/core/maven-example/src/main/webapp/WEB-INF/web.xml0000664000175000017500000000110112414640747026473 0ustar ebourgebourg Stapler org.kohsuke.stapler.Stapler Stapler / example.WebAppMain stapler-stapler-parent-1.231/core/maven-example/META-INF/0000775000175000017500000000000012414640747022323 5ustar ebourgebourgstapler-stapler-parent-1.231/core/maven-example/META-INF/MANIFEST.MF0000664000175000017500000000014212414640747023752 0ustar ebourgebourgManifest-Version: 1.0 Ant-Version: Apache Ant 1.7.0 Created-By: 10.0-b19 (Sun Microsystems Inc.) stapler-stapler-parent-1.231/core/maven-example/pom.xml0000664000175000017500000000401612414640747022501 0ustar ebourgebourg 4.0.0 stapler-test stapler-test 1.0 war org.kohsuke.stapler stapler-jsp 1.144 javax.servlet servlet-api 2.3 provided javax.servlet jsp-api 2.0 provided compile org.apache.maven.plugins maven-compiler-plugin 1.5 1.5 true true true false org.apache.maven.plugins maven-surefire-plugin 2.1.3 org.mortbay.jetty maven-jetty-plugin 2 9090 60000 java.net2 http://download.java.net/maven/2/ stapler-stapler-parent-1.231/core/lib/0000775000175000017500000000000012415270723017164 5ustar ebourgebourgstapler-stapler-parent-1.231/core/lib/groovy.src.zip0000664000175000017500000365311212414640747022044 0ustar ebourgebourgPK @4groovy/PK A4groovy/inspect/PK@4h ;2groovy/inspect/Inspector.javaZs۸l|t^C|jȊOw~hl's7'I A*v:߻x_󥝆3)p_X]rgxI2ͣO#&h8Ix"/wx`j¿U<|UB rC3'D !iBɆ PHG=IRp'W$>zyԂQo86죿az7]:jm/]L٧ $s kճPvq9> [X.oЭTL#eδŏH1lb8i[1L+V,F;q~&sU|W_\L&x:!ԫSl'n;σNvtq'8I0c)OthkB~4Z~$",q0HYHt0#ku*žH:RJ;!)H+`$b\ iFf+CgIW ' ~S!"f|QʪD EK ø]̳!'I};8XЪ8q!k \ZC]^ׇ'ֳ@)a-ѵ!ϓ E(fkarCPaP 郁h}X> JG/vn91^^%`v\oKܡ=^- QZVC) <R!myzϏL? 2]pg6{}F m{"~ )|WXzI)!4)rB8F^i? 4 tMXHo{rr*q@kU܍&2Fm]]_)ᩯ*U %r;,4`al?CeíhByW }$_0bF.4ߤ$̩8+ uiIHY@'q Q@6)GlQ^F Z COk_$1ޜ%`y#r%;O%=f,cdذ r1ĕ'o+GU0k[ AŖ/H"Uw4UY!9GD?N~pHg8! 4[}t)%;:sꮏƆ$Ы>z7R8IF\hLglE b֌a7<|((~_av]C䑾#Y;͖ϴ:mD.)ƪ-Iwڪ\VIj"*F/,sT>Ewz=CQY6er?PaJuwnZ%wa#Щ-/"K4;`a1&|s&|ZJg 8DZr4wR@K;ylDsgAswg*xsQ# }^A&іťSؚ /Neƽ,zhHv#u0Þ;~C })\WYqӰ9Тؠ mbl`AP} (v o_vحvGT^iQl@./Tz^NO>㷀~"VVu~-ʦ.(52u ԺgC鹉SFhH)/b=3@g ]KLW,%K+i_U]mlAZ)sT,w-cgD^S P1HgO&ZC|Ak89/:4~Cַ8֨1P K4ω |TM9-QN <2.&/"Li3e/џJS<{Vcr3ƂXgsljC|F9'F9gujE[zT_cPK A4groovy/inspect/swingui/PKA4+groovy/inspect/swingui/ObjectBrowser.groovyXo8~8Bn;MRxݦj 1ؑ@;/ntwY$y<3fRڣ\d=|Rǡ@H>%J{Gٙn3DCRA¦]t#՚tyBZ 5+Ă 1EzNPJ&8c (j,5p"Hh$•]RHpthAZžCϹRQ(Ss,JH N,5ZP,&P$Jst"|rlLuh[:qġ J-z+3ؙ0Wq i"/ J?c l"ǁs,X Z .3Ue²]AH#c]q؅TH>U|8YmSEEBFFr7+BەW#SDqIs7 3k6,׍n͏!Fd\M!=KPlR11F˓ >VI2<_ @<m+ =5bHyopE=f䇃9=# ĝF1:{,) 8jCz(Oxs Zx)ķ.Z<|Eޮ -<`!&:*ڗZ#"Zw-;?eycTgR6uׇ>skMH`>jlsk7Vyz=*ܥ7Ǩ15==4ri)$PP<=FsvZsSAqd:ѤM).hgmꓔ bg/KOhĭ*+T["1<8L~SL;"TĔI‰76xZBǢE{sH;ncI[_dQ'm } 7pJ[{9}xWc:~TȶzM/j]$I?x/mhطLŎ>v΍Qo hvW6{oPKA4&ZQ$groovy/inspect/swingui/TableMap.javaWQsF~Nddod,!T@vxu Th: َvowlEUK/퇪0[VCZ}<9;w4} ҷ9uA*-ٛJnC~sM Er'! %2UutAȨ6TAFe*7KUrO+]2惪֤K+FLT*!QJrJf-NePE_8yJu)v2~Y}hS{!JuTTJ YK㣖BW*Εh rj;N !\,/@YVK&i1/FrF!}2m .m6bOKɣ*4"Ád7ѕCr  F4ڡ"y))hʘ^IT7nL~yR՞KŞ"}yqLaD|{O0<>ĵ_L֍"7H|~0-&~pXnpQ8k/_g~rO:ETn̍ha10x5rpȍ<"sdo2xؼ$?8bP! p^̼&$gN k:<.3 y3p\R"'[`I_,)%W4"$f7p!DݠX?J{^,mj.< AMM\?LmN7Nmݧx}wpc"#[?c"9ˎ9[hmA]df讥c;^H:SAkגțcM-7W.a&7>gbabt|%ݡ;]NraX{w {k}!3ʂofeµ-dvyXɱkw.+hfŲHew%:ͥX+\U{Nsԭσ&bk~;NGg_;SkC )]z&*ֹ`l@r-v { Mfm.bնe؋;˟Pl,T=h EdXe T$ªzTkp3slsoگsTBxc,RQKQ' #j7BwZ!-/̮a5hd)=_oBn}j 9Y`sVgbOMs{"j0T|be兴I'[41>tf>凌=~ ٶ^N@WÐNvOP6@̸ '@px2Y@ FrB'9 $8x*gLHUeܠS9.6h: DÀ@0`%U`V># Vb GD֨<I)3fIoc[8999ϊ .g$1 ~ cv;bu8NF ']>I8pػßWwqNn`{/ݷu8bWdDjuGwx`hx;< W#@?Z;wG`)p2fao0ߎlV(&Fo$tкq+g@  _2X@ OlrǃWax2 ޛ+6y7`۫\{2Fl(|@ {X,63[joA-N-|"Fw^ؽnǃe|Ed۰Fa\:ɵػ@nz]XT0ɠ̊Gd8FOTbe<+ܭZ$bd߇ȅV4-[{w>Q N։!P{> Vy&DHd #%zBDehaOA إ0b<"\2+Dp5LdA6\k &brw#_oAο?;ouwizbC@HtCIL$LUq#0D I) ,HfLD`$ޤyAFv$EC dUah'?L cF.GEz!N}b P? YNpIlF?,H ZlRLZ3),^(2 Q/@Fgb&{d1X+h"1g<ٮd !CRB`d:1N#O9xϓRtGKw.0T:E^RW.xCV;V0S#JbPIYZ]6/Nl&r00HdO$RLl*Rt*xD+J*<UTԊ*YbT 36$j\uQ+oCW;;Fx 6gw %I&72)=~btROoJdrb?2@ ;"+dFd1_*. }U=ȯ~&_ Ru3I;=wѬJ4#/MNb3Qbv/OyTCW?=\аJ5l0%Nj4 T)kH1% .jq0 1&o5& %xl[ vvƮ(fj_EG۳x+YOGFfJɸwGVB" jQ Y]JҸ߿6;v٧N`R MRhjPXUyK l $+#siG"e|߶OP[=dLf|"4A7J:Lj8E٘BqBLccdbK!)4[UB @LK`m( r%bIg'醦唢Ю7ҎLӒBZP>%I/a3LFΰ_#daK&|o£+q688me"~!Y&$TYDDUPJI 5wT(Yv3yi~__JZ(v`^ Q3'"/ lM*d dq1D|x۝kʜ/=mupfLGl*` 1H+ӊaū{M>Es~80 0[ $meo;D﯉pzxt01McB1htꆍ}U, x#8jC-1bgŘue&Ic]lkןz }``N]U 6v*K@v0f͗ b5!췓 IēJ<$NI̙b[,b_`P@ üSsc_:k_*'s;!,yT#pH@xn0٧C&?]&~Ć;vR$C1L|!Y˹iXc!@g;&SQ==)SPgLU 𴍌 Б&ԙꀘ# m}a7b\s]+3<6ar[8=kO}z0yP)3|X@oL(v[Uu}.ė8N1@Yޯ "ZL i- H~ Ϙ& BU.`:e F%dџ]"*s-Wڍ[ԞTɡ^]4}2TS9ՐWPx“E=5,/SlV|./>&a`-RKIHњp3r$hIEjϭ11S>5o~V`*c;?oT\W{H*@ԄgtFX'g*(SeD,$7tk; f I.wj.~:,1מT68fRυ閚6b{\)Sa;bI! 0ƗRl8vR j8MEf %<ĹZy aӝb۰k,3U10l3S#ŭF/ٟ(7ݧ#;7Xfn,(#DOTa6!ϕ; ~p+xB|FQ`/Xt{tR_]$<_gES٠Lzzl|C|U5}&!}akytd`sΎhw.c;mDqg{p dvD${_լqwtMܗT)qLwYBx'IUt%sq&ʿ5P@QYyEs 9/AJt(s# %V {x7G^ S* KĠjzZϐvb,~dEAZ5k7LԥK-V[S: nox*pjt_tP b޶+ VC=(]Fm&=<&om1+^ ?|[ 6XUѦ悎}[VMA_,}kp[NNϿPK A4 groovy/lang/PKA4'7 %groovy/lang/BenchmarkInterceptor.javaTMo0 Wp7%뜮;b8tإAG,-GJJkA1` ŏIRmdP{綻H[ϋB7V}Цq60++l2Zwd/B vA6-Tkh0]JK\9 mrEa)%ϊ_@u Z7oe mFh~i Vp#XKnM61ld3XƱ8mk$\k |y܃=V?NP$@ҒZ+9\>>Z*wˈC%`-+*yŒ/z\9.uD!=C,B9PpvZ?< J$gB*+DjD{fe,TLV*XRdTfG)RZ#DԪ(DxHɛV턡bqH!^(2oK!}5W%<*Rf2ny (<͡X2QSȍ*)U`B92AwVyxZF1Lr/)jUqThe졍5bi m)J@+ T$N1@Cm^+n|3V=Cp41$l a0sU8a+7ol!24js)kpbԿ rdFŰ ģNx |¸zbj|&a:QNzV`%˰ m͖ Y&9W'Yyt0~^ Q2)^]7JooEx׉+Nչ(T8haXjҚ)v3AikݐI\:By=<$*w_Q?MCe)uϷCPՃ%Z}55VmQlC#Sp/};a}N@ CC<뿭 uu[GղI|T˝Z Ѡ/vaQJZj!GaYxJ ;cwӚœIL x}̔)Cj+-ɮp>U"tU3N]ڱϡ?7DܗX|'#^떾41u|d a׃/Av?n?y_KءqIA:BG?/I/d6ǯPKA4e1groovy/lang/BitwiseNegateEvaluatingException.javaUr6+vHq>nqd=r,,$@n|C(%5{yXZn<> 1N:5\/GanDʢ/ꐪI4`Oo :+…<÷[[ggP$qVݑZl&}@!c  nj'a2[ׯ^ }]CD,m"nhB&8K4*Di"roÔ^ c@%"QZPBi<+NB@Ҭ,A69)FtF;W21-Rc," (E/2FJ(gNjX I `h6 ^t J(rF3A I\Ptt67 -HL݂|%(&BYbnBͣ AO_H\d(eA`e# YƼ_%#!("_1+dԻFӂy(h0n>4K\t(9݊! m8.G2!%4&n7s0唹je.!~y4o&1D TqO-MwG0;_Fule#+טA<≯ Lvf#x-'; C?7~8eGDM[~oHBф'``JBv?;KBeM+`^$EGe(} ֭;)j4,xB0osy~;tuJaehQP5x"ݹ!h<Űlk;;o콥]ӆ=9HFkR{Q\ktosd~H7hAN?}ֺmPU<{3>?Ϝ(Glp,AucvxcTv ߠŎtY?v_cePc\HT%3r= bߞoPKA4u﹖e 5groovy/lang/Closure.javaZ{oF_btm"ْEɵĄ"u|q |Z{ ALiw^yjdi0#ko?^|# O蒘7`@6 "J,%NPoE#B#ŗԻYILH,fliyĂ0OH RW Mi{͘O,(R pϑFcrd+'ogdUc6,Y2$u3h1ra|DKő Uʩ,;_5ST7c@[S 4AFRȟ_:3\e`_4t{l9Yq/&I^fAL3xr|_m ?8@7|l2OlqzaĂGlOe:cbͧ'3kvLˀ.9N-湋1ؤ#7ԴurdX{9 o,w7!g۵'g $hr'ԜAxYsIw%dPv'G'v,ۜ\>ew2&Ι9c&12sd695a&ms~世{b1C1wtx;d.xV0 GQigxq9>]̹~\\𻍈r&`<(dn=ޚ󩉣 dsa9&0-gXBsKxbv̝I7d2{L *lǒqKq)=l`KX=bi4Zz'!EH(lL$ /7mH:ĒcBf(``a-`~>A$   R_2/[cfN!& ![2 Ϡy;&Cl# 0\MB~d A1B*ƮYFlj>O/_G#*"cb~jDTDE~) &(TqGg~*Zp;|ABY};"|" \V+sEH#vhK?In0; [oI:v.TijRN}*,%A&€ǧ5H(톥jVA(<__dqUTXd?HH0&,0bn¬nKe a0mg`a_VS8^-!gAd>:F󄉊7Oef|NXd7TH=a~\&!'dc~ϓHUD]\]9vq\$d(0ĒXyxt%JAf\qε[(lQ%a/4"U}6u"~^0; h;$N0eҪ` vsþLU߀'e5~4~RvɌq;/Rݼa(S-CS}Mw^KY6]GDzC|ͅ܋s[/8d4"A:iq4h>5* hM4=CBK" Oy&SQuVmH<C:0pAK7Ϥ䪘"`d(VvxձI-$Z*ʑ@b,+uus V7F cuszkGãJ"񇸖⒋ǔ'TSr")O6<*]B=ECAvg+72SOe1Ψ!" nZݞCK iJpkv4ðEwCU@O Z`"~ o7μ sVvbb3U=RQ]YU7؛m,fV;oMK'xV  lE%. ROء ^JrKȨZj†ZHӚeuebDGT2`"6ӥGKCrG[/?dR)6 PrOԬvVߚ0o%^SqD4UTTU^MaGJ{Bݔ1E5eg@D`cpV$+ ,:vJ۶TN>2!퐩]ئ@Ks%AK0>] ʰTٲS)^p8 ew1W1Eţ@tڌxTҫ" 62a! 'xC}f^6z/^b5pHLD,)KX0l^F̯vM}oI /eH5{4AT$ :^FZdn5ubوJڕHA42 G'}3rS;Du%i6&H*> ŢP[3䚲✯ +NP|9Q@7&tcPCM'yMnO* ii',S[q& Ee.tu؀=U|Q(+6{KMPKA4 !groovy/lang/ClosureException.javaVr8}Wa2$Bt%hl6IVa+Xlfv{$!Iv{9GW{O~FK#:WewCogty͟9}j-ҥ(Xӑ㐯:_,kO %Vx)ʌjN~Z.yEAI(u,G|.6$;yEvBTJsQˌ26+Yd9t܉zIJoԴRY~6%zh&d栞Oҝ* u JU&Y+YAmЭTS MUK5!|*0xeSYuE $,ۻsyy)$Վg BEs4ܶB@S >Zi!ԦDaF9]7z h;RK4uZC4e@J,3MhRuK 3D&[7Zui6RUF0D|,R4f.65|S] #]J<촦(V*„ȵ $@ fɕ_A]6`༦ HX@fi0~˺^{fЮ)//b4 ipIF~8d#o $̒0Ջꕝ[b_cdt1r gK<dz!\CAИOx$tmŗy^҄EހyrkJ:tɓgEpIP13(QB@@`&!m?Kc_f㰈#բǡ?ލwt^5(rEg[`rٌlR[(6#-↋E Sha<`w1=j0ٓ[$Ex?RE?=ABKc&ur)(0W(λЄJdfSWsh|ZC,}^zYrsSr WҗG $gD(V[2Dչ^X׍exJ^א-U8ҧ@;6`rK\"pɂ^NȸT"gAGdA)PKA4qq%groovy/lang/DeprecationException.javaRɎ@+JsDs4H"2|@z"4NU! ŵ5@0DùǦyXXDw. Mq0bHy8y)d}LБ X"d+VJ'8.X.< % G<`{EҶ䢴w\^"[AH ߀kϊ>훫 su@~+H"X Vߑt% "3uPwڥRVw=:?/ݫK{&/L'Q%Aѿw߷=8D{9ҥX#'>nҎ)?P4P|y #<9 f*wǔi X>SsHF6~5 ȳ 8v/+<եX/ !'R !zi~PKA4;c groovy/lang/EmptyRange.javaV]o0}ﯸSAV$QD64!7M:vd;I֔:s]d2L+xqBi JgqRu.9cPsQ;`qih0Δ4V2K@qv"ޱΔ>)Ms9=>M'xkFJ?^$^| e S*Vd5 BĴR3p1#nn_!:nxMJ'r2Ňj 5j1^.ZvսҔk^PM0˕=$X:h^KWMJXv&^[Q('LJe1y[-M;«_LZ^,x L̎w&؇M9C/Y#(i-MlB I];QٽS!Ux\wTæ$v+0ilGtCY/2,O(+)UW]%[ץ< zHVCwc޴tIeԽŴ7}n6DL[,m΁oby eJtpɥ*6p,5O_PK@4VP!&"groovy/lang/GroovyClassLoader.java=kw6'iFv;me[I4ǯdzzr:L(RKRvm (Iљido@_>_ g"oҸ,Ox&]|n?.~𿯿O}ϞJY/J !|uW$ |#:G]x)K1xzg"f0뤨`$OS1NR7r)x#9KʪHUsu)E>uR2Wq!O31˧̪{!X5mR]u%,'Sjo%eR!U$3R]G"ym-4f +RVϰýD|]L%tAuYBVqMpzsBPY^%SY68-sDPGS!"nB.WIw0b1ր%UWѫ)l2d3ZqH;CrxY%H`f5c՞HLEL-hTSq%qF,/pwWRT1a9%cɪHp22^#e#u. =Je\Jٴc^,xV &̖4NShdHH;fū5V:= &êYcd.@~,}*H[hr)f&J\W>لW2bj87@X/x9cl2^NGc#z? y1|$'C Gp0eOqv>'M{48^pb89 /.?@p|t#׃Ƛ3E'cw@x2`GSbp4/`FO= `ǃF0_;[H9 Nk p<N.'Fhh0~.NDL4<@k~x9ghty1uū7@vh@OA|7|%cX-aTĚ8< 9z3 y7}Za4}_5# ?~=ȍa1j^W*s/i_89?>0QN*IQ,D9E/@u8͜:s!T_Qbz28|zҶ _bk }0(DyMd`WqWqy}oʋ4~h'ⲊgS)mՅ̢`WR N/bЬv~%=V+ C~ :ID8a^ iWKeI5MӼ*)PXL3X˽s\,? ɧ;akfH${cUJXRC߃O |-S톖dVx,Ä { \6}wźNG4܁P}h U8!myeyiʭ)> }XM&bKy`~#Mk o3x[7p:2đdR(6LPNX.G-X]+̓ l* s Nfg~[bA3=;lg&fym^tcp>'Q/u~ YLɳB#c&BvXP?pj@D2T 0=`-DF&KY P q{Ǔ# 2x+s;Q oX@ilBeF  ,ag*ɪa}`t*QvBrh2 j[{Fi ,f?tȳt9rF|G_-őgvcFƲP.%H^=gH=pO<㻲K%u ^>]xJ5k z%YlªLXsa0>! H8g&i6>%cǏ(in?n66 ! p%n_/xzOG4Wj=]G&@ *b:Zced,c:*$U@7I,V9N,8Sn`lc@~r{;bZbDweTP=6Vn`ʵٸԲl܍55J(hC )ЍQ1ĐJ!eRUS ǥ$+PT $su"'VϖҊ<'G9xH$EW 7k* VP){LBjK@)'?F&oXu1Gv,{8+o).mNԡ}yڥnc]o^dB8żƝXf OOPy-'x>8fz4 Ψpa$ "Dn6\s8AF_pqG6B8252[si2N}soXUb)0\;?d/u ~㤠:]?_N..'-3/0G O*4W-2F~ a4 _unK3GsD i!rv1ZҷVLC%,qa7F4/eh&c n8*q֙._!q! DR~S&]s MnqY6~ZtX'R¸X6%*f>c+'LݯoMLR-u{ڎ(h6*?'o9_kTKf.8S1|%$GX\5(\ bLթ;8ZV\)V[1#XhX1S N9[o"cd0xZRY2exus;geb訙 ac? P&AN Ww@B+T5K`jPV;-yA5%zw:L;G㗻ѹ؂z=@!C#qu KwfVSf3d&1\R,RG/r mX}PRehc3i}ll?%A#$rMzAP4c,,MG+x9ZpVn ~(}\C/2 VՔ`2e=խPP/1.A P XpRMza;9>$K=Ef򵸍3jFt;N5Ѕ*ÄյlĿ:tRCu8&0p=7q#Yb]"*c&ZL; -$К sj2.U:)7Uu]JFp{l %#bfecNV #y1&\jmR:2q:B:r}tc[kT1[s8/L RA`_`b( sbxMTBvFf2M6_B>`eP#%xDp F5 港iuBUS}2{O&u%?ESU)er*p1 ْx_T;'n5(suÜt~[ 8~biV-em[n̜rfb67mz PN@/|bKȐIlk;^⌱Wg=do 'Kb7P063^a'{o߃)b'z[ἀCc;{^u~w3zfM%uS'c6QG-F rIӆk\o\~HRMfscuKk'rSyyװq`/7 {˛Qw}@k 9*[$Λ^"&6'Pc[3 P*(R>Ry:cà oa6Qt9EvC`x QiaJ{rVs/"pN^XХKXziu4 rL1J"CӜ/e=CqVFebh$m/ѐ?Ăx+{,IժXsrK*$i\"8\w IQڷqL)_r*ScN]5Yzx(z, d.[kϸR")٩;6 Tf|}4Epiw+xbdmdKZzQx17pKt zf ;שt <2[>g8]o^|XLTΰV XV|Gx[m JQK]R Uv\N ~$?nG-Nu '͡BȺ ~l) 4d ꍰ2sKqz dlDʚ[hvT,50m/uu<ӋtE)J *_]gscrYd +>?Dfye4Aw`\.L#5kZ5sjBߑ q/}r sx[!vy)> Jc0C?G#D~ e@{@"AzJˈrS/W\hyIcKk8й2 ^Y :^_UӬQX[rMD6ia5=<#dV\]omg" : Ա3(9Κp(/(Q6!n\IOB+HN_T-bR3m00 GF>~; [{8A&6\rtu$n C ˾F@QQLU5ޤ`P!i?wc;34ՙCvgQ;_yuTqϢŞp0wHjPgT}gC& (* l=xYc2]*7O8@'x -Da֜b,<9X&/DiOױ611`q%X!ÆBQ+DǺN-H®uF e?I`qsSe#vo!Y7ilƺOIj֕^Pw+]L?f" ~YZйL_H:E`y*pثhOAZiZ80䉋FfazJ =1m k+#5p(c+cdJbǽAEMq'yo7cIZfHwEj`f]otS X'eUǐ& WV͍*AxA/ jTdP$%ͯq$&]Jl5"+w(u oZK2zgR>זg&;dm@HPkȭpx.Z\J_*]7X9XQo b 7n}.,MHTפi0% @0|Mßs(/Lz#p.ʈ'7zWSw)*#$ȸ˪W!oɕ{776lcu |xVw e'WsE= >x4)aBІX&wN}tqMxg૧ݦ86S=NjZKR?mU-7Pk4[ߊ.")9)zM@~H ( ){?B.i'˛jpņf6? X[oڔxUXĉ[gy aC6^4Ί`m;8q/NcMx&qwss» !ږ?{wQ)7'@&0*EO{xnh>9)%GaNgNSlwrng2uJ-JnWbUxR6`E˵);S5nͣS^9ƞƣפQ>37S1H GQ؛! 9.誼J(yQЁ#**EzuGԫ*I0hNF;Gĕ:.~kVS4*u{Q r̊ '[![.X ֏k4ɒz 1p $:}١<#ӵi*}ݨ}ty໸R3#Wu{v׃7>iڃϼ,7}XyQ_Nߓ6}!S)t7 }g<PkԆgT-e 񣘭lSxoۭ+Mm<67wGԿb G u4yQCǶ7vM(t: SYF$ImxO8SomwsQSK-u`0POMjハPKA4e?!groovy/lang/GroovyCodeSource.javaXMo8=ۿe֕wAM(Џ ٞhJ I5ؖ8Ǚ7oFnx[o7yd oaXQqk[sxU;l# d!kt% )`f @N5 nP%[]1K;x[kîq.`hx49xNY ج遭Pp$0 eWpcεaK@LNW+Ge-ԅǣXI "S!P;ހR(p.\̵FGۤ `QRE\8J'jB%اkdO ^q֕XE%)[ Oi8$3 1! ܊)e wlH2'_ m6΂ A3mrHPIf!ٚ[XEZE;笆Qc,o3.|n@X&UyWmJ"QR>HBN!kV%+֬mgsvF nE)6 Ae4 <&-ZYlI5]{Nv5K5FvM$ K;1±eC$h ߐ%K[½gsIDD=ƀcW 庖70+ȹ1K $jfU6XנԻjüJ˯^*t*xFVkVdQ)GW!︂q6 5 Kz`Vyŗ>Mdzu' [E<ؤEf+ ~&(|L噱zJi_H=k68#Mb<"V9YnY69K{2jL&!_:& sO;|RrOP9I\qi4=dR$3 &jՐt TOI &!7s7ܚjwg|{MU#w } Z@yDLY.R/H%z؎PK@4?5$groovy/lang/GroovyInterceptable.javaVMo8W mئŢd+JIs+-6[Y4(iPNCB3o{3<>.ajSTN.k5.-};k`?w 4{כE«5L{]ײ*صAPאQT jݫjətY;mM}ZUnC)T)$eyL^p J.B)JU֓Q2umt4emUw/F`TطXI;EƊNQc:]v[C$t2sVԍ(nPq#S#'P# ;uyse-VY*K6>ie%wKݢV‡ }s'2Hۻ8Pgk7g$ KE# 2tA2z^aI$'SŃ$!sc\ 9-Wb'`p`L)*錮t4{`/UW-`e[>kIJBcꔽ% 'FXXXl&(kGJ^bϟ^kWޑՍzP \gHV\+Tw&rvdO&+,J[83nSTXUע0Esc}NeKښ5ÁE(AºыO{jӍfP#J-kgvL䵳 B5Dʌx' ' ŀ:`)դ^-L ;4=,hreC1}bi#>qJ6<(%͏fL(<~ʨ4fnlWHPJք->ynB`U21t| U,nf(e3&kyzqq7!}-L=Em"o`.r:g:sϳg$ٯdjz@{yΙ<7jlLŭVgYqSҁ-Lݎ~-C~M^K+S>t$ñrgU ßy-Mv{50)GGkC,w=  M͸2$^Sۈ >7PK@4YWg0 groovy/lang/GroovyObject.javaV]oF|Xbd R8i:HJRvy.xI5%Y[owvfnwѡ/躲vM~QkYY |zwv;=_/N\f5#ǒ=|lp9Q-tMISlJReNvBanFW]bN)ֵ:+ֹLVmdMM6n@յ͌jtNV ]6<::H6z0͜ld.C4 :PO5ij>rF-sYZϺ߰nmWU#pU7TF/6fyO ƚNQiK/*j$r sgKVHRUT-8_):D5kDséV(mU,tegSY=LHR02Pv\ vޥK4\r@&[,2OŨ ۴4[b<$)6=Ywc3lkvFYռrlqO[9¶R;EJO;X(S4 9Z{L-usm]Ow8kt w9lկ&^Omd_QIͷ^4R.4A;U.s[w * t3DmmPnoK@kU ɩqD2FI*(pC]NLN}p G?KF)bq:S6w;Bw ؈O;1 7PKA4kXl $groovy/lang/GroovyObjectSupport.javaVo6hhr,ؐEe9ؒ'IEjeѠ(g}wkIa{Iu85i䛜^67.+x~~չ8_]_^Z@V:/ E^Ip  1ZLQfUN6R{ĔTA,+2+Y^Oj&$E^AfIhiDUi. Sz)K#(ˁ <:u)7 PjK|jc] JuA>a* s2)YKiQ/ɭTS2 +ZCkP$ᕭT&ʃB"HXۺq|R&MRg,I/7FXE;&a(@ݛܝU<-DhƃQV[pE%spۂo6u ҃.qhn)DȠ(̔фTٔgH3\l vXV:4eMRUT:ABlBԷ]^$RTiԠ/3yIUzN?[MSQ2BJM+rmg[P$piw|&B]yЫQ1*.2*aeԯ.Y]w: oW>O n?fϣ8=փ#.2_4qʼn_ {gؗQ̒p4ȱ%.0{RehX}aX? sA=1Д`Gq̆$H$8epE=@{Qb'EԷԈ^2>w 0eq<< OG DX4 mP?*`wn֐m 8dDӽ2!dw~€jD0Y5tuNO})L+W@K_6x/,7O7mDC )@#G80ڛK8'jajO}~ߧZ;~񸻴 >ZTos=|E-h7i]kZܺ-T@Ԗ_y |]:36VP^ ?PK@4#lH]G%groovy/lang/GroovyResourceLoader.javauSn0 +"b,zM NW،֑*5`b)w ҎJhuI6T wSFM< I[˩@L <6ZGTM@/5Z.:O<fӑ ^^'ux7*.Ydwe>fCٽ9UgޞU*KJWcpf;$0rުm6_'pa#Y>lmutNlj w,d%@|r6bѸ4V&`J23gJBTŊ2G'A99XKAy!n.i@B? k 4&߯wX3;N\\um:6u>;bOEk+S4tC\lXCv>{_ӑ4訞X +j- ;d֌ڂEQ$ |n~>{REyA3dv.y|kBh}0 ߞ2fgy pKNOPKA46;g 'groovy/lang/GroovyRuntimeException.javaVSFba&6$!?>@# a:!FsO ۓ v&?} v:6Z/oú2]?ȥ-i^v˃_ȿI|ZЖP/nM68%uZ$%&7י铛rRI*YPYYf6.+J}UH,KdR):窨$g9Dm`gG7YuMh*Kllm<ha2KUꠞGѕs}3JtfUڬ@y閺6BJȨJf~hr/BWY>=@2/5@0ܝ;+Y!2+$3_SHR/=͖S˭;ޫ{P9%FpYqE5@K4VMA] 5eb\`Ȩ3i,]*ҤTès]54j8~Lщ;;*wmCX4usbc(=}de =&bx' /z H>Ei䞺6v7My :2)Èhz^<);5D5bז2g]Xt{Ip_@>i[p(/}Dn֐ 8TL;Pj0^$ #𹋪S+^l3;"wtLEvZoÓt~vB& oOj䲘rl{4ewϯw=(WM3ma܂ꂀ}(v l q_ekIF]eW<5v_vz Z%V?[VA}g )'2]-5˅4Ȗ8|^2jcu{.5ۅ> !DQOYCuwД!{V8DLoZ]:˜ OV돕Z,RU XԛA~Ak ;u im@hrv#tSƺWƘW=C0 <`vE&(}'!Y7۽.]Q:3Ӧ=G[mʯs8y=/֗\/y@;%_1HɚA~ I쫿jR{KΣfՀοPK@4:Wgroovy/lang/GroovyShell.java$>?`_;!;Kx{Dڿ-÷ۗ/mw/٫?|?{/ ],W3_Y½|v_ v$Hl6 C6M)T$[k. ͒:ςXnSMvAx^33?2X窅nlc? P:` O(O6k@$c7P20M$h܍ƒH War>{LN{x8ae .b6w6ra˳gl4}&O\v̹r.&'`^pt7*H­0ʎ'@|"'|2^Q:S9}s/'c_L2fF?`@AձpW ;NNo}g.ʝXc1"dԜb2_].tpށ\Lt: =BE9->DIZ# b/u0dٹs6't`9hW8`"QK@|iجEd) `j5(k!(+=l %xtGz'0l/ eO1TV%qh&)JB7Olo8ne;< QN?!b=budNM( F! hIuU*ڝ= cId(]Byw/kk} >$>p߀Lϡd{}@DeR5S luH5T̓2}KM ! $Ϝ@G5h= ؊0v$ޏC ,Cgꌥ[؍PV_KSίcP1Y2d$_6Of,  *IalG3A>P 8Fx`}]yD<;E1Z;€wՕ1rxCLXH)ZoD,A3+ڦ\47`Aя0X$n5^ ZR>h$mjU$ک< TlQf}viLNGW狏 cM[wGo)'}2W[C%OI|K8<%K9i*va=Xɜ*iGŖf4(95D1ǯͦ"o Ck^#X X=~\f5rzR%DFqLO}rD$}qMSTvZ?n#}Wx)HbQ$m q rs!G`%>(GRDRJ>IqdIEQ@O8$.`BU=gD@2[Э*#O %vy v)R[rϳTY^OYU\V?|PM͇lXrɄcU(]ˬAW#tҧe,FXkdq}P.DY}Pn/,Ʋ;U8ޛj҆Uk\)amΘl͕yc{\-lYJ#@[eH J [\6-Eg.grj]w5]WZ GlEMNW  9>U=$P3ȋkt0o#0ABcbD]FA#nݠQX "B2 7e}ŜYR+Z, !iw.dRQ;YwF) ?Y Lu*jRڣeUmֶ8Vezk/2V/zQʐf@!kyGERs Sli!;KZl w?I@[# t)F<şh#9R mU+ϜnJyu񈽬'|fI딈oiޠLvLm$ve!&N!QETx02ə Z%-5n_Zb,τAq;%%kD}< dشkó&u/\KGuO;CEk}p72ڍ<0q+dY=bdÆ]+ ;< D{u.imqv5CUڻ (&B?Mʂ0yJܣ52Xi/evN>D ٢.*=qMW }aﺶ¨umYCj Myk1ܙ2JmbhѓRRpu<@TPp׸E֣-z&RlhLkTеF0 L]Bh-{g8]Q~kj,s`=L&4GsY8ϧws'`|mc߈KRu߻I2:@>TމBgIVhT~JVůubOwbU4nƾVƖ^j\->CT4= KbcE`.΃ϥ gh,n%* Mu] [Qy#d~SRc27[cӷ'"8\7\i6EILDw{BߵJx (& o@k\j0*\ʄ۟(?CS1LDI3P|ͽ@F B07 sI#}و@-?_9+? ԃ,p|YqGc}M-n*nwa;^mj򺂱ء?@˪z  =:D]3" ;0_0lw,V1&G&x#èJm[(J3ɩ8PF3Zpsy8UYۊd)3dC9H`Jd+됴KHDڈS8d~J/ڡSl-sE@._FJBm|JL"N%"5;Z@pC4Y$(`՗0M*8KZsn:-]v'1 8WD"^)q7wBx#~.7\FlJ fkTi-ԁc{Izy "X<)Zw2ڰz'Ϟa1O^J01_=3!ɀ̝2$îH`\+KOB+RMߪVL2>"gm1w"K3]2Bsզ>53fl$tKlԆѹw xd$ ӌXtlFBK p. 3Ŧ z}yߍ))2h `.2a-"tN6XJ/PV?$STD;A+-߷"Ru;6U #˴C}T`p잌]ȫ3;>G*EP|inT>!b&#Gk~1)̍Y,_ ?2(gʾ(%urB+qX_Pp`8s*exoyP_|G?Mg&8CX.ߜaSRE V$\n"<u ucZ=WL8;Hrg yPpqk߄X+A4#MJ֪t]ٝ,-$`v.YCKRa] '2],Xsyi 9S/=xeULݢ/#:}w+fLE>C+: ^pTn-XA}*jRC\(x75ͨapWlo*nh?yElQ;ճw89QmX\~Ҹ싮e#v+YBQeFF|BU 3\hQهEOq$KbQP1zjre*MY^, e:C?w>3j*5فwD־8-?3^{KNPlTa7{%9_i,ZشbP6QV88;>WT['WΔ$sNJ()nc[gnXŭO-ob9^2TeSe؀쪔3szqvDM-巘5*;chsKc+3<.M0C RAR,٣Qy)q!Uޜya1aB\Z. |O9_Y@ Lbq\1} |͙ Q~8?PK@4wr /groovy/lang/IllegalPropertyAccessException.javaV]S8}L &/cj$vvb+PGrvw ~{Օ3/ 9XT\?Zk:˗o/O˳S"i1'uEW{QEG~>(H$Qft4JW"YIYq"UicXfT/*5V JeFJ,kaNt])mYZU3kg:d Q#* usJUƨFKY9I!WkJXdkE^bcCCDJٔQ=qh=R#q#fK(<} &ӼDƟ| 3II"_JmJcD%89QZ值^(n΢\+ﴩ)Mi R$Li48]blhYܶ[v-ҹimƦCd ]AwOѵvl֠d>[KHuRoLo)hxڲVZ~;#6sEj|gr)'fGhT!psX:oݢWg~OTq+S^$7^q^-%WpIL^0GD|Qs+[bcxȱ bx'\'N&4#@- ]4bOyrk":< .̣%ܟ ƓhƌLFC= Bb,H(C C:saGO\ Хx|n3C&^t'PȻdst=' ! O& 0N̢k- R5gxI-cWҴ8pʳ{ <5CӾ,^:]LE;HfL\;}FB~ &w򾳄yvOM2I 魚w}zXKmҳHs:gfZ&W rŰ*AWηj D7s-9OTh%(|uɷ87w@.MePbJu7W&|NU9VW_2;Evl?qa?J7_M(.Y.jtICxr!qeP6n^m۞yj`r,^ZΘ#S_nocm`vSATwoPKA4w?S 3groovy/lang/IncorrectClosureArgumentsException.javaVmo6_q044;08mQYfbIr`PZbl%h`e% N@bws)v^k8Yx*ejBJK_Ϫ,aR*wb%Oɻi=}{ E:%oK8$d Q糹pb! č(3)\\[Dd F `$SӊXHP`n1*ͅd*u "Vvm{9(>Uea6Oz[Zj3\عOܭ* 3HUg\B.9pO"mTSAVƂV%ftT6OyDap0miTpj›2K haY,VS[z[>^@<ʷ+CЭF4-D2%ku! (αc[@]6$h(qΠ5J[u))e4 &܅Rq0'ܢ.͜,uNSi2zF!qsQGEWF=K-*r>MҳwmxlLEQFRM,R4]ȵly_b"S3HMJkɅ/Я-8Ȉ K,M!+̭]v;:[{WNsH$C'~(}և a I _FI{$bՏ1+gG7Ǿ#F/CKĎQYI.<@ %O- =rFpHE=>ɍ{Γ&s؏L~I4cX!y }~my]Q+%I_l!M7d^ČXPMU!á Ê#hٟtBc_X]k#'E6,`NIxp=`{D:|"FPv<1+ #v1l0tcv19:&,cȭ^̰ wX;0|=8N`U_s齘ᦪwM!AX*51}Uinr?t^[_lҴҴcsS^6=BCY-xG<ǥtC;YTxi `BU;:Ĭr% Liz#>9:HrZuUVy N2'BX: UTK5spF<3;L-I(2oLD/k?fz$,,1c*h&Nu.1`i7m8\G/a-(⦚M\kqVOi˶du{fnyV|e9/Ahz³: PKA4,bgroovy/lang/Interceptor.javaTn0+h/FߊVJfLqr".6MEəsAgOStۢجV`z2n>[ j4PXꔓ5jdO|<} o5:-fثVX'F瀫Gj^`,ͪ7Aft4x{rL{ vN={&:YXiU/[·䉶g`E $(*Ν.cp}RS$ZsϐK5V'|=eqXg`h1 ˗]=K~LrRޢD z=hElUč%?sT ̉R) jGRleLgIR2SM|J&dp^K[eD' yok?$5hYb3FlsЅ["=u"~M%2Ha1VejWZ_r5ʿl <9Z^t<݁G V̚ħ_l[|/~PKA4n1 7groovy/lang/IntRange.javaXob*wr,v)pv-1 YrIʹ|)n%%&WCNZ"e*ce^Idŭldž;8ӳ_O_^] ,bl-`$_hΉol3-,p-p|ZGiS 82x-04Zy$cq 2?ebeIΈ GCx5T^EFcC i[nmSBPG)JVIW&6<@V uFp3QK,!Y)Y /CĜgҢDђgH"X !1)U)@|u Q/hR)QaHT)-ĎajLC!F ]]16<%FC"p%tDUT$k  |`A W XXpJ%'H)}RLFqQXM,4I)=Mɒedz0kVPn5¡b9˸ 2G<ߖ%HWdڟ-tuJ?HM 9l EJe?hc%1LFe;>~:C^[0.1G9d;ɄP p"|{qztZuwmf\t`4;{:Ƈi`=Gk8{#~-Ji:h2wC@)=wntl(5ot;q7n0E}pl's~;@F]4;gNQ'84֞LzM+ w7 k1GA;ǮLJwo2t wF.8;h}`;#.ؾ9A)>sG`8n6&3_k;CR5@_2_}Wz͝w6==al*Eͼ$ ?ȣ[tnu:Ԉ^ jfy7q9ӑC3`{ORFsi6E qZe0{B0+45&l~jVzybf+=jkؽ/{hi-,e/2j᲋{"5,)=jiiX-7ىO<1jGȊ!;}K]3 _aG , -_bC"%9[$ԕd!v#tJX~c0XaQT :c; +6G7쭔C*/ʀDjbFA%s*!_bzVT}BݘmjlYyX}#A'xAJ8]2ʲ,WZzA;+6P8ʩ\[x} vg)?܉c|̷?ʘKX,' WSֺ+R)o{`,VNKumG#/rB׮*iЛŨOOn_Sp-H=8GݣԨЄބ͏u :_M]:.W3`z՘Dx,uEzblrUPKA4; (groovy/lang/MetaArrayLengthProperty.javaVmoH\I^uo=8iukhYZU,& ;3 ^&OkbiV3J$6{^|3x8sTz]R bʭΖ+c??ZV-(@) =LU.xy!9UJL/iV&Ss]IP 0J-̃nRI&L!UIE859(mUm`l%י!RM¬*CV,!QE_e\jHW։DMʀFtUYr"B,c< J #,NN2z]B-&#8% ^mޞӄPuMrG%"Dᦆ5J3l/&څ7 l3/RmI½AF d*Mͣ w&USYB;$׵̮OJQhꌢ鑪"q+QW哦ljTdH:GMVo\Zl4hPvDYJU!V꿦׼-=&5K,Ԥ\ IUgF5E )_b~1`Ds3"De| p= >b#&?ko74pa?zz<nE!lqء79S< 1![7{Bp x w6%.13/?{!,`^4?\qݰi ѵ7gJ8!Cp(a2?+Cc9-yCh70+C6!(F4F11 mBXx}qYs0H6[4fa8݀nyΰr<"Dls>U 5˃vl]_7clcG&R$ߩE|/3x#&=끆0xB㹜dY f!j XiYn'-8ES-?"x7- hڜr~yؤ>s~ =^-\Oٳƻ~nJڐgo-ȷ IvhHSdbvfCM,ї-;ۡ.7"铦Xd*.Q .%M{Y\cUZ-Ո$6ձ#)h3 M{Q)Xw֪Ht;o+#W T6*Ki8]:jMȖa(Esߑ9S/PKA4ӝAD g8!groovy/lang/MetaBeanProperty.java[moI_Q͐e${(a1Ct00k~Uƛ1EJ<]UOU=]]W{ ^}8 ;,>bercf3VxO7oo :4FQBY_٘+ɂ8p\BpiC#GB z\q9;P%2&0SA\A2 (q\3SJ!K"y0"=VKV5ic1@ϮCaB&R>$#](a<@ă䔖d&`+T8u0) "HU,0jYV"%Vô<:Yl c&o!9ǃ)D_]/xjD^9 @1BA1d1 \H 8(a!!zV_g0~h1 *C)b\Apɉ0HBy$q5QD2<ȐX#R#@* hL"79 ȕdBW,w1 X<Hސ36pe!:hjSN:C 11\R%1_VF~5E85Dh@bLi*0J~n@៸x#szOni:출F߃Fo:~=ݞPK=\>緳y({zvuufr;5@=vO]ݚ6BGp'q]B=r#׀FwvgYs"M-kӲ;irߛwAöCH:{N'&k9MѻjT9$ctк#4fj ?|w-Mw F_Y%b3>,XGdE1O*wu,F3 g!=VI2 ɥ W3 + 7A=Fb:ynXf^4iOSկ=$7|^S[]EpZFiC?iFϡGU6J tzc{SNdt0e )$]Tw*'#)6v%.n|Ƣ)|Aqɳ~dlVaXv4ke}4IL@w.#8 q_8)4kfk(q zbEJl[@y(k8-J#oC]4,㹡\"ظ󢺎$I<3rrog :j D* dlZ*Dj2eЪ R2hcP`(f֗xĎ)i8-T q55|@V2mSqf csQ S]MRkpݷ3 #mn~[M_0Uʐ .tNXdddUJn);?y!O/\+ne+~Q? /|z\DWS筵wmcndY\D}b:)_R/zcB%94 - Ki`3 J(ֱ:O4# b& (,87A&[Ԯ c@gR $RE &4=9 hpuA>x7Ӿ3.0 \Vv}Ф*f%1̡:RnG0BfPg4bsܚ=B/DrK͡(m\o INQ޶6akT%Z'*촤 ОmbfwTUnM[Q}QM#cIw)VŽbSQt8%)BT *-U=zz`6]f=H>4{=) (6eI3OϯW֦Tyd[iͮA[]*s?DI,M愎k%IfӂbtRv/#)Ho`T 2+_ 7NõWWOntm_Qlyt3 $<|n(E{ԶWq\?od5L:]qze͞'{yw-ҧT8Ӈ N_m-cMkU2:euKZ[gKunv L^*-jm 嫓Cs`%yciv:PKA4yK4groovy/lang/MetaClassImpl.java=s6@4t{&*O|\&$$1HIU{.>'ޔIi],5p^/]"wusϞ1_xWDޜ^/^ڤ|c?VM~4#</\0in1edL3i44< oypuFI2#"H{/Mi@_/i{h5'^!a IsLpj MaxVir4h /&)%Q܇I1%_4b!YN} [g9IAa  HtƸP}9f3wM; w(ސ+7UK};~As5TBrֽ^')REzܿDzA뗓;ht7&kןhDu=wi5 (@NP /'.;뫩;Fo@$@#Ƞ:s4dtF㷈e$!o^$EaL@b^ NI#/Ecq'v;v'X;B׌ejaHs={ 82tJD{% 踱Y֛x!I.WIřuX0 h*OR[-7$[Q-mge{M;&d`JM]{ȄYnz-=et]m˨u(R"ZFLsz<0?f_8] q1Nk]9#:AׯZMX꫚60qF\0ueLa, mlq,%.^/Y oiPCeg{#Q2 SNĀ2P1tzPp4v\e%fp\?@bU1:`h :6 3zc\lkt9u4EIN@љ =IW%tKu_h'}?٫޻`اH^Ʉ퀜'4ta;F=X1Mar@Sy_ =~Oo,%xfaK7`Yqlra@=[r !L~[bID9b[|LOͥFy=z8+v-a< ֌9\( "7Z7|dEwC/.ķ< sG7Qs̈́aD}%6DȕwU2fx9;0 Dc 7Z9|!f7)ծP q|ì*.LPڤd_IBb`!G!l'\F= qMXtj9r4cykXK13rJ2cc&jZ eHZ<&I ԏI n{J@La $Hf /0}{RH` 8eHxYjjiY{]]˗zLKFgr^6pٚh7:bݏ۟k'įư3z+ȹ鲗6hX)Ÿl Bj)S0l,+ Th&I9

*#T>> FaB"U]GG!_Ԓ@H6W{Ez4Bd[4V@/H6$+8 g_iU  vΔE0LUWڊB#g5X)T1P*(&4hU7dbf/=1MNxP;^+qƿ3 hJ504(DV~`X}vF'ÉɇO* iXޅ?a:רFm;"M x򵚘ڡ6mN)2aVxfyi).s.%& BJ@+Is)a &~nL&O0a+7eb 婀yS>#־2[]3XSX3d{#.DCCw0Ս#K5j2D<(CC= bA}?9"Ot? ?񙚁eu` '3lI ۳JP'Ky,tDq.HEoywQ%A'2_{e°{fDp iaA)&F~6Dp hu 8`GET2y+=b4h ht ;:Z |DrF5'C[ 7َq͂q}mP!ЍϺZteQk$~G}fE6͞I$0χʰ|FSj>d .ɵll1>b}%Di͏5!JYupe[[R6df"D>YK\,Yeo̊OӬ9cfIDp‡^",q*=%bK ƭhAIw(tr8*# s\so8hV]#f}t1W"[J_[G8"|f2sbӨB6-HdVљ%̀Wfya5ia!ޚxP,iG7]2Yu,uⱪP;/ZSf>Kb7A5>9h0̸ )l{&l5.{ǧ^,VosKÀwwOZc :293;m୰LWȈG>I:Qp0Z0\r04\CM^g|P9FT l÷oQi£bb]9q>Mvj!h:*9_]$_V~WY!/3k\5\-{Vr*q@ZwqFkL5%iv\b-LŶyUs\ls2~L{Y??vXFڨbH61[lc|u֟j2aB@W/oh R%q\~ƻEno.9կa70M?M/ 2=ZSC4Af8 th;}$ EqS&B<,M19نW: Vڂ^~Lۯʅw8-{ŮI 2+?.yN ё܊NJW]0%=&Ylm_P2Lp LSeΤ"BeO؅h-ZzQwC1N$/3oߪ6}ZO24$(H6R$jӈ-IߢX9uGr%W v?*Kt0N?́L!qVV,)*&E+7[SWUee- >zmK9tA5±_NSdrz D<`h.;ʼ9ٴS.zyט'Dp,喬<9= T;;BwEYQp!YkAsynb'7;JKK5&..rנ:)[n!a6Lg#v^ "Oe"y&fcjNٖ0@`t)1Y%œ[St޶CׇLj}s}SI ?V{lS]Z35dHšq@1]IJJL[pAs+ax f8:y垃z rz[bvkthMDqyUwmHl*djW+[.IUJȑ4Kr!-k7ݍИJJK-i0xiݍFwy)ݲi? T,"| :W/5>?l3ӮfUۆ=/3"C)fȪG˾}6C ;G_Bfs"{ur|k--]'0Y 悄KrƸ9otrT_%%?PYIdts K.5 "0i2z=}_8 ,o4e zy{r:U'5IĻ2^ItMh[wzdw0fGїQ5Ri*`IQhhSؗ+#h4{OZ;!B,^Y^:$4+ۡ:t #vY|QڱF 3OBoJY.ؾ2BYO(y'0yvU.u^G~Zdڛ|2+^lrZ.qH Yoj=!}v^_* j9?L{4]qv R3 nG`/Ag,A)~:-.CY7pVLB ~UbyGQ ?@ Go8d닥:Um;5srB;I agYt@,[m0g}ɳjvi`i 3IP~s9ӓ"AG.ܠ`Jjv \(r]; *՜.D"K\4i'ջeӍHVHxMKHa<p2AUAdnCD_;囗'?~y__0g(`Qs9w%M Y05?yވcKWk~x*յD6kH1Q-ʰnkVz֘ BͪȽwI ߁Je׍*act}r¸X6FZRԇ1yl De K8=+jǼwD>LQv8p9u#YQkО~{HJI4Lgд._/|jFCHerh"+zW 0gj>;ù4]\/h-JLU~ʽd0W uE\f)'li[R B \~3Y-:7sEߗ(2IF7gFܖb<:YM0oVF A2s߲X2__ f r>υ/6l b=J}RmqYMÇ0o/?9Vs!}2ZL*4({!7 ;P,֤yX`3NmZۓYd;{J[]vVur׊"~+F/ 3O;0sC.)?7o gG\L)Zf|OސAfop|pz+qn˂z (7("oE~W2i= 8lf74/&+G?0`U+%6~Hfu#|t_O`:؟V1QS}4d7 q7Ɓ MA::6JdtFLC+nH>jEjn#p]E qߎ\)1As}Xt1g_ Og[,bG0j5]P=dS@8J7jMK/_5{:SFP\\]lrb |Xܛa8.Ց)`'-q X 5tZTepPʁabڑၨy@Pl:.s`pxl;rґ.X#T5My~AS}!~<}Py-BTOPEA+‚@4_m\mZ9"Ok%D}yX@{P~ѓɱ**̃ Dۧ~LE9i/ xe8H8F4JQ"1 s>]NSI<)6Jb|̓1ZiLEz#( qdVBx})M?_>g>!J8y4;<1-ı=W-a&qI;5-(Ď9a' ok/,CI/z"O$=ܶqea+;THjz<>],8b Yh8X::lYskv! 0u>Neؑ,6ʿ\^_0-SHki v8tœ\">!(Gn! OTM5dVOEC&:P}a8 FΠtTΰ&y`gmLGh>J'4; u7800د/%\AN vxh`vn7ȃN?Z >(qM9KA5}kwXBd4Ih>$wF{<u;FMhƴy}t@PՔx}19!\`͕y!cȨ^jvU Vk9dRƔd-bkP''"r)G Ik$MC )VwQ6G%8 |ᛗ'6'S}IkX jsu/.Gr&SYCÓ޼|_n<8 SSsC[O0pƺIAyž3>7a"]QaG}^48wX*fm'DZCb R[C& hİ9>Q'otm]1Ŧn~a~M6 O^%!X.ӜlN#].f&upF)PRT s_Ɯ;9WXI:9;`~p ͷ9%4n';GFz2){Hd, HFĘN-O%:Y=V @|FՃ]|؍tk'QZVj; r#)RiX.v ^2<nqd:'/eRxAP3-Ï mX.O!E96QڙTNbjCu P灠S\IZY tڪcN<^P;dc+FGv5/5> wb+Jv%ɫ=vTVbzW&^ NN͈Z+'I4cHe`U:ʠjؒkZ1ѩH=;l=vLFNsyޞt~4exb˩dxeIaSb/nT6׵Az[d~!C9vPh&S0IqQc @V.=z46ݕQK{؇ʫ(`jZ9])cwo݊GkP /\5ɂֲhCzN f\EŠ*aZa3{\1 }zg\Y$8Ef[>HɃk{.M*[(Y߁N.&טe |q7;qBFrHIz\>Vj D` T=iOeiGx@ޞ8mBom r f0e68rp\#|2/=:9?Y[n+\q0ј\rMѩ+dspr׉_fa-| BcTvlt. {q@!w o> MNq%]!CN}>~ۃ7nx7k&?Po,oQb2Hw KT3!WEpec2u׮j~g{[o;cfc^`Oc:|=WGEx93ܛۉ_gO&;}7҃lƝ#|6Tx0]OҝIJW| pk{sw.ۙ)5vvo1;EwsɤWג5EAˉcsFs Jw%l(d3rއ!F&f׍Ҳ zd /.;_x7I99Lfwcn+HmrjtxvΦ\.(&+ΦJ]@TCvp#*k >m47#Zqn S}LGΈ̝;(>A\Jmʥ1;T {$QCcn-nt6XO>1K^Uq랳$$"ҧ)r^$dKLb (V"V[DZh7$41PUGLwc^RBSԈ7dٳ7o̦ A5nÉ%\hqh:S Ck&kشKRlޗԡ۩Iҭ~KitcyB1bE2Qi] Áz*7'e]؈4B-P&V+غA[y|ڦ]Xu ;?"^4*@s)cFn JR+_YYf1FB$d8u\9M;Y4H]M렩quO䢮9vQ^\j@kN#4 xqL^WZGEmV\<*)B3%ͭ&10T?-}joW]0Na0BG7,-b2|̸jM7di ak:f!T184ROtcY=!8>aBR'~:$ϙU'33eyácu9oV>43Utq;fgV_EU>(Rw(2} 鐴AJ1 #W/dg[<9GDV^M?NvAÙ5,v1N௨}TD0~lJ} Rv_D$*5|~BcT_]6H}Eͬ&4{n l CMa ˽DmCB}{PKA48pn $groovy/lang/MetaExpandoProperty.javaVmo6Cvi [e&ag[$'ͷ2cEC(%M#eyx&98)& efZURۍEE os8?;2x{g]^\\ 2/q*PF狥w zQj.E X&2Vj DHE2ˍCms$Fz h. Qi. SiE8㸝zSnTإ& Qzr3.o%%M@~nQN%&e864; rDݐ&*Si^9QE$p@;w.xKLyK7(HPqV#K AޞO)Q ;\#,"_IM[ -% pA5nP@g fpJ7Ǎd )ښGJY Tk!km[f'Ωk4uF1D RzujB #5K-:>DwZrl%6[( TvcخBik~-=&5 \i-2뫮 _Ē0~`T{DrcëΏ, o`xAA8b7<:/$yF1|ǘ {cfc#٘#bG4,O80  OpZ]6^E ~|̓{W'S,WXχ%<fh P!x}>a#9`]`l@|ϕ$~.vȐ?3*Dx1#$iyp܇xNCE~t'hٟsA̟(/M5χq“y: GDbaεyX$]yDA0y̝y|(N{pޡ7-@?Nft* pЇ\ɋ B9U@,L_i(YW47|aɧCnAݺt]#6b6/ٻT"*j~4(;|U)mu›c NxvGwBsnAԸ{h%rkquNOqVC1]<@~(kb:Ն(pʺ(w:?vRSx i.*C#ۖͽ.p. nN^oZ=t9;ɩ*^CZ΂vكȕS_j%sA AX)mNi%Xmg#^%i[S_$?CkVUQu#ִ׮=QgPKA4 ^W"groovy/lang/MetaFieldProperty.javaXmoF_1ZJuT4EAiy%IȕĄ"]Jq3KR^)833άy{BoӍe,hTYE{M?Y?ٻw:~}w@r͖O*s~On-R+EJ""M0U.EvJt׹XiQ6-),r`dVQlѨt% 3I iL>1fM,RTY!M6|n1@̐i%"QVEhr$bg14U_4ySXDu\>޺=Gt;9'{ÇA`_Ses9Gͨ؞=\o;=wp&`P߽qö1Y1Vtxk|/ܾn0A=Fqh4FC!H=mYvɹuv){^8pӾ;l/0=pL۷.ȃ6#󧃈lЀ!M}c_!7AfcϹaA?7] =v|ǻuC߰661Pm_}אƣZt=7 >!z801wϸ̇C{Laf.| & 3K^9ûCs}̹> ;TplVmWr/ݺ ac^o/G&NR_ g84HgONN2Sh1sTUA[nξHu-_ 4anK ɲC+ES0ZșP.!_*\0^m$w ¹s1%h&ѺT5MibF7As{c!$?sDFKkm2o|ڽ xr۹ 1/W$ O G4ר,1hд)@5`| MlhYXh}(X6^Y¾I?w2\4l5*{д2]̀rɵHV|+;Ӽ!\*lؖ):I۟vC`T+U ҷl[T>WYOƌ܄|&\-Vhb1q8xy!OJҿy: Y/\* 1_+ _Qƭf6yׅ^ϐ9o mvLcK}CwK'c/QƏ5sU 2*&˃`aȖb̾hUOSj n*ҔUacffw 7 UH/x^r4]rG2?M0V͖^vWcvSFrDUD"_?@sP]q柏b0HaݥR@V5Xꦶt.T|lF~t}_vKJP^MtK X&Z.='PKA4! groovy/lang/MetaMethod.javaYmo䤄msAVJbLqU(;ly}fvf:Wž5O\vLoo'v %X68XR~]`k_X4s1kn)u0bJ w|g>4f4yp HWAXw,r%9̅](eEr7#4 X~m k1/5 yDmb xX8[0wA_Dɷ  b 2:4GmBP>aKfN'D<ٗ'0dä]Zv_̂P-B[}6;^Wڣ)!#}Ud-1B~Ȃ5Ica-Dǀ\azV/#FR(Bie,\AKa)a"<'&krP4ubהsyyʚ2#R9$d>"@6&ҰVR 6!g W1SDd!>9ʫ0Ɍ{̲5Y"QA${VI7Bp gӡdLƮIخ94kk k{e uOrϭ;{n"E$EezSye"xhPwb6]XX|H4uNeƵqv#cN뚬F0Գr<$͵۴S]Ե4TR=JApϧ-G8ӉgG=Dl4HHO$q㕅Vf.gz$BZO,ˡ}iLV$Z=44d}ڦ.+9ɸ}Ɩ1\;K yUцl;JmEӣ`q #=拐:#;Np^7|N,Ɗl5, w yb~Tyo;nG;q+n* qX GA!Ȩl28F CFΎ}Ez n9|- Y:k8JU{ \@=il~rvH@^8|Չ_0̊8b"l?:`kaW .pA0pKne hiv{ӺPPfvZ[aD!o([ׂ/a1G:~[,#ZlDXKE^! ќ/f TpJtVD>j{~iu_z]>4r;XkDu; )A( Cnz-hj~<>L x"NYDOJL=\ʥL|&VO`k^q6)NV X[v, N󲧤$#,")X%`cwZ-Yi j;ӯhOJ6*,BCȱ4JR}YzQt)`G)ޫb@S)=X@5;zOk<+aivB6ónO*[KGj:v7S-%K276 AU&zVh.6]limx\\r9uɲgٳ:8TV++V Ogno9ZX#˅O:A4:VK`)jkjI!kG'ObLj|9$Y7Cԅ&U4Ff_Y+Ae'j񱮜M1E5g/.kBPsH]H9IAM\RB@=.~&DykK dgJt_I5{ۜn[e1%h=5 6xLW,nlGrc 4欧|W_7sMK ~#Xr*8ݣx8:|qR]nk[pJ[2(֚m=ؼ?S5{kxMR^O=͙-ʴw9u^<}:YאK!@a1˗WWG"uz ^#cǓ˨׺~EoN[W&hKnY6^B^+t3t`R52Pz-E U^~DHG`,pc&HJ?_u~`l14vyJ(m:N_`i̺V:FuyQp߻!p НFqFaƛ7v},0?'#~Yt[ %4;dBpczCu|[> cMGni8 "8p?d<$ck.y{^L(GXĂnGՀyڸs<^UwmS+v UG=}~F"^7ܯnk-?ߨEnou ?{M`| xC9Yڱ8,$N h'(Ulpvh$`JdQG,8-[SSHssSW|8[ QsmFW=q^),~sӤ,OVV L tЄ~t[JT^;GmFqǞ;W(W:GUP6mf}5IR?g6?MN<>ڽ-A_?yB" ux;=+3d孅&Z5݈iu'2O'_$?O۪,sӦ .nCkl.xX0Ƅ t?PKA4NR &groovy/lang/MissingClassException.javaVmOH_1 \.)=B[8 9)[{u E{fPku<:˹WȪ_Ss]>ˍnwJ/??9韜/B_2#$qӫ{5˟ҡwDRUF Y,3:׷4N[RE٨[6횱XuHϨ^UzVIP4(zZCu.}uMK<]bk+ey͆VFoLetQ;D.*TOzߡn&UP j2y-YᩀX1FT:OUգ' YTAXC`s;v,0/m^Jsr gk E֢m<0U2_*nG)b>RcDRͪ(EFzsiXU\2I6\>.ulB\h&meer.Q6\,88L0I^5AxO(JVI`Z~nUsh/{4tKy5E-S ,#GVJnSK]?c #;4_!W=yM|0G%k_~u>]}XL"v#AXO?C: /+w #H"|QЧOn gܐ8DC;OF>A⋸K~C?8 @. S= /h," ?s'7ҡ ? .Υ%7M$qPC?F?C'"H(rG#q;Jh Ρ /AQA@OB|ƍnlFcBؤ;v/h<|LNo1C׺ pmϧoYDDtapUx ^/d=6ðm$ǻH# =wъO0aKh rfE-Ժ~?yLKEOCNkI fo:K37Ktj6hUTuk|kl "y5&m[`k `WVѥG.k ҇v Mv_qNĻԖF_bPXGpDSa'X!:Wh5NWJiqoj_Eٛ:@H ~i~ ڔvYS;QmTM;)Boʇ䷆ PKA4% &groovy/lang/MissingFieldException.javaW]OH} 4ZRhgw;k;P:ؓĭ#ܱBڭ6t܏sνsg?hM4N2-V*y\zGtIqw::9З*d9o+ڳ,rH狊_Ӿs@Rn,eЙq|HJ=v*)P**!V ۚǺTgT-ҒJ=d̆,KR %:*${Y [AjA0꺢NY.q*iŁV^J,~),wЉb'){k ~@]2RE.+*T%_bYO ĊQ4VeD4!dVjaIm٨B?E4=( *0Nj UQzb62tJA*d3.UiYG%b>JS%(R0ܖqݡ^(9:B}teJ]pufC'Hƣ66˪Hu nf (@y!kaq̔,US.3!޸bh~5Y&SlGVJnJF_r :#N|Nz4iE%rg SfuLEU~+WK7?@֓rbHg7CqiOC!=F~Z g{7$>MrǓ%""9.(y~D#wFԏsğ;rNiѹyGHg"י&`⇂ zIJxhd=fɸQ:hDוd53әkƨ}@eɓ y%O<ϑpZ ͲIq<9YcxVҢPw%Wz}|ҿj"yۗM*̔ :<|[ kH=XTJJ0E^8hzh19:m]fߍ=@Bj?e!4V\]P^u {77WN5nvo[ ~`9(ZJl"YryE Xv׺ f.]h]42jOYctb9c+QZBJLk?;Wm[fZ>rMeQhTőRJW $@KTG2x3 ?$KaT!vq KYr pt1c΋}=±1yI_͓0w/g5/',q 0":xr/h2̀P&4~$؈/(F׻'~r![(F]v>mO?Cyޫ76K{QWqbw~z*_nͺ&''[LwOs{~>6ŽŬ.0uحu6!Ni+ ewݾ%&' fƴ^N I ݔY=<.oWGVϵ%E9n\>WÐ=JTzS~ )f@-PK@4D_0` )groovy/lang/MissingPropertyException.javaWkOH_q!h6a+톶Ip7[{u<Ѫ};!vڗ%9޹3t-:pH8Kk%R2Y\~켢ӓWݓ);wvF2\f$,Y◢NS(YWa' [*\bVEI*eF,@xaeL"UtYDBf&48V ,sTpO2A)_lPq\)^#Sΐ" U7R!sdrN2(Jn\"Op[nus;P34f֫uteJbsufMHƣ)k62Ournf (@(\V\Gv*YQ ]]q/[k$FL (d+\.ܔ"ɍt @ 4CuT[v|2~Рb'%ȝLakׁ~0euuή\]D 2}Axލ3â7$ $./^5۽#a 3"o#69n88U" i茜v6wI#ѾpNx)-tBl~'Cۧ{ &5pvFbr\$q#ܐk{8Y20#J틡E?DS:n  EAߵ90 H{d_ x/3MP# !E:$tylQ /szk6rI xQqCqxE-tL kB!Ͽ㨬ѿMQ6!#T wh+ΕpW=sl ©:1JUlK7htѭ݈[k-eYΰ{ꭑlvnYV'1͑N:)lO"e4Lz,`@S}Cp\q1H"qA&Q|X0&_"<9\$i3~}_>"y'+^KjR>|pgR)/:*[oo&򭉳C?*ᷞJWV xA-.ïVs$+uɍ{}\/yU#^';|r5PyZ^⣩Ǩ8PgJo#zygkX_1/Ly} |7#ߩ[ ӆ7^Z3U^MK5sLe,nR}#.&>爞"k!m8> :eY_oAenWPKA4,a !groovy/lang/NonEmptySequence.javaVr6+vI q',Д<.mf f>sr` k4e/`M9GOEy *.va)Ct1N3-2Fq<=JYrCY:)# \h`@+lc=^ܩƣ%b8:h_AЄljG.]('j>:'H lb&E|Y2[+2pZ  uҶU~׳+&3 &AWl)v-nEGdEY,qzQzT֦%{00 'Op' [wPY7w\] [3]Y g+ r]mX >Hnuf[DEa? Q :+Cl靝e*r#K jn(; d;LFթ9UnJ.ymD &d݋~^^ÀOӁQݕ[?9{Q|ǘU'URyәF;PKA4}; F-groovy/lang/ObjectRange.javakwF;iDen{vAPIwf$aFh=3>yՂ/lNh_y-|}sWBﻳӯNy->^Z08XRA~,'ʋ|sYܯ8e 0)!%0e w7֔A|\"nU@{/fbKv͢#mG;]X|m kwBvmXR".B~^0Af|jVNH܄oCI 1K X-O3<E< ,1FQ„':Ȑ_եByy3Pc7;SԕB$H슖@3ܽ"5-":Ap\ a7ZPt_Gd^ƜRB">1Q]T)UFpQ*M,8Љ)<"M$ZWޖv.v%bȼI.RaxIӄ'H2]^"Pf)B)$70/sE %1'y@K)eﳵrߘ0ܢ 'fD*" JɉiukgrO-=p-Lu@<cwj_i?DyRvj9bO`܎l|Dص- x0 . '.E8wx0k:ƟK{de lw ?ulԟlz;q, 3ke'Xבּ u4j$](\Z(crdI>ОZG ͆Z,T?%HԱ=C \aB3el̦ pfk3ׂɐDncM99Vy}ip/g-f]k:ݺdi=D;XCXL?U_[~J 8h[ChEX:!2mBS![2~G36y 咏 g};$Q1[EZRIk}[b{ZzcXNdQ6J"vY|BL'a`{)!O1&% fsh 5tEἾ,1%`9d`E;JRr ǙW61b[K޺uYU=y!$=#BGK"'M'b]^Xʱ 951#ߔ'AgT[_L.39o`?8Ohd@jPm&찧b=jC&T>oZLyy)D1N!9dža uعb+/mT$薹vP`Pjr|KjJ1QE{8Iw`ˁ)Ba劮򮐫@30abjnɿϳEjԢ70wNQ,| էl-mVmb~g㥘O ihؖl00#)8 %y1O4x25!RGD"%KFKyE]P4o!sKe[$! aÆ/-j-VX,ww*U5ONl26mBȭDĊPVLN%|Cr%@% DUo=,J%LG͐Etet NSVZZ@#QҀO2NDX;*|JLڢq\*HEi]sY~,RX:*uKD_Fp;ħj-2FЁ/.H̱<xA|`qPCr>aQ3` îdE";C}Y%G2(=nqcnH}( p gk:uwC6;qzRmDP }&%i Z1Jf*eOV^aU (R|!ߵHK d;#]IETРCPȋA-Ys~\/6!y@ZS3Te^ akŒT?jMɛ5޲DPaBЅ&ju|iLePcqaVAՄk,3LoJ0.A $tϪԩwKbɂ,0"pcRJ+2"pZN-K@|4c)"S!4v'<O\QAu,cMŕ{}O32M whrxE OtWbEM8:7!>o}Vͷ?ok_#dے~hSӜ!T3K ,H@-v.> %T|ߨP>5{{:84WfoA,_-.KU3;65'+ ;9p9]Sf]IFbudrO+e0@>R&,y2RLCmK*\6r2F4vDby>>Maxᨹ#v{wtL7? 9X<(]M`kmf{=}=zt #V7F<>nwN~뷴^~&=~4jm'*Jj#(I9 n2#((IŲf+b6jn7$=z*~F QU:S9:۬dY Q(iN%i\e.Km-JhmV2PO4ETLY˂[|ueVzc2&#kJhOR*U^ :QTڒp@X;;_BL5r@fҶ HiemcQWnh6yhۥj~?[ǝLv>J%Xؐ9bb8q B Hc \"hc*.r+a].z}75{vxBIt1#'qtˇlH{L2 !ӄpa4ģ)^9?'a$Av9@0,t.ţ0Jiox4꺊/(#|{[ң+GW(ďSL~Li<FVԐ'7l!jeaJ*-4y& 5uschJC ߸KɄ1~|ߵMSa`c)/<ӘX0"Ӕu -e%44a]H}W  w0eq<< O<Ew45B'EE>8t7bx[G[3$mAzp1=I!kF' '67|T:vl-&+AWh| Fv+>vO5 Q..= ؔ87Zbww;-\͉>ɬm{q`hʽJ㎁Xn] ͬP᤯@?^{֪-겝o 'w\H>O&څ]/ߩ m_huiĵ\f'Σ}}poLIlwE%r-;ڼC^sk :_:_S_.ϣTmG/PK@4ϫ: groovy/lang/PropertyValue.javaVao6CPIIah%&`K('ͷcEC(qL޽{ݑoxyS[eYUUnޟ}18.>~8_mgd -_UFoR֓QpZ?T ݔeYRR>^D)ɪY"cEĭS* DI@p{wv._¤yHj kdRzjrN ]UXeRʒZDYlRWhP}\ !28^7ǽ$ sE#4ԆJw=^2z^bI<^nnҚFx4}6  "6y)Է@Oo`ѡ/b͂} 4J>1h烫 ٛ#V]+*㬳S IvG:2_4^塸,֮K@ 0~sˮk/fph ҫ64Koxb&(( $yƇ<̈́_S޾u{ar4cB`vL9 3O,ɵA0c\3fw>#`07!'5COH4؄(b69g94e7g;x,Ms&[i,v=M'J;B%>܎gs+t-"Ȅ]5K"F)rCqA/|bՙM]B^ ob vZohk:wVO8j,.=]~}j]ٽ8݇.;›`1󯪠E6>T0UmNE+ o9=csrPuJ\ hqV-8{= %x]9cӬ~E֖=njN,'׋}/To+ȝzx[hC_~Y tPKA4Yygroovy/lang/ProxyMetaClass.javaXMo6W rCA ҢiM=ms#I1;M"=k$gܰ≭9R}^1LD(mAu^oXk`[iEܪ'Uu ۲|ə4ha2 /P7t \.jwܲ['=L VUVZs_ހU waK- .Avnn88e͞\CF ("F>\lYqX IXJOܬPBiF XNP;ܗ0qVh_cF'p2915Oy`x%F.*5$~vOvY<g%)\M_'O20+YckmU]WuvNB-eajG(pn_}l.!W'Y+e;w3ol{NZSx'ÆmxƊD=XM 6_CbGXؒc]q"\ l½ bzg fjL< )fU?w,ur8R -[YcȯTDR!SnddGco6k_M 辻{R}%SI"7ėf*AVQ-?Z!+$y' BOt|^ Yo=-vFV]҂Ql˰2 fa5y_Ė?ݔbh%qq0 #M0n[بc(4[+Ifr8!tjy^Iq {ӣ.&MS??~PKA4Jn groovy/lang/Range.javaVao6_q4 <;M[`K$ɓVZmhP`;NCw޽;48Pgj_F6+ogoO^җ*[ķ5zf}oŲat?Jה,U*[ѶO~YRN5źv>bPڦ0c[k2sjEM7wjdjtNڕ^$[Ã=+%ɋy91ZU0ښMC5k&^* A6L)pT`!OӬGJvcLCT3я4z]n_ >JYe|R"$;ֹ -C 9׽48}JB?Yin2Xn˨+t4yhM8t4Ɠ(Id}y%Fh/"&k\4K&OG8]9R4 K ߸GD@2~|c`&)I#ʿ(4AEi,2H$4tE#Q"k5MD1R߅6i"j2LEO'—]F74FK E-N\ 8 a7Ka};+l/+,춉Vn5en>eTc,mJ=f,UCQVVYWO 0@ tG[>2zyG #hF2g Ȭ_ \6z5{v^Ʉ"cAXOZĈD#qi,4~zėi,QLr2K,a*E%H]GaXNd4꺊/(+|r,[.хLCԣ iǩ fc?,F 5I0D0^2DM"L)cJ&τP?td,C)ݒ6w)@B|Ƿ]h"!4'My :b1a0" TTeGe 4,]H}W Xgt0q<2 OXI.TqgLVSRbD9Pn7%h{ݢ 4MUY.9 KҴ H$T}AUC SDule2:ʴGdfڨH<@I̥в/SN-H{ӢOD9>JX9bb=_Ը!bvu6+>s>Ƀ-`"yj$L!0@[YU-Nfkۮ6>( K/dQ\Q AqDË30r/Bʋv},ć#CϏ9\~w0q%81 LjV|G YLIxG#/ywd=Qc`4hG(u8zk@g)z4` \F \ Ј5F svMy f;PѸ<nj΃g(;wYtJ ~#FWsgqcQС~p _@>rP^Tߥ>8j!lq-?g~\򈁃D𥇪c+x5[=$~F^ U4 nu+R:j; |Sfi䢘:N6_ {4bYE#x,J՗99RGX(,²^]̲y-M$j !\dyUܘM;\ʼn{x-f23O'ֱȫ,!"Z?NH~j:TQvV{iB`t5ԀndX}q~ OqVSYaSL0b] :8<݌f:h~@E۩Z36}(}<GY:e~^VۋVGٻzz݇S.sͻЍ ;.YCu1g4%o˳CmeYCr:Ay:ȅs'r\۞C&W :4 s{=8ܓi0C@=7|9G%={#w<MG@ixȽp &=q_&txsOܑܰlLGGSr;N ]0 grIΕ3?GVK;҉퓑ϡ9I%{`ߨG3pށ3wc`ߧX4/34vq s&zn0 :Llr|ǻrLN:[c\L}W󦗁;w[t>/0<8CX & 2];1-[⃶AP_`1Icl9O' sl=V|mCTQ]=LrO^YaV#|dmpnHZ6lF$V+\5,frK~\ީRfh߬FV"&r?zBɖaKJB# < vӤ9[^dj\$xCHSPoBzt$y 2)Td۰!BҌbۍZm}9j 3C`R~Ltn1퓅k*o %a`<ͭ%DSu-NNG{Ïݝ~}AUL{f/"DJZ?I3wv~NJe(EHt agcjǔ@"+>46֧wQ(;ci^>UT ¤'Fc+bP(]%/͉ dYJCp.<\4^oOlB\hDY9!7A^e`,yA¼\S.H'Fy!QTyas~UMC c*a,66V?਼f+yu٘M@ۣAm.Mo&78Tk5s2j~9WTEe<~~VW'0UP$Wfaos0.g m0~Q@*Ū:镸gWhҬޅw-0' K5ԟcmKS}]=d˒jm^vSu1-Oت;<=/ KRhp(S8%YrA_jXl=)bG:gq+_gIvi$=PKA4\I˶ fgroovy/lang/Sequence.javaYmsHίR8a\x/2ȶ0pH6_v,AaGǻ~37o+[b/; Ooxge-~>>~;|}<<~yr7o!,^FUNo7:g+KC87pܭ"s9+% \qe<\F7<qq 2q12D,!"$<qu awQ!!at$me$h-6 yA},?nE(]B 0"Lq%8c{ pцll_Y /u,Y~QYO`:wmC |-Jv^h;>Lg>LkG:W`v׶;Gܙ8'Rف ǟ>@u-wF|g dF˹ǘ^u]YIi%pn#F|bk=hq푏IL-YnC|>xs{ЍX> F"kF7N Fdpk ߆lL;gd{0y_ RQ |9kԷ]w1W~*2=4s?T>^KU޲CSMłՍoy,lKsz7d(9[$ ۈNԸBGwsG`Ͳr*+tATfTivLYwgЈ`G!CsGi+r}wx\$n؈hg2TjH,j誺l @a}jN Ca Φ-*z`024¬ebaPES :0ú[((U;R3XKE-eeWSC)a8L&mu$-p]b4Y.7ثȔ Cg[ccPl3Z$DG[ 9>@SW{/;PGjspr7[bx fi mG}s LHӴ?7/7m%G g:!H4J6]C}GËbnUʓd/8RQmHU5 y߽ڇIgQ"E ^XyWZdl/+D-A?TX *v'< o$'<F-<QLeo5폅 L%OĖWV>-d'֦)rT­ ]2z+hk1ji5IGiY;kY7pjQ/TouJ=6)Mfr5FSy_3Ѡ!jcT:prlb\cކ6wWEׇPd>;WEw[2t)'cL1.vC`pAQ5ys:bz<ѫ+BP|."a}-Osv[SNZ9ƃy!`-YlɥTAo=vWNSXqH'mB+:@n;&HK6?PKA4x9cgroovy/lang/SpreadList.javaXmsFί踶*ث/:eema$T4/I7ʇPe3Rco,4%o5懃|zjВG%&ӌ(C b3B)6X~*Tƕ NOL)`i*GePu7b,A hኮ ~G|hC{# EqD&3xU-peF贫j 蝅W~vpz.zmt A ~ ӽr|.(wxVgt{!tK/Dgi|;Ko]Ox5vQ:zA?V.6E~v!NS[GIvP8uF=n+ĤоAmypv_[$Hv.sX_wʆO0"^`p^8]8dr :@keק^~5]_L1u5\PϿ& .\ɣ[vHnkU:Ԉ^ +0wsrGbE 3:а)JhYVr gYSc^-ot9ݱ s5bLk51Ko fl;ÔpF]plT; V$Bn{Rqucña/D+ _82bUPAO5H2,=]IZV Ju?Ԃ#?mD| ,Z0 څߩ.x C_O $b۷-KUp 7M >`A! }Rܖ8p%WsQ Ia'TΌ8_fcɗ<&v³iNr"J%rQYՁޘZ c1iZ10\ky3Kӡ&õc LY:~h8ugybRwOsج 4L*SIn-3UE59괾a7av].?i$7Q=+uBzi&6oHs 3lŏ6Ha³:ECˬPFܾj*g 3J8׿y2ɦ/ahwg3BzdPPF?(S)KSntќP-xa|ۂ&d^cYNc[c$(M"7$PT]E+ɈcWJYq.^%ԂK!ӆ2k;RDd6l!~m&o>+~ks%kFZ&6۳y+:V쨋WUg^uE?tq@!n~kW:f n;dǻ`W@aȆ[BYX?E&xΧsb5㗲p;,^lV(_v\zUeWn^L m|aZJ+18R$6$e=4̃~:u[Zr\FTtzV>`p L?V.߷L# (NHH%43[Ϛ.,Vը0 p';TFL42Tu^'il83i|g<,+SPK@4b.groovy/lang/SpreadListEvaluatingException.javaUn6+,T;t"T YrE)ܖh[, $$(;iEQlZyޛ!5Z]U\kCv鹩5y*Egjَ;btϿ/ⷫ߯./<yA(gU7F^ix_Vh`Fr[myjA@f4dB 2Q!!U/{%Z\\GZ˲FTPɲߊp X H~eo`+zU. Օ< ~ Xɦhj]V+|1kmj٫R`J6ufy%Vzo$wŝ YaҲnzFIj{`Tȗr'^i9Cmc'!*\6 eZߴf%wKݢF/-RdXm#qC'k%dda) ) ,V =$psxaTmGGhl;,Z[%b7}Cb#CK!Uݖ?i0" b:NO/H;B#$&7> ICL4Ǹ<]yNaNp i~oKz0y`XYN"2X"e0D8^4@nIqUiyPLb2AHPd6$vAdFPF,07! AOߚHXddn)EN&M#KF[v qʜ_#>W1+`ԹFdYiy0K>4M\t(-݌: ! m 8.G2!!71!IHnja(#!(t(|`ɶ]B^hf}LS[G0[8ۛnҧ G~%_ Wn@ַ`))wFFgT*9=l\??PKA4]}groovy/lang/SpreadMap.javaWmo8_1kX;iӻĺs,$7=,m6[(I~3d/) ,pBS= àWN-9 o6%kGoݷ?,bdK0X_B߂g++KBJgp;X 4"H)g\nxh-"SRr%B18 P+A.\O,K)B'͆_ 6ZmxjԿi NCs-2 e! H(}i ʴVUC~mDQY9GL䊉?dOs <ӈT9L8M(K)midnN8*T'$**D)B,]eLC] Q1hKiu0%)H#R m i viB,2h,en fJJ'a*|$YSUY@FCt ,Vu-T:#)XP Hb9z'\lg/8W"0TS$hoM =UX,PA{J0 ْkΪT ƭQ a-1;\ҒW|c&!01b 2a0W]~WJNӬAw;˳ \ }w`x/sʏ?9k|}v=pn'#hٳƁcmptoڀV ['@mkz^íj]9#''\;5`byӟ,&So6Gsk1=Z=pec. ΁CBa|6F0w&hԷNnlO'Գo)d$Ÿ^Ln\w@!Go=kmX5@pWSѬ9$pqˀ{`ȃ=9u.2zdxnhwlYiu9,50oF΍=4뒙;Ƿ1s|p wzjؔ%j 5XhZ4oaI:-s-qK#bɲg"^R&n9d .fRE[vd(M'٤_ TaCqGYqA[ 6hZGk8P$a"U RoK<4NUAI>ɲ]GUz1 6x}LބHP^Sxn/|>} r8OiC*BΌxoZ9(l!oM`Oh\InCQ=$s(96QKJ^ }&(6Z$"@+jW5eҴ|M6.48Jϡ8q:ۺ6٨sNA²^[x,'Blf@JcUg"Bq얟IEH&_оR< ZtFt^N#w [f!x,ML;ǖJ<]9v"($s=Ֆ جik@(w곁ǽ.־JS(iDR-:D "Wr"Jfk_Di51(г[@+$$HTy~R *-GR(2;^[F8~~n*UX`Qlߛߨ% e%DtNfuYUiW#hUUt LI%oPK@4Փ`-groovy/lang/SpreadMapEvaluatingException.javaU]o8|ׯX:Kr<ؒO歌غʒ@JNC );q.@q8#iqwvfvIMy$:dz}լُBu}6N;:Ӈ?Ow~N/>|wb?:zyݣ֛F~[eHZِlJw,6PPה$C2JT9V, 8E=ʐiېƴE%{URV5Y}əOUVviۖ}UX,Z-P]UC=㟢CE۔2.k P>tM;B!D`zҪU{<ǀčSԴ}U(3WB֦$tɝ Y!j~$=rSHuݩg{NX-wxrB墖Vi[E6k.u #tO-RdXm'q!n(dNّTSڎ۶iy<(07OʎьvX*%9ؾ]>cbQcܷVOZv[xZȺFW d:%OO $1@ktGi{d/V \dP.5d6_ }w15'vM͹ \f7AU\E4&0<qqY%۷@ [ķľR&rX9 3E'x'-gU|G%-Y3nmI.y]\@ x/VyJ#+*"\|"Q53`^3B(8@gSfJVlObBn+ -0@3G6) /My :)[Z0B3,]%Id){$XzC&"ί\056ֳ\p3*I|b(P<%&H͢6͓-6YSnvFqGG&GOE cݷiZx,2#F[i,ZY.r{h<*LUn.A/5ӭMk3mݐՍ**ؘ>5k&^;EiL}z TY&န`w.goY!顨}$ܲSHu+ ^W uVrVb-eZY`ź%Kݑv!5f|Yz<2 eHW<>Qhvy፝FP@xgޭ.Y8V,}T񏃥*\~3 !48c~Oo ;c.ҽvۇի $@V E {1ׁ"hI-=ݤnvv!:ڊvks|M PKA4Xx#groovy/lang/TracingInterceptor.javaUM0+FE9M+!nTa.1I^Rdyx{ZaĞa[ViQ"BQ/@esو KMV_b$zVݙN״N_(J1)섨rȄ2Jb2 []c皎mٷ CW Gƒ5z50R뎕0y]n75sely6ihRT~PnFrw~c.TZa8T)Qwd<9/n6qBf0 g砷 B^R6)uU4_^V':gxf/wy6[(v^[."<(o>\"~0`$488#~ݏ?8dQAf<ȡ?9\p2+ŁQÐ <\x0Ø'C?$Jj7lG;6!Cg7KG;CŐUq0Y?Ʀ2CِЅhد ;4bLaW er V? QF!Ex3 Qv b;g 51b߆F bq, 'c[il`klP*`wjVem;*ƭ4aĮVC~#U[NlT%U=zֵ~ `WֿEXF*řZp`?v1mzv\nؔYFZ8Х /Y<=xV~=(i& _8TV@=cݎ22@E==zE~%N,o,J }R,r#Ss/]٠ (z:4U3+ϫ;8b_N} ^\8Y"_|;=@6D@5 pq,:Se‹Hi-{k9$r՟/^*E|}5x?J<бw-m(I:8HQ+p֩m,qLܚy{ `zg@4P|ׄ v6[gDw9~y]ڟG՞) N,%=ڎL+4+Ҫ@ȕ'v۹mRO`.\K)H5S̏PK@4aK% &groovy/lang/TypeMismatchException.javaVao6_q044IaplɓVZm.hP`m'Rl]$Ļw=INّ>DץluMSn~w~g?/.gzu 媡 8N7Yl%+U3IvҶQ ~Q@LI5ĪVv.cuX=okkfJPEs/rMerM֖j$eNxpz3-uC8kk6:W9kV (̽*הTR5}κrM\kLaFqm݀UFHNMe /,jC|{4foZxu%ʱ[2 OF=QQC.$RRQ2PRL9e5{~^.@Bo+,,1V 2FAFTKMc 4UfX 8Y[M c)*LRפM J^O+vݲ-Y>% oVʇL=:RG_z~ uߧHl%.G0wJi^1 bnEN(u: n4~-=4X: $ezpg 4Y O0+7凷?Nc$ &ӱ!~ x `<aaXLDaiz/ >1-Ud" \b1~`6cip ECc_L{JFyB2cL!Ng"a?m91Rp7"U{Ly h?rTǷ"faNПW!hB2$Hg)(aZ^L{g;狀X]z(ΎXm4'QG;/tx-?5P Cy vqKYv.пgU]$-o'o݋/.t%hZ_u$xS4 F |.PKA4=G groovy/lang/Writable.javaVaoH_1"58ȥ=]؄=M|b/͢!NR|9RμyfvƽeqIw4jVڪΖ~^;:{zZ ]?9X6lNtMR K%%TSk+хA34ƶZS45v<*k o*j{tr N;h%YMC-޶C֮2 ݚBi۲fܮ ^ts ʿvb]3n\RpS7t ? 5}F+ۘ\]z!TY[&ၔ`gu*YifV=!%WY!bH#4w:mP RJ;2({P]+ 2|.A[7zK~^h>,4 HYҫ:nǨmZmм@H4q&fY;í=V77K]sP Ppݮ~vZRZ2u N]&],aGZ'zq ;&hcDp &sƍz,j! Y `0]sh>hL<6Cw!+⽤fg,Qwe]Y,!^U ױ0=#G[1{:/X׿)zQb5 jy,_\]t-W94 HTA>\xl5zA|FUɿn*l|Ԛac@(hH7 &rAH+_9bȷ^JqTL[ۺ\v z~s'=I tmK,X{odzo/k ޷y SuYG2;O?S/,jC۝x}@ir竗"PL JD!Hr?XRAKf05j(tl(c\Bm@FU]-1{iLR0A>?1㮹7A3̽sXg~f2a٤/qOL!nbKCt֙5Arwǃ~ +;1CSx%LYҚDu\*Uv{\3k!E>LCdb7Fq =wJHk!~c(255e <}&0cxZ{ CQkpNb|Q1N[AhqGrMˎĪ?dak]{$;<<sUޔe#zc/me |txX`qIŏou9 痴t ǏL,yQ!' i Q?5;Dn7, R;UҺ wP9wq> l_PK@4RZ<&groovy/mock/interceptor/MockFor.groovyN1}S& @4 J;@Yh׶ ,ww{i:}l#d-Kg[+kM@' 167R(Ca0%6KPxDO)| ً΃D25h(ЁdzR:@ [v>1'2%i~8{sR4/`Q(MvVe'Rx·*~Dzl,8-k~U6~/T>Z]0rSqgN3Z:)oNwS\- [TwQ;j~ߖIt5AG ̡U~d=ED0ԋ[|VbQT-GԻұ8p =xBktl 4$ -Q7*]$uRsK\OXG-ݴިdIaL⊫ΐ~l1 }C'p⮰lt eR T덮td3.6SD^_G 19nCʡ'8 ~Ƴ7 dHgm>#Z.Wƹ Lԙ4N +zfWqBxO@`QC0rf]gH_;%(H)XRxۆ48Z;!1c*'B$h+ uTIMb($])5r7i(;S/S^qPK@4\I! 0groovy/mock/interceptor/StrictExpectation.groovyUMO@W RlRzP*9{lc僚;Ď# ] YbB<%LW Uk#`T~Ղ$W­T֨ %fJ˓й}\cj4dX1a)+K2.X G FBL<\RLAE sPJ[$9"I7b,j$ ^ .&AZ2anOM+ ]ڍy SuY5SbW.puhpg DjӴ |M{;,/ U!5A+K^C9+X* RkpMH.نi)uH}1l\DQ8xSv&vé:;5fӆěD?[Sލ?IS(stn73TkL-Flv so>;;OtM]fdDi}Â#( w3Gs-+<'b3ؼ-YȐY$>*.xUW \hsӌsDBW}87lHǾ^ݡb[m8 WrDZ `΅]o=Xm)}ʏ7.S Z^yutjSxM~<34ߚN[q7mc%p t15U ypGK6xegi'נzɳuV;QqwEZ|zicEj 9fnC_Q{-0Ͻ$tx/ ~Zc $D-c*߶[̾ n`_PKA4?&groovy/mock/interceptor/StubFor.groovyRN0 )|PwGB1L vqIұ I694ID]&x ;OVx, TD ZKBJR.g=ׯCd@;pѣQڔaxҔлYAP. +%mT[ <7,L5^x"jsMTr!rk+ -4` P2PK A4 groovy/model/PKA4!}groovy/model/ClosureModel.javaVmOH_1 $:[%vvtR7&1u EfNpH*Yw^XpsrU.TΝX {)|ssN_q~Jd& `phYŃΦÑw \-EBWa2]I퀛S ,^XL3LUje)AMe%jR -͂(Kd)*YeQ j mϪ(mesf,16P@ VY*S IS9{@o8yJHzwpVUN`G2a\AxA]\qȻ8# |q#ty¬-ÐEz!#s}?qb]&0`w]-> L cnQ8 "D#a{qsf~ ѕ[, wm.Cn<ȳCؔo^ʆ6DCqzaq[cЈ9B#\;p/x-ʎ&XoAF!Q7y<\A [{,z 2z"fc51jEܨh?*A]&zoBAxKQI 7W Q5D(0#h.Հ!7Y:YG6U qկM1_ۻ 56@ěn1yW贕N:B$_wO5txlPZE1u;'xɰxcV"Miqpf~S"7ŵIۜs9qd,hR܌F"3l9D?'wfZNEWJr%st Y|ؾh& hxr۹-y ,@l]}˛6'\[9j6r Zm<8/E>,pJH~,- 2Ϗk4In{/_@v]:I嘒8V-cvZ!nClZYn/6vhKujТ=UK]ގU NqLԭZ3$pgh [Cמƫ9 Je)k0 b3ڹ ٖ?5=5B77f.?>KL盂1G4V 8OuGPKA4/$groovy/model/DefaultTableColumn.javaVQo6~ׯ8dܤ-8mQYfbIr`Pڢmd`%;rblðȻH{f {0 QE$ft\g7-p;8wBJd6pbYG,W{ ,EC?x~JT! NB@NF@ Hfec% (V/{YZD28k,hڰuځXA^d̍mm#:)hmx c ?L qRiL),1͌tpU^[Ŵru1B*u8 pЙx||Ys;`_& CɈNj8 ;=w4pbG0c]wLė~__>BZp#s`w#'4!JjCw1`{qca^,w$ }Uq0aSrRf(u 0Ӏ}auACpعf(cP`EiD04bplAȂF~h1"DŽF qܟܨƽtq;`ߢ.Hu`SS3B~pGѿC)jr !FM;*F4c#~<ѪO0.=LQKn9ZmĠV J†v{[3w(`Kj3Dz^\vJ}|:mҬkO$Bck*cMӨѮju sPK@4[m6F#groovy/model/DefaultTableModel.javaY[sH~ׯ8JH)ٙlՖ#l1O;HdDh$ǻt8^VU}nw.rKEI %l#mhl|o^\tś˷"cy Z-9݁_a5pg9L Oq<&E<5VqNZ/OK4IKH/1 jA U"܈2q7 Z3 \HD)9&,Ja"8! ۱S@DGJ8 gʨqH,b2 ; SIXFnJH)ḒIňp7 l? Ζ384OFVW\F6Gp2p-{(pwd=wtkZihcCzgu\ FnН \{:KpJ5u^cE*AS͚]Tȟ+q0&_ ޅU'9H3:N7e fлnA٢MWtu)]Tv7$nBi>㨎3l\=UAP+*x<. $χMlR \(,5&Ň6nŐ~N';;}M` ʠ.!4C-4Yip3Nՙ,ĺ:"EX\LzA-/pnםNN!뢩v+VOe#6a lPu=} [8y4Yz5?YYت* vvC,mN\M_t*!A~B&v) 2SXtPczV#i'|"Q^Zo}|ʢT'¢:(jylyiQ4@U6u>ѰW-NE>RZ<|-Lh+.ũ9&Z)XQ>ZjM17gU!/Mm?ښ"s|x2NבOђ[y4:b[Cjw+CRȎD#e̜+2t _sRt,-iR$Li>ڠhv)C !xfoͲѹimڣMԵJ">#~XHQˮi]KwUzeR{?+>T:HX8bb_\[hHm >8,Ҩc Ո]d&ҬL n`t1&"FXϢ؈d#61y?$yFC߾y1\޼{^@,bq 0">M8@ ,|ă>š Lh§<]m~ДE?!t' y4l˜Ijc)xXP<&ewH uqGOД<-Mf &}gf2$E} И>6iM[{/Ey *#65!D< O 0,>iVyx640cnUA¢h>Kx94 hB65 . jt~<2Z<+H br&voY3{3p" un6UnyԳ}[L7Yb?މnوFi.kˍ [,ܱS~c:sh\*-8\Zp u1q*sjDJ'<%bQ-ĕM{xT5X3(h14}ryѨG3021?V&\V9}@|8[vmnVWӯ]yJ_+"F"HI`7kew;׃SlfG &uOwvvm7)x}zɨ>ݪoGYgу*F6#xi8i^gݙJ6CŧՋpߝPKA480$K"groovy/model/NestedValueModel.javaVao6_q4 4I[ plVFmuhP`#eNeX$xwG Ny1H5*neթ.T5.w޾}7|;zOW.?52_˚_[:< ɔu,tmĮQԮˆlQnA6K Tۨ6ˣ<9lפ6(eb}h[e6ekFB-uUDz^Q뢴YڨvʗX7n;+욖jeY,Ӏmf@mI8 ,ܳ;WY!顬y$9SHuA{N~_-wxrXy%ˍ2El-X1.u#L -RdXmu!ztYzPvd@J mmO <֔vt϶4VDB4y-;۷G~X)٨y _K~Hfe?ȧ\V>J5Xؐgsvq5S3(I Qn`j#͟ À&#lAVY~'/pݶp5b:D| #,ίL052Ǚ5,IEܣi|_@>i9p(N-ݔ}bun8bz$"v37, ]-  wfNxG3f`r L> ~ZotoJCo+? {yn [{,T;v'HMqb {n@RX3";>IZd#˪գ4Q}vp͠V> gC=[N+}8uuU©~BgTw~Z]/PKA4 groovy/model/package.html510 Es@TuTkwH9 l_zt^&=0/[12OSNx>'$- ,-^;# $ ZCE*Y*(qTp#1-MvPKA4= }׾N groovy/model/PropertyModel.javaVoFbE$r%wJلI.n 8ghmHά ؐR"̛\Xpʓki|DfΓ{%\}ss.r}RB~_eV/:/Jg9*h)j"եY!%BL ebt.SU% j"-PYhiDQi*J@KAYDuɹ i.atNM iI@+6i" $T4TIJYZ)_: [JLI0p]e)_fYK"^E*ө,8B4"+0@Ν d1+L/(I/PqF( =͚]U5@ܽUXyt)5%DY#ڤ.TfR2H;b|c\+y9 YHj$@>PhVKb +۾5J:#YTDI^5>hW&pZ/3eMUzN;RlNEaS)G3GVRl"ƺ_j܁"! 4ّ ~p'r)<cpZB$QfNL ,WםNUiAĸ# ( y 8?ywadon)oޘ1u( > 8>"r1g l@ 6 ! >t|G*i-}X΅FpD HTGC>v;Xm;ZBːy16%GR! шyWb&`oc ACgmS<!e4"w] Ǣ0"8b6ֈ]S1+85, ǣ}A9 |# GB%6<Qk 6/naEt1n =Fx6ϵ=4c/DAe.yr VON"j-"| XLB>34Jer\Dj!ҜFP6[sJ2D۶ЖB-✀JHD90I"tF1yek!|jdQ\@ WYJ"oÂ8ubwNv~.QHxp,Z~أp:ݷb{9.vYRa(\2Ѻ":>ClJ-ʆ[ ʐߵApf(c({`E2 . G!kR̿qlC ^0FhЈZ2>_G!0t<؀w`z yZIQ P6;aDT1]kڌV=u9XS0HӦ*a^cg[\սA pnѺٽRtJ'mc' wO5TɹaċT9)nO3 ƣx&]S2X-1'xQ8'ua #|/sɼ s}9798hi%.0NDf+%22/|K'WbzX8e瞦R+b-␙C>gF똞:sT'~1R6*x'x5Vl?.wԜC;%$\UUi)KXTKLU;n| upkKmݐՍ**<؋>5k^;FiL]zхPem \A-*8͋J'P*0η@ .~i3鎕TȜXkiYW%bJbcB K͹`nq&5ftXkn2XnQצiayhviЭӁkF\ (Yhu(EathhG\}p 0.̙4+ױfڜczdBIt qt+bH{l pa,ģ?.޹=?'}$wLKD0" l(Û!GaXNd 4긌o(~9=Z!54TtOD$r"h/"'[{͒q+4ƢC ESpdf J"}#h"4'gEy *b1a" TTM Goe 4,H}1Ta*x6Me{4 `B1t5BG E=Ge ERgi4F9GriC}W'"'P+Yk@` ̛ܐPEz%z4FR= rw5/% [. LC\-»I?<6 /s*f< (A8Lj ' 9ItIO!`IS P00﮼-x2NV}hmB\z('2WM*5 0(B=Xl}![zrk%s x_{}0ZYb h5X:˜N i'Zz{l|~Om''¾`_ ;c1r;?ٟׯULlSLuY9]uaˆ΍0w%j+f%k  t0d& n)N'@/tþsc_X e'{u8,k6?遾@sj\ԩ5い.M쁃??lШ?E@vf- $Y _0 xfp;oPj0|:kFj3{س36j3 L>*`2x ogtz;qîǟ6Dm/ O ]>_|%35!A t eȾ:Wh`1xΙGr; #_s D9a! i}jx%L*٫WbL?hi@-PH*o!ӆTg*^8Q7o0AQX".EϪ1|*QjsHHDue>ԓ'"7m'K!`˳d[P0Lp6;&Xׇ²^Cl 5u'Lc>y[A{S5 Qio(Op[&7軏TPy|JSĀA" !)%Ȇ0 @G#%>R'>*82gv SLly4.4myAx 4Ur~*p<{z=AQ ۆY#چaӌM?2,RV:^z)4kwH9 oYXaϊ a^D[njjO)m#adgMZPi>BD> _bsl^+  | )}`R#`L;$q}!ݡN6# P0 [Հ;SٷPkhc`|fԣZay(~pPQU>*٣o%&Z:$;ľs?ܻkfVi!r譲u:UZD~ 8OdS0~BN;gt9Feh8X9B"v|Lɜ08B ,<nѮ#D,SݦwSgvﶸup#3]2nL{D4縗UC  `Zeuɱko-fނk rWJJK-CEᦆU%Lienmi.nraf.dT&tiQa鴠16 Wqy,c~:?h0l`9+,I휟T1ԒI}=FZuLː F6۝Q(xT'{#$NRZ^QA* f'_4W#TX5+@ j p3jJX@ 7X0B0PEE4ZXL@dHO 7V"u]r;0216ưXhZt")̄q$tPSew)/˹B'C2;Öcq4##m5ȱ4~~<,ԕ>SԤ +@l )+@VZWc?P~aEFX5E'Zv鰸bj\f%:T撈 s4$4ub E_3-L~>vHlѪGNE%LJ7 GBVU X3)^X4zqj\۩Ӧ^gh[e?U^l=a&J[$pL<ɕ9eb%cJ nR¹I O&<ڮv:e$v^򧖯AӊN;(4jL@4Б|=;'h?xQV:n)>eU,lڼjxI:2K@QS5v[@fNMzX}&0-b)rmqǂ{"BoA991QbNyx,m!;,}7 5`k#aJNr/f5` Ng^7o_w:LY:ʜ rK@p &iO)gtizVTQ(gUϿTgxtV-}'%OсXTJXV4Ҫy慴r1$UӾC"JYzjR&ZxIm"|yWtSOŔ\mrN-Cu>T Ғ0 t F\r:SEdА}XY֏R2oDܵOq07EnՒ9HlWJymUT77f%#W=lSq7 U ;}Xn)(ުT9oGIoeۢ9ㅜ۱TCURU0$D1N-Y==19anhB[qktIOm},ڑ>#n!XףzVO$issnb)x>i~QuJa$t χW|J'f7 .J'\*.77q8G8L}UOPK@4 j!groovy/servlet/GroovyServlet.javaYms\ T(q:HH”"Tt8@9Վ{; 7S~}}vow1L˒޼~=uG=]UiТay^qR2Wegf1UeRPߖB)FXy)Σj%2d.ӧ\R.w^6uXZUR2,GǫWjk8ayWw=r.&!NLGؙ rh4q.dW* r{F73q PHg78d̻r}K;h2t.4 b8zʖ6NlV/dz(`O# '}6<z7} ,^` 2g_ß]wf4>8#&PvJR) x>ϙͮǝ½6Jxc;U>)׻aC/l{ BmX@o%Ϡ,MsnOG6,"LhCaLm}Wrh8DH1]l7rppC 7T?%u.z= uhgFi^TRֹz#K;[$Y;ڸvH^R1[>r'6?YmuИ]28zOQ|1uF[Co[VYnhp-rWkX65hҘH oW@}V!R4PnX&Q=4]^5]KRÀMw15ij C٥GoJeX-9m&̮BTWD|nZҕLI'h ΃  4: #$U}}*CKS45vZ̮Kj}^<VR k~firѳYZ34fC 02c n*LMsNF^ _iT>l-ɵvgwCZ E~2[; mEhZaM'A)PꓴqJUմY"5&hŹ(,˕B٩-Is09D!CV4MJ~)8|!LҜdܤVGөL,%5+cYֿp=\*DgUv^$ -%F/v!{yL]@Jcx0 8Ѩy#7W)S5@MS6ڔ3P߸PܣJ,;h: Nd&E2D5/Ro>%+2Gy͢WTpuJK]5yx&ewg0eGOd>E[D&x֒nf FYþ!D7ħZSf54_t;uLȓ 1}T|KQ, $Bw -5 Y{aíۦ ڍa^(Hr]YWfA%ɢ=\_vdaád(,D?FdKHQEp9rI!]qցa-`YΗD<Ŧ +fZt7pvfOWe ͛4F\PnV a#`$FRG cE*F^&/GXUFK\gHqbUؔFeԯ`OxWJm)YWD߼~m v~7RݖaQÈ>ԺV˅x`562[7VRgn,v̙zKd^j 819 7}?c(M1?ͳABG[Z-oiYDlr%d >_\ HYe*jrE)V(5_'%\*ކ[m*+:.t8/lyקXJR.jL?uf%f,-T㗧F%>*xCk_PM;`_0Gh[Jeh矿g6z3S0(GOzc,3N8΢ 8(p.f*3k%pev[p!ѿtNr³7J`TDy ůB5Te^4%2kAmq!O':q 20E uѬTgS^9a(/*e1eb1%=DcHx|r5V94M4z_OS?f&(Xճf+'y٪ اI^#72YW210_%m4Yj6!k7E[[{0jt2OV^sOTjGTF' ֍ZF?6+^۠O u*Tf7QVnpɣ= H crr-.3=ĥ_yM@q#A284x1Nj1rj}68}E en'Or|$Fε"GOM ʜN^_> x ܚȂWq"P)`A-'=B޲E yXf@en$ jn+]+QZю 6B[fٜNNM6~42?|D $UUzrje4=y4×x3XDzR 7/Snp42oQc6<T03v+uzWpifWe+5͈y&qv(,|6 s94h ن6S]aSzYoum/J/bf$C>mI'YcLXvjx5*|Xj.+f-AlDTݣ7?.an3Z< soh46 #0z:FBTߥo3M!/zٕoGZvQއԾ,yra)!iWm g<_rRܗgi>W>q95J7$ _ȄO~.P F.37v,̯oaVFr.pWQ,:+yؘ| $L.́.Bb},7jOPKA4{'T#groovy/servlet/ServletCategory.javaV]o6}EPIInC2YbbrҼhG,"6wIY X,{Ϲ\8.U%M( V[^>8<Ã7rmdYjyݔ+ba7܃*.$L5sCPU( Ԉ' T6MyٚR Z-A\ϢnAh)PF,q;{|.]Uk`rV.[l)EileVe! bAH 3UUsY!WuQ$r6emj6ČZmF@y l%]72e.w Rpuͷn@ _ݥ)e-klY٢Eئ'.JR\ֳ`" uHW\ƂZIBJc3ASbs7w~̍|i-pvR띮d  2R B5vh[tub3\fDMiCQd;!ZPK#DoDk:\^%oAIf꯼}maj q ^S#qX.=(oD:fFr!wyC"[ - h K-֧xՖ2fy4tPB!7N³u&O1! NE8M"g,fN$  ) ;zKN)gN1g4M%%( rD hLb*)Ԋ  0C3bz2f'4]Mls Rm`Ĝ?ȪݘTϹ kDds'Y8Zˍg@"(_ݠ#-!bL?4 F=OMKF'^wHۥM6^Vex6h bw?w\8x>Q^aXm@`Dз.~wCunucn `\> >g]@[=[>_7{_O৹%Oc PKA4dDmD#groovy/servlet/TemplateServlet.java[{sH?} 5#SI6wu;2mkϖ|"Ljf*KmcaGw?`![Lչfbl4< 07_pgw1/;p^گ^W/^c/_yo^fn_2ˆt͢@1kgVϕC{K3[at4z߆g@V,BP&>J,H0Bּxdi7Q<-]˼`/(t9QBNIZD)Al|b Qg[P+[+@AAc/;nH( ?%~8i$$R0iњg8#k aYRx5X!@j h݈P@7y.cew۞e B'aez m! H ~wl'CI9:(eV4͐W{mb\\PQn"LVͮu Jch-2͆j-﫡JIw<9fs#(~^q]b|4&;`d2=0æ3]L.' fR!N٥3ßDN)LNaͽb4gW0 9Lhr ˜c⢮)Juest|DsgNէ1$0Oغ_ xI.Ggi`escǮ7=f'(6rsq%]&F4=pk||NxWd6G q=2lJ:fOA0`x>GÒFh 7af{zl]LΜ3dq:}X&b#ti݇lrF'&b<8;CK0|L/aG- YޤYKa, 82Ja@5ї^APaG}p!\dW% w!B5I -)]t;n i#ɜCNВ wyԤiw9>iqߊ#lH8ױ $ƤAr'C%XG4ÿ("̃__jo;GGy1g K(.t<QXZ//5Wm 830:_I;ś4h"ԗFQi*-I֠⃍'KՏDx) kXsqC(HMѶoooo2.M̛(}2?Z]E !{p,;*J/UclnF !MCPgPzTj. Di[ <)J7R]3(y u&j;E\B 2`{J'WbB#P *"ͣ J`S(JmdpZ(o.(Tz>_vա=S΋>T H|xA,/xA- s %櫳2c PvC\T漲_T.bH;ݡhc04J0LY]@M=;!] %<ԫ0jJUч_ox Fv^7T|wp[Qhdb,Rf'ѥTTXhhKe!|$m}?X6[b2?d! @6a*{{EGi)stHd-K t6 %MaUJ\Qa51lV e$ MfAe<%}-48l13Y."x=X-*9Gd*nE&A*@PeD Y`Z7FErNsFo(iH.9\xb9m@sR̟06zQX>kJ^̃LUA3 v3"T3:Hl350mV4>)_JؚՍQ|R/C]u[(̈́>Y:.2  &n IQ` TV;*A#`X5Öt?A.?flgԁ}ˬ ec#+w'v=@ <|$f}յU?Z (w$2 T9S-N&l\)³^{7|5+x T ?`2rSS?bOa~qC3t >^@P(`WW=)z&Mi*b$5O!Ҍm_0C3of="?:W@ +pe0Ba'P j 8.I!W"c#]2-c(ޱxSEHx {,jM ajMYq'L£!HS!PCL!&M) m1[бQ$o'&q (("j͹\^%q*BRmTJÙ'r: I<E! %YEIA+nt(2@N!?GWʓWŶZH rXMdA޷NY),C z :>J<Y>"7*#ފDNю "6*{I,yH _|!Y~[zR/sLo[yna!5冮bv-8T{t,Sgͩ̍QKա5zR aRYլ-e+c憡#a;FOۼsFqI6Vm*i }Fa:B>Hpi݈?gcjo< "S4,t$diZbo kڣewTS:w(s{SXBj*4k2_PZq W+ӹ=2)RX=ӄD֍VG&p̭}OÍX¸okEB3!k?4k[xmWMV$ 0ɑ4 ^d9Đja=GW{Bc S/lײz&GXuFEof9bͤPqVˢbjTߛke4򈥲`xA씛W]sHdr9/o>RLa|m}D[Fb*#Ӟ.)% d" F[@tNu*]k~w"gU%- ɳ "1 tϖ B^_NJgKɨ|jW?*Qhx)0FU Q@X/yG[1Ժlo;tbK:[ATq+/Mv6Pxs7 ݤ@ҭDco#9}V)Txe-ԵŻ#^1'|*@@$"& xtfc{%`;mm݌0Kd'5~GScrs\F1vɱu #9KUz7(p.d~J</Mla}FYV_7d85O{$&-+XsUW2Dف*N4ebI5an|~S=DBBGhXKeV=zn?vKW@4=:ꏇG/-^R*ւ yq!͎*܇óPK A4 groovy/sql/PKA4*6tgroovy/sql/CallResultSet.javamN0DW1)( !.H 6uqބ"gIQzmZ>qMf<|1Z[1J3:BPhG,V:'o/ZQlf`O3p9GRT2M0zVqPx w-2Hsa'# 5CI5U۬ \upI4MJa .>>>DO?}8=>DDd?.mFxb67)y*98Ey|Oדy(X CrY(%W2YK߂.WA~RIWD*DxU#\)D򄐒E"Wj>^ˍO-c!B6WF~`y`!60nHI JE" a7-Z c`#gI&8KKN$#?N|ֺqӄ }DD`^7E,K'4Kr@"s]lK-#JJ.I.'3E7BRAs\ kxƳv&/ײݢdЈT5^㼖wjL#CH> m6SfL%ԝ'(Dܑ;u P6zAs=H2?Mg>+o2W* KKtwcZ !6tl/~p9xIQDޢfqܲ{{>+ASh䣜/}ZVU/z0Y\q`}:!T}cKZsęP̽TdPXP95u.@jNgݢ`듮4ߍƦn[\-] 0lMVIw|'捰q%fB?4P(;DM"Te7ktI1fln.5 #&[33Z_ " ȊY#D?&Z0eտ/y6Y~pyFaI+Lab4- uSHn#UK6b. =NuYPT hUMFNؓTd=sO$VXhlǪ;;fCd3mnU9ylZgp RpPϹעEwF_x#fbopl#UT2XO\El')|Hu?b穚97+HRa>GfZO+f;80̤_|UOF^g@6a:'ww/>2LGMcTA`3a)_eY fcO ܽPK@4  groovy/sql/ExpandedVariable.java50 D|ōС|@&6vu@'@`heXq};shCq J3(<P B sR< PKA4uG&,groovy/sql/GroovyResultSet.java}{sFS٭KSqQumÇ:ujϐX%+owDY`Ubt{gC HDk//~;7u={o6, ؟_``uE_8t}}v>]a,.yaA"NhFqNֱȂH`(ŷ<GQ0uy,R1R/7c7/;֍,`e3wJvR[pHh7#P n]ΦX*RK&fZas`NquPŬ >X`#TD]H$"ĉ3\@Fo>KR z쬡U'Hԑ5x@9eVASKbƔ1$'!]#BzhD FEn`eW c @cD dQ.X6Svx@<67,E_FD8 郐|rlؑ=#!8/৩. ]k}к%}rσ4&ZJp- 7$E5hB8h! |@\9ߺt -ݘEP`Me`"Woe]]@ᘍ/?\ |4ex:8e'_~]Y O.G7"~Kz} c(}9bOgC G`aËc χWej̗c` φWa/؇>@u=7z#zr<`ةN^ ~\\Ͻ^bƩwr6@?OA @9P_g6hY? C2t7x[t&lU=G =C%nRejC7) 4܋IsNj0Z0Z:s#KW$uJ$_V%uOIPyka+>]TL I[VfL%\HCli.ârt4po-63% C: 8\d)|ǔJb9NxD]ZIal(_/'Ak쭗~iBtEtمC P8,U qn-Ė` R΂AGbEZ6 ^>Hӊ|nl ]v_BRԟŊ֋WtX6Gta\uCH}UR-YP92Ls&ً:%шl7Uqƒ%sUSX)G4|<-ew#p[ku7ӏep#GVdGUb.|.J0wހRw 1VvXQy wd~z) de;NPC8C3H(G/ Ǿ m7ˈgR"B83 |F/5 k!QDcѮBۤryVΖ>K0栙 K}il 2VUMIbY !Ycd]Mn'MBf IJœL# 2Pz(AI楖+C]P!u/*gEhtq_sC8fC^9K6L.jON`尅;-4~GkxbX "WN=ާ~4]0ΐPsy@c"@BN!o?~Y LIY7@׸$"{GФ pYVUfpaȆ>h"tk|v ծ YA]LݩWp`Z=Aa Bt5hTtn·FqS?J!tEt[GRq/ʐuQ*yi NÐ C\ _dtt.VSV ǁ$o0P`RG#rU*`tiy wwhnK~,ڠ/p- B/\u,M\2 zwF7OW³QzyI̪I%=^$ a](1]S!^<)JY izyb8:ۗ؅1CUSyEW'K^sNp<7|4 S U6BeNHPeI  b #џL>;S4xEtJ(k(h U8zڋnҤb@P jO١iYHm|%! |S*vzbnG+V{F]lbY) L4l}s ,Rx4gIX J$-TdAJ;LdY1%Pbk(+!X"{pi 6,F&Rf;{ݱ}?vYBb۴QuH aAu*/Q@M7,BgĬM2?>=x> +HD~m XޓA],'90!hl ݡD147G]S`B~s@BZ#<'_|0B>"΂p"T4ZDD4|/IR{*hr`Fx7'I)}k PSAT;lҍ^J4 I9*\cF`5 OzV`PDhDhCG<U&S%CƸ=Y1s2i' hK[gP §o{:C<3QS3 uOսs9~!܀O7 ƹCtXf!|{E-Γ1ݑͫgyvbXO󴌊 }1F[o#ա-^5O5_iT3}*`}}Gi)G(p_mruִT_M. +B4ޭnjfoڙ{; wגwcsC'8DJe¤.f=5ӌC_ yOdJ[5Yy6KZ+;dz+diJSwֲ҅`8$Ni&+uI4) dS`nQW()_9 E=.h79BNĂ|Yl K,|G6^tG.HMQwMB/W zSU5  )%r$|3>y8``SlRZFTnV~@Es@ˌ g8JA5%<M6ge,abSe ?A> k\Z,0k[MɠhUՎ!yE}ds|n\ijx*hs'UB+U>Za]`,>k i:PӖ:vƭ$&i0-h5* "\zuC'o-i#W95Nt 4&"{Hsb,*#ns.O1z0-%oxf S.f>M(]ˇ=R0 pՋ٠X"f `6ϻ쁦cI,KZ*gĽOj@^W|]*%~AnG*5IBrx'IWeP.o`ͬރm}P?`k fhoWqU->3, urV^E$[7zW?n*> -#F)3=Ϭعnh2ė#p|"dY'QZ8BYMใf 01SwλqH8^l6vu\W`&\Kn.o=SٌNe3;ffEؙǩFop97:YvCfRd G #IL""5.#SIK3(m cu syxĜE5>oK?M%w_rA\dZMBӵzm+/ߒ 0 *Q!7hY>ܠ*^iűXm퉸C a܋!&eJeX8ˈTYnfHB5#r5.Ɂl)!ׂ&*/CDqpq_nB e;>=c `TacR) * bE[-}𽂳y o`ՕmPA ?2 ;Ll<|B'ٹ*mJEo;6, ob<}os;l)Mܶ®\̜3 gZPd|\*̏,+FpLH\ Υ%LRTgU(n`U0Q82kl\LaX|kv&̎E8FHL>Y*9^$Zy59)C]K&-%,P+Pru2/ZS2$E+.z>Q?|2yK+X0uapY;'@b4e0:Tr}^4rզ&৖Skoo)NY(xbK`f}jN5{?w?G)-JզJ)}Z1L n\+Lf8]V 6?nn/U9I;h%NH?څpz( {d~aD-sZcvr; ? 2ł[MeGեbHbnQ&dzd롁/UnzßSD6\_;2lO$5Z >ˋ^a}lTq:wr'+>sm.yYv9WUX(/xGм'rx "+=pk vY2q#wfl6xiܗ6l>^[RBqep+aM`,H׏|6k"8j‘P OYQ|qhl".!F 8iU;qhJHtP*IGlcEAQ! մ,n ['b`oyd4Ҹ,;T>J fq"Ϟ_$"Jo(\_ ŠOQR2sRiej*)JwDќ[}+y$/:NgiD2=iogpU٩=dJ<3wEKI+4p@T#n? :nO$4+ZŚld3X=oNeQWՄ/IF [x#R’d.eh!BXCx_$׼Z-x5xy"Zj—6ߙ#`KMKc -[k2( cEyo8OSk݂Qoٱ9_QxeC@tnڂdz:&ą$crrT6S{9ڗvAs'͋DRN󽬌]-sF\l@4>hgDG1_EtF8|RyY_ <.^'- B[$*C,I/u,ɰJ.Znu4ٝձVD0WZZ=KZUkUUjJ:X޷vT 6qŗZt. IKtJ[ѰEto:QYٓ.w'}$78jmxm촉<]N `+yHru=u.T7bUMmk펽CKW&65hT۽yglkrW|Z>cqxmj]m={}pxmn{]5>Ņ >n{U[ ܎FK3nE{S,h&im8b³- ov=p%mv/춻Zmfy_ۚYFk.s$Os8;ؔZe:j頶5PNѩPnZbfV*C5Igv{X= emŏMjHv㠵lgnhkh?~nqng{(}}SEs[q 4 ^l+6南T./Hy1p ط\G1ڕV{@BF&qD-m+̰xaݺY\7ǂ3*H2Zo$a؂y%ܽx`CW%fgb lbXhܦ?䚓i3L5qkCTCV2i3#Z#Y,MB[B'ok^փ?թ5l,whQ bRdtBPLt"ݔ(TvʻO﯌v ס[\oTW+*'%w/{w,`Ʊ-8=3';ՉxWE/ 5 =?U_|ˁw@9Q?S>]n@WnŻIg_Md{i:]6_&=8z c0{v`6cWz~1j4[3@C˄z]TJ?܏aQqnOlY$ȍ7grH¯D$Ƨ5߲qY_Y )%w) Y*B) K5(0"@,{Knn6z|0a[i,}dٶt }ĜʹihpB% O}NgT\ŤCtĕd6 {87w'ɾvRxxf))xm/_&q W ع9t*@;K6Y RDFu x\D8G+1u'meNFeI)0,EHpi`Z!S{eNͬB7Gh mEݿ; 96վgF{p<1SS4v˭֛iT$Gĥ[2I۬㲩ˌf^X^F7e.בqes*)52XOZѬCj,}5s(-w+!LJZ}|29]Bha:Cy^7?&!V`i&;Ij<"͚\ƣdu*DcV*[`+\j :U)ڊvazo$fjSUsЯ| F20q͕ŸI Q8LxoUM"C>}p L %[&|)H5 O(!`F4a"Z `e6BR=|a,x&=[ عZV!/lD:q?~uZPox45}Ul=h3 O m} 6BMi<A-O ^-Kkԯ*Gdq<-66gZX dڎ=Ҳx?}:hT&v:wX)|);kjIpBgҩ]_M1U^dBoZ4gVm^.ֵ[fܵ7aJ)yܗ%nMq&=o>qnkVl߳5ṋq>k xaS%Zh6c7}Y$gwLmrSZ?^PK@4u3bgroovy/sql/GroovyRowResult.javaWks6_q'i$Gۙm#*IB$,;{zXnQ}{ 9/nHOh \;)y3GKN(C^.)e%e\_8!+UJ*Ir/"R@ he)S\:1h-B aF ߞB"/|D8rBBYc { ^m=nT$oZ|ͥqj&Zao@[6ΔZĎp 5ŷ 8 eDZD@5NK h!kRp\d!&O1zsC:"<%#y?I\͓0~bhze"?FLf0y$x> 7=g&4&A$Yj^ď#quL፮̣%`>"ͣYd"` 4 OGxEh@'Qtw5k7rD 9y2Q1(<ċz.l/sᐆĻcs=#bx~'A2O| á~1%R5<$u  xǁe,&~gIN(%Mf803F ݎ| )ϐAr( 0}4o?44Vn:^F z9!UxP=E ~#ql0jF K?1,٦ť덐}Wr;\SWs~4xİAGs7fbngZӣq^~وՄm?;s +g#mF3]ldxN;CB !>;m܉*YFHH'-n˸;xZGtḐѯ 0_)iB EEj(3K_3̥Tj V@mpB=s8bODꊑh?_O|9Fr =<]QgSbN}KCe?lKniP k pAs@dtw;yk_ :րJ6O:?-U'J=Ư:]7oNjP!~pƢeӱ0;ĠSSL~tsjtj~m+LiCBg5~w/x'uުM6~gRPS{n8PKA4groovy/sql/InOutParameter.javaUA @ }Nu)(\)xMk13w7n w'6!;+S[TԱ:&0+g5RPيQやGNjdp3-<1Rx b/0dj{>PKA4ďDgroovy/sql/InParameter.java}@ Ek+R*| >m`,,3㿻3:6VI{z,nXl4G0TBV՚E>݀=#㝄ĸcD,X6mm Cwt*_'~y)Xk$sjJL~B1lErBm9O^<PK@4Xgroovy/sql/OutParameter.javaE @ E+Rh?M}FA 3Bݩf.9.\ j1[eIBHs+ ΉhJWXy  ;DžI'hkK}$+.`_Փfv ;1X#o\8XsӞP#<_,EoPK@4gw~groovy/sql/package.html510{^5E+- M 6Q~OVZ٠ԟ-Q& <לK'ԝiC?Z.;pK$‚Gscp]1H$Ov*mϔjչPKA4-D4q%groovy/sql/ResultSetOutParameter.javaM10{. @\B.!)H[͎p(5[Z!6Kd1d7VvwnSm4ELsklvn2*EoPKA42 !Rgroovy/sql/Sql.java]s6+pDnT:iݛ}ea+K$'trKl(R!);~ow7Z |vX-r^';W }ݗً~=?³'О2}un ,J/Y~[9: urڳ+`;ew{gVcֳN1DRVC&s} ?;V#kuig8gΐ O#Au{<4wfFo;^xm lvz&BBp8t5tφ r llF9|gu F$"܆g#gpxv:vdCh]yH qQ6{քC,IcDJUXk,=wM;@Y#,` ;da3j>j x_5n^u:,2DQadI!uߦ'GbFe{ J蓷;_ay?5^-CWvjpiEOn >,/ýb\Oә6?O-s!6邿/<>RceIyECt탠S:+!JYz񈯺u"{Ud7 e/X0ozKuQG$8n;’[x=ȝv4;%a#vK,+0ƉOf+0~ր? ݃FFo!"S\!7\E{ ceȺG"T^lzq7cac`"]Ұ͐_핈{yTa~B8XپaLy,[vbxh) b.+Lڹ0һ24߻aP(DYO(DHy8X hAt AOpw!:aR,x5`j 4$g `S ,gJ6ƨbŌ]ӥPp85gE(f[`K`Mf#A פf(% mA H+aO~UWހ#lz9_Na]ĕb?X,Y%F $ QCeNJ qhi%V"%fE ~!uKs:ľd"$CWlbf,k&:99+.]`b1H }wz V N[Nh =v{Wul+pw 8'ͽ'F 6Bp zfp F&d7$n39#dN3&Z8MȚ]ӻ?Yӄ5[ޔ%N҃3|LvFNGAg%Nޛi@λ·&)5{PRwiN_:{oDgۀ!N#'n,4Lf7`i@whv6"hiDmQ#p$ؼ;Uӄxx@+p['!Ѹsrӈv!_@i=(W e-*jYFW)ZXUYl)ґ\`mG@S6Շ\a-**\}`-_ O ʯ%)ݘHOCX $5P\}`R*BM j TZTU4E끩X}X ׂbf{¥M)Mwu=CW?Tғa`U{юm+EdXqVx*{h7$mt[EY-pZ:xDC«I4CV!UQ0RszQOuFZJPIxeNrIRB-a,I#ĪS9u#'J mfDv].l fW b9h,:Y! ^Vjyŗb|%ӯ/.CwFȥɼ+2H,mnb\ux~GPLjq~1%+V r*ڸJ\N 9A~;4.WRFiK̴'3K-m} ֵyLʭ~ hTǥz}U`%/o˘ 5.GƀQ4t:q%b]o%m ɦ2ciU nLV=a^{znL Yf}_̎DU'` Ĉ"ei=et!np &W>W;7+VUi8TST]M%kkUŠ%Z]wO!& jZ'6Z{y.>CMۥ H2GNRv2vj$'yë,6y 籰h0䂷}RE*n[MK8T  VuS>HG>-y1d3LZ,q?BQsn`߻.[Ӛ%%k9rRLi%u.134 *,kc~rS 3^Ip*Rl*%Z}ka!h۝qd!I>]Onb^~]ai\^^@"ɴSYUZ/YjD+Y5nbᅝKZmK-Gi*Ә8j)iu32?k{cp/7- _z$# D+I9vqSU#m<t1T1"">!{=LM\!)w=bF{ d )#⤆H.A.xdO3X> R(K3S\y/Wu-cL@cG'`W8gۘ羯`{^T=$Vj0k57 ^!9Hoネ5ߑrp>ئga@ϩ;X(D;yJzKArI9v.v\ŵ𩖻1~%~j%C2.avߺ;mL$ݩSF e2aJiDiĆ8-_i{G9/D[r͈$QlI7ѐZwKTy*u ]i31v*yћk#ܔ'płO0P2B;z.5@̋ bR7qWdrkCC-H<ܘVlk)?Y70vez0&-Ѣ39"Jsb02m> JTEтd#"vX~X*0<vG:/2RKp ϐTXvIF?zO2rWq< c;ړpI(5zr=v-dfPi9>?}s~2G]0[h7N_Q{+d])' ٴwjL(URhFNnIhq@+LeIWkk'Ju^㇦*|37KݣYnԎ@Jibel~"P 1W(^D9uIg;Ej'UǏZ*OKYQes˽WPGBԄ ?{Q-6qEʚ3Jh^T \~%}V,O2̽̕#t6~Tq{q}g؇Cf+-UQrQ]>ܜ8ԭlClvȔkEޱn󋊶 ټHef]9Y׵AQO/=dIZ= X/P')XJ 'O.J2jd]x2^)dH`P?M4 *9b͞sY GކBb0޵f چa`[=4;Mi<#ʋe+r*œsH$t@2n {1w1kٻAɻmSً+ݑ8aM&+0x d "B|B1+<!q7pDY?Rb+m aDPqv y($*$eCM;'%A>\j>/Ys$WY(!vilX/ i-XzVB M/׳˟/óq1G9[t5pf74pUՊKxg#Yd8?|.SMEXb*SV+7$ % ;{Tj{Y}F}R͆Ԕ3(ݒj4`Lq3}BG"ɓ(~i/b0 stSˈ#'-g$MׯxI<~df[||_|TGL/hYj))}hKNݎ |2,H'XNʒfʆe!B@);(K Ce?o nkWכ_ p* 21 ,ɂvwx]ڮ.5N r.kWs%y$=I;=,I,Y,،DNYl0#xijN l r ϥ `tbi= n8hEVu9$r5ƣg[NbsϿdKt7sySO)Cp}|Fw~Rk:mƇz|zAlE>I).0AQiT![Sf'CܢߢiX:XBeo&L"SHV Pq0JUk6(}9GF^ϧдX} 9ԋULv4VRLo!LH,\=*>-Lo&t'MYܾa|s[i?fXMbd~y::dE?pGw//NC/>8n̢#Rj2P%@D~JGO'N7!@N\FSq,c%xsxkQITn= MshP⿀jVhB0*q 6 '"2LԝfEC_2 漀;wfwl >єiR@'bz^yr^@r?Z4{lV$ \:Z3XgYu^X`_;5fbzIhNǦa1'G1^񳊇HvH+NZw-vyX!AE rвS."lTb TVn:z ;xG PcstoZ!1nVr {Qz|`U)(b0O/'T4zUrCW܂B2r"#[0͉׸kX+RB'6P.u A]ܴ2;l Uza`<ys:ˑl@@X\GBޝO+(Bn[to~ǁow \Qus<@IFI:ː aPً{뺾AZ2rbkhT%%rVa"}? PKA4PDvgroovy/sql/SqlWhereVisitor.javaUMs0W09ʴ0P-Q1# LJui$ͅ]% TO ۓrClhmRz&εD;!ގJ#J6Tt)RV jZVfHs+3hTOxp&h;^z#O)RAevF$ n{WKXXs;B]<4#w5!TPo0Ů42P~e>Eœi,dvsjXU 2jCgZǖ`}9Ib @ j(l؆Ygˀc2vo.k]he9+_)g6oNAyuM;PK A4 groovy/swing/PK A4groovy/swing/impl/PK@4n ׮&groovy/swing/impl/ComponentFacade.javaVnH}W\ED^Ӥ]v3fm4o46d%jysν3w9jjY#\zb']{t{=6Zй`պt\QɆCsMu[=˒bP,w2˼@bm %nIjIhQIhi7DӨ)Wٶa8Kg.=횔jRbYd6%*ZjW2wPOxTezEd56mX7n:HmZҲEf9WoZE&^!ZQ6ʐ@;7Y!iQB?C8߂)ZDP;枓U(hʝ:އVrVڔ56h% ;ڦV0BPxlA7z"h{Qk RNB)EΕ6 jڎf'(%6;9Fft64F0D4y-o'nXJȮY _svHUzehU5eR &hl8ֺj<͑ '>_Aܯ `ࢥHXAfmu@Xun^W;tJQznj! (l!i4}ycY̒QL|:p,aY|[P4S".\[uE#8?>xPΧ׻"`oj(q+sC*rLgŭ飠?*Q?+R iZg^,90qމ."Å4Ro.d{rqPKA4 &groovy/swing/impl/ContainerFacade.javaV]oF}"mQn[ݮ֘!L6d=SAcCU=3B6/Uc8;^ytjdQ)3̕(wkn޿н~߽H7Ǻ12[Ɋ_:<eIu)Q2;@bm :nkEzAͪ֋I6d]묐)vzytq&gz*i΋E9heEcm= ~-tYꧢZR^Zk [)0 eUƃX᪁XYcTTӛ.,kmA@TB޼EyQI Jf}@HAEsS/0:mmS%"2g,شVW%^]Dc850K͹а>q&z|X+2IU6}M sD-Cec :ƶGzfkJX ![[au,U[. 5;j>45e .S(l<0Nr< Z:# '>Wki|r?41j.sKa שfvۜ\]DLG\}0zw|&0Q0DDi4NG߿.޹ z m0!''1 J9Q8 xt!D(S OaC$61OlJP׺ni[ecjkI:ADBhh߮^ma)5_]6Kއ`;(KL:UȂRFV(㬳S %4BøAƘjػ,HeV_\r8l{v 1* %-11 lS1~Y|X捋=)V ٔ 8Kp:zAg07<ü, g҃+E] x8 ,N1OioNjG-2H't$Yz$F 9)k1OXP[2 MXi2$FД=$ 8 ?6'#~8I"V]5y(UxX{^ O±+:ag[NLEe?0 G-AOP5eyvGG#DiUqʞr!~/;2KIoB-rhyN?WOE%٦<ҷuWT/ּpٗ_<#ޚW?PKA45SY groovy/swing/impl/Factory.javaV]o6}ׯ4 {IWo߾]]˫^_B1X Ezdrx{:wK9MǕ24] Rd)V,R!o[ǭԬ%ͣ0okuD#K*u]˺+loxrޡGլH ur6ҬUmީR_TTzlzk [ېP5  QUHۥW}QY@@p9z NsU Jf}@HAGs?`1u tJT\TBqi/Jz(Ǝka>w=ḽR5NFIK`i.]&Yڸ1.Z7-̖24/G l},\uZJ8 [W#NXIae[. 8jtwiЭӁk! F|(ɳ8bP etr| @ DuqGR~` 0V YJGa ױfs9r1d߅)#irl@{l2x?q,O,_ .o0'e,wLKDN8,l!J@qӘOx<(҄>ޥ hht!M4l4$cH xC>a-sFxdp gǬ(GSxt ;MY݂}a A3 FؤA8 od<{)+MPh !Y?y>$A(c-XIeyS#6Yƽjpp 芽5 nE(](%NO{4]T?4.f՝ ..8 .W -w~RbX(heⷓPU$Ù;YiLۭes;Ǟ`i*wʭii;TqnRB~EH\\G8& vȅ)[Awo=`4R(Mܴ w)m PKA4groovy/swing/impl/package.html5; DBu 6"UN Ʃ{RnZdǞ놆>_p!{qWrTNjIy\)Pdd"k T-CqX=ò; 1u~PK@4bWF  groovy/swing/impl/Startable.javaVQo6~ׯ8ݤ]QYbbRҼh$,wG٩ CBw} Ny9IEr'\.ëk]:b-`n 4gWYxZM cYֶSvAUAJI-UvbX@/6}U`Эu YvO*!ZvZ5,N>܇'ݭXl;Mp>FZwfKUzXOvGTy ӔZUn/blm0mہU >؛~Zdx5ӅjAȪ5DI@p/\ #޲¤n}FI>BT(f~s Rc'!UXd#!Rk4jTr#2|`{> YX(j$e@5>Pk4{y%`C߼4jjK,mK* "!GQ'VJ?C_KqH5vEҮ0j|ZȪ R,((y8 mu$6 OGY2_ZoPu-֮JB q] }]CD&\Hn eyE0~MaI Yyƒo)޹ ~u2!0;ISKDN8LpG<Q< |3U| XNk0S=PInxc=r̃4a> R< HTE8 E^<ƚXөZ%+0f1OY_uF`ܣ/H}`;$vrѡ$} TunqVD#)eqh7!{.rR.(;tJȫ_ `W죱w-Mt16.Wx{zS}at "groovy/swing/impl/TableLayout.javaW]o}ׯ**e'(@U뷮ɵĔ KJQ̒)yɝ9s쇇g=z#KC&Yo+.wbx.^_/})+#,7yzl媲N\,R&OT89TRJev*u4Ca[evܖ#UR?VO(;!R'TJNkUTz?Ó=eՊ u=fmYgmeJ{'+(zybI.ҌJV%(_8߰.n&QpIa-+2YX=SbͨUҡ#D !R3 $-٫B=f)2N`T-|;B4#pm%{""'pXS"$3ƺ!ɐuݬk+ C1>h2:Yw'u: K[4"Ն0ZW5:eh"$1Y'ClLƭc=ڛ,9 (D<y%\v̕,U].d͒S{_[}su `8rQr_X1(I4Q TǡaUT"vr KYp\Ur8c:m@oEDQp߹Occ'/""w6,haԣw#sg6(w'C ,~4 1& (=1MTİxG5Mлū;s]xxtp.0b4_ țb^bg1Edfɼ㨓(|ptG<"M)f͐3l7P4=7ɸ.`ISƇ(G""LBDQxtcܣ? ϏhDVE#vmh`@+Lc GouoBxtio?ojyNlߓn2Gs&X:IߟPOͧUOrITodB&@ͭŪ<64sxթJW-Uux>5Ecmx!D'c.;TvQ Ӛ MSn8. [a7dkU 1q2sx]0y:V}wg'Kiz[i_^ Cاг}+6)Ye8?T#Vk'~ucŐ~9L\W:-ٟ_m49:^]:,PKA4W0&groovy/swing/impl/TableLayoutCell.javaXQsH~WQZcEV^d!]aD+ XV~=#qӃ-E/ˡxLW% ֢S^z;=락?}ȋLL"!%hJY4J: [,dN~%)lQV 3c]ǢM۷'sLJQ9WCԚ9zO/wv=rn^a3Gc]rFpwF7]܀έ@.pjc=r>W -vklgҝ5ݍ;׷;54[rFؓw( `}/w9JW60WC[?g[ha;rņ3ˆaԷ3oޚ76hr "b=!|N0lq>Cno{/howG`a\aWcQ9]ร {#.rlyPw~`{UlYA];Š&웡sc,W]6s60㳄77XQ.Zٮ &9dFN-7kPGe G-EiVrCl JE{qtEᕘY8ZѾ nllr-_f{=hG\Ǯ. )6ur. k8%+놥HKLxtzŇ4E/a(F YVԎ2; 27TC u?iQ3 |w?hJe}LdAceTmPgR4 U6ϩM!Za(7{ȼI!;ϑ;Bna]eF% Z%|?>mN?>< U#ǬIRw?5es k0rGED5 aܻ.:U ID>IjrxH것S)Wf|xʩXE NBnЩ#Q}j+_KUV Y)Ȟ:uYjmy@ք*|Qni, v f.70x"&HNUuQBdί#U Q3)`t4,g7`ۺRE6ga`}@n<~GՄaP}`q/K ֭_6=ljlCp0ZVGN5^_롆>Uc+}j#\rZL)Up9Y%s-4KmmW78WH Y.ҢHޞ ʍчpj6 .>}RIk̾aK,YS&NbR!6[=S,^hlHi՘=K>ecY>PKA4$DŽ%groovy/swing/impl/TableLayoutRow.javaWaoF_10T6T*Nsw̓,Hʮu-M)EYR2%EQ;͛ụwQvA|PUEewM9}xއt.M_ٳ,H|];ϣ,_?WΞ:)W.TIR#6V9TRJe*L#~\UԎRyYTj#r ,LJejJG1<9FWd9dIϜmmBW f3y'+bN3SdJP(K[)d0\YUI]C#GxJ0VLt3Ut d^&ဤ`:[XǬ i_]lY!lH!GV4N:B@VR!,z,eJ^=`:JP͹~)MF'skNdQqˀ!UdrXF]Y 3D}k:ۣYʒL$Dvj2֎ 8˓<ۺ;>4 eL9:HXN\*-No!:gj!G~H_> V` c]Qy)̑fj;𹪖^obz% I<b@, qL Fqԟ8_.}ւ'Hxcn'@QK(NK@h4NiF)qE<݊8Ϡ Czt#ģ+ hiNALi<'8A W4BLwbRr ~;MǠ?u9bhhԼrf ]J&"E,L?tFXAp\ HT$)CdO(S(]䒆5MD12$rETtFѩG7{A \M#.:8t#=fEZ$laڶCDҤFb ^3}p(a| ԥUճ]WL(]X[xӈΣtrcz(yb_z3">}kذ1 /CLkF\VƾT{x3/:Kid͆7I1(w XgcGIV=}:YHW MK /TuǞa;ջX5]˻Zcgè,n:b5oRI[skƑv%9{'*Ԇv*vN-:Z5}jv=S0CY!][ S;Qe\ʴyug 5&6ѸieY6БsVuN9Z+9R¸ c5G"92%ӎUQj1._YFnDˏ5y}Z}+Rh52ev;$ܥ94w+Y#0mJj%?exiP9ʥ 5ܝG596-Zyu:g'rUFg}z#? Է_*/tp!dr埄Q^?on0WWfݚIUGydVηA *VZ͗P]Ý3Z]K%xfû&us_+PKA4iz}groovy/swing/package.html51 EPN:q @ܾ_k~in12>qZkCԟSnd+Sq~fFr٤(ݞY2Gյ| PK@4[. groovy/swing/SwingBuilder.java=s6?\*7뽙r,˱Z[޼$$H Iq;.E9vߤsI,b j$0^o(`iWzKEo}=y}daC:8 dsUo!?5,O1q@kr߭4H?22eKoYZSYM }lcsAQMXB3cԗ@Wyyyt$:ь&wdxBC &'óՌ'0OGWtv@ P=e{2t8dJF# |4uh<8:t P9 ɜ.FsO:tph< #P]\?%WlHQ'?yP'dv???(J %C|>@;OF`F9˯2w%`_Bc]$ Dg ($'!+ &j:@A|4ɛY> h0"l؅:}^5YA1|?Fp:&9 d̛ L#U;)JK2 &R$ћx0 y7 t4C]jF-_a]L2:%@BBFZgRؕlC{D:8כ$[ ԽAd۔]`7 \A0 z,ꝰF^GTI 4ڲ @7 B)TI yLdNHق/ZBy7@r(.szNԀE5!]Mv Ͷ,*`pLףwy8I•.4p)؊E'0 3SFe)"\LߤapLaMl.iNˆ0KR7iFEw:iȢWhC'irN]3 KPmchr'<GS.a|ξAfq Seʲad@s;g~ >Y(va6( \&7ۄq5pQ|d,\Ou6 j&̓-k,vW"Tx*2 ɆD87.^&go0eSc,KbweVKeVk dA![-SSݿѥq5:|uM,+Vp(6Á)t5 FyT(BOv $.JD1:(Cp4tN)@HV|E2wJb* CS@AzkD-` Hqu&i| JtL3evy>7)Fxl W?Bb. }8a25RgSk{MN"QѢYDM_C< V>8{/]_)tːBq &ƚ|զ4/'C$`H=bʱ 0fSqxz.E6GV0Mf,6ΩQ9LuvKsr9ĉs]smB9DZS^[tQg]ĩf݀s!{ך t!m l[kc =h)['L`&HT pFfuA%FZNoxq9EѮ6 nqm+P+I1d?3S"8n"_o/?weJcP@vRz0~Y6 q`]9D`P_Ѵ{|.Ëx4rR$NS'HtCXL `,+[l Sxv|go6_uXP˙hdu)JkCKFܼ$0 dR/Oe^xD,Q7!sǕ8i|8W1} Oo,!e0X+5է0Q#^O8ɒŠH^PX`\t]L෰O~*.Hgq!<3[ /\SݡJ9$Ye=3Ą2(;lz^XRAxug֝4 d-αE[m]-b7/n!0* G"`]8Ft2y>w'z!͌XUB$w&tH˶,8.`j%g%b2_āTrap=3E>U;OLkJWc_ˀɣhКс EXxɛĩ-T\?#_`݌3]3X:5nCR@NZ2Ű(ieV"˂JU>f.s'u+:(Du)yI,É; <6Z,9$*Xw8h+v @3DnyqB~c?B!v _?9]}ru/e0]OAä޵déϻ ȗ9LHݒ(2(nAS  zqN Z1ϡM@мe].">q=BmqBS?ćWq@㘦 [)?EƯ1jc\k$p-i{8zh[\ıviq%7$oMKe%aWuq%#F'ȿWp4uէN˯.(a8K'{KM3;KǦvBWO:9xylTjqz=$xőwq4=T~o-q8ܖB8wt͜zMIqgq,;];%&̥Lkέ<X,V '?Z.1>mY,ծ-d_48}TRl/_B+W{2K+H/& li|*O國ۊ>Ż]xq]H_V6l iֵa϶SBAϜV2 ~12 3>SK&t^My$qkJ,ߦs6. [O2O5sَYhȚwV|c\Qd {z1fi00nƋR5=N1 ?[, -71eE"FB4|[łB֊qAi\.jڟݔ[3=:(1>H&E|G!Xr{-\#h%ROa4gT6=}?Z ú̝mz%Q}ΘTv>̧n @/~BF ?Xyi~=>ȉy6.n;+q/Qxْص߈-KsWr:@{~Bϱ)/@j?%V{jo>xo}6R@VK0ƒwؖkdz3> |ZAz#^5mMt/-ZSS`YZ}oU˨!*7b{ӝ?ǾEXS_˟[o+BO1|[)[揶O4\ܘz*~o \ElܱXYKaOuz@ڻ8b|.OejGBVQ+D HwgI? 8c;L|MӠ==u uQ0~п}}C-_EX,r |ޔ5yp{p5jVAg*-f9ooyxP4rު_e2*ۣx8qZO5xZ8Ϯ}}XA / 99¥jg&s>̄SpmQ"\;iWI0a;1ݣ"N.[I ٩I}ʢ4W4{X`nmna)Y:o L_F.e.YJ+ԹDۂ(J C9Xڮ >F7.;UzNvb6<|=--2)[-^)g4DW( :[1rD 6jO]w.3{%Po8uFiO—nj6/ݵN' Z?,NU[*UP!dv>PK A4 groovy/text/PKA4 2j $&groovy/text/GStringTemplateEngine.javaYoH_QQpޝOVC0IX9dGK#e_U0$XIH6]_UWW}xcxGpf%.l\NpLݹuzpp?|GGC.@_I! օ_u~P5Ly$c|&> =Hc|ɵCɝ11w}4钅C\ܱrNw~r <s Z`cݙ`Ċ/"] @٘'< +}4 !dw(ɹ΁}21d+Mm8țZcW~^ RI@-ֈMQ+CquRLx{M(['HQ ޣyduUV7oB=!-Eߣ$"u"aפrA*Da8 ]9#Z yZvG-${CmL:g *}x <җ'_%^;7"24?|7O5#: m͘ΓE=- ? Rx4R7&ylu~7O՟s3-t>G]Eh1fƈ?*ټ+`aҟ.w׈L Ń .gH+!w+ŦF;ia$פW+{*52w,<>q%'߫ה==;P5]O;Dv{C}kyi7COƂ!c6O_mssٙ[Y|6M]\voy6L![ l0I;UA.$I~zQe]1LPn YŠb 9;G]Xf{_ \|m6gFKmsܑ"QNIO4KBҒa !6q"jfuŌr.}&=hᄈ$zh$}^w*hEM!l\HT>%t3vp t4h|iIk3/u|NIJ{ 8*ꛂ,'JiZ7VîH޳7vTFfc+# ߞdkKKˋ[|jtFqViN8rT?UGV<O8B1 _esj.=P_Mvd$Ui/ײZ!kbB4=^"fWs7f﫥coos~|PK@4G:E $%groovy/text/SimpleTemplateEngine.javaZ[sH~8c%\v*;q<Y6[0mԒ HQ9 @_٪}Xb!5Jh1=nsb3Wd%~wo~߿'-ĉup-<&0J< ALq-5čb% $` ܍ .XN`8ɂ1#*lXa Vn<@ aLܩ- ~! 7&Vo9'v Kt[#zgKD8 &-bقCc&`n(KPQ*PܟFEsP'(3NFהmYl2$.勠UvDi 9K0R ^[[""i1o؂3+yh~  C pYmx. >ðpAlLA/AMqIB >C }*cqV򴢛Ys/ }1u9baO- ze`GB?[M0F}o؆nt1hІqeظȔ0<+^Ι7)ܰ(Q^F6~DŽ -.3nc\= u@6X~l)in[ectTsIC{wm)P~ 5F]G:MX#[K7Ԭsչ@O#iΰgmc[Gj7K7]:В^ )pƖ!g l4#rxܺ'=HSC?dZp}s+!_X轮M\ ;Q*. o\胮NCbtmX!Fΰh$_wd |n 9ܒq:/LD2đ^ޗ 2ͰT[|<qcL;si yo͹U[pør[x.Y2R096 ql o﬍şT=ơiW,~:."n]OsbU\$~P3ep%Bc}tf! Na.]4"5OD2r~?'[(j7 H!qDB' Q+EN ՙ㴿W+އi;d4x/o8r@c.H|9z%}R$ 1dS(6 3KpN آ;8z\ES@r 戢J#I[p.I)b#Upd.(%{AznN1D>|x~K6;-}N34o#Tł#>V'3, 5cx*LmX_EQx^ܮ8Ӎ-d暩~w IVk( SR x~qgSl~|("l*'vmDŽC޷~C̮9;ؐCUN4}QS #YcN>V꛴;Te}9 Z5Oz%gj1~ kRdT;=u:4yH~ЈxL#=o/u'tX4P;q*~U+u'pIDW#U)a5W}(J9 vUxܥh25 UXa3ut5uQ1 uRn6G4$z!:o+m%Ѽn=-U u %]5 |[ÚpG2H F=E!K@V28P\/*tZ5%u ]EQ:ӕbT^D+-׵zc^|L i QV٬Kr#Oi^ JܴQ/)ShVՐ/VtH;*6X,A`<.Zeʕ/KuA+0CuQm#9,$5<"E3NYH1QiAy(ELTTX30BURI^ !]ԇ_V|<3k.Vڍ3A-8pʏTM)R ~u o&794>UGͷ5E#~::~8靕&AzqJLfҥ9JւGV,{=e5,.Ϥ.:~O<ܘήaiRiW+w }ۨwRU9˶]9v/eV=: {VUSQ}Bn"7bϻF}['$byV._KWʤr ķq{a,1Σu=i);} ǤxDm>eNJdkmG#T.υn]]>{YN9Rz#D$B րLJK$%"JIĨ.@^ G\9sNW}x5I Cil8 OA 6}Y*|h}mgmQPUAw_КTۚ@:9&+]wH<=:{݃;L^;5VEGP5"Ew:wg|/d k_[J54:xo;S.{RŔ5e:JL*[C  (Bh8> ۢVjL=&4Am^nHKģX Թs}f**쉁*_TX  ҷ{˹41 & [M un,%t(s\U6pC[PXz]rJ]KXzДZzX֡ ws6:܇KR#L%|R6֙6ThuP: sQgˢ- mU+evâLXMA˜R!Ú*${5zOpul:2M \/M0&-`~Fa` D ɄS'~ zyLAtKx&aB_oVLxp.xt@KX5xLƞ FpϞ_š%sŽ2€pa ؤ& !-W_9`\`, j)e.Ksi@|3a$Nϫ W 9-#he+$x/`e4ak\H.S*6 \ X© aTp'$Kt#y2AmZz:gT*Nn pufp?!aji!PPIzbQ +CuX:T1mX 5w8fq|Y}7BL'ʾޫtGw1Ucl7n7xնVzqZ5=u/ to ö4> gU>{w mxq48g+7fp{UhcjzNZU mYd8NCj|{?&?#%}?l"1=9 PKA4xi groovy/text/TemplateEngine.javaV]OH}W\J P`-}q&0Rbgm[{Hfk{wL>Ң>,x{ιw<߁}xNjdՔJV/T-ĭnC 89tr|yQ[iZk ='O?A0w]I/ͽQG0 ̺F%$B"1V*6jQם.T- #݂h[+U@󮒵E8aw.A; .ԍnRoUv),wRߩz Eq=A#np;K (p[Z0 kZ,y$ڪ\([MC!9+|8|תjED |̮%Qm…ny)T=KGա!B㊁ 6b->~-* nµVABd]hCmcVBm.0v*VͲ(C=QѺ !Vu):XzՃ}r/*P>F+(KԹv-ob8n\HCFQJ~a!Sܦ1iY*BY\"7XZۜ }>ۦj8d<4gAgI|GlW G<D#e ?gq·oA߻ "M8^"vDg< '<@ &|3ܖŞKFpH0eIx_S>ٕ;Y aI$H`6Ofqu҈$S6v `2ygc iF"fŒ4mB4N_u)W_1xXKϓFXO]Uf,P¶~|O^fƒ>,)BoKpTߵh{<{opkX"groovy/text/XmlTemplateEngine.javan6=_q* r7AihN<ФFR"h;K>Nu%nY- ˃{"E煤^}TW/kMYv/rMdT,kfpK.nͲO5ZG~gTd'gw4gy}W/"s8ر$;ɯ% c缊*\YS̙H%-kMc }*"gÁ|i1gPы`2FP{DO{@M]ҖNvPr `3q a3ҾpaĤv4om^P~wڀn]z5No{gt|,DxQz4Uv)sF1htĺVX[+biaԷ,Z5us">VN{p,N&}ΜŃUCpqBxl8L7@wNm<<`X\n׹Hn_ގv Bgg ItGGƟdښC8hW^L=PL CI2E2cEu-YVsHü,܏AuN2둁s -ll:l}j/x5Mu$w3Io99}w|z~rvj-@r-'xc>3myp: [iQ;(͖Q<=pN]g&< A_i;@m tnIOmxv+/twWMz"g4 2ZB¢i LCYvpN)y*{Q| `%> ?뮗6%Hc*nb9MGh~4YgDJGq@9qK {ܱZ8_tS؇B fqMG?oeR۫IB cedBPy'(c 5N6{PK A4 groovy/ui/PK@4 CMgroovy/ui/Console.groovylJy}N\47-:J)8im@d+j`?7\g0 _ssLƘ"otEhtXC4%ȳFU.pQwqK;ݑO(?Q.z4yK_GE1fӶ\= ˧%(@b[I-0Z^W/>aO;h+Y L‡ۏc/V\2 Y<ȣk21L܈ȅ3=y/d$P=]$X\L "YLX&,գw%˂p"aK 6)Z9ܤgW?cP`Iꭳ%ya7 zx }" ١gƕsvrq29tbrrq0LG}Q+`q ? P<px @!HK?ΠDe"2!0]IgoCYՄhn!W"ر}mq{3y_oSڎ8xMk^&ʷkCx!:N=5L:o -p-á,&,A촆6xwB ܈!v6i '0#)U<LMijspa(^f0\Si!S ȃEOr0>kxtr>:볇Q1϶epJ CQ!Gq%xK9rFZAA">@M<' !!bE-%eLh"RAs؊z9C#=nQLՌ X_;9G /eSNՂKY 7^m 懚Bi-Lj[ k_`!7جM"mww^y oz"xW?J,o/V<_i(߀T`ೈ|=9F"UL?Ώbmyʣ$φ dz]M^eA*㘂,ÙYk>K(RE吼п`U ;V<ao-xdvd7[$k*i0Fx8q\SY$P>c8=?z5/oG*B˷2(0U+6l-V5j9szEȥ0z'>Qro^`|=rA7"VvQlQ$22ENz ÅBoLt N+:(uCŋKy,^b_G>Pe,-d_6`]I췴AGmځF;X">;2l ]K tho5_XyB!2p,!c}߇X"2ErPөY&h5-b&Q*X o`*@Nv>> |VwX4 5%-=cBӦkz DӿaDg,Hd~D 1lp}ؓ)D^ngCy6Uؖδ.MpR$R?LZ`@`UZ?,lӥ:@!>*yX,2JAy-20 W`4#ʅ˕S׽k_>"Kz9[J"",p0y|w}'w+pL,2LXA*JfT`D2G[NHsUa(P֕ݔ@z 1JdĂ_E,Vҽ_ZT6Ǫ2q ggY볪T[_8VqvƟ@@[]E@%nՔB%}duH:R]_ l1z J3rp ]td[@]K̻a*@b 3ؿ͞P=JEȫ'd0YY,xS֓dǰ"BU}-ߺyN"je48\ɉ~X6p}3lG&Y6H N·nJkK!V.)iՠ*UѽR`~6% [UEmL`6Rc]5㲡TߙK T!4p1[HS]q`TYQD< %;ug72{4dȏ6#{3RǎyQ p<%a9ߴYXU:F$֛Zzmէuy)IEߍ&f9ՂY4}[@TTIY..JlU:aD,6''5v.Ds m.C8Ք}=TEUl%3(/"E~|ǾT]n7,龾n<>}m`)R&X$muKE,m T DYy8+O@;u}8U.X9|TIjjW& Ugu-Ȏ-)A7Hz LmaVY/ m^c7}mwF45 i5T9 >gPT3X2?)ӔSF=h7Ǭ jޥk$d+uGU8UQX %1կU#,FÞ=4@#7V6X |ŅN UjÖ2gv _ap_̗=WMR[} .UTҍI1IuY 'ԙﲳ10^TޝM&<?1+]@ڶs(xct$SC"XZWX P#b+u iRhe= Kd';{iYX7xXW/GK|T^(LfHu)Tj~ߖo oWz jpG_a.T^gZQB5r)j~_o]uh?c] Kt7MՄџsb QObm*O,c.EF^kki/hXV̷_$ҡsc6^OD̀6[4_k}W'̅aO`l?yXҌPKA48];groovy/ui/ConsoleSupport.javaWmoH_1BJRi>$MUc`6I麱xzMofmTRewfg}wl ?=OETVRi+_s{ 'Οp;89={ eQe Mo'%DZd E }ya)-nCHN%j-Rc"JJgvJrzPʹ~J^2ɸ)2М,vưsdC _V2Yblmh+@+%Y*R ?2C 'H3*R3|SFT86=C()OŒoN;ELCyJ1v?,Xh:j4-QW~Q0oܐap ʝENe~ad/n./_5wr 4dQAx:qCw,x\ڀQ,1]!Y]W -`p.L0 a: AĀ7r1`?v&1DWhdgIh/Q3G<~ȼП4C eC~#)| q[cЈ5C#\;v/@7 ٘(Ѭ~<\([Xt 2z"f#FhZ27lȂuA.*t0psp>$EZ$BټmbJ&r_h507~ĐY536U yVڦ\c n1yW贏{֊'=nzkTٹeeK7St;f-D vv⻞B?qщcez5hد/As] 1LoozHW п³M{ %%r-ϾG.Db-rg]Bw>Kgt:љykQYdIn`n1ygwӉ\."SR3Ӄ!kWxSf] iҾN [^mWvOnx2vxdfƒtD̏T<\l h-SY98bD˼/PK@4)<groovy/ui/GroovyMain.java;ms۸+MC%::u4LǼ%WfnI)R_i߻H%'b}|Ǿq4I~={iŋ?_}W/gfcdO&3k<`?[1/O`̏,Ya9Om6"6Cx{׌/,OE,2Β7aƲd?)~%A|ɖIPlycVߓ!{ KRLme ;dmm#]܇Kz~8[%Q<I *#-_/%EpY"Ys/ HaXr:#v$٬(KQ)?6=c?3V. 1:IP (&Jwfx@Og̽r+`&s̝n!,=6ٕ{a|:plz~+w w>,7b7^fvv3Lj^;Od;g2gW{5Fٙ4ήyΜНȯ 2̌fznad[hՅҒ v\# ̛۹NHry;vSv5H^35#Zp5|?\;;ܝN=v9}r2A9tB삄@P$ lۆ#n!DAcq*+zCK\hAi~|sV򱓳cӈ̶f'YY8iiȼ`n873~W"{Fb hy>WsrY(ЄWF~^CpyC]lj rU|13X"I ap5s(F$P^L+;ȗ3 H| mf$CG*4>(Y@1AÍ8pvlK6by#*cʳ""81QL 8w2D~f rҧPUVk2lC [ԱpĂ >H&inogxo}bD㽙FIfbyN2Q68Ab[}Ùzy9ݵVom k #l ?uC@ϘȳDuIzA VüD:'Q8p]A\z_V=c"Ię鎣8Nέ~:~* > 1H^MFY7NWTSi"%&yH{o!cc'ǔa>n`l(_af**]h%R0r/\Vu6$ӎͥݴ[z>o >8?ݗ/(}ڱq,* ݚUø'JС eP #gR"jS+n'ҵE6FguΥ, ZthWI%>ڻj˜uOH~V~!I wYg;: e;fiI5eTCLִ23FkAٜi调8\ȟES&j .`Bh_.lE0ؑ,EG=}-4Ipu,i\f*bª61([qkeҘ^v C}6nP¸76;QkQoIs!DR9߃+LA5k1&bRl~oBk&@Q|sE,`6{X=g+d(:1&"U.hSΟqxn+5jTk5 D{gEQt/]+mY)qPk6I (/C3Ңl7AfVZc\)O4ہ(2xuDM'4x K Kw][e{ȊuuhNo,-}jsDet2ɰ{6 C 18Ne8J?әC z#ίL9>ҳQU6o&҇J%%9K0nqj.qu"VCfڮZ&ȵ$x(Whk+imLc#k6 HI_41)efʒ=ck3pQԯ\3jBƙil 4mY˨Z]|k2[u8a)kV)i\\f]Q.*3h=Ig3-K+6lNoHG**M2ti幌{܈VOL4cvG &bl] ^B))a˂;K͊ P^ ir$R<o&LC࿶awµ3>; -/wǣJcʸ`TaMOvGb tt8tfĂŒr.,A w(:]9K1:-˯*bc$Gv@];W |YG*\J)]Ef*zʳHj<$R^% MeXBF$YR2^yKI3ElXVMB,:dORƱ|2YD,R])\" ӌV ;%2BXTPP` ?4S!+D)B-4OY,}k 1*{'{ 86BY" %;!} t JG|NPd]Yz\2pJHRq(ֺvS 0£%6uVE\:#\,iQ vd$vs8\9ׂRfe) wR8M}wuk1p(,% [Rq(# :~!6ҐCpLR؎ a&T(\gr06*\h`6yN?;#{D׏شi8w#k2:szO˃ȏ?{?fyٵ&c{}r&|Ln-L};s_Xlmwxֵ3vG6١ǟE3|l4g5rr˙&ٟOޝ5wQ߾W mh]mmq(JgR>rd 6>+R}CؤuoڀѨ]]t;y^ܳ[iVs Ԝo|;ICw7=*r:Z>=x2ZV؆~,E&M۱skO6NY̓rO8"lҏ$熬g(AUQSVK[ݠ / ݣ[#:h*۽deq|ն*fY~3u\r[oX86@"45[{g*J\H{ .2kP"MzLsw 0#b(Qz_Eg2|#ܷi+p1S3UA{UooJn0!emG!Ӵe²H lJ [~jgOX%n1b._+^Bnq6/i|(ys%43z].ѧۻ^Aon(N$ =H.S{Pq# ׸ MS͒<9_||cQk\ U;֩ԳĨ_.hPffԅ\l h2SSy 𐗈P->OsVbDZB|0qx&πIiX!:'C|zpUI=/~ %ٳ e !앦K9ގdT۪ G^n珚զkjUƽns`7X\I{uD޷ѪEs!!x&Ɇ:˯ZfrK6Jپ_{pW3lkO=U.{dB'UCL\n`U7^'rS jqWJTGyPϞl'Ξ]x '/]ـu\jmwh=/W2Qxܦ4To ֪%#9vQgA>%*<]i%A٫+5R-EReM}TD,s+ݹ"YҟQơK?crݩK2oyW>_HMBI[,R&ั^9n4ؓ+)OkޞGM/) A񋷒@Bsq]ҏA cJX&2sr'i_e),"OD]^,$R9hdz'ڭtŭ.EgbkceSB.{O([?\Y}Jj%̩pI3 9fI*bz~ZX{W%1(g2qD #$"&].#:WC/`Jp3p2F*!% l!*P1%1$ b3̗@ZӠ)nP2ZQtiYq%IeT$d8bRT A'PMM,'ՉI=BMʒ$4 Hc^FvZ v` DùF#.ۘμ #  [gYtW1G <(#c2rkpO81H@;fHe'p}Eӱŵ׃No{cWxfp➈wx}ݻ ~Oǃh<{oYp Gc18ǽt?< `磩SL'F_gx0L=q:8荧74? 4=pW%=&*];y2)rp 67ɅWu 1N <'+blR V9vψebry<SWN=1qo}wr( rvAccY1_N,//ygO\&yhX]c(K@l=!ũ5Mq^}`B#^ijlS NE @+h(dN[ڛ}=jkdޞZGqjn^p}pqg_wO3&{X{]zڳ1X^r:gg^8dy (LIQ3DŴ#7'aGӏVk?`t0 t8 SxD&(2PaKeOP , Sx(J(H7x,ihobGi @ G06@ A iKv; G*rEE3柽 XBZ+,[|  #odAʴ^3[G~918$ӂ;z_{qͻ,dW}M_ oUH =eQ=o Eٜ5|OIF<]KJ bLcyӷGv3-Ij SI 2q1Pkx0H)[mQC 8k &"2*E~&yTrQG8Wpsuݰ H'3ᗢeJ`֡ SCF];5v$>r$%x>l h,d O姴ݡoo?v_tnIܖeWwebCR>c qKD#܀4C|lflM%;C3`u a o JfѝǼev9_[u=v~ ]^l`lwʩGbb~^b^bl:9@n:* g RX ^l1~ at^ɣ7>Nf8jL)#Pv($K޻;01[t Oߜ1ÜsqϷۿڊLWB؂JAsKW8N5 HQar[c7Bl?މ{G؛L*]#sjX;uH>׵lfbeպ-/OdWÄM`HE7RKj!+Riؕ4jEP^V#YMgHn.X]n*6WM0o)ҜQu<N,?ʣ)b=!tm,fj*BRhҜTunѩ!u^éXzFGꦃpL*5hQ[zr)*W(8{us{%]T8jUKh S22g59]ܨlm&hi.4Yɇ:^1#*J.Zw8hX.(QYmRQsb3cƓ&KbMNa.G tb)쭉r6Pb䧵ѩ)#98xσan~kQKJ453˜=pv+5bd,gPBHֺ~#O򺈋edMOf^/Ցm))m:&>oejIy\Xd*ua>7,EK(zE@T<%@\O<Q%.?XfQ -K{9WA"%}ՅROf&FwL">G%y}Ю_mzGU46rԈ7}7^`6l(ܬQ#5ѵʸkG8wXD0w[ŮwDnÔV dk8K3Vw(]OL=Q; d~_x ےJ} 5ͷmR߂6]%yG>RՈ#yU I}]Wp03z}@~Q7Fb+@n B/,[I_arFXįյx_.U1Իw \7d)h%Fȭr˚:44o(Kta,ouAmy#tkRoEQM; 2{)̖rN)j/f3NyhrkNlS/-<0u{ATcQSq?`6ɮ͒|X7ETꓪWdgO;T{yVZ시jIC% {]̚KKJvr^;PKA4n {groovy/ui/package.html5A0 }=" .Xu('@{[z5FOHJg2/C1[f+:!~=X F ZJ=+A+ Zt2!XZPf~pbS|/fqPKA4*tgroovy/ui/ShellCompleter.javaWkoH_q4eMfJԫvxDl6TjblT6U=ldr}sG;?x!-\Rۿl>ᇏy#^Z QmE,-WZ5ۧ_RVo EUDwBiANSNEz#3۲")WOZߺTΨ^rV-͂2Uee^ʢe?U/r]ӲLt@l%Rgˍdf Q#Y*攖Eة2NKY_X!W*:`jҲD+EDJ]6EYTV64D^ vlO!IB^n!lLx=Р#'Э^$MsRsR44D-Jh\B@n'}S/^lJ0[lrzPRz(@T,Rsh,ka 3$D k mZd7(3wHU10\v!\mp`r)*-!ɬn=K=6M~Rny"aՀ;]j%ŶJժ.&e{~ߙ\ |fY?4Z-LUMßbu9ܢWa 5֏)'I#oDWz#֙#|I_M0~sbxYrG~D^9ȿ} 8r;f@baBcO`ԍk"Ε?Gh]IltdM(؉h2&a3;v;o B  :HҕkҀȏ<7X~Ў<~ĉ1cSaFΝsVP:pwx!B<?&݄[_8T C4b~xQ4$~#4Fa`B0z䠬Q~@#(1sA)nD~~AΩfԁ"cd(|Mb$so[y·Jb솵,\N墘7fln?ZՃ2-\m4!O/qn;Z15>.,KZsqk,WF/8nZ04mW-Mk(Nj,FjsF¼earn:zAs%'' 漪uxdysUFj4,C^E_/ׇơAywߢvK7wkKkBYFV8E"W}!gmvq\O9Y]pL'ÓgYtuH)nE?5qsYEO_nE7n>v5Ք4wLpglpe`|+L< f &5llcVU{jxqLv҆of|ޒ{؛Ref4ϖPۯ60qh}M{lNšU :n}1z>gt8u^|J2ݦ_}u7 Ύ 7:9ޥG_nj'M}v:T?a6iߘp?5-67^ac(橦߭PKA4"J&groovy/ui/SystemOutputInterceptor.javaT0=;BBN)z)=$Q+KF e3&BM0f4潧)Ggm.:Y. մօ)9elYnׅ P6SmP~q\*r5Ug)l 6M '-:8XxHd\TZ !|| hj*ZzPIKm\3"˽*ŒJGPSQ YEZ# %'yC $aԏTJSܠmN2CPXM% %b5[ӕZUoY+,ݗ7 ')mΞ_[ґejjŶ]V#D z Y`6ݶ}9l<Ğݓ>-gљnua$Eöe&[$6*|q6 -S%soR (b+O$l#44ӁXHrWAP㠨P+Ϲȓ-I$,Yܞhw+:0UAs[;;sBwѯ7PK A4 groovy/util/PK@4-jgroovy/util/AllTestSuite.javaWmo8ίa/tQǭ*Ҋ^[T;(ovBн*I<33/v =9zIK'i#6z)W\rk5dF^^*ҙKXkN8)ZByiɴrF\/ !Z]r!!=gPTN,!:JÜ©+ ^>_#))!;8F9$|.k NN: YaWXi!gB1xv,B1=c!;[Yqo9`: bfX3t=f͐HFX\\f܂;_rCTGtKBu lQj%,+L9 6 cJpO&/"kӪhqY[.ɔ&#!zfuiZJ2 BԞ  +[ rP>@͖ B*6 6XKV]qK,`N 5 ؟A\aBfa=#H8sXU +L $q9M:(sR[ |U琧=HB7H^zx!\/FTm5 뷭eEޖJñ7O6nax56׃[C_2"F6iZlW9Ŷ_sq+2{LNbIT{ S/iBpOty2|- g]smh1U5Rm췓 W}gna@߇U-tϹRy$牰e F-h #j2i:+S ;+jd%NvT͚[mNN'ͱаjh-8W Q 8-ol^9vIs!|Cc{Vn{5bC]U6:$3A-st nܮIom@TSYb"'I'C6w@ѳ |0 >c)2&ئv[xjMG}_'d45~t5tg,WJYhq/xfq"60 ,f,}%yexJ; wěbm^y[իao'q -65*ޘٝ~#ܡ_PK@4ZӺ #groovy/util/AntBuilder.javaZmoF,9@G'ip^hy%( ]K+5E $eG%ER'$6;3;3;ɳ6}Oɍme!}G//</O_:}Loom%].W9@VKkQb1xNg ]WaQDcFh,3ɹZc9< oyhm&)YP 3ʒE~/R6D%PrNd]8&Nצ0_Q6u2L62]9ڤ]86?$-(JxI$)O! !uf6IrJe. Xm'ĒϔFq39t@QQP\i lȗR&EJ麐 Ϸ*&{1L Zr{S,Z̖Xsc% vR!.~S5X`9FQg&ݮՁt#9d TB2')OTI*G lj)e:)G9X%X[hkHLjreId^9tҭŮu&@R0HiHQ"L鲿cI ޑ)|pr-xPaNxGsVa 5cW|szry:Us(OݱGx}OgQo.i@dM'qЦw|sp5أ1W26!9عt'~o:pt5_X^<{ '\A%= jҙݳ@Ͼ?z?46W^eG hw lR߽ty0U7ʁMt]0D0= &d:hgx~ ^`({MXlmqvEG.j,@} [@py%rX8RQTy$S\l7آU*o:kFyr>^T!De޵x"~XQ_u?'2doйN~;w!?[}H7Q8#BYV DsyemӠwT{zL_IgXOv>|4u:&``OmˋCv_I Cz:@\/ )+o(OcYcEץ`wMO4G7JY$%Dӫ^ud>ܪYhr@[1Q 37:ffyf7VA}0ɼƀA{4-B42"[NNt O?PwKs#ӗXŞ\Ǯg8ߞiW)25 -vQ2+n9proުqCܦqݵ_NA1`炍[*QrsiB VfOS7"[#2ѪxR9,ˣ[Rh8KeiF|Ua=Uo|T`OLSB^̑X[W;Q/MLӪY1PuD0>{%!H|,6.Rl ?̀y]N lRw st~-}8-6a,8w T7q=-(12ϖĚtf:1MWJ޳K{/_DR*57MŮZiU-y{ZѦvx=Aӟ} o4{^ʭhBKi=uoD#' !C9.ԍCզ!dO.Z?[L]}-G6D9J7B JQ,X鄖b O8D<4| Cd#zPKA4TY groovy/util/BuilderSupport.javaYs6[OREݍtBK͎.I K)Rr| z3$Xv_7y!^Z"|ak^C;㟻[_o Y> ^6OW"/2| ~ ~cK. ,p`-"q+%& .\yAY.#hgQs!lIMvWL4XC _$cՀgZmBy4n@ѶXF Zt4ӻ(C&aD\Rq-yv&:[VK2W8H X Vh1'å(I(;˔P@Jt ȓ]i%LܣKbYX9Z*lLcS[kQ "vPsh%k!".$X2:n>N0h.t}Aca)eШxGei3ˈ9&|78,L(uG)Y$/ 2A^v!5c̙:Aܤ5sr~uKv_8F)A+VN>R(0.h3>K&nwй;0b$2;Ʌ9P F \d:;U(ѿr<&G˵g`3П +k5w?q!˫Wjӵk{rO\pFCoQk}_4``6+p(aOTφY5!ȅ@gjc&#+Ħ́*ݖv\ޛwgFNl1`.Z:UNxiMyDfqN h?!tRwvH忞hML2JzvA\V4զyF ckcnEs̩HԯRQT*em8lnib7xkTnJGIk/Jn׻C%Y4zU_o@S84?-JT[Yߓ|#f  P͔n|#ͤw㷕GnsYuDl̟qk[n$X`q"Ԝ<64 -z1(XIfI!([/SҢ}iQIM {OJ:ɓ_\cϼ-]d9rrX0x=DBJHpywJM'K*li>ՄRKv+qr_=~E۫9!KqU6ԃ ?|ObKJr(ߑ-d)$` =)w<Щק5<3C~8|l*Ys:jK]3.*@n}@xgPHs)QKr2aV]1dSٙ905:g:),dӈGߩA3hHDxVn!倮:r8S4qv*x<)H"{Lp{P:V`?, %-yxG7x㎵m>88?xjO/Z/ f"H7]8zuvHJK5:dž+bCN̛Per2, ,^ʈE"硠ELX<?8 Ԟt!$1[s3`Ho-•: %- f?8.q+SA$ 4IP\EP'$Lp/ P"ÉPAI`T<܀BHte|܉LLb=gih0y\D5)A0!4l4CJ&C߆ApyTITD<xB bqDO<61N֡D 2|e#Q(CuɓWvm'x$Ԝb@d23aA(F d+1jθA?@$7H-}k,Ȑ@vUO-h-hF`501"DC>+~D7yBW 9 *8Mǖq~5mqGl4vW9gwyәX~\nw2 Go`SSs~: {us#vǮ3j0w99w/ ]W b!l$ٕ3콁{߾;:3egn&ÛaR:wGˎ{7A˜_1\^5Eǣ]t/d@_9tzc){x enohk i ;r:NHu:`h`fzsRIw4vǓ.snb69 `2{A3!` #W{g|N Jճgr˜6ޔAW7> 7|@ s"\X‡|7k[|Bzz^HƗ!bSF5Z':E._ǟz!!!8nBp |nrކ"4C[T ?`U)2M "Z.Ԫ3n6㩰U)ʧ"6G"$J{oX r&a[D8z"K^+ҪВSgŨ=85O'W7p_;6O7k Ƀj3B#q#>KP1|歈US͖ Pц lӓ KP : 8~?lձ?i vUv&~4XI`_'ņ:zrQ !FyAϫ\Xċ5\gV8`% LviZ0~} _F>Dg B{R%KlD _<+5u@ hdq8>r BW*L ^ap1w|5 k IϴI #@6tՖڮ3Dz¥!5C?@XEO5k- R-xX ?Oƒ4OZ*E=nqV C|BiFTi_==lF!BFRBd;nYBY:j\Z+@ r̚U~$R lKD eETVٲ Z>*ږ mMBnt>Q 3=qSQ9gQ:jg-uA̧4UX1myo~EU )0]@\' ֗ylhm=-7X)`V3>0Qޤ܇h-f{$%diڧ{cI 4O)ǟ+ EDY=!g쳼U>$ya0x (QLփEZ;N\+fߵmz!bf2vy@Қ W@@ *Q{SPAdh ]{C6 Bjy,!0Fy3qjN kyW-X-T )AEeBr:Oh)QH˥2UUq+}ߢ6pj%X@6KГS- &Bhd=D:2Yq?*)$93H\tN&5#+^MRP9QB/Z-UIZ}M 6z"&A$"OnS`I HۭS[P+51E8.b:yDԉA#CFPNO#8ܣ4H@ܔRF{GזSnL^C ĔTeGO/z'Wyjz蛞!xo Q}!Uc[FV0:Vi%""ejG j}j%&=MM-^=z~U:_,'ab'z!-D']`h/yTUݡ%;d-[uh9*rS^ <Z=siVM~JԞ Y":tH l#}:.+U $ֱ1Nh.ir: |l4dyLiU|}dACA0~ВN~TO[9/0jˠ=eܶsu%Sc1TPobTJ wz ;haA?3IHh>^zd-Uu6=H в:YS;ߩ]0鰲QQe|B'EIs-}, /Mo'2z%`O-tN'KtHUhF* Oԁ0M^%t8m66W)>z2W+L;ZVRF$%ڴUp_~koUձTEȱ[fm yKK~0y8˧l<}ժ'}ji׿ܲX{]@^ۇ_1h_ӻ'^}Ų/x4yߊV{x'8,hgˊ/7v%']=udǻXV2 Ef)k8c!㫌@Š<#4Rji)RΩ*3}a-їaHL|z21ʴ$:V )9VtxHRb94{y*54 -]M^^ePYxz!i\G ]POJRtl}Bux~u* .ajHENkWOמ&:Wź:yUZO두!$^<(*yZS $;ŧ#RFRE"r7vc#xVN ~vޣU% vWoE]@KDC*vVpw=)7C"蕹^9}܊^}iV-2+'H[+.-TFpm1UyBVPTV;@& "7to"6T訧6Ե+9 4 &:Ś4S}]ߝaTߊ |E> 焅[3; ud]K;zCkV.tG^̡kfP-E{mG@։' <`OUCe]y[8^`ըfu]}{dߝ}/nU%nzig} 5O ђ?1\`J{)|a}dSq:?7PK@4ʣ~ groovy/util/CliBuilder.groovyVKS6WtamXrlؤ6THA=c[r$Pzx,Cek}ZvϫBXil2J[PzxϫYNIêVT^> AZ!U>_QgYvtp=Ct %J+aϵBUrEZDeiNxY^2 Bc=21wy7V#oƞkn>ᔠh*Zv4t 8CZԆMVZ hWg-`.lC/PUvpeUˍIKj\`Z 6( #j-j̦>sr>6SWʈ (Jw~]WTbopמkXl7&FqoluX"%!+pkT I :+FT{Q7.n ,H3eXBq 3JQ0':R"vo?we9h-Am=d;YKZʀ9d&u}/naUƈ{R@+hW < ی*"OJB6># y=5%T"s tRe;5h`)&h0%8 qV W~~00]Cޑ;Y71ip˷\a(tO&L҈?5tge ̣Fީ"E7"Y@/` ǫ縴W#N` _a "7 GȽ`{\8_i^:κNpJ8rrYrY!}(1~0΅ɢT ow͑`pÎBD65I6]PK@4δv9R "groovy/util/ClosureComparator.javaVmo6_q <9IW`sڢlɓ0`jeѣ(gA;J~ 3=sGRKyPUVkQ"6k-\]]һ_W7w0/D5b5;jҐ[X bE%2$}YHWQPEHfyet>M, *l^ J02LJFPuhr?2D䩬\8A@N $)+ ЯX^mYaYLT(j#4[N&CP 位KB+)-x"aKZ ]: w-hfCʠ޺ ZYSAR d)M uLC)50%<)p;7aYFGxM4 KUQKQS&MS NEvZneY=,{cq8j>,Dp+vk ޺[gshZ]rU,|\K|^`:&3mԺH(j%ZBDZ>8[0N+<*ܐY(^4g3GA:#iշ3nS?:|cO}[mE<~0~ IKXP߬,hN͌m8J*8Jgk˸|$eIݫtN,{k)3@~nz&ð Ҳ* KVɁX2Tfܡ&HA@p[vjQiR7(I/kT8.bL[eH5*d%B-LNثdu "BT}32ExBdt2YޜT,M%K2fh̊ fU28£; VֺيeKG<ʛŒ\` }4y!Jqð[9&Rj/wُ5s./~ԵDdJMJJX6( hHSX.~wwhP1UA9r'10G)@ߚXzUNIWk?p|v|_o@o0Qjz#a%)6\a:"_܈ȣo/-KБ׮bȘ5KV)?O_4"f3x5R!iDb؂`~%PM/-d)TRdgoyuҎuNeN*=Zb 6[,2ZkuI ׊ΪSړJ4Q3ޛa9i6Ҳ[Zc&l˭d~nm6j_~@)9ñ4W8Rڞ.Ulk"esYjƤH#F4YR=Hv{:l((k} m: vg\3AlRwX^m{d%j8|~WX(qTv#peGK:([cJEe>]6~4e3Sxݚpldr#v"W*Ot*]g$|>3oKzFwULߡl{IKZl;Ʒ+ļS:/~Q,)c, yX3\AI6W<5yh閭kheRtәĥFUlZ8.֔5cIk3ΡmH{E]UtCмޓ|u'r'dFky^)/z%a(p\؛"vSn\`do#a;;{g=Ok3V)KIybTmu_fB5Ϛm鬉8~Lwnw?Qtq(kLczp@s窮Һ2+O 9Ve~:늻3\965PsK`kqC#ƕi)VN*`lb*є h6RmdFfkDeZPKA4Uu2"(groovy/util/FileNameByRegexFinder.groovy=Nn@ W$/KHHUUqXaD&tӹX=PlkW G|o7Zq7DtH9"zg5 Yjo)+Z%}fxL-$t86z*E \&f&>SVZ{W+U>f*g˒ݽ/PKA4j!groovy/util/FileNameFinder.groovy]Oj0 >O #PCw( F)Xvp93s`-+gtM߯4}O%Dca"܀@&q@,Уۃ@=c+}r"hq-.=8X6$o9D'HXiP9Lj6Ps#kB~L֫q[_* |nN<,we&PK@4 groovy/util/GroovyLog.javaVoFߟbN-Rڊ5I|/m.J|gh&w3k *R`;?yfvf/=z4Zo&z[+^:ퟞѫξ#,I| ϣ=LȲ ;g|Jd{T8o:No#^롄Avwpuy)2i|"#%'ƩA)!mޜQۙO+ud;m8KwK4*׆ǰյ-6dp% 8l͡X61\UR` #$y%ţ`U,U/ |͒C֧n-eYBhσTȑTQWFHȎ2|eZO CTwsKYqgpef>c])Ev$&p,4šQ<W, (K,ԣ?R|; [NЎ KXN( Eڣ0Mf0xM0\z_еHFW70e]YtwM$ GItLT5$FI⃈2J{%'Pc0e(0-92|S1 y!~&Hn{lFS B8qp\ }J3N, Da,tcQ*H4S,=6бFH4 ģ&xc8rႡ8ẽG7W 3 !)her0)RD#1 S A,ox9K.jI0IpW-ՎtJ/F?%nO{5s+m~oz|Qmlcbc0vWcHzVZB6mZǦl&}@XO,Wmt0j||OX^6ѕ G^s῟e~2j񶳖Ei#w9XUFWJλ򝳳Ћ,%R4鿞aÈA||r 8`v -*uGBW^v ? *N;rP9}iL;s'>v(xlstZ2ϔݮT6BJ'&no-uw/R;TҮ;:=[bth-՟Ե^@o-{8A_+$r801D. w Z+m6e":2CAB?._F}e(Aq}DA1N$*7'jOCW1"/,M_[#sgo ȼ\0d>ήә݁s`#ɧg[0XWc /y6-5GҁtcҚ/w\~Yck+k>n7ln ǃ\]Ϯ $Ȳuiн ks2b0wRs$(ll}PΑ53stJk^d6oZtah0>#mC .&WVJM'h̼$Q=sΧۜ} -um}c>[# ٵmIY9]_ͭ7d`M).jh:{K>04*5 QmùwD-51abss24`X< fM+,z-&+!_Rپ4&X`0z jtJEmx*BqgÜ;e8 ̎i7ag7}O܉dCO͒ ƼmsnI}Ƹ`bu6'wXpsV{8"cixr„0*?BÚX% V償.Rj[$ۥCYX2ݐXu+aG=_>ԂE0 U_Pm?V)1`o`Ň$? ݠFʵf>!)τPVj:N`Kn=Fdm~Qme3YE{Q ]Pֺ7ؓPYDSRvKQ,Aeew]U}1.$,Of|Չlԟ,|켄[zﰲRI"oK6zM_Y'N0X3/=g3~i^GJ M>UPQx/@g,vE@!Pe(dG8*;ΗLȜҸq%>xBtXXz2`7˟o+0σx>H ٕ"T'!+n'G_R_{="ucO\ v!;1@HgAF ;rO0% +H 48v,!DqؙS FN3WRj* Mt|V#z4!$*sAMą70{Qe94m 4Oz7w01%y/`t]fW%x5bd:[ur98ˋ|g7҈pzrb{"@|gVU"ꮈ>CJ>1HjġbeK}d4&, O1|Ŷ^DF!u++1J,cu}4(B 8wF76(_l̹GU{4bS]|sTр1@`D˅y_y_1zP~iOJ ^^_(_kePxVĪϥLȣpTW]%t(ڳd>h,K;079S+.X;tLk8o"/~G_rݣeO@뺇Ԛx)uԢtdfu8Z-}PjtGen2ZoZS?0)A^j@Y.sn0_ʚkk RK5'Jy3${䖦Gl<_Ry:}U6&?70g,򁒛(![%i[p=UuװxTr>kU1Kɨ3h;_ߏrGN]Q tD_Y+7=h}AVkdZfZ5`f{[9;Ϧ髌s,V0L귑=9}!TĐa90*`P=e'&?!I-[n:Cz*W\Kz⊚8ŵnWW\kxyPK@49X<#groovy/util/GroovyScriptEngine.javakoF{~ŞP T҉m\"˴B|4( ܊ZK)RÎ.]r8 p8ivv^ }_$o6̉A$? ݰl_xl8Y_nDq~^~`<Eo7IXf-]Ð'f0dOD1܉iB4F ih%lf̂'%Yi@yLQNӓCL DsZ!V`RTNڃa$a+? @RX4fߒL{Wud) 0fMqf U &%5ρX*IٴNm"֑> X%aNq5A{l b~ _z"l1[ar℆|X ! pD,HP OӾqXFD9 #\Wz-ljoOҳM5i0=s=Ood=v;t`|/=/='?xwbxO{~1tpOx=cwtcS6t)M="!r&sg28_GН#'t 볋d. \=\þ{eg4eY8JOG?:H񁼀s (S6./ίHԟ!j@9 $SкG52ˉs\2#oN/;m97p.=D}"X@e0 GKsGSg2Q߂n#45CZ{{ *G]x@95e#t:cD.!+)퓅/I|\1M6ܣue q%0*! J# dkZp'j'haണAۘ!a [:i9D; DT y5:X3/K_Df_N[!~Q$T9č!%`A[ZOiO|2₇Y H* I|:)psTU$2߰7HDF eM%%fPeaRަP~xC: x4CA<^0slDZI@Q'4:A2Z:WS^!^< SL۔&` `Ngꁍ`RC[ [~P&2'9S—gϺr|wSbfuKw[z. X10U%jj6 R!aDv 1+KrQ\!̆,,u:V|+fYx%602L.;bEmgi3N[A &_WgP|hֹ # ~8Ie8t5*m!?>B" S&VQm䶄Y7PCyPՀKTt`Q/1HZe--t _0b( rB~~c(lڨcy%V*THM4;Wι ҎBLT@q (yu%~s%GdȀ"n (5VU 5~5jfFX,RHe(3QP/k'X_WFpszjv*F0LUy _n1,aoy1IpI&1U J='jvOT#F1CH\ !Eh >װ5s`CwC,?=Udl_{(6T]5 [ā=d +P!{eCbVyd@^F@ XGy :pw[W Lu!QWÞc-H1 -Ji#K֢s![n!L|,amףQ1a@dx ;ӕMW~seWv p@G Cv*%\BmgCMMѮ4rAo*zqm6J+媊,, juDT-}#*@V<WyH^\fb9FϑZx .HFzn:~~n)Xd@{$nV%508"5|;yEjB7GRȹ 6 2ۢtK`d5ӴuIdVY&l4ߖ6=Ra%Ge֣"+S%H/FG. cY5ܢO)y%V5*@B{tk[Yg* &brX!$P]Ya]F2${ IJ+YN &Uc4!Q*t+&"]q[0y rX%B+]D\n_$ZZl)M8jmR=x1j]iP,xW2LKeD-y(YZ Ry;3>1MSDiƣ 0'!Lo[2fݞ#7 ƨ1 mijkx UGc@GN Ľ]Mu2z_dk4CCO=JaTF!3QG^s_ 9f9`"6:(٦C>Mi{Fu 2Rz6-aͼ <'1>=sC <"F>cFSmx 9y,~&B6~HE78$S`ws)kid7hnѻ̪k ݪl5Ja[@ X: l Yw]05#1V0Dj] LFk@(@* %OG=|?ֺ C~kGG T6vD$BIA@&\\'Vmc+܎gfYC m[MT,M6r9nW%>fç$|ZGZAw0dݲٌn61uƣ=BԝնSAә O't1>;`=eLQ3*J=EںVcfoLER}A%c;G%/3Y%3Ix k PVchxg'q"VDT#IZΈqwh{کntvvxYU`9viQт1X[PWXͮC]O٤i7x#踲0dSy ?B/heW.roYz=~SϿ"&{&h?Fʙ`"!Ș?~y?nܵemL(4lzc[K*bbjմ7yAV (P+UۯǬ%WR!>f?g[gGe66tN_徚B#/צH 6C(/k<ߞvN< \>׊"2%zH?*/a pIsy+RpV\Ma}4};Z'Rs$ɻl+ ;t+.?n T_ل6jyŨ+Zg,Mn?84KE9JCV{  i52xPKA4"FL!4groovy/util/GroovyTestCase.java[ysȱbqŠMCy$o) H|X.9Ks33aOEuW)T  yp\J* +`Hy7 / R% Ҍ'$va"!&!|A˻yYKa%YCi,1eHmbA: Yx6ӏ^X :l=?Hi4 uڔZ/WMRA;iU9 H`$2us)sIBx K"Fw zG#yӾ;)'Ϧ?%V  z?2=>W\RCš~2UOVeR4 T7 Ҷ:F;*!DZ"gNu]q > (Bz!1j28a4/bI BLBm|Ѱ{e$Pb~BX ӞdeNi˜;I?u]^;vEw]$/OkmTŬ!mڰ`&‹cV%(,\{ Ԧ'\e2ј 7B"ݽT/ 2?=bK紆ӟ1S|btev#JCu %>LTT10XY€JA28 siLɩ+pp)"ΑVFRae[i6C⌏+(>/y OO֗Z6S@:IOf}?ik|ѷy7eG9TU U` "1VQ=feUfjG>m4"$:CܿD |?9]7.PS߭",kT FeOzP"ZapSZSY([,*9I2D9lꎄ"mHÿӾJvNS,3:#:Vx&^tiN S:OwUQa_wyChDI2E]-ojP/ٳ9YoRgaq ⅷ@[;z^  uX<@cj- ‘M[2B9 f_J%Kt(jU_/s\Fjݑ6A(vnSaNm_-mkg:iV7GDmof'y]< FM]ci<)ȴ _L{f<_ yi|[ˉߦ}E'a -̤q&93f[9hQۊ=zݬk"$BmE7u } s,Yqe'w8R ܲ֎S`5-)Va~wD?Yf+v9k6Ⱦn?x˸Ll?^TR(N5MGcA{fiX"\7E ^Lt&%HdJu}s-ƙ Z|ÔB>QY2@g=z]2ewT/uOPAI^䑪}WD]o4@Im5x*iȗ[J]ɖaO.xl޹'vw/A5r֛ͰY@ZtO@|ax7WDUYN,! 6Śn!a{LHѪGxETsmX+/QWmy8@Osjej`%']4ӵHe(\9*(Cĺ mi^M:kw*.Yoa'/kZf,iv+ɣYDxkcb k PKA4[˝P groovy/util/GroovyTestSuite.javaWo۶=(VϓӮ-i*hp,?IN HVrj )۲uĴxwi ^ k%zJǵ֬Op~~qߋ7)^ y(Xj^~f+^AKVdp%6}Z rsȩW\yl#J+Xk!w]qsKQA%)n&XUT03dZxyN7^^T[V2s>^Jh*\ z47y.DT {E+YSuAqDUșr"Bj9`y%ahV&y.`j Ֆfs(|OoϧoCG2qkAӜW`i "qR %P3ۋoVP ؼ~t  : S 2GN$"GJj6U]BK8g̮ۖNJ%jUFak>*@<\%+CltҴeY횥ˏQӆܷffv+Kζ  c"UኔV,+>TFh*1pX2]Xj]^ 6j=$ 8%nQx !\=^8oY d?&I\͒0=^4S_FN;r'I}&x6 &}@ A$원=!y7ӽ A`⎂da\QxtM̋A:Oo0Sbć^Hӽ0_Č|/#C>S hcFn'h' 3ֽ! 7[bbij8 Yu6~tx~| 06bAׄG q|5#^0I(M &Gm zC#t819Ra@Y><"aj.iz^B(-Kz&da_k4}=\ &FwM3>rV ͺB0wxBX qϻ٫o,2<;R*}b[KܷU*Qԧڙ+< ah5K2| x) g|ɴ"69rg@IEsd-lʼ^ ODaHR x*x`}gD'ryNUNuanL̏k4KEׂF)a7zÞjm??()un?ցP`kyl준~=z>=~0m^o&YKa"eo]/&G̡KϜ l?y{>M:dok*pf'%=-[\g>lW!ϰ%iqz䓉Ssgxݢ0lt_= VjUXSe;nT'g* !6;dlnuƪŊh(1Ѽ6vvk+HWGbM>];]:7k* 6!7%Is=aw9􏯇|Gl!h)-2, e!F.b2U@ݮKu!AϠ\ =+ B'J2T'% (ʁn';=Sz]RjB[IT%ިT%0YT>D穢F-ey' [I$.J0*X@ƒ\* ;Bd&HX{Pg fݪ\{,,tLT(nF>Ҭ9 R{(fN2PZ"cK4Z ]Fa-fCePmo]uCzsߩAp+idB]겢Yfh ð14yMRT*ADXS*0Uu6T9΅`Zefʑ<#V+)PJWbHHͱ;ВT.k'ͅ*YJ%̱̜ pQ~6#b|# $  ]z<?8g8#~" y<ؗIȢx2ȡǜE=`4r0c_l8a%7ҁs1/`:BLI1<<>fC/cN`W̏!F#]%VpƐw6bUsC6q(_?Re( a1^x#`؟StB# wPn[M#iDgQi"DفW|Sk=1P+44V5, 54Q6= |[.*7J:X{p}}HZ<+H fDFೋ`5 k1<"^%0ԖM]B^ccf{^!NEzZnZtZJ}g%WO4pwNG-Wڔ@kk\ҠGBf袠Ӏ[ٻm{IYq0AR'h= L#f|j_>'ATBQtb{UAL%5֝v[m@eMtDyO[FLXHPp;Q} n.0xt\?^}'U^&!Ǐi|.u4uެQ.EPdY:u8Ks%Pt'gS0y (<ڲ6OrrVZ) D0!rV |$ثS ]oQeѪ|őqiupFPi (S[D$%?C Y!7: =x~piT1 Nca(3ֱ\v>cʐB:zAXO^Ĉq(hĭ7 ɛ$ ,С?B|=&$~" $c%,$"쑜 dzV坌 =t'-XFҡkMΣDr8{MgqP#Ǟ#T'{1(c4J'ҕFj,j?s$1Pr,92|S1 =6 B8w=%'p; "Uh Cv(-5 E>"Ϻ pcfI$`6?9s/ ԟpy/!K36g Ql2I^7TE#eS-mC:_UjS_ $K'nxdwQ̫Dve3t~S~1 x2+ kTܡ[n}|ѶmJEZxجjn}<[ГrI:wJ sBD;@,LOgkgn_Kx5̫j& TQ!޷/TZ鷍J5=Nd;[i4NxӉ1xa2VxF[<HԵMalA񇑥1k =l%Jw'Xrճ:oeѩ fVŚ_ k]^Jԋu:CQg/J駗LTogZP_+/gx/y B۩;:<T7ʦ b|3O1GU5Z4VXBݬ-um𻍛w3']5Wq{(}PKA4 %groovy/util/Node.javaZSԓԑ$.cl$C2NZcYr0 {c%<ҴL@֞ok^(tYw {>}Ͻx~K{5w+xjA?\G"!wW1If  \8 p>]xQ# tbx̣5w5eq׋țJ4!Yx1[rxG\ZMjVdnь#i@"bN£ L5ؐ(D0?! $@'Gߴ ^{t)ZVnB"k^ԕ|HT$ 5|-yDj W$ĕH.C-&X7ȷ |`A: }[”SȠQ! # .D)]F]Ts\qS*(t" @rS1yH!}KiNKb+}b.7p .,g krϰns_g(Ah ")agVx.N h ~0]d:^A#@}\F7/$YzRCΙi=>ut|Ɨ\4?g}4/#2O&ز[ﺍ,;;bM}e6r-0/&>dK9aw9҂؁yn:H猻B&OܰgU?1TtFNQPbb]mȩiyn 09`a%G@!293 v0&= tFtI0 &H0Oة Hbd2aONlt&۰.;apl &E.T db5s5phg+DH/$pw!* 6wT:Ԉ(:02> Oƨo\6i)_u"ܦ]B]`>D!5mf"peS*Vlvî1{dj`uZ-o #XNd(4H"kfoxt}L%[o# j$WX&M]#Z?Q~t1nX5Q"K&C. 56U3ؚ!lsIıKPƱcR[ v m3%Jʂ{E߻BFu) & X3?+fSadgIsߋn'ښ8?Q/B2{4吞Yc Uqh,ײ&+.~u>>[2x[ ڵa*6 d D V,󂙟Iv SCTh0&= W !'3aʖSD |˽m`zfY xLvʽ6|)vŻct帽8LY=2,">?n/'Wr 7_s?L'_=Fj,Pدd.SߛeFMyb@hQ[$I0("ԗR1;x"F^aIuAطEt΍L"r2{( v9>FRJ4OΗMJ[1lߡK}ՄФ -5fUQ)VJ^J o9]lx%TŪ9O BeƷ[RJ5+ߔ O6ɨhTYu7AVGazIG*}srxj6b62Cυ?:5_dlPŒQ9q%IŹG)]oo+p8{ 8Y:4I.eǝz|Grx%8Ʋ F`a))qK挑.#qnFӀ͠q1\y;, ۢm Ʋ_1m]O8^HG "Ɍ>T9~?R"䖈Ѹ!}9A!Bfiʵ<(0 P^=?0|/ w˃M`-ڞiϞ*U pϽ#$"BTAdGJpVG06EHm#]oW؜1E Bν0ݽ1)E S"4v[)X$(8OiivVUyIW|=W+Wm9S\SD~dO# W[)[#)0e"&=٭>6b=7ád>'=kW}FA 6PΉz$SbEM:AmEr(x0M$<в&|h=PK@4oYm groovy/util/NodeBuilder.javaVao6_q 9;ywvUSU`VpՃQ#SDGXJ 3XD]@`\/qª,JeRY*댚5Nֱ`Fa.pRRNWlcxpԅ{Ս.՝*mm%R9ZV,'~IUU=Bץ"/뽖ҝ!7X[kuc .%6ցNl ?K"n}Fv{BTV $<=U+y$Ww]Fa%h]wҠN{ FAARd]jCcu]KM5nWxpm۾ylQ:ڣnY,P "a]<v[J +u6sJm&RdC"(pA&S>Is˫W~-o},;I'#qYGǗ]@$#ArcFWx2 .0\0y4)L$PRCEۋ5sȮ(x%γg€!p0bmsSؔ<\Rf(u!000f)" qxPsQ4DӔ2 MYi2ID9x5d:LZՙW9lUif*69ՀíϚ㯠xW{^󺐝#4Դk9:߃IP#nU V uvY{[,ddbkDEsB':sP$D9'?}-E,ZǗڗi_9.OGZ81|PKA4k62 groovy/util/NodeList.javaVQo6~}PW eF(i .N6TIʊ[Hl)iaO#X"'JRV›F-yz)WX1˲[8U@pS3(d !YJ?Bm&>Rd95ۂT D ,@s \m dPr4'Tegݢf!odƼXPT@3_]OfׯItx/\S-DlNR+Ai`Kf]jn\-FGqc5hA!eP٘~2l<x1wO6܍g0n<ݯL> 6‡\H'wĬ @BUL)_𔒓˂-jZRN^skHby_sˬkҟ{T{Olr1H6L>E焭qmljl{C׮:cYtX= 8_\CuC-@ =LT5{om'w褎nzo%Kŀ 3!·®w/Єߋzn;XBtY>oW <7\myYFGb ̫cLGWLK,XDaÃ)?E'ʳa4֍^;y:AtN5u\v}VrA4;~#'S?~VUy63ܳuTg_oՄlùPKA4@groovy/util/NodePrinter.javaWkS_Ѹ8n{R%Fd2Hc]YdT#?dK5ݧOw߶"9ⴐI,EgIw}z=~¼qJ9iY|?-'2zGɜ"T$҈]8d% y씓's-ed˓QY|(bU:.rIjB4)WAdR/C\LIe(hxڶC6,.heɨxI$!N)TiWf8j. yA,D b%uF*P&5Hr$4 Qg cTdH)Y!hHU#;[+N2B@WU׾[9LD<ewL D#]+ipn?u"}]t'd@JL#qd:SEILG£ u)ysd\iŒ`"=lT,xηNHrLԯUeF_n&׹"I`AGJM6\Vę.?s܀@cwdGHD>_1rN"Ni_UANb~1ͪ\] O<<9WG {8! }ǽPZ8WN`~4<+]u C \ģshdy,Fco4mXΕGy9.b}m`͒yNtfu68ȳxv/@Q:3l7?{?Hn; PFXue]ؐ v7+ !88b83wlC_5b he<}G渁yQ ݣ]o hBttлeTAߡK=VTeiA| vJv{6mpR&8'fᢘ/ o)f7h lg/ MktZiifJ8 S͌0A ̕TYٕ8(0RTEo?BhGhԧgVW2b:=t$ե2nX)a F{H;5mO* }Y_?^?h>[,T)q{W Ư2>GY,zsy-{_[qȿm?<2&ݼOz sFh=Ҽfx@ܽj~V_ >fc]ٙ7 #H">%a;cț7WN#FϧyAY٘}@0 ? %af| ?ßވOxrE)8Iy0tMØ5?9xs`A78$IP1&Ƀuy+U!I)9 >#ha{ e=&sBijQd08 1Qv fY| 0zbgS#jf|bnUA¢h6Mx9p^.Hu`c0BatEտg GU˳(laFT1*v:,YC1C^cMKl%ռnl6 x hqbN?kE?pV"GiJs]Fnt[3FMp?zFT^,q28(K:yh4}nn$iÒ<*kӜs%pXQN'tA΄"j |0rig)T^f;\˜J7с2Fr^v\mE P=7H֢=[;?i%{ۻCY_~PK|7>[kW7W3Sj^hǩ!߇4nAgW܅(tQ UׄM܃ZntZ/>r׎U9xQE-fVQsH};|%*[o 특s+C+{v+6m$ѽVs5Gծb,-膃m۔o FЍOPKA4F‰groovy/util/package.html5@ D~EφlHbBQu4[-zt53׷/OGm"I%XCp擒Ϧ8̍(i[X>l$n;GJ(3ǁJDØg璛Au( -(2F!r )aeH mQhjPKA4 g groovy/util/Proxy.javaVmo6_q 4)49mmH0l˓VZbl(&HLw=yWe 19z%s ˼0VnvQ0> -݆0Fe2\eRVV᜞$ӓ3 ݷj,,U^<j%ZU.TYǢC ?^\?6DبFgr4k-(l'AʒRlI("@0  mيû1+*ט^n ay$1M3Z:^ _":Tʝ^ XJ m}Trb-hXbb9|pg$08kV6$ 3IG )U4MKe%9窊{mnò;!.h:U{:!(q `&ԥF, >d[G>/Ėb2eyvۻ8(@fdD.ജcY&Ro)x1h9fXQ^m=XX[_vmqӘi'sn+4YM㔳>>x80RO,<rFp{Oap?Ž5 `) 4D ̋< 0.[6N!qIXZ@Z$^ʁ%FE=ӃdanCFaxB|M]T1.ΰ -w5Ðq򅃽҅vj}sWVY^u:ŲVn7n;&MMW/ٍTFL}wԴvWs㧛byR_ qo5"D>f΁v(G^tɯ@vBKK.c;mDqJi->N2qܳNDnEH]Jc7Y8F!-sӥ!7 !j Y:Rn -/[(ͬĄq"'6 eo{ ! rQ[$'TMIE%')}hbGnբLq`w-dIkg!HFUڕD11Ew!8; 434;8[lr9nL+AqZgZsivjL(l~o@{3%*C?<"&?`6߆I^ޮzn"}Z n&[w:st}EH`WcjPKA4*s "groovy/util/ResourceConnector.javaVmo6_q4)49u7*L#ͣY B^4q0qI\iB؟Lf̓iCp"8!_`F"H8*x`8(@B|ȏ=l,#HH\0kχq"y"< GLb]@ħ4 c<$ HmX:4Q4%286-b.g(F׌z:xt5xN5^0ʎ%Bd'Y<@n@W2@v|aܥnÞ+3G5bgfC8V}7@`T*8Xݱ,NQ8jƣ;A?V\v7OU`Ѝ.u7js_Zܦu-cά(qY(ç;&o:ڱEմ}^s 1D!{T;8?u{=IL,&ǠEFWaEJs?`4h8 eC2Dt\1\/OW &l/$e>}z<Ē@(>_8.;Ä3rs(͒s!n YLO\30 ?Nx1," 0/Bp|>gr.XLy"';fH"<1c$*@`0#?a{Fs<4X`9F1r,,Q4!ڄ&X|&,N`I|QP2x) "Qxqh&N(t9RQ|ESc֩ BٳĨg,|Y0ڍ v xw-]T1-zsu~䂻F쌱6/>!<L?,/[<,ѝ ?ֲZuoLWB7nVRݨ]M +gֵxO¨^V(N3w4Mo:$Xu3)kߣz4z"|{xmqy/>e- s^f[}ݫ_^8S4+kou:;?f!b[_PK A4groovy/util/slurpersupport/PKA4`M*groovy/util/slurpersupport/Attributes.javaW[o6~8S&.Ks4uA.(=mI;FËj9ۢt߹:Ѓ,^ Z%^h)P|`E5aI3'rSK/N {L쥅 ݃fhkXXi ,87k'Z!ƗhC. Eq %~-@Mힵ1`V"b2xgQ0A?-WbDP] Ԃ@*+ŐgSpꃖK939F5G9 bu g0%f8x~y7d>F|<;N>0awr LrcG2@%gXYb[F%S]U5̝oƓqA=DVEmR*s <|d2*.tek+ ߰ T+R%Ok,&Sd~djd-ɠjsǨ>CXX+Da"s6Z"WL\Z  R KJ5kma^lLƊ+ŖbX֜sat*2VцWu :5B{xO^?%T0֠l\f]g {A!wM&]5NB޵³̽8N!UGB]{J@ELJ?fV-v ԯP6_@Ϫ}֡&O@H"1yϞU G!Ji/b?"Np8Z\Xn-RI),YsvkwNv&N=rtu M׮!ò!-=l&q4d45[1'8+?nDL ׸ 4fwOkuv ,l-sz{ 寧DS7[!@a{JBlEATyP;4Af'lUK#N8H=L'h}g ɬoml2!z_32;mf㥏y1[HmAZL/ {WnCh $Ao~X]K9TA1;L(.!v$ cФz'w Z/44$MOäߡ%/qͫwB9{ $GBDͬ+ =j0ճdyPCfZbXK,zoi6βr%z"&=b`qD(1t(PB>\dDǪ딞 ڎ\TrKS4F;, |SݤueVsOqb`9 AWZ"N+Hb| {ao0xb@(H(,`|k1qJTPӦܵU8W㪪 3mX66̮˫D-$Z {ahxIR&W 9HWF81Xq7`2akhvHwH5ldyd9 zeӛ|\-aqMJszz 7ߌI1w MĬnF7l؈FS9BwhM%afFpա\0H_5zg ɬ/Kmd4"zt?7CÝ6'^*h,[ֶ0^9E%:YaH6zt_;Ž+H]߇I[!"fsj>+ *ܡ,<F#ڮv9 pԽ]qK%K01LR[\Z(gkF>=%EemxO|{UPCZО,i,?1>u }J2L :o(ܟcUkh<6!o?F;LçcI7l\p/R?%@UooYm(ZWdJ%^A/ 6=x3ѐYq,RFa ?A]PV[0#K8м=PKA4Y4K+groovy/util/slurpersupport/GPathResult.javaY[s6~ׯ8U^(Gv:&3%u9c#,Be ,87| zr2^Fϧ|Y*y-i&iEPjC,'Kr;c ~O!C5M=/`Kq(IX}Z\`ɷyHcjc8)Ar 9>|B ?n18b=I-\.>ߠю.K  &{ 9$hjJv6z'bz Ԏ$L* 4O j$f!-fr?r}w g77g\rv;'8/@1CrOf2&M t J&5ItVlGYSXG*2<Tl^h`ŤlQfsb8 FqL e\`ᏒF &ih"K5юJHAßt)RrOH-Q/-IY蚊fFU-Mn>@dw7b)thWvf l];M0尒Pa쌗<R!.L-EH*Aφ'`rb27R̯^:La td`= KnD6f uLI(?*T@.BLHcM.KYFmE bO!JĶ& ;pF/ܒDB$5m'[wƒ4 -::ø{w1sG|ʇx"M<vePXnFq)5 K0]C,q:&Pj ="oG10 *Z9ex4MV)ޔ9i;FYslMG=r?:l9&386wB>+ԖVr@7B ARN4߽eZB/y/:r+(ʮzXX?݈7VQ$T53f8O)4jWA~'/썼kͽA3gEǛ24ڮ5}|p9z r~.POװtrbNnܳoe sS;ZI~ixC:J imaϪj]!県mG!~fqWhC"h!]^ g<`x}nd]țK7iTp 9:WVL UB_k?ٗ] .޲t%I[cjlL|ߵ+?ҮUheM/Ms' :F} }zgԇ~2[Ղ)ձ2MMTiSHעzxCFe1r ؁V8JM̨БLͬt>ǤU)\5p o-]rn$I`Eȋ?)Bo|V}Uu/ZMPUh7ym3_DC}pӓ2>σPKA4ls\ *groovy/util/slurpersupport/NoChildren.javaVKsH+paɕ/K(u84hF1IGA2ĩJ_M|63jx 7qa$og( dl0XF?f6\Ix]@ V /=V9( 72,p *+6u%Z ZF*-i)fp:%HNR1N*" 5*Ozr=Vv4zylf;y׀$$^bAxL0d6JlJ^xNW#@J &ļ.GaJŒxFɵckG-)#P"{KnEyEM JJo#gp*`@agGxyLwS?ҏg NZ^u=Ts#gWQ2(}Bbf1? Y=?1g mFUq) dQjRpk227pb _5$xЊiV}=d% k\Zw{5\qD/f?F!;ed7\Z3PcQ;-8 FG<@A!RT\e6CJ{e*ǂ9m64z86OQ'p4w e:-t,5N[FgԴ:]rv5|o_%`Kk3[h8aoLaIڢ N>_)95w&ɉ#ޤOҗ?y*%93uVLlo9)qx^Kzt+ۺ`>|64?AO:-57@o$%I~Ϸo;k-$ å :vM [rv̻ŤO~%ӟ\rtSuCO{qX7 ʼM4PK@4_Ǥ!$groovy/util/slurpersupport/Node.java]o۶ݿu{YPYz뜡I {%"H16{?$RŦD&'5{>"ɥ5_okؔMJx!E g,'M #ݙY-(WI`lƓsD =)"dK#1c"$VeȎcC,p * Ui|6JUf.TYa@jqs> rOhLet tGDMf2zJXɹT5_6*Йc$@k$27)"߾pK.޿Xίn{ryv~;^|0aUrV°$+@r5#k$"\U%0#oJ/ Jg^㪅xاE**Q؃ /ryl{o7(`vrίP=v. [a<;3g R٭H¦n2qFqvQ4jb*/zo<>fIҮEZsS0l@C˫ ;EAlB7f~v#~Ko9~)p=v)Ary)N®BF@i eJp~HhŞѽVTv/-XV@^3Gڔ˫m~2:Hy ُ &1&2:ũ0yJydS- W}5n!|t~$*t ;r΅IGKz< 산wwTkǧWLK1NIO:[M1tr[9厫M0!~;'{6i?BH;o2H)ܖ#*9 3Tphv3A "$^oi;~^r qZ/U=2Gj =OZ:;zmU0K)mgaK}Pẃ)DF A9h~aub-ڠX8_x ou !B]Nw;gYA3(Eh'KJ¶\|k^~J:Uk=NEv(!eXT=q1MJ Fp(C%AQnڌKeMi!FjU]-OTm7Խtrzۗx?.pue}#;+Z߈R㑄 C8P{F,\'`4)(~]2H# f⏠pKf!0j,gTй%LMIp3*'aM:M\iCûO6oXdz ‡ P;ɚG؆wK?1lBtËk[m,L j7rG*3 n3-}v-N5]E G{f:={cFWQ,Ma. -&G9'=O'-4š,3`w^0|ƛV*2`.}!n9F}6y?Wh0PKA4G|b)groovy/util/slurpersupport/NodeChild.javaWoF~q/&"&=/hituwzwMLPUOm$~73;Y Zf o/.~r!.'j)|1 "Af0XL \ x^@`-Fd@0O9er&b57bZCN #wF 25;3[u ¡T^\uCt};ߞiQ5(3neD*fS5HllFZk .h93k$\ŧӬHH5&=C4n`)܏'4xx 'Fp=Dh4_`~7]@RL&jbRH7Fܣ003Shb9\P 2TKmV5L,Lʗ0S mo4*PzU'8gJQkv dB&fdsX^"eS_JA4ASA>IpF5/O/\d^ڪd*e4L)ԀF^o ms={dԦkԑ;Su&}XBTcmQ+b!OxW<Qfҩjd6l(SU9 h4 T% (%\T5出UIaDbJ%TW:>% ɝG`%ʻ5-k2}Ex0&lZ\㛍{`jkPG#Je% ʍp{2 (]wTVri:YNs{!~=Lq5\vT+r›_&hO}+lj _PzCD( wİ\XPKA4/ '%!,groovy/util/slurpersupport/NodeChildren.javaY[o6~8uBN+Y뮳8YP {%f+I[Ey90rE}O%QH<̜T*&8r_c̈؊d \hELGC 'a(l^$R\#S"C57mQ\D'Jgupl\+ v~_\NftT)I< Q)QՀl@H KIqN F2X ԈҒ#],U kC4xvb܎Movtu5\/g0z<`4'oN"cxAj2&cfTX Ch|%#"\3ePA߈ ؚi\p!_bYRi*$JTQ z=T?ky0}V7{3t˂k!\䎸Lia2w<c0Ѣn懠DMV%w* 4gDZCJ"BcqY J Zz/VHͯ)Hꊪ(JvG4נؿ^OIրSKC΀B3ӏ.}<74Ds N΂q4'a$5CSY4&wJ b`T: V莜݆q@̭LzwWUX9p1T| M&0QUA#Ϩn0(gP%%J#ɁM,+>iXD 0k["^{gꓰVDMP~۰f4!x.D@xej,C}X h=BOk 6jzM0xq-݌f橥޵꘷OlAOgOSBZXثpxhvu9Y%]cWxẇtsz%&N7N1Ҟ?|}F_jӸ]N]RAAm&OY&iN~G'Ƈ{ߎe[cǪ]{W'?b.TC̦!@>G4vu3-{M5uH)7Ql9X4jc4P'5\vlۥxr5;,g<Ռ9Iupџ:vQx)NRͻr4u<{j!y.~@1\Oa_I<񤶚 me)%řSL"siP͍P~2FKM0c^ -QZd~.ؼ-0t(kKuWHBtrU8g{M5שT"hALͿ7fLԋXZfJSL*8Y໩5|A*o4V=P024. / &bcX hCxda)>h ¬Bӳā09 >`iy AmXtc㪱A6=kރߍtl8߀,9KU@TF&n$xV8 4dЋ)S lYC6_n.Y;7"#Hқ '}ٺeʐ&]t K-r) FTY,V= ,+IW](u\Θ&nHث1o5&QxOb-v 2k6>jV DM" EAP(SS➧ WaOd\ X T3Jwđl"x"=O__K|ѻdKӁA||$z}ՏY~;\0ڔ2&Y.<咧@떂>fǰ=t`كthٗ}@-kC9oWMgp_skdyd.,F{p g #Áԙ]ȩFum1,mycWhp{pn"F|dvϡвG iC|>s`уDg cRmBCڸ4&)[`DSǼ&H;=w=˛z&\Ctnh*GL |Z5LǙNVA߇+;ĨbPHˡEdѫ y9.M{`Z rI* huܦ(!ⱖ}L.ޠ̊RlQ J`/?dzS qe*dsix+Ը5j\.s-y&"׷-׾LۖFX Z^_5r\y"9hVr~bEK2p 9MB-Sx,xzڗ]/۠H 1jϱ ,84(]eQv f=#Y%EJ!$_9=.6 =@-*v {#VXC/O٩$[f]oP֯劚vl7n%q#Nu 8 ^b+ػ 8=$RKa !j,2?lI3N[-{xUX8Q_S8ֹz@J͙2=d]uHj.~ޯݟx TWVh'8U'D&6*uJDѺNH@?(d5e"،c#t@_R&VJmJZӽ$KSx)H]?@^)UQ,k%~z '|֦7>*܌*"?_k\"oMӭ"Y?X[;+D  ,*oo`Ng{}|\?;4[|-VөoۈBXסLMa0 a>*xqOzU^sY \-VHƐeJNߛ{j$DwW; ֪˽YgER_ S% f[ce̊}1n$4BE'E,dip -+R4Om!Q+446YX%"h{ d+4(ŻԣJw2ރuuIVfI/i2fa1*?`%?UvktQ1=4{=\մl,b5e58ńkxިjUN^2TYF}Մ~OhkvGd'P'hq% {th|IՌEkr8jJ:ifk~C r!(V7>f<.et:eZʩ2FzF>ɽb҇~I<fxՌX ȃi^7i#B֚*O*fq 6NRuxnph 箁Fͯ[6v!jkֺQڒپ6̩JJsc3~l*g\dtXOi-5 xģ$]E^^]{ͤUpjw%j̶WoD 8na޳M6%bt!x.+7azFxXۭ.ѫj+{I#8U5KPKA4B .groovy/util/XmlParser.javaZms6_eNvnSZcvd!͔&! E$%ǽ߳H%;{wIL}yvutaO_F^x {}w|g?9!O?1=t Yݦ|sf o3/yqNkv,4fFshQAixD.\g%3/Œe,R.&,Ky_/y{ÌWt{&,Ide=FV<]91Z& xЁ4x&,y\&p§0Mĕpػs !*2 .`Lu:HSL6^x`ؼ] :-3!JM^^Qٞp&Ϙ9| & Epm-Qg9vȎыN'\4/?/16{5C&0hˠ9J7[%=n Ţm2o(93EqIvT <0}n-%\X'Pfz#ds/[\x >Y8i%//; mJ}k+BsꓤT{2ÊC #{u(ON>R_ox(pbT_y? >Bt O D B_Oy`BM 5k34ԧCnBÍD^ IaͯSqLWQc2q()&.kք~T L.Hhr/O‰>8xxl[" ]mNvΑNEqțU{ y^65@N5ı6 ^Pq2^z d9Y9N޼x[>hD%o]aT6.}JU*:2?.=/ije\}}e )λT-Eq؛!HE\) N#ݬ"gܠUp- zխ U'VyWҳڸH(4=-NK;0'Ћ3$Bݿ/*[6CH,ED lpSf[mBA_k^[-Ove'UTT\N !j˖.eW]f"iC,DG73j?l"[KM]~PyNc#?b~f8+?. a(ϩ*T`DF-AbUgbE9$Lj"Nd}oB #6ir.^vT 48S$OŠ8m %8vcPwLn~eEB"xp#CȥD?/!"c7t<8%%Bh(GYs_Ґ*XpdzaqRb!4Cr +kNiYhi4l613 BG%UٛT19W $$|wlJ%U6Ǵ 72Y13a4SZfw0TD}DpMn]ff Wpvuy>\]_oa|+mry>T<)1qD6oMAfk4hqB*A_SZƐ{Ѵh:ƺ9&З2WL*tf|l^JoK6мeQT1nͪӮwN|Oo bt|G"dLx8ڱ IRkys]F?hŰ?9.ȣ xJd_|(w!&|j7:͋TA(} f\Vj0[  J/yWPy~%'(i>]_N,t_+flQ~B+[/+b$N MJ4,F2?R b`Jr4c9s-KnT{X]9V5˳BԖ8>VleD+<-`I}ݛ jxAa.$.ee%ͤÖFypܳHNқax%n) s]?lfu "`R{ч@nr^pr]b"]FE^hqﱮ VD?ֱ5a=B-Y`7kVVm18A]do6қ,G\ۆ:rC޾&%t7 z}]:ڶ zN z'QkLJR)DߨK)7 tJhX]03RHj1o lguL*r&RͯQo7Bv.rU,_[44s jD sFv[L5:gX"+~ʨM"nX`0ЊsB0Fƅ#"<weV{u8>^#)&~Zz+ciz [|?,d1>D^nqRwIui±k\V WyD|΢-@'uUsS[L{0J$d9^ dC4rg <~-i[$R8:0)Pf%:Kye=a=^O$:EAS")HݺuxGVTgi ]hܠ}2s[77;p 3@TfHEyԗ\Ѡ^3-vB-R # Oٶ5 ǡcmiu>='i7j%nY-]#-37DqՔ4˓ #}`w |*X~'[EBi-R@ӊ=܊6{%ݣ~-kSK;' Et )+?/lȤn)f͸Hӓő^ }99i*8VU b{ ^MC!2?Rlo]8\[ts k`B!v /|1㫅XeeG;.\5 !]_F:5kVfA YK^5o6\tZl_r~൯뭄F%XJUD_!UV;%y 6,~TI\Bk[S$"HdPK A4 groovy/xml/PK @4groovy/xml/dom/PK@4ǵ… groovy/xml/dom/DOMCategory.javaVnF}b`/1-Z$R%8~˚\LxQ̒KExٙ3srvk79?qd[9}kw#LreRKߖV*- ƃ:>ܣ^*SNfC9} eN";([Xk@%iUzUsTY$TΩI+y}'282^媨%{1No7lMwK*2IilxKf.o7n^fYy "Iٯ2~䓼+N*W:VpH`jҪ.(T!eřWRQix@fU 0 I@ hY`sx\uB $h.ot | x @8s9N$ P6&Mf>H8@L8kNȍfsqڦEuDxBc?4B1@60Y\/A0F¿6́bd=JxF5uQg!K8s t醢ʹ!MKag; =<0u%G4bcfݶq|E+9)y5 w2*XT͒gVR';;i,5j0w1DfN<15{ؘv\= SKܡS u]]`~}Fu|Kq^]WƠߡdl:usE'L7c_%X ̻wOh+>@vI㴀Epb{ Ǻ1@ƞali:5֠׷+|uoByPK@4s `groovy/xml/DOMBuilder.javaYms,MfR%qsj;%P|1K$${:w@v:2}g, /,F˳<}.lzkx޼zc<=}[H< ``&݆a܉`̈a~g+ -Y,,Ko D:C)\,A:ςX1)eBd&\`i{˸~+eڠu&Ȗ b? 8 M-#? Trxv&wN4΅ǑG<@(*":GSc &XBnxCJfɲSGxU58h{hcH+J̑suXgǗظ<pOS-80:hDM?3X ~Kgł0O?Ӧ;"n|8D<'_5NBG~^av~B,௶nʨVʠqGJ% uUZ`oRx(=8 "tbVC_VOn]#j5/pD;Ubz#q~-s톽']i݁sO"8*e ƻe|[ÄKgM n@8Z)py Z 5/qxdyᠽW/:( .C6.M(I7 -%In5[7[[D 31z"[;(o=%[⻈f+s\鳎Ze9G|B gsiVG~T{Q]^lg &WB[J3|[p T}T$RR/JNO?U8G- Qbzt[HF]:(e.|)R\dG/&)i. <ʈbH8@GRܶn9 Du] Xg1U8 Q< Ӳ-n [񂅆XHmw&V+?X8*Qo8=cQUg!5 YVeIjNHFYdʼnWJ|9Li&>o*=Di-l[:;#B`JB} ׻V&q'[[]) T?QNSWCm2_@7vmtI3J;:]JrI;hPPQS+Rӓp ߻sc:T47 _ҋ"'Kڼ:buYR8!T2Ѓ*QpKSC_^|c7T: =4:{<+6QDIW+BCM n)%)Jލ~߹K3<BeXlJH((%ʱB!&Sc~@ ٭SBl͉aۯL@5ӭ=_-*:)Er$xK`Ž9.=]EW}PKA4@ *groovy/xml/MarkupBuilder.javaY}s;|4ˉ8t`Pb\dfdi1 |N{Ϯ$$ľkĈ}~Z!]8lZҁqp@/?ƿWt~n QHOszZQ74a6LHqNHNYtCԏNЈ$Rxh$oiąM(d4IX GDxEb&a5v XoO3Z$4< ELm.♟0y-}Ox5s4 [rK*H!&dqe] P,Fx$$,TQBAQp0:ؐ/6ҍ:=TgT[@R(:7RLeji2% w28Dlٌ%1V.+ 0wB-4hAF8u!">1SES #}M&ys`%X.*B[t t}c|Ԍ@ءi,&'It6TUAER?-$mHNʅ::&H7Jq9_n4ڼ bz=g\KC=]=Վ\_HI*SKDۤ}E FC7kO)ku2߱ W (qTJ{ˉJf3Ay[yo`ꔈoՂaYQ 4G RUUnjU/7 t,ܢbm)j?Οu:TE6.NyHfC7H+'%5`Q@'RetXp򂁩(N5iRtBzsq#jjO db5kW{e>SYԥ w5bZȊ*"/.5~ S7U=8fqT9l˵T5v #[Za=dd\=cs"e<\WH9lskl%vt&|D5QBgu!镫 @$#0\uUw(k(ѐZ„WSzP.A^\VΗU{)?\Ȼˮ kg?,z%9^QF}}DnqGsKAxCR['10Qeѭΰ!/fuZ^|"bC݄7ɐr9&nzMOz/u?7p>Vo+9^n#ѝ*]f+ O+7.;&Fn+nO-Vʸ~*+oAQ? "s,jWS񒵽U"C"4@dvXy6v?=?~ڮ7H|T/PKA4\Bgroovy/xml/Namespace.javaUmo0ίӾu*}Uh;;; "=sgn6kVZxnܩGW2 `nmrngYg8[E p#)jsn"),-p%,8sIcU , q \Lg2BȸDLA 5E$6zPT<@-rGӾ o{DKƀ_)Td ,!RU2PXlV9ҙ˸Fl4:)7VIjD+RUIwpÖ's#(BM8 =z| {7-@*Ѯɝ8͵"I03Qq2NY%jI5Azk!S#[f޳҂RfF?z8rSq(( DlΣ9R6 ~\>[d7֍ ʾ].<s|#2tB-,8Cj5hdaHS;I_uq8!4gؼ`߁nS\Ҿڧv?w'SYJ%o[MM5u /QPn?(#˄i9`Cv>ڮіbl3U53h8 ]LcE PvN U2PíHr& ߋ-Vُ^f ~rt!fAWa~[l ĕP:x~]!ZSV*V(c~R %vG2B塸}5U 3D%k?~^m]DL<8Ln^ϢGlcI|Ř][`fc#ل%"G^p2Dq )O0. ][y0e?ƟސOxrK%Iy0l˜؟x|F8^X]3-m~dO&j¯X3Z 9x)o<:KȫܛY6%xkqbMwV:8K,q[s_8*{xb7kZgpcqUEښx>]n WoYS* Xx+k}R`].72Xꗲ{Vf Y IsɍsqЪlrv~W@W|~SpZ$zPۜRcT~%Qc2Ɣ K=|= 8%Qv([a|>zc3cGmy!+svF}/?PKA4]$jv 'groovy/xml/NamespaceBuilderSupport.javaV]o6}ׯ0 4k-*L\IncEC)ɱ؊@b{yC'<=qV^<SCldIQE"Z,[gz@^ShJ e)N eΖuƱ.%[YI@J2QɔRYTx9EaԥZ[mTfuDJ*h.Ke Oҭsu+JTfƫ^Y_PnjH0ˊDV`!|J xiYIDB2 l ap{u:/2+%PqZ)ڈbvfm2h*ܝTȜ"HmJd(‰30ܗu=aPMFVjwk,-iR$Ti>DݨP)R oͲՙimڣhMa% 1Ń8R)`RA[.\^j h/m}5yN cGlRtȴA$@+TGjseOF/O@Mj qVQyj(@0:t_luUm_ M\CDxDQp_{!#aO؄F78d4&[D㐏qF}Epy̞y El>X"r1gKO_(ALS>1QpA3)oLJ.x#] Gs/x1B/y12&<O=>c]yөs#4b荦q~4 M]l͂}d 7 {iͼKǢ</B63!DE11 E,,:iYs#ljĀV8zU1 <Up ]:i[P(oLTߥ+(j dLJv)d/䑱MkYp5˃um1_7  [nVtsΆV$_ _7d};13}nMrLޚ#83<ЉkcxYgvn 1Υ5U5&ׂZ޾mDWgY/w2W^ Y(6frIC^Y;,LH~KKzlG Cx![}=o5D=Hq d~̐mpRwڀ4ӗ5 ov69l8koਓ퐌#91];Tj[Ql/+VFJVF~/ikCi P!Dz׸Zwthͥ>X6֏yscj.YoPK@4y I=groovy/xml/package.htmlU? Gw?ov418^ RoowDWvf,8UEj-iBxM  9}X]uxJvhJh2!a ɚ^c4 &xz[f/PKA4a (groovy/xml/QName.javaZYwH~ϯa igd`99(@B"*aު؞p#KUw^'p7 _AoL~4$3x}襛]-Wh:/ǫ.m2s ƱdRFλH#gtKEVI%Bl&4Jl'iVH3N9QYh͘#HQ˹dM4E sm,,MmbhZgF݆tJ +,cV(!. =2H|4VDJĠGdJάa],0a,Ym[Lj Z&yhMw xu, cUfCCUI&gp JfJ V8r,;G#b654 g&m,K"f6*bэg卌 *xXn-OE2%@-e;n62$#:PQd` ZQ6 | :cK/I-[ZLu\c^JfSJFM3D6\\ZP"Vސ(44~FWeyl.:bPQ(`Wmw%U]q}TR2odJ)x_]1aϳFG?ryף'»ɉpEx?_ HW}߻ :rc zɅ? Ǣ_cl6"2Wިw~ax,]q~owGz2شz}׿.PA 73_Pr8\c8>D7G>Dރ Ƥfy\ϖ kAOw!@6~` Ѩs&#TD}0Ǔ'> 'EDcx]f*+p~ ?{舏 0g Xm7}!#>pDh3j.޸h\W }7ytH>ׁ=gl'c!dF/+백)܋O>{^  |N`h @1 |Z#w(nxLK,aC"U-ADTx`i&5*𺒤{\$o>?Vz\Opp)2Kӛ]:~IޤY.~ onvm&7Dup~Ap"F W8%h>epϩzYz AH4 $B8C 쳑3}<L.޴J߾bǣS(:|Z|g?噸s6[Ӑa盷Irӷ\>[GߎS bFmѽ_ƅo *֟p&U.AFX]ƐDDϣ,/dx&\%^{Xz!l:,Јi[::7:< :SR,WNOnThJV:La9Ƅ?ˊL*:0:tu8R[HY">_Ly(׸,eiAv_hb:_MZoc-U:3c<R\puHTSt55\rKJgЇB3,4SMPc]=j1ML4s30=]&;[.y1(N(Z4;| өfS*) ەm"*5 mc~&U=8OEF6RtTvP C*;w|Q~]1[ÿ,L̋RMp{| =,ӟza3'ƚ;<ҟɇ2A[ŋ"Z{A_ E9u9;[sJ >D׍L*U-HTD8 klU4":=)ZiU /ꭈkt|>G~ yk!7v[,iHAC/S& )E(, iIҴ$b?0>)?Y퀊 YZA+_~MT[K6:[0N,EwBJW͓ySjޫy/&ESO J::$UͿ+owѣ~BUs!UMM{"~1ݓ;oPKA4OYgroovy/xml/SAXBuilder.javaWmo_1U𤜓CQz4EۼʒCRvŵĄ"u˕l3KR"%h%Brgfg-zENWqI$Zwwtͻ>~Do?>3U%}XҫVl\[8]E,dNVb:)4.Xi ;Ig|KQ|ŹVJY%ewqNyvfAy6EtբN;(]c=LJ"xjd-bkKfCKHF-$eI錦YŬǀ]oupl*W&%S(j%MDi{gјI1cHlnNy Jq*#BR "V@PEqf*<$0Lw R["#%VQ]#M ZxȨ=SY~l,J.HQ|[]dY Q1 XXͦX*Q\iŒ` <+V&h,8.yZfjơW[*֩HU<O)PȆ\JQ"V_qc hH[v|$B}CphbǚrN"a0SW]5Z/gNW /`|ؾKG,=  0 }tEjPf>wc˫[XQ蹁EN"XihлBȅcxף]sGzGv٢3/MWzdht5ƁK ]7OrQH=Q20hJ.0ڧC8:!hEx|~p0 H>wAcI'Ȉ3K "iz$t|<09npBq`m\2O'gXF-߀t<2Ⴁ2n.\QÖm @,0isw丼:f37^{Kx^'&lpL2;#{p #RxeޜtJ~3bk<,V+^,3wIjK[󅄇+tN.r= nzxٺh2?9ɡ_'R}%ws5WbA_[ L<ƭG[,ƿ?Z͕qOфёZ&Jy/~2vʗ9UmOK8pUNxGMh^QWRArԏ)=)}ȶ:uʋ'N| <_*S>78\+LTwƷ xrg}eUXZ(&ekFJ' HV( QLbQ(ea/?Vܷ}2gǹP;ih!Ftq@VJv6rZh6>K0{٬WL]_ A+C>d8txP跕H&R [UXhw.ehxN|G NN%ΥG;:OD (sŒ9&.e|)( %:^g$|oYj=c5=E-kքմnQ#_f` 9xš7mS3M6ʞ([oPFt b Ǔ;; 0\.t//}u`-=U_Q[GCy)TSLF'x9m =X)cO~M=EUvoa*″eO(v7g\:@]-t$79{\$Mٌ,yH$/=Gght7o­턞+8x:y-Ytna8=kArBo-Y Cob[`yx݈Ԩ)]ق /`YԞ0 ;"9~=h"Ta9L<ײ)L u$ E!a 8p䰐.#xl> D@׋ e($0Ar񓰕c2 ?nCB $4֊&I{k)V"Ay,z'< Bhp$  Ѹx Μ h'L|ZlD cN<4 ]xXζP!&Lq,1.˖UM PR2$ tbl,x]is-p$n]2:8`f,Mh 9aDHbe14V2ôaXxsY|-6I "AD┧$nE~N+IQmI24y*`F~zjR;WeSGP7_U Ő2ۍ2uЮovQ LM5Z QO\H }Z3m6^wr54J9@mpQtS7#fh@4Wk9 `0:0R}`!6p"B弯&jȞ]%iGV\ƍը~SEk\i!BOV.UCjXtGzMx 05sdp9dWj 5P"O8 iSэ Mjx.A'9S;C[p{s)<3 X̓>t ka^KuUitHRn5CmJD%jo9&S|UejKD Pz_QFOJ1&pY*u7N0=gZVeaY Bvd\`i񂗌D<)^e,-`܍0BV8Ҍl8P]ŠZ<s 9V˄3, b5̸z30+}@St3#|[cXtw\ZӀpn%uo|B{ [( س^Z._VJwD@a\XLq& ؔJeShd~q9셀J#v'2-%՝73QRG_[GS<2g9|X0Q WML%\i9 be $@qɫ>s'kW QuOI-_Y?QuHJĢO5Ih`#/Ah6lkfEӆڨ;N(ת:7*hVfU91VJ'uGu(N#\5]v4\VUQ:CwXk]jKn$|KєT8dJvT!F*XX=H-ŢGD .S0vBG pY?oXP"6EEZT]nlP% *miU҈m$ "GB"RYţ`%حc2!Pݟ=;}ەDb'3j煷{&?<=4I /v-ŭ .Og+Yu2ܞiƣw<@p)zFSm̬YGf4]y>OlzUpUy+- s۲WT:%a]'65 BOJe[B鴝u\OYyaOM:iVfGM!b_oHꕧK,jYVJ9q(zTqmjC%L 1tUoyNM@簒Uq9݋t&Wz!޽\<`0ҵ$ms06*ǿeNKnLwhĴ0Nj@I9bDvk-#\fſUf0('awH헙cS;s*;*G]\]r݁ΦoO3j՛joMvҍ92z+þ#nUeimp|}}T(kȩV1sG7,WR6']?;}[ߊWzgra#󓫸!ցc }< N|DƧ,vu@_>~?|JF!,G+|SmLsh.cOB1ٽ'77yr2x ۋ)}d Yj<\<>Wef]L 뷠V{zjG{R2mҊ(& _HF"-uO)XV&M) 7P;ݿޫPKA4gT +(groovy/xml/StreamingMarkupBuilder.groovyZsH_QJF>n89,a;YʺjG0(#xXz_$5ȹU惍~1=&d5qEAps.\4n,^`قC#Ff " DADp "J.D`̬Egcl0ž̸US$\J̔!qLFc;g)dC[ qxdqt4 -Ny|@z|@k0l7^o-0LG8FKélI/ SDn1*?C}SIZ~]i"b# 6ԡk 7 (D,纅dH`t;ß>ЭϤQ:ѭ!jT…jXzo

%1h(LE$| J\:oSl sDy50J1&sHrHܲg=Fsx6}Q-gAvG`Խn{ 2@T'4p3{UOHڿ<\!(4KS}Jh(>ۆ3 Ϗ1e]Q1rV̐NNhSi{_9)R++qvK9Z{Leߏ }cmJhb ])0)]'hUyJb[?WU+"4re> 'T:Qߵmvo=iLJ̣|H4\9n=xu>>ʫ "?W fw9-8ķxtF{fr— g\Dd״^I o,Ke|y!?բlKɮ5vp`,ȉwj tuUR ʗuKUҦoD)ӉtiٻW;Z& EJ+F"ga<"߀\yv^OVWE8ȋ;_&ch72RL4?fZGAPK A4"groovy/xml/streamingmarkupsupport/PKA447Yb7Agroovy/xml/streamingmarkupsupport/AbstractStreamingBuilder.groovyWmo6v` hsX$A'E$RV&X6SLxFPOI :[jKz%EXAO1ĔԔdnT~|tT7&QG>ipey y๗vs]έ'azߖzr}xQm|DÞ6Mnس3Ј ;@5m5pOys|N\Ĝvwط< 3z[aM8.K[! !B*7dX70 ۩(*d Mk0˻6._CMY&Ew ‹$?au{wiw+]_S5K;Fnз5c0us )Adqk2JhM:gGdj,"GƺAS !<;g2uʕCl핅>:dj,} VmZuhʺ5xx?щE B jޞqHLGv(e|{ŧ&u`O86tP9 \4K1"E7Px߾mۋ02F$[Gq3hk -W&opLfw;8m+S} ENB5jI-*OOQCرCrؤq0E$HH=/jt! *28ZWr^( Zl. 8s(=0d H?ّ9$4y?c:Ɇ%4{Hx+1`mteڐqE{SP"S2a-RdG;R%-[9`^?i *D 0ͩirrO Qed 6(Srl,arjDSA cݱuuis&[P %L-gucT98 B #/,8k5wps#hW,t4'%Eըo1ńևݮ(Q5aD4͟xεgun5{gL53)]j;7Hʵ<jn':vͥo[r2_OD[:>2޹8װ 4SD 1 +znZ+dz2dn k=e/auk-}f|u2$оI,Dh^-ڮ5u^V_2:x+kbӇLL^'ӳ~[ aj.]>dZ ‹$x+ϷoL Y=1OR,# .'ڳ%cҷ\wmg9fRk*,eȎޓS@2sȔLDMC}hru3o"C^ljk{`w&\˔>J}:UU-j2޳&Mfxy^aG{ڦY5&q*ʜ/n䷝ xVj?3pg5KgL, ZV>Q8ㅀ+m (%ߟ^eq;Fݪᔱ/8Χd]ދ;vhŅ׊'@J 7p'L4 oƟ[Jc굏N88NP vWqSWq|MON^%^A!^㯿k01OJw'?D% m`@ Q7= 8h,tzx ՝9woR@GU )ڸW$w2v|(6PGszMJ΃Zܩ?N#a*9-XLA^eTJEΞaA_0c$?E뢴o'w^й/H^g[ݪ`dEWnÛ-Bae\M궒f?8Og+qflW`lf֮ (MhP h3|jlUVI8Α %xGOyq|N<6'MNrw[J+^IcWç4 $Nk}Ⲟ}Tny7K1jǖ7zFj&x;hk`[]hPKA4ʈ0 .groovy/xml/streamingmarkupsupport/Builder.javaWmoH~(_+ޗZM'|FM˛`IU7_HݙyyfvW"*66uY?nT-E\_۪iظxmnY=fݛ7tG[-&͚2h@6mLR޵*- Em#\ڦ 4Z=Z 4e %Hʸeyy۝,xHZ/[y4֦PJy(NUi"CmBH 2LHRrjS.xk1冸6e[=kT"-pJ"lRllxPGQqS0(ỗ.-D@ MZiRYE~?;!zzاeb9Nj8 -;_Mwe1-!< .́D]͝` ()ݹl==|`̋ 9q!£$a3򀹑epP1$7 \20'(. +4M: 犅y<k (BV+ߟa#d5wY8jV!!r40@p'kŸ X-#{#cߠ$5`S]Lө:~pKAI73rHsC3C#+湌v}rC62d;1W:e:U~ cL Idkl4to3Qll7+S{Wٿ"c7`E 'ifD]jrOl̟Xq4hi 71I'w DzzxCe!aUX.$Ϋ>B!nv=#AuCU>? ioqaf̃V4j4TeKHph]hΐ{&N r$3בߎFhnpҋL8>Qrw>J6RϤ5ޛ4ޓAT{uJ=,+mdfH~G]CզkpgaKtwgg﫩t'~viy*L+Ch4p@dB+'ff7'dL?"iNt%{0}: "R%ݎOH54iu2PKA47N7<groovy/xml/streamingmarkupsupport/StreamingMarkupWriter.javaW[sD ~>P琺 n6ˤv0$aߑM\J>})cLʇgiy >gi^̊3udEI_-,' Fq.8spE.0B,"OB(sr$!gZy."PT$'/M?Q Q1UeYT( *6X*iTNɇ(VLx!dGL9TkW,RΉk.,]G 4 GHU6,@VU# '{f&J*%t=c:tF KibNQj1QHZE¸Ạ(( 5t{!q%#)jEܫ~U0o ׄOExTL^P # " eFET:[;ĀXl0µ:YHET0ER9S9e"턗_sۆaEoAOSfcL[;PYc4i@q@4|QV+&X6cA"㡠ÿi--F8SLhpBpH?=U)ԩ=\k>\u.\܁߳t9]v1Z2;~硳>"k>60v}lLJ>f>N%\[n_ gE.oc4`& Lgata0tgee^ok5ln,gBD }IvkulDYbHo`u=XZ޵ 1=!"tk4}QX3tk"x gзqDX,u, WI56F*0BNCU1۷\w8cs GVU(iP)߆۞$fIbxXoa<Їy`[W}veVBeLyd갷&V) Qj]ٽAq=SrMi_4c="nxEZ^5oXld L864:}>F5{^h 9h "Y;‰VO/ 0 Aaa"ڔ0Xf1Խ 9vNN?gX\%q?b }Ui 5vL>E"jk|0Y2윑~WF c%w&R%Ůu;@lKn2'u:VZ g}ѢZ;cZ=T4v|v"%s8r+~|OxO>M7E83XF m:՟CS}90Q="=NX''#|j-I"o$b/ꛈq)'ޕY~֛ 0s@}>A/<m +'zc/Waxq ɻZ3Hw& Y?ft`0ov}Zx*o |.}twބ67;-}wjַylca|lK"kyW;Ŭqp,/Q4ϼsH8&oP6/\xS$/x9ջ6h]_c_{uk)fȣwbzƎ^]o%^]l>^nu*}7m.볝y, !]7}r;7<]el2hH5w簹r[DPyg#]j s"-7&b[EPKA4 .%groovy/xml/StreamingSAXBuilder.groovyZsbɌWuQ'b ۴;n{w$ 9m~awo!b[aA_⭢P$8`b64>lۧ\T簡?_ /C~bQ%+_F[,x{r+zmg 0@}~ ]MQ,z(ǛҘC8d .o8gK n8KWV\P2`5DA_xG m Z|~a,-\3ty\N`LQA?EK FKb@~*n$QsNPEq.Lљs[5h>~€ިo\ca:y:vFn#E)o`| FKdlC4lao0s2900/M9#U'\VÓ|&ʙ Q0t1{nغF} tcLCh /@)iH$P?ToZFQs_Vh17P2z&] D>yƿǸ oB_ [i@_ƖqIxvLgp> bGgȖۆ] Fh'קc۔3aY+ MF_:s4uFgbJ6W-2Nưb= C|`ÞAwGڴ[ML쵎2Re. J/yz#+ftmA"Mֻ͍/M @iB_v-jIyl">Iק T5|,))ڀ9cVC_%Z.cJ 0%)f뀺&R6;5LvgT#=j*s*Jȕڡc+]U&h\- {K&t!C {L "Yb{,ɜ h͖5abUz@` TՓ"],:4u~GVUTX@[/bY9%/4$pZ"ƭfٮ@vШsV^WRDQ}l{[#[|଼Ν,m'>U1:ܺ{yYyka*苦wWO#b!V}dAoP'Yf~&]sxB1h-]LOYD lWÔ'ީ]wZE{I-ӪW/."N=*vdqR{vDˇLs%FO^*Sν [R/ϐ }|*f7znĐ{{: )FdWO]t['m@?`׀7#lݬO;B֘n* V3ݼxu-~3yl ."L&؎->~~y1pw=L5J"ٹYix+nx${Ɣ[ާBWL=:;H?mO52|b[z˃mKwR^?"A&r&_*r H87wrs򃸳xCcGBYbN$Wf_⁜oRw^/Ѯ1OH<`52[R"! 'jѨ^CW%Ú8+Kg'0u?_6h*z]u|ؓ-r! nx9?'UWSaSVJ <`4P yf{PJ4(9?Q'ٟL=zDS !5 ֋ h9UoLLlP:dHU@r`U~Vۏ+Uo=(M苵R¨%J|X,''#_T;O1]n*肯8}$#1߆W>* pHҌyVl{oSZi|/Ofqmv gɈg,⵩o<.(#|1i+% 9XCt4nWnC|7D=xY9KdPB?t9y "ԔY60;uϒ;0܅$s\b 14O^j3WέQ:}{fOhY tD[F)x>&(@cb!*գ_PK @4org/PK @4 org/codehaus/PK A4org/codehaus/groovy/PK A4org/codehaus/groovy/ant/PKA4"8/Z9org/codehaus/groovy/ant/AntProjectPropertiesDelegate.javaWQsF~WtR뽤VE:8I[h Fxz$lzFt=ɻgff?Ք*7**U3i\ފNS'99>|8;==WA3E˒~t<͍5n.$MeP4rӔ*(PW*v8)Lܗ&,P̓ `e, =M@1XO=3:= kã=&fN:ߺ4qLm8R^$-sJbw' (zilFS {k(:XLe>UpaXredEN)X1fiLUNDBf68FF.+8'H)_4q\)R^-͚SBHJw㻕 T& 3,Duhu!nJPͺPיDCrW*{-RT' m*U<$X%ͦYy­s{d77KQpPQ,n[arL,TU.i];-u*F) 6و#K%R$xc $@3TGe1Bw J0qbvs 3qpntr btѭ8or'!Ew> !\~Ѯ;CaQ8x!JF~DCڋ`=G]soEw ١ /. "?'qR/]Z ^$n(;OdQ$Q:E<^ Տda±{ ~H zAC HڽTMP$LB0I$LCn?^P1|> =7DLƑ珎;tBЄb`klP8*`jVbJFr]Q_anPx![x ԉM^cg{];AtEm[nZtJK9,g|Ͷ(23;dԹsӂWzox;8cSJs#Sqw#n8, G|._X=oCe 9蝼5&KV]Š,dJ9E /86I;THVlPBwy#2՟qNmH` dΦ\gp'9)mzQYǙ.O쟄eJgI*u/SW'\d3zT็\ld+WE;*ZzT,Y,J[Y&p_w$cK2m#Qɝf[rsؠJb4CqyĿ̦*sIwբ[dZC`uYssfZ90]Ws=X!n]=5[}(ہRVx~k2kAP蝃`*}c3DGk)>,FR㨈Ux GFKH|Ū$n%+> n:''?NߎNONRhrp;7IL&gN[.c{jqIJ2aDpIʑnfXe*ao{EǬij yǖAy 1ɢCC!*qeL>RȬ6)W )P2'$R"@*̒17I/劕G4$HqBnt.QhWXjQ4@V%ZTb(`Z2$>(!H H`}Ph$㲦S]PfZ6PGjPhG,*yja LXZ4+hS[‰ QZ6gP3bu,bї\lS ̜0$V4:Dv7<kTb2\FbjE:4ʑ8f_Cz@S)) .)Y*n DoLAf,MkЮY 0׵pce2J2; K0a)1y[HLy=%/n`0HK\75O$T$|(Tnfu딳r QM?-{O>uMƼI;Rw'զSi5eS~oֵ@]m|ęo~x}O]gBxԷgCpg|np5a0u91ǷžrnIɽvʄkiýx>}^M'n03VP08Y=*=;clb7C{ {wQuA#w!ټ.TzR+w.#Yiab7NlF0tx;wd R̯ 77 ;p Ck˜儶(H$y*JY8[#s0r2Sf#} >w>Xm G[e/̜{z #WKhyh"܈V{U7c 'ML0X|Hj8֊6"r` M6"BHb!b.pLퟞ|eB$N[쮶\>A,5x*V=0[z`p`~wpdk!K l+ |)LZ9_׈DK!҂ZDb1Xwiq/o*׼P kחdesu}8ɘ E3u̼U %/ta^MEŀ(JG!J!^R\jm?^T3N"M"y(oP"jhطⷶD,}$h5aAڥ[Ÿ^9.D7~ .z`HK͔URVI]ltΤ=[`_ʶ4H):Omqթ xsZ9x_ӎO\2llޔ1EX`qxj QsK,mDRi' v:1{6ZcoMQ42ڧj#eXlIX"`PԝXǙ .yt :tVY֩Dj.d[spG^aG Q>n  +ciY,MNpYMVjES'ƞeSÒ*vDN8; LI=eєH8ڏ`/5p_ZDYEQT(VrpƩ}+_0K9pߞPyQ Sgy6Xu`rOGz*~ف =xٵnO=ߖob=PK@4'k (org/codehaus/groovy/ant/FileScanner.javaWao8_10Xp6׻4XŖ-'DJ=͛!;wӝ4u&ʸ,OF_YZLS?։\jo#?V c8_VѹO.(Q|# d r 󁵨D)'y|O%'ԫYI˼=zɁfPovF=K$XWy"J:Dn)BL1*JO''TTNL,헥ʅJѳ*פU(NJeFLLiު/Z#YOti ڤ8mPxF*y)aƈ ElH6mlicI{y@qZ#!cU.]V1z9ONĪ" $Dne7 ueώLΝNc戀+fIKsGbS`SRe!UAR+g$T UZ)S^(4mT|S wW Qg %Wy@CN 9 MsG@LտFahVP#^y?0ڣM*EkE吣V: Rpb*tIIUdXo-զ%!q}7~sC|gr#B?'7b 4Gt8YmnMgM{?Q4Z1lL^0ƟwGS1\4w.&n@E06p8q{oVOᘼoQxN&֯;w;-#7gS~p6gAH7Ȼ7v F~ #6\ =K+{CCnj6< Ƚwoobc"9H.nȏG(d ^dfcX^~"׺ ,BJO#/sVf Lg۬Lmؐo|aN<|XmrPoM(b xiN[o:xt@~#~ N#կG۳&LZOF~SN0bx$ᇤ5@ױN+zss&w +` v3dz|Oxt;}Rt_l{[!tmŲO?|x}iN}LvpL<;SFׁP#vyvGG6'j;k*N v4MO'E3FEZx}ו\7odXh W𡣰R6&$14gAy-ZX@=}Īw*(ESS ЕTRXXD~:׿6CW}q}q/LLcta;mn'.*HxLUL8q*)qb( 6 }g|g3K{~Y#4uρCؿߛ)9m-ZS~mI>pW?h'w{HI_20FǸT%jkw- gg5_MnÂ{hCDY7 y|7HH2wۥAcjQqPKA4eB/9#org/codehaus/groovy/ant/Groovy.java[ksʑ_1fr!e;"! THʎ+{kC1p${goRZ~HLwOwOOxH]I?xc9ߟ<8ax CG;:xMF? kt,C&r(fc$[ P̈"3^.m02H$˳h)Tx%M4^e^"yKL.22՛kq_<F Lle | 6H.\a>/?R0h-8Zĕ2VfouJq,Ki&yA3GKRme)DR8g"Huic! y5V{{ɌY-K`OA&R.Ʉ5̌h 5 d`洫@ҝ|i8șݱ3g1t\ob8d1snHo9Xdž̙= WH ' י;]ݎE_@ʑLʽv[L й[aP nNi+29פ21=/T>sg9Sq5nNs,<5dW۹^s' g6Y񑸜~_&yM6>T/>]:x>#96ZT0#)&ŕ{LFNI'w@̝&4Ĭl6R_+1?BBS#殎R;KDxknrcEQI&Ћֶ* Ӯs,@ҏ1FYHY Պ4vy6mOͤBA(;J{S/wTRZc7IGOH,kݚU( pYg^z&G0S(x8Smm'8HXo'5JA~h_Sd;Z|B"sfb*eW 'qh.{PfdG`'ޓIeH_dr)]Me$q2Dmp%LRU$P+@)Q}Me@j2Ix'25+lE`ٻCe 1"v')"1s*KDS`ACg6?_M}Mos켄1ZXmb8OM0D=;=hP اeq^?HV=vZB>k!j%*mDA55zWpCտMW(߀ẍBΑT roHա!PHhXNk3ZRS!Bp,哻Z\ei.TL7@~%d ȥԣ5%Ot'}j-%jTQܗ{&h;=GL18wp@KmƎD ʯ 9%DJ~ cotc U;D x/"Z BeNqF ]!FRCA^[ TDV:aWKŽIߋZKٖ4S2l]<6+VTˊ81$SxsRHGf:&ojB-spC2@DuuRM[:܊Sx!F׋#kw'TTUߪEW_Qg [l!K )_Y鐁 Xu`ѲˡojoΒhQcR#CZ U-K靖a6BUxҌfJę,"c5UR0Jթ8?oipα+[-YD R%f uZlξ$K }Td&WVq"Zkzh[EV)')P*lgXi)ajYQ :kh*ɰ-`2i: @]Jl~-bf_W7e6OnB<ڥ5te!](OmܴE`)ZX4#EŠg i5%()z_46҉&; ֆ"%/bO=I0gAt{XY͆[J%\LY*]h񎱓#}@X uy1Zcin-RKe X- X)םP Tː!/3eo g^XFըh/Z)+=@W]F@s,Kv0iKJmWP&[Om̿j'`.Z=ݎqT^hB#ڏ-۶2CantSQR©@P'^Gજ:8~e^|3L ]{G]Lo6rGtq*g }.>DsOm_Eaϔ--jΐWX3. a^[&OsprOmGES9p} iաbp[U>EN,3!`ӯf-u:VT;9V6D@4] OW~FR;/!t=ykʤnU+0}ՑIr|QKkgԋʍ;-.R1"N&T,JR&bEy?Z;??ZD($aLg8R=lH#˪+*gBd~ Xom*S8WsDzB\{-:ZXrYeQyND+Ё=P0ԱϱSyH>[FhbE "+Tlt%sM\`ۅ/pđDKuz_Ň= >1QϨCo?/UgJz_IPM Sk5!EepEp}tY~r|UʄKvlvuGH `慚Ċj^ HZR꒺JQOhIl *˄wdzGb9'% Z}Io:;H)pqMEqxrE Qх*&vA kUlx_'Vv,Hgף% t˽&Tf0~/J=[.Ԩ[`oZ5S?j1~DdR9AH:2 U~͠"S[UЩ]BWOﰗNú.V~P櫓T!]ѪNN?MTwVa+25|%߉^S`ưPձ(/u>R^8PVeO EhrN\lȡR敫QtB2J1WHud(<4P%S;2ay*fX&!_3JL?kkHc;|2խmjKw}@h~)rl\.] ӳx4){D:c5*oQ&Y:ZVv3_z?<5UK:NS-d[Yj5vʪ^K땍fL4{a1zV~-mc'kZ~,4ڪD]1 *ȡյ° <j?}ִNPB$org/codehaus/groovy/ant/Groovyc.java;s۸@47Nn2c[('n^)SHq;߻HK)gKbX@z'/:fR{y3{{tџ?OlI.m~Xle\G6k1?A R;sv>bsQ)"el3.y),|B!n3Ă8cX4d D]4}_!WLH+9[(^!Rps$>xԃl!D=Қw=sۛ7>豏Ϡ`M'$.hh2TQ!хS(ikD Am 3gڽ.뱋$]a4|ğG0-VGgdL杳' ^|O{ mQ+ҫ&%e.: ׋!s%AtT';/,UYawb ?q1HSBp*/ȅlRr ;Ib:4 t'-L%abC4GW ٓ)9"R,HAvE\yM T7Az ܔ/ ~! LH+L*{x'J!t6U]ӣ3MPp3pt/2hXurVDůu |5d@`H_֋H!Kzcn|IAъbi^D<˭!:LX @p57?˩ƻy9Ż*फ़FRB߂CT7D q!m΁0*wX[AN@)$=XLS!=Kâ6MbmAP@2,XLPzCSZ>b/SB z گ!l%}I.b舃>sR?Tw96_V^NӔߓ jS|;O␑V 4#ʘٿzhfNU=KC;BdX}{[ygAT0h¨$;Ppbd=č*G[Q&)-X*[~=`%Ya S nxPq1U~(- w'!Po}d 6KvdOH"oDwDiЂ.`ihh*8@A%Zfic4~NhxlG8AQpk){pppRNav%Я9 aAb(@L8g*XGL$"]x(1A6H\+Z[ORFE1PJ(Z%Ew4U|+S@J{X\Er{h3"Y@ۓF$iwBLJGӜ#f,٧\AKY0TvQ, I_ UVZgca̯0*2X#4HH\&5g[TYCm8Xݦ@OWGlYMVE}mQ6JhT,4d^z> cHSU)Cq?pUP;DT]7tε&-%V}DiJ@)6aj(6I_9W`%jMRMx@$|bT `sjD&a}`֣\x%7Ģ,ebm[{nD)o Kb=ɗ\5._i$m ]^ܲ>xl5 SQL'v,ސ[`[|Fa[-O "E.|v~Zzot.;݅p[-h fV: vfcS?j)V4M-? +r2XaP#w?mLbP4X%e5Ռh cE_[L/7҇iZZp5 O*8W|^(HQxlW…jEӲ7VTxo %g 6XQCEi V do$4qrQx5bl](ǙеL2Zr LEN^UZQ[\,--KނZKCuJj6 ; b(iԜĊf;]Rd-K輬] @Csq ƞafisآ낹Ne^+A9v SRnM'ǻ1z= YR .`G׍m( ɭi2Ces)7Ӷj֥_,5ؠQ3jXZOnR e7 `WSػZ:Ya}nER7z&LaFpSEKIY|ûfvCXr%}@#:[k뚥[\LۍMB̊"Q6gX `b8:?\wA]{]A#ǿ[Bv736Uuo>{٠׬[Ewh!0ðO9>K,LQ˯6/tЎKd )\ғ@JS-*_7,j{Kݥ8b&P1GVs0GNWJ+=vPS8}\?ZnkE32:ǘBA*4}S]z k E:IE"IA.ehAvx,am4z9תacuAeѯE-2=gclB֧k!@ƨ(S늤20:;[>l!EuMf;Ɛ kѫ4S'jxh$73]XgwE2Ds@RֲC;ח: }o joN+kC u+{}Od?Xߘ2=_~Y8 FYoobV0CˠK`N]ژ~!t6 >W@^-i[䳵z6TmX>|sBli6v쬆]Uf g^Ků !j8T.wpNIa!ժV$ƀ=yHM#|xأZk=H_5K[3)Fj+ߩd1a:ȱ=Ӡ k m؜Cm"zsS@+z訤 J{SJ+ʰ3}xم&V|5oWk޵7cR @iµ\U`b:LxlV6 PKA4p$org/codehaus/groovy/ant/package.html5K0 D=Ŭ+5\ BRoaBD|%!<ތ4@{K} m#' ӒKhMu~:,CƏ6NC +/xPF`.X˼$cQ@NJve]/7evחPKA4wm*org/codehaus/groovy/ant/RootLoaderRef.javaXmoH_Aκr>$͢4:8vN-v"idW/IspFe'e |HGz'h]NHdȅU܊-tЫ/6Ŀǯ_yEשo\,g>WU7uE+!7M)`YV&tuU* IzAJTEy'riDQXR&Zˬա^7ݩrE:7*iPmdV%mr}t`OOBSْb% 1\~x]XB%`UR 7jr:Kv0eT,zh DZhv p[vWҵD~u"N*xP ַrfZHLFwG,ǩPkYq/E5DJ4NrBؼVk+2]Zwm8p% $3TOΨk]Z7mPx mlrťsydV(8 0䕨8o;*R&0.BU/97]wkq4Pà ْ#6)TPW1nA@-#2GXšq!J*`;M8%8_mznWe9MMхR8;>G f7O8h4{<$w:Ɨighw7O?3w߮/ = ȿrN# OG؟P:4E4/rl`,>ԣ9]z_3Gdh {ts.]A7yp5 =~87FyS$7(p'~wJg|t&8~"?/92& oqOhc!ؽt{ON<.eȏGg1ܡ >#/<,4|CokL\g7 UϦ]> ljC2}p?`F [!$m-`1jISMGz %|k s6g ~VL2?'w ZuF5( ;`%ɨ'Zot^tJӂO7+G)f'OʞU*Mop~Z뫌˧JQ$rQ8Wn F(W?"M)!KV20B-\<qݖ3!^9&/GhzϺC->Ud6o2G+ 1ŹJecтeYԮ(zivZ}KPFl9fJj60źo ۨytZF5vm VTϠS-ƃְ/C{Tbv>Y۹t8nw#Hn^eHۿ[A9 <BN5Y c;JztQ5uWXBVuo9зa^?׀lPKA46o (org/codehaus/groovy/ant/VerifyClass.javaXmoHίE+8'ٹ]9L"&jmzbl6d2{m$x鮗.sA?z)LM,֢=||ɿ_i>Č/KѠn|l{-],&?D8 $tB\elrFi$2ak$#LMVJ ŕN)+M:"f`P\Fj!\V_ 6[zP|i*4bkK-TΆYV'rIq>dFaDZOg5* %T"tN̅JP 4KMDIPjj AC`s[v6,0?QAi="lA"TcQLҵ,1u 1 *Qa,BfiKk!%)v2By3086XNPdԜei~l,M$ @$(͸|2Hf28GSlnf[,Lqd\IŢ5G&HIr'\Z s2MnTlơӦ7[Mcmx0`-9bb (  ّp#}MbSoV9i#a0WUa |yztTtbp/;gߌ^'l+g3 y`8ߎ~2{܌\߇pDMWX9syn;+  {^`1z4kwԽO{'v٠K/]C7(3fAu0&k }Rj #Ƚf _>= z]?7|}c\6_}ϰ w4pj&xp{&Á  G*`ݕ3jr !>hU9xA%LGwuywf<g,x9KU|l$Krz0(QWV{UGQc{X̸v<'" XYN|*/U,-zr㲖bQP.vg爑K;OX3 bnl.}$ھy8=`aO%|a ' ,#"o"exo9X4 fy-A[UnL4Dds 7I8$*?jm|fˌo7-q8z]9m (@:?.4^_'!)3-RzTBٚ_dʥ3BqďG3gdfa qD%_Qk8IR2D#HS[9}5yReOe*FV'8qbn8)#Y_EߞuMYiPd RLj&iX^ g-flk Gl+B bxi']Aن^Ș"cBR Va@+Z67;V6ndMMDE0."I<7ZU!o!u'dt1@YT*!J6CZcFyBi ٫,)y 7+O rT݅Z:(Svʢt* WB0K\=k<\#2z+\?ʯ'텙]8'"+jqUM͆J&\F+j:xP?L0 ]xBV_QDgn@+O! ]k@-ZjbV 3DSт.V)JlR|@;ϓg>prrL/} .2qҿɟM:ma9aΗoq>l)hootu+IC4VY^~n1*_-[WOF RMNddSJKs yV碊>oEơyDVsk8IJ" %CEcY5)6Ӳ_^msze> kq MuB_g7<5PK@4a KPorg/codehaus/groovy/antlib.xmlI+LR4T[d%bX~Q^r~JjFbiD=wZ}<&))o }PK A4org/codehaus/groovy/antlr/PK@4 hnF0org/codehaus/groovy/antlr/AntlrASTProcessor.javaeSn@#+r ԋFIFveF9avv{g:*Bef޼fH $뭃w VWHcʃ,PY,S%-BjD12oHVj9=(B%|)8 ݚF U ۆ>#J1G q>Ulj Hz뜙'~E kfHCv{ϘXvXaP!6L{&Ӟ𞤓Օ BSJHn:ʯ=V} 4,4y֟kxJWtsXvr.K[_ yLSz' 刯(Tzd KSu'jZ+J'j`aJ'\xpD{ÃqK܊5ic\CQ49GNj,pk'a9!UlCD16  Rtކ\m!ވm9Jz?ilnH[{Fao;~W qOVmo 8`nKqD-\ׁw_AOZޔup0΄E]7Fh 7K$t)0,Qn[헎@uM3 H0p`xֿ?PKA4SN 6org/codehaus/groovy/antlr/AntlrASTProcessSnippets.javaVao6_q3BT) /qZDM[ RFQv5}wdKr wwI׺Z[8?;~;g;M W%OR)7`%;7 ΃30nƓ r-T%LH1 y!S kN%_23 (-ن" m@U(kXίo$|R%g% V = Mɶ 8g5aZPn&5⡲=ZzXu1(yGb9>B| C MAJsޣRYDd"Ԫb++FaEPp:Z"H ˬ:+5jASfU֛]f6} F5Sh, \G DKT=>QQB#KꏫH(%O2h輞rL Uv ֆgo9ꋺ+1ns`u]o\Kië{~NDml]*f'N˞ *+d0EŊdWDmlnKuse 5| #6ry_eRW/wb!du-t'`)B= :G3VcO; fԧru1VF9H;=M1GQ|]ESZ - Q?ŷxAlZw טX_rҴ^*ޕ灮l@7cd'3R*&Tin9Ig@4]Z"5+c(6þy06OCĿj1]gŶզsf5MR۠PBAaiڷ&$T [e@CWE}OuMԪ5 _k=j#`J*h4I$|OG(GRr`-{n'NSv|Pׯa ; L:>8Zڷ6"v6 (P$![E @&}L!Y;Ltʰ/UbUؗx:A]P3M%ÿ::ۂ͛0K\qhO WTt yW!x!9$Gv<=ܫZȔxt⑒i]dxq'vdp(xn@nTyOט!685X PK@4P5a=0org/codehaus/groovy/antlr/AntlrParserPlugin.java}s_h:10ygޙQPeHI3%$%+>p_{N:"pwųtS^_U" gaY<$( (hIH|io,$SeЀ+nU$il`/ 8E',]q̢1.i;J `0"$CRaM~-ԂAXpbc+ȶtɊ^;t% 2 wgOA&[2| ,ﲈ|+R@18ky(,08/vSh^$8nO88oOz&7}3?`N8 io8 .}DZ:4cd4dD"e(h/Zr .}(XG*aDs,U\}eh!Eݚ>䭻,MZaR,WϞҬ8wI "CU"52Ѿړip`O7DCSw k]7앯(Ccfyzcu%ןI 6}ZGyc@jϋ%QkˋUYYluꈗ;/CU(eF]\$dpxG?=Fp rYV*ʢaF4 n*ci'ωb:0-4&kƊDmrTg!] i,/E2oL"Zd4*l@y|rb +!Z;wGfS6<'٢x'}Ñ;iWII!ʷT@a&RK7q Mu [b>҈A0iIR1f$[6\MNhq -.M2qx0 /q'LG4#$ LWNqg"̉ C |0B>s҂`'CZITpٺ'΃) bLav@ QVv dADu&wNJiC ȉdQ|{&˟T ]@h2C\$qNž= mUdĔmƆ4 H5rEͩ5#.J))/F)teH 56a2'̐l cSP[-M="M;Hzz*t }Ċ 7.QF ѝxN *kptYFpAɢqrvo`tXU}u!7F_@ex/;"`!ADzQe%Kcd6J-Eju`-##v&"9@aɴ=n5Q"M[/q!.JLJ4(]:cF`9&*^\aѠopf !Z#pn#fq(#0!dކ\^Ƕ7_B􅉡U;xUW*Q]&AQg#*STjw:7~w] ڍhuU6މ9Y;uiXD"AQF8 `1_t8]v8/RN>{<~D{dz0G>Ai![z7ɇ$}L@] ͩ;Z_LrV`6]GJgDz$Ǩܛ@g-ϲB!b>OϬC: lg+p. =(p+aXn\9ZyGwJTNIg+W[S53E|u ^AoEn)5ND<iTی4.%O7^.vxS+fOl{Nsq޷_.j-C64 3kbt-QFxkr սM:'E@c3O^>S3S%;rQWAytߑ}e+MZ^vm(]?봊6(gUa vbof̂ uFIpvXJl9NGt*8W/M9VMOLlLw{&՜GD dQY떞s*ZnCdhAL!8M6:w`(ҔVOWhe&5nS63U %TL-dS^R/z vbX˟iFDL4'Ơ+ IY"&QV"+X.ʫLLbnةӝa.ޝJčuuj,_p?_.;Kw@)y3M e9wqZ*-Kq%@yB[L򷭦,hqNi-z\2yz`@+f64?mOx8v݋۴=r#dGq+ `ux+knĥ ކ acnvPɤzZF3r1)z pP"{< L[j$=@M]S$TŌL '`/;1O7\P@IX!&;r(L"c#Һl'[F; vۧ,rN4ldfavd:L8C/ H܁}:7,ʿ9.iR55f/+),;s q{0ufa*vm7hvLPR!F#YuOAJSI|#cNrq͊6xZ2Xp萌:qZ!NGW*K*s}*l",PP0n^gz9:&o/<%,̽?Λp [1aX|R.%N :Z4 h֥_, Wթe Ka2S5]0HHx*4ˈ#Q4!tSp1 7n)6;yTyn5Gt}ͨ>V7 o2R2m% \0XۢM"d{jc Kb6ioؿ 2_h*B)yvZhٿ-8woeڳ"вZó(rݣ5pPd0m$F4jd;f$j=&&eY2'-s,0ȑٿ<=3,$8!+Ѧ)I[RMbn%) ܲ)&#dEvdN~cPxis+iiμ, 4q-nczsf3L)bFzA!_ Y `uAlcXhchi\w갚*3XyFJf3l/Td"F !:jZ VBbR;C]OjUG԰9R`y PZ_xfq)¨f ROD]5&-EM:c{ŅH'Mi(e"qEm cF>~DKqhS$920!RsE*jMM gY%jJIUT"ɛ}twSܷՎ[ b”a>ith%0mTe:M:K-A䌧|tNls `B g{[+ﴤ^'5Oi%傂Nu@E#[ٲZWU{Xs]ե]x9_Nh%uTj3+%ܬS gU8i=U ,}Nuq\:'S\,n;[}-DSJv FKko}_]JĊYF; Ou({HaUF3:lN6q_-At<'mՇXָ;n@ 7o Y<@)pG#'e'ۅ(24vXh)cnS+;U3smRV/VR:Ixx=#_ڴ@ZH: ؇i2h\I v@`E\q>cox]t5yQJ\XM рT^`G@2l&)=Jd僵!#we.'tSEfbǢT1NIIjE4 d*tCǩF%_| rQB)?&8( !w6cpx>4@IHK|п0P k,u_ޠZ!V}!k5Ck#-E<0lBjم:T h')EܻZmEƜ6@zS~{Bsr@w6`%l FB|2ؾwWTHn^z<(OLҢ'RD5_ \μ*upo \ 4oˊpUH.;zx.o"OR8Lx'q \S!y /}CVI~jQJk fds(Σۨx)l8̝ü w=S<)U%x#.Ηvގ)O3;myLr ^Ads: ^p6Ċm-ˉ,Lp~u!Uzjt˩[͈+2_ȼ/CkN #uef*e =/c~ /ca\8Dw2!#` lfuk1Ep 66Pm3XZ0Yp\h-TV#=~s\ODM;3(1ΣAt^ ioaUQ&a0ƕ,Zltͮi}sU0@@b%QMX1ҼhHlo:G{{ntyl) TStaoמ93Z^ <ᮭL|]lL"77Aemxk%NU;HmG%xN_\dlyKCDz=H@ߴUݿḲ7`pP*qt?& nJWiRϷ'' 3kؿno@&w!hxPnӪ8-phZɃ53SvCխ{2mo-Wio8^]:01z xW_n T!3uR`G>Z*>.ӡf:lmӛɛ vG%jԷfq ih/o`k JK4GwGquZ. &՞vl-PlYE~"́E63v U]̜U4u/8N' J) qR`¡MoR^&l*OH`O:?M8Mm@j|5# [xSXҨ:<,&>F1L0Ht>(i%]>D4hݎP<" ~}̃<&̐.P pJ6Z+3 ^ ~sq?tBF@RC? N#>f߼b}\]{Yu*O\Ol$04(P?~iEI ؛\3+ʽ.`DIGx8[\= ˾FцkQ;}AB<0 J[#B抠2)lĮ#(ō:Uy[wE*{m3WtDvke^F 5tfhKyAUrۥH8n5bwgxu.e Gb ,K?d([q57NKL ]5&3x^F-] Kfrl=38ƌMNaՐ<>N>a(i˚ɛCUqΗ `iAMbc9]OڈT-ezRW 7VV,<,pIk:.E"ԛR6 e4Pc>YoLmz6˺[+& Q!zYzx&Ix}رT,tR˪GCm<i%^FZR /::0_"#46c! g`LH6BK?qy4jYG@Kgw,Srʭz38<մ5]񌶕vC𡧨1d.dGekiGѓҀ7)j#vIjTfƿv0_܈KW8sǵpD  }8:Gs ]r YB Lae6AM2yi4 O^9^kܞ%ԆMATsIj: *Z5Q밚ܖ%˱M<1vy "eߊ|b)~~e7v QviS*_U{y&]ݒU0u)UKk4tiG=]L:7QwܞǖV2"bI)?5ѕʸڏ8ZοHKۍz83<;;7]筄eɏ`?5дܯf&8%y',kBd rj*a*\ C⬆]m_{] *r&:b<8r!駦1DS>J: S+-tMa|Sgn̓Pr5[kvY1# Ksz(]!)_@ l-b-7~=(BO8;cüIs,sK U6JZԜn'oxi"Khztr'{*:}Qˈ5c-- d[Ki)^^<,BD݃A;$ݵy^X,%, y\#E ZLY0q\lE>\ Y??&m$-T=IBfAkC֊2h3LvțYcaX$,f@~ ]-C:c>Kﶤ@be[oubHIM AI<^In tn.` xgah8u"a{qLgƾ߼7{+'K1?my`phↈճZ<aTטgp .X(W*^{vRPIں ZKiA.M`Q3\(3tOAby_msތR+F Ff(jTLIe5Ɉەu%?^·gqi,Vuqs.Fx~-mO,`֩(>?f=?G&Q =XPT=?GTM7E:=֤\rIÝIh;wusQp-gj6ڎ76Θ+4F$i"'T8:*ΪGFWgq,MBd*k!޻W{~?sĕFȊ"m(Zs$dW2+Bu _NÍ Ȓ] \_HK)$V)˄#kVĕ(9poB^ͿȈŽKcn~Pư-dQyw64_p[qNo0 '6h03@K`(x7{Xҍ@5`+Pcjh c"t`jJ.ŃiRuq͊ s6SJQbs=fjA[Ƅ岡qZP [˦kUL;k:$3 I %UNT=f3|bKZ HWӍsqmFH; db?py>rCy pf0nΙZJE1s!XfxZKL8Ĥ.Fmi{CW*g&AxΓD--rһkiz7>#E:Wl}՝vǓ,zO{W~ӛ%M~?9>6}/}}QO׎WUyC! DW4Ua8v?>3Wm\]~^н͵ǎ=ӄMi&S8Zݫ սWN`a]촇վu45fg!3ye[z=TD  $RwAfL3;i9z-f|X)VhU`|E|}.{ͧbC)R\7I[#U`4a+:jSx ͉Sew8HҺG}*E}jR;Mq6U۶ D>0cG5uo-5 n=aj<:%wJ޻ ʿ<U1ڛ+yI"jiqkʻ&Q-B]1DY@1 |B[_5[։ 8EgtNùVkoL vq*)OXKGu;ʨ?j,Χ-VN&J6\A24aShU烱k<->a bsMW\zt'h䏔Q7rMx?h_:7jUQr'7辻`^;lTf=[Z]JZOFLM_)YGQFDi04?K6ԅSAE".~~"KWўfE vA_>32c/_sg0ʉvJڙBo;hśDÌBv?Y8+rH"C0 I(%dԣv^v=&rs%Wbb_0 {z^}FD ([IS-'e*{< AwlqF+R_&Am3x9W.ԕew uw eg\)Q?v?›GD:ocER"W1HmLwJܒ7|ts^ĤE,g7[_l^ӺB k4`JGzYC<唉Ji;=D&Q0[vu8ewb"fc`J3>2T,2W:%ʐ -"5yZݦ,?$ mK)j jQgL-M차y20'Ně9AgڔRacG 0aQBINEMGEr8o]d? $JD|Jc} ӋƜU_57J:H9QHz2@N> t ÒRh=vhW5xq1Arĝ#|В؅#\k4 G,OQ{:M!I>5;j="&a$oƳ=Qw"ZM":`IxZz! O>=?PK@4=R7org/codehaus/groovy/antlr/AntlrParserPluginFactory.javaSN@+F ' Кš۫:8&: "vImˊܩ5:HTV)3`uaɑ+U&ik"<Slm kcZ¡F m dzîX \IC#bssE]ׅZ*zs}27"xhx45:ZMbvՈLDf:$[/#ڔpNz\;&j]^o>@SFq I:/qO,/lܤ0_t>N|&[g=]O%-4Lļ-E|';IL:klUP G 'D`ij֬W$ $꟞K3cZdf*5]!5L9-߆[?Med ijM˖z1o| }op^lV{!hrjd DaXQ\u-ǶP`9tqz.ÿM݆>1S[2`hp<^PK@4[ufK 1org/codehaus/groovy/antlr/AntlrSourceSummary.javaVQsF~Wx2C&Ԟu *v3eR4Q;=$[i~}. нɕZU3 OO?Oه\ _-@kS.: PFkHQ *R*ʶ3Cߕз #tOe ~장Q@K٩ j:IY&؅{mEX6B[*S-^*';QW~.)JjmV |uKt[kطɲg-2VDݕj=8@j5@܋;[CVP6Id-+T\ZDW憓;T:Va弒e %ZDYclcSk4”Cl )ndha^9H ҠBCd8xܼ Ҕ4:ƣiXږTD$&?ɞvwˣoSY]-[* `+5ȂB^̑˥VZO/HH-;l63P-:Cq=Z]$a2ndny15]ƈθ_w~I|˧l {aS/aM`,JA0tUT C$dC9 RJm.IچBĜ.gb%` Ѿ)`G,a7DDjfeSp3m&+S|3-ַ`1_rAm\lIoK)6ݛ!7o A!}x+/mpyx7F3g|'hi3$ Y+b}"5H-Pdc &Uo|6/6or/& 0`oQ78v51wh34:)W۟Ap[ Y Lo7-0;PKA4+Qi1org/codehaus/groovy/antlr/ASTParserException.javaTn@+FV傛R㪴](5aUإ \9Iv͛7olZ#|x E"2"Ʌ02Ae1Zhrb#sJ[Chq PKA4(v2org/codehaus/groovy/antlr/ASTRuntimeException.javaKo@|$Nȣq UF a(m]w8w1Q;fvLpx6g!6%9m-OPhL!(w!|Ap@x;P ij$ a |L2$ DPs7uZi<ri3J3-tnL5 }ReA m4L1 w@Aw5(aK,X RH\+nȆLI6/ٛĘ/!=xQ'N,|4(R ?z@Ot!ƺU}A4!kנs4~#HQ'o)u>q_O6Vwe"WnlIg{+}n]ᮀ/݂ Uo.Aآ;+}8ף&ܒ? G -ž{(+ @ʀ0KY;rStǧw:OPK@4 z )"org/codehaus/groovy/antlr/groovy.g[sȖE_dld2 `2prg)W#5X=l3-!;jw]ShO><9=C7b(+DYmcߕH"肋&~p8kndDJK&U>lt(=GMWؘgD5gŹxLr2Tёx$ H?N~cH'4Nd*4[)z:ERLp)\+d"՘fL:(uEFgL[I!OPiQU(~Tƿ`|6ԡ4k"JeB]2 P۽/ULVʹSW'BwUq>ݻ/<]Waa|oFDDJ$t3JiɟE=Q"-=r'XbX C8 GUĂi(i|0pUZfIW HlZR<(9%*׼?$=@AE~!=EL͛-QHh{P)`9<c ňY<ζ%:D>n" EX5|ϖ02=ǁ mѡ".DZuYmDYw>>>DDelB>sP{bOpU.Ė.a>RoE3}bӖl]_1Y,SF|vW>BqO"j(XZi?W") epz\]"w1`Yus;yy Y=.B|[4 J?EŃ߽29i LF wZqbdD,fb{[h)RE%ϟ >]a\N/BW&dڤ _nqŵEI=°h 8pJB*Za#OP{ aJѓ1B`6" s7FJG(1kSFe18BR\//OŨTR~@R^bqo jK9o"ðC>n%7"H~l.jr '%J6n*P3xxR87OIjjTbq3G/U6~6QM~@nYM1.cN[I(UXW^++r +5')`3Z2bvla5g~ .^2 ^<XBbY sW)M \vfHʱ~[{q[ȠCZDeipLewqh' bK@^$B-°Gl+P ٯm'͸;mF~P76?eD$l> kIUQ2E2~"Dm]$r!?!~h 1!n\ȱ❪&Yr4>+Wʽęip#OiDΫJ\x|Ag@>{w@c Fʹ/+s~~vwB]ȲQa8sHhl5 &&G` G:c< &ēr˜0@e&6l9QbLp uL39X=\*ʚFQEPt34;s,.x~(Lh}~lhښ#il Q]YuJ2IrQ&ߍEP}sEZZ|T&o0Ov"jNm0PݗN8i8; ɏY,uY:{̰;~8!RJC|3~ Jr'=JH&~>@vȺ4dUe\q3̠/0=,aZqDw3vc>.MIiϪ^=prC`Lsj K{4zY"ZzsIıߧh`kg |w췷c&pFzwy.bүo&T;Ϲ.C;wV k{d.T0 Yc!L#7Їl6WmgX<7cL#2С2(d/޿)P/NT$,KHd|G 4b/J͛S#qn7)Np?f(.ݶ6ڢ3zCwztdoeGtoJX|="^ĥx;=łl|tAѻ4+6kGD=N. Ͱ`Kq4TԮ +QX 4HQ#sFY5s.;ڞr0(cT""Hyt=IXGL!/*l{ѕ씛 \Gߚb0{ɴ)FWߛΚY׬ӽnIu7&Nga{2zme~k:5{C׭va d1eҚ&L#7S ;Cʤ>ygCߺ[̰nѶzN%0ui>f]H'vǃh7Aox3;&1^&V&=vzhhC͎ްտ4]s5MZe-;i 7[|7.kKZ3ZSL0w2 z|YrA':@ {Nxΰ0i1"1u:}vDY#5ڽmA$tٞN#}Uj'Swk'AklGmwn- }fN]Cmt7c~i33DQ w{/}~hoHSssHָ"& ܰS5ۯEh~ݚtnw$od?Wx} b{fI](d5݃!%z8_مU}ڡDd7iQV(ߐ5bWi]cӺY}yhw*f obnR*?buFGmc v}:u)%\J:vn|-{y_-8fȮ,L!kOe62rBLD^(fZzH"GߎqPؕ\rGB2O7 dt/[C52Nl/uhZ6 u{OpzqXԽrA^o?ȧ6L#u5mYs25@fӊ)v@UMXOe}8n e"*$RG;H+ݞdO! fF5[~8n7yD6a`p۞Z _U߮?9Rt!2Vj2ۗPq֭*oS4T:!ښuQvsbUzT@碦-C .&gFe> S72Ҧ_E7Z3~ֶ~4ht` sR1}زȌe\4T+P kY|A">’؊Ot/tjAv}ǒdr SD.(w{Zltmx2]nD"F%3Φ7%qv7RayK3.4j3ܶOr$X9U>Vn}g]= /?!C@ $ۥ ]gݕɡO+Z{IK'io6 P~|8t98 'Gٯz:uW څ:NAF'I Y_VĢJѶ"fk0*K7HGƕfW MWc{W$?2G yH42dӘAlET1+5J}3FM,*~C'ц$7⺼9lO@D)؀.WtC6XlİcsO{oƑFDv2sq6 dfO#5BQKySB8νj&\e_b6ʴJ Ḙ,4>u{l.⠆FwHl {?}FRYACK.O!FEM vUStD X.  '"H, 'S.mj+pNR;._NIh6EsWWzRyJ12Cd{4CbND|vh?Nɵ=ɇhNjC`ވoty 6K+edO4HR>&_8MML;'^\SFzF9i*絴9%0-tsV:gav:%=hg*D+9躕 O\_Hΐh&W ʗ(inMW(=bi1T0<׀xыbnpOs d'̐w>E3:VYf@[0)rX[{4~d|g'u va]e؀y?e.&}X0DkDW>FΥ0Z)0Id%<(0'Qq9a~ˠTâT5|#/Hh#g"|/]ؘ5lm>gY/IZI7P{o6?ˤm7>0@A1OXJ]=xO}='/ȣPQzfkZ :>M DlQ:*JM 6( qROٰá5p>bC,;ۑ=#fml f9W-,2.W(G΀H-:95 㜃1pn]:hoid9C|).Z{%%ohD̴ Ϫ/Wf~{bT}|]?57& )s'z{=p(mǸIH-c,kF2Mb] : ?4|8ˆ0N2tE]-~a8.%+-pf8u]ބm@$tt=W` PPvmOYny5Mn}YQ[m~ZȽ ,]V6ލ /j^&ֹ.rF;\#`ׄJ>k }7.<DՆ]oH s&mMyjkoK-F=ܦuCpm`tv[+P#i*:9YMR2+"뎁eL>6=+wX?őFq4 )"兦6&4D [HY|osDȋ4ꡰy9.4Zjy>~A?P!˜_k?@|)++W';Nt(fԐB"w쒃bʫ\YόXf~2u-a lE:Vhn*}F.awGcd"C2$!.=2Gg̝9$+x=`1FJgp1DpG(!倾x|m}`F:m]͗D⚝FY8(!JS u}sCB`>2y{8}W@OڪE٥5cwlбf׵g.=d߹X()V:$9 @h:3U3ossn"-7w3҄&Ź,n݂qZQL24 CPR*$XdؑNd ©BlD3a@f:h> |wL ޕ'![\#l !)=لz627uvcct@, ~# J4䑼|D4Kl[+͕{vh|n, )3f?GȠ,`sR@/>?(Ҩ4LU.H[(g+dt#HAȜlOÌT~ׄ+)5UdVkAu&6BпȲJefAluCL.g2%8Hk&+jlpF*6!nEMȟbɴŚmް"NaT@Ѿ-gbLF(n_s"uy# c>NpN.g|9cX`) Ԑb$%X~ɴ$1> `?x|*ɋEWT ybCjp4a˖C/6&/my#iXϽ ə# pTh\|zNv_ln-9I~Eer@߶W?):EJV\TؒI'ЂIˁEDv]rǷLh+]^~HKTӤfǞ{Gy쏺̖^jz2|oH2fArrv:*)83nߢ5By7FZ:RkPU)r3_YŀK*^BX=9}2N ! \%}mmk-1a$in7{3O^hՓeyO湘a*ِbHG.kt~"@ PBL|v^4Dz!IɉfR%抷LRTh7.m)O*6D X͕A.7,1D-@1`emRYN IfEc[Q <5YBQq5:(+LJ+(^Wa"a"36"6٧|: [B=`u_]wefbXF\?ݧbn39?'VCq9zS'yuȖ \v6:,ǦĞ8;PbKD|c A-E明/IsQdDu 6HYB\@恠co}!N]KLCV0xuhK.cN*~?⳹"Pzycaˤ 'K(ݤZ PUZ DGM"\{΢4:H *7emn ܐ}w'b~"ѓA~D` \j>{vv(8WC%a*^}%fN7pCllla2.Dk#P +3L%e䥅N80[W [+ZgﻃGu[ZH^RӾ̈0d2$?Aݠ0^`G3+' B5)ϧRHű|۾&ː\*,~/ ZKe.< %ZO] 0j}sb:IeOgJ70+Hfz;ן s )l&{7reZ+-ǿ_&R q; {6Au9 (< w1wv`^7={KLLX´Zf?E--RuԊr-s~EÝIz̓%=dt0zUFާ辛YPPvgbɱW+Ki!0sqڭDXGieط(\gcl)jeW~0yݛݝ0L QB cR [U4>|%NuBh2&Ӧs Bh 5nv!{'N  ^~)BMݯ%-qYq:lS>DoU}JbIP|1hOσc 0w҇@>ȧ:|y\Ļö5=ti~;'y h3]hT2N4/jʂ'xN<>X_MLXT> GR;[`OULI/s닛W^_az%\]:}_ jLwwotSuy/iU"&͗Տ*ZAPܼ6N5Lo.09#w3d'>cVdU͝+4&])~ut,0)Z@ar !1TbS3Pȳ + GLg 2ibb, +؁='@2bN *'N/>ZH Z;&Do}\}bsNi-_N+Y' V1ex*e "IZpk#IMDr4=#Kc!-Quf&t)Ir!PizUF96<=I }{"OYgƷ'-{Fɒb|И3:ɉC*xip| Í%^Ngp,^޴T0VF(ƞ+[A(ZqewxhNMl39QNy^V@JWsD /X.󴴘CJM'8)$U!2"]d-b9=J0a=O;)!7ᔄ]%f-LYпD >JƪR"W|"!O)[U7ak5*ߋaR/A2I!TfR.nytٹM>ҪKF)4Pvl2qplZv 0fukIBr|c//vA{{n9.7.9"d,}Ɉ ;8j0=]#@7YAVZZ>l#тf]a;A []" KonUH,71.6EO'Zۢv@ 쒏l \Zxy(y eXdC9eO2m|mZ 93?[gn@ha|Ȋ852§ӳM+H&gEn75LF'sa)ٌ|s6%\"b$G0/%3k4]+y,/r Tj^A#nPbI˼:6DmMcy#lŷJP].;&iu vR@L3 :5gzhPޟeSxMgfI!q9;{s>N⺽hg作"GP_4R57,3;1*QNoѣov}awh`sWx2Бu <3Z=hpiȇ⃵vi"WVj鴂ssrE\[F.zCy顭O 8e~yp9hsYūsȄArx<t]Ef(3 K7uz  [@)|b}o[w98ᒐk7 cAGhF87ҏh|5/e2FGT)1+$9i)5R~ os'˗v8dl( && A5":-1Ɖuv0Łm]-t͜^ݰ("nJKC>hgqCoxz 0=z(`BdYpB_u(CiN{]7gK2e۬ U?e$)vf29&e_Yɮ4iH}Mm^>&)Cb730hU;1?nlڕGI=)ʊs7sjn~~;8超Frf>^rt*׬H6ƶuz8슀<TI%ԆǷ>^JݲQ38p%J&gfS,Y׌vUlhԢT!UFQ J;M#W+@`.\!:B-$ U 3U:(SVB&ښƖ՘!1Gg8zKHw"Z["Z%<& M9hey-%`@N Ļ@ sbo-?ܖI+uN]Y\-9e _.{}d:}hM堃P~{lze%|$cҤAz0w%MyiJi5Q,0)nl/n^ !|S-VF+4Ej(}@`n9>/-D9F@Jrwlx48oW/BkYLʀRAQ=4!]Ѭ:6Z!j"p~7_c#+j[> h{̓A֝؅^+v}5W, Ue@G%G_W6RT'!f;$㋇(`nB8{6~hAw=o&\TtOVةD}DmGwN_uqH•>Jͅ#1҇~6|8Ke/%a <.00%l ge0?OGg{zNQ jSM&8Jk48^ O5V< (KLJƅ|Dr+ fA:^+/`b&׶*yH${":q9(ZŇɋF}Uڟ=s+ z{mC˲Q6SyP3 w جqFCEp<Nle|&!$")ȡJQk--w}I\}d)Mҍ$ۦ(/MeC;brOk-*.48Q{.ϚNުШzI署Qtzy.28%b8 {]`r|X%fE|Oކteڛ|jf_gy}9N3Q$xi`.*k»e'ϡ.jULO 1fFWН^Lh] R1 5ҝdM1ņpށ((-+gkDp^W//AB4O4lod/L7/Eyr3~%ilaAgr!LzGӎ v_"pFͮ8I:D2X*vkœk[fn(ct4km)1:7Wp:t!f7`ZOErBMe)U>(+f>U||Y|a9}!d (\Եp5:ZLeo̲:MSd4gWR$')xUJumW[6ŃlUzE~fK򔍜6*Ր LVפvCG|JrޢIù5ƫ9T.s yP^ޙX{Ӣ"F^}ua5Cjpׂff3L{VFqʢn,5!/UT+;"b{r(k 78vܵ`+z!( cҸ*'.ĚGȺsdt%ͧI2*Pv$aC dpLfj/9 sȅ p{ =LO2طd6r|rVwiGJ)_,У\T>AeW5kC=< nɢtprO9+ShpfAIsf|t{̧Mw[F. StI4U){\<#;[;Gɺ2%GkUK#HȟH~Jno'ZjKr 9JS#{GW–Piŝo_`%xbP&[w ƽm֋?F82Wi||i`xitĤ?3Dar=7; ä& V3CYsésGn t1`'p#7ΡI^ɟf.fv^c>Pa І&v&[r0&|K҅7̔6S닓bLS6t8Q 5 9b~/+^o;U j%6/(b٥*ϦNORo!8v$sa:* /En'|V$XhdQ8J8IMq'll2B&r9 Qys$Bīp 0eG^x?h [cKS|ݧ@mU)lsv* Kmd$N5- w= ZywP@g]]+DZ,fpu*wKK;JX-)I4Eŝ m5PN<0=; ,ӄtԧF­aT>2{q9 'bl9T̅i5 F! (r9mR1Z\cǬZW.-;a W)0[Ӌ@Xd7wfIV1C}Uhe9kUKW_qu-w[0Gt0hԜ6`Q'S}"`e{23P5By+WuA4L)aFk;JsI8 Nl5r.j@O\\%Oqɵ+`59gٞξ|#GLf/kMgQo^ob4&F C"qpU`EU`Dnx#:"(XUɣ_,XsQJ:Na]d6G,/CP(dz; 2"#`R4Y:YR}1rÚMvФ 6frGK3NO6zcvXo$8 t1THBS:90 ih%Zi8e_9~v9UP2ȟg/(d~4xT|H vE9վd1BEM`kPA㼏ƩM?.(һLTQ $ i`4ַDl vMT26(X]U>吾8n> 0`o d=ve~quwK1OĄHar?##Md⑇jQˇ^{":L Ksi[OD ghOظPo9b=G؀e/ 4'< [h2^0.tKvl6ѫύӝgѿhY!6ERmp0 ~: MH A 0nJ ]uMlRnT6CzpOM/ J-% PŘ˞#<,|@ Х7;xؘ0A$DYA~&JS ^؈o?O]ᄌqkvJ^},v`` ]+NS^Uހmf6jBN=`m= ةRX̪&*+O+:栘S˄~[' le?w~aXʾbߒIh^4vDB\콹ۋ5(ňHcҝȮ#~fϓ@'iCxv=\0$Mi`5V93tQ+_Ċ&83GҭT9ájU(yể?*. 8rZ [m]Z!czf  pc?  Ӡg_ëν$AkQ'd E<8َ 聀\XI@^u|Rk/I1tƯb3jioTKj"^P* v?#ޱ-6_A!dؼZ|iG!1 \Y4U~Znyk*1 ]]?1K槭fI9D1"8A[Wk׻|]e6ANEbX_nNn"߀QHalCTWTF sa56 $ۂUC 9noQ??yւgIY^}:.=ݲuG%wHe TkfL'7'̓ttvsRzGe_Pg>l;r!tvnV{D68x_V !o5Ko^J7i|z'a;pyأA&Vg%աTf2Eߓ6ae{s$gT޹nlRUET3"a+aZIF?Ѽg WǶ/) ZON`9VV࿍dm#Fx#YH?H^7_6ۍ,<*zٛS(p{;x5yR<l`ǹ@Ƌ9 =Op~ݎt_0 vm(.C.Uۜ7pWOs<~ /[ɁW[3pVVZcEyp~K+;X_?%] W_a$=?IK`+7w߱MZHu.}+U r90>gaIQ '31ΐCBT]t( 9),e0YsNDf"}-[eR\ʾÂо$`R$ǀFHu[i#10RU@_d_p0V4BdrA8pb1=@. c\B' rJК$c}CiFWQѾJ F% Ufl;|h#<~)<$ыU,naC9Pa.Mzk!U3kkGiG\9?nu-)@_FLYE"Y$‘fkۺKQ9peF<:mD_/˰!Ju#7'!}_lkCYr8&wǠ(jyǠ=nXCH-:m2 Ĭ cPn ͅހA0٠= ҡoj )2m6Ƣm\W_ד+Hocktպ;᫛n=I'G~ shY`-J4)4t=LaN8D!g=${%cDTmeG':NXM)=I65#蜰v|dϹ4}%:mjY?n@J PBTb79 !E*ROxrpkqzŏ֨&dkSMZn#*&Vtf\% ү@G/o2F#`ݍң}nh99Wd㉁[ ݻt:$mf-C%w\hSAx`X [09NfT9"ԁܺ><72lRXhE nnEK6xJM,~?gP>saWp4ak>2K?an`#آ0a;]x O~ B|X!G(߉zߢ;pl⅟t|375G>ِJSVu죹YL;:bQ&b8]RާdDՀؑ K sGL$Sa w-J ^}ĽɧkH#k =qZX]KSwjcpv^= -kIJ&~T~}{n!FE,rn}~;I߷o_m|yw}PiW U16زneo/#"ah(8DY%$K3aEHO>W爣qM^Cj_E=~[hȦyW}1M FGyQVAо5O8ּ)Sf$L:]F'2S'3F@2ZBj[G%c^Gdo\|qU=sgŚ6qRyX=)gZ#-ЕnwL<#YA_yItGPAgJ;wi?x8.m{XgWT#w}:]d&aƔ2VbY׳tU騩J@ɧū:2V[%Rا]ɺîlfg'Mni-j rMٸiY_W$¥$ѿ_ӿʹIi=2J6I )eN9k,>/MbZ6~- -upwdjJB 2O tK;.'}kᄄ0.wahD/[zӄ4z9"3:?v(Sv9ΆC}zkW1f ٱGv ?m`9n0jWȕ^Bj Pm_&5Om[{ 9iw㳸> i)'i&(YPqrYP_eycI }U)d1JUN$m<4L@:wOFO]@_x2J= & aLh9ޖb|G&iaH^ %j2NH$1+v7yg0Cze Q7T )'C>25$U6xWRE `yz6*J%#RjHn=o(7;χuט *'l܁:Đˁ!Y]UqQ5F>dpvfx mռ*V*&_zqe6;φ}Y,G)rf[8-MUU <<'*q2IgDr}}tpiq!rPb=d9t-ZY]A7_QÐ2)(JR0!&jX*`S$njźId=N BG/p.C5m'F$[Wdf0ˌsrEIvx67е-F57ѲSz0pk蝂~bo3W7wFxk$~ࢌҏjp.[kńϐֳu$-"!\ T گ0VA18 NEfp0L7\a2Ffz8f*BPӮת$ GykWvԺG#p4ˈӤvNOYn+E*|BI\]W(JP0ФUfԩI94U6aUXB)Sπ~|}E:\F1('m c,d?_S̼8]0`3 ֒s;A6zy %=LoV3pwA .ld Buw)n3 +W1U_EW̆дL Zc%I+4Pn3Wԗl,ҬJz`MǕ `uՁN{%EK`P_7;\|uGJ}N`}Fj"J oZT M mVWEڟgŴ7ش,G}+1gӧރs ܡJa,Y_&qXG<Ȉs$]u-OzYh{uXͯtM> ºKu7!f`8diB֊{(2&#B,J4ac d\Ce׿J37\Y"R)0żJ@L믥.pJh{K-ץq ,,|3U^[9>޶! P+7{e Fz+!g| E%q@7H+OeQN=DYbEgy `SEcGPPiqgjo3N+ps8 }J{2tԐwao߸"},Z*VzVbxa kxc 8Q'tI_EzёE_cfc_Ђ:@w~G^?=0ڧ<]ΏqWsֿW؛g4dp~?<Ɛ-}P*zb\Jْk7U<8*O(`32^t*xooΆQùY1BjE*RQ:FցjsJsTm/@F5M枔?l=M wщ|r#okN!0pd][h0q|^un(6G0A|r.kէgO~ N0aMtrWp[_7yY' >m/dʹ}e0^2D[דR?w͚"Q2qj7mʮW;βxܲ('imFml6])?_{ ZMo< W,&re/5n&&&P%ȅ0o@,$yzwٹMG[Җ}U}=0Sb ȧ 󵱶 6W%\tчlEўw +y>K,7;BG݋}~w|]yRϭ\Id$)֐s8UGJÅlńr=4= =Yy/ppq"7!m_Ʊln-`_w~ܮg\`6y?u(D=~LȬhـcRɔ@2Dz\̆\<* Bo_eX{~Bcd$YO%cj?( ypx~1@<X;io,rDK_.lX| mh2 v=(јh'oWGTY=O1Şm!#c:k}Wp"ܪb@*\@[++>) #(FzWL|fHeo6G'W5M_MdL6} 0WwYwzN!ٖ}3&_TӜ-,P"++`k˭]b;KJvjV֫7:͈& Uۘ(|myag_݅J0\UEl_ IU[A6bkQ/sh48L]Э 0SNlleuEtt9)>vCv1FQYFZΏ0)%[ MX"}&&Ax~r[/-&OsL.q2SQ_QZŵ$PD?pz[#yE1l6ѧ@ ?x)=!my,Cd9ⲍ }X,1]@b:[HM'e5I}&|#؇=(Lڕa_vޡ5 hͲes6 b-E<.qk,*AK@5W1 ,| A_6Y%lAbm:2tjz8҄7- Ob`liv1gqxUhԱwxra.2zv<d~a]űg6[Ȗ2r t^vJ<I f)UT1[IMx(tHJR7GqT: QקJo%bJgqRx::~_HwBm:_lM_ XcxƱ̻fijIuue]D6lF%KvBSJōvk+@u,v O{mG G1y%'H2=Ka(yn%l9 _ @!ׂ 1LB>x y =#8>Dg#9)'&cn\]*vf*Vzow9Y;}O)k0XȀq-LM*8?1&V{2yOt2"O2>%F*$XTO%f>N,_u{O1a2>f+ꪃj z"i'yI9nsavu=5Qub)=_Z"Lu|}G D(8[YIO-xz3#u ^KZ%)WZ6azU YE$O'=poؑ<03idc"C腌Kv;j\=qܤFRP#.jBLnD@*Qݒ.kKߣ\]vgm:~{[E-ːPķl͸VUuy5u4'Z_S FmcQoG}녨=J~M:)/~lb^5oϼַ߽6}4o79Xuit\W cD4zg.9T+9lR&Hz/ A~cuh%}- Eps;˴bXd+8:* oʅM'`};3.nKVV0JDmIkq_a!OXʯ{| YaUd62T.lR@8!ΈFU":p۔y.leaާx~M!2pB%T ʭXp~;ȁs{f~]]ؿwٱw"~ naLsYs7x79ⵤ˙q)BmRu&~H{]-!e^CkC  '5sAbW`|y3DfT*E'w60Ɠپk X*Wua}oCPiR'|0``ۆ'\!K]s/uA[es]LxOv.N3]ETYz -.u`R~<Rt/.X ѥĚM?,N+J- }7 ҚO{ʲ:ȵU?gqiQ'\l=SKCBJ(ǣ!I~.>P>y-N׼[V"YVS2dH%/RrΓ!r&JSdy 9U ^1IZ7:6MfxN\ JpO,8Hv1I!*gA 6Ks mOoi%0qF9'q`hA %HL ¨G:_15;},g@) )DdE;^ U:A28! &?ڳ"@ =< SGA%|xsӏ`#?h\ 1oHfT*ߝ_նڞ΁nCy'c13'~'}/̅{!Crֶ(b[y2%A4t4&bO?B{dm oOʞFZ}j?'rR@pPn#_t?ŷ3 ۈ6ɲT*ZLp+'7 S=:Ol !{t ~}N%S,ohtwNf~g|Al7vM=uY赥2&žL5RѪWvP)iUmw&wUOG>熀j0i Z쫒y3BٱV7lnlNph?YvADJ^gt*& GC:qY>U3\*k4\A㕵1*q0cģ1$л~3#N **PE1+wFlBhg ‡Ổii8DT.HCj=~ 3ɮNB!לh$CU܏6*Xp&{%Ǥx?Ew_e_$9 ^\18u?7euAv\ho (A1ȇ\SF+< ʔPfN&D? h9e㤉M\M邋Cf}f)fj`.i\]ͩFwׁߟiO)χF詤ˁvmX̓x0#@ؗm)kPVId#6kdS`> H~^՛GF6X0=V`tDz];.v&$ Rft8;VZ^'@"Ah-'kx)D$>C`MCVTkԏ1).Kt!|#r7q;g]4us. 6KRnXQQDr\juL(#Q6--QoeE]E1H+ͤ\5iڍe[AAP#ou萫 zto~(3uI/P|MaPq7jwׁFsJn2M&&3 @`s- ~}YA=ӇiVKdc&Od pJM wFm{=d\ wؑb7"i*c^>^beO/>UQAt q| G =\+TpcZ2Tok}<%¿cC̾J!S110nvdS7(-$&2!aύv-D8Mʚ8)[ȹ޵7^:DqǏDhR%;7[, 9&FDloTbT]+Ȳ x (&k&/3Q#E:髮RSVubtK(Qagb=lt57 / :V:KcxMԤQ!TҎ8ܰP&oIKu8*9g.6@l[ylO(`V >eKɹ(#K,PYfuc|/D{yj ~|Fإ "`:W 30?cOO6L`` '!"5,O*%a!|X:W.Uq["3̆"Eh;yɓo.>M4HXz JNL~JS76AJy[;o}gE`WbT.$ ;T#)œm{3zf0>|c6`46~ R >hӜi./7u-lR2^˺)=JU j/?mWjF"R+^n&*]"t-hFfNOc'WTtwG9Ivw6xY;Hjp CCMµ 09#yIO_32pceg@&99izB8SJZ*|Nj^.8bXn:nl]Ek\5aЉ~w]t†>MYQKlɓH #1 ΠQ0(q+I7XR g.? fTMqs9?|jnj~/_cVLY!h9&M.oRn T%(Yfr(+QOQ wHMZyKtc8~Ѣբ,EK%rXXHY:W U-AzRqը-jt؂*VV= O KaW9dIO4/*zV_R+=[i,[M[+(nirP*:WRq]b^ 'X8yQ[6Iuݓ Y5H=E4yDqu0=;O'uP9T<յ8N럠YiN]vZľGЪyJԽr{:,Һaus y/Pn3<Kߚ߮y1u˺'=eNSꞓp]]uTκ@&]j1iTa޳ښ')nYfBƬQC% W,1Ů*U20xL}XقB@l)Ѵ|6!3ċa-+ Tx%8~QxOWyq3C]<1y )TaCjQل:R+4ktM.h4dRL`#jkNB4Fs愱6[vѶ<55j J2i5om}[;ꋧnx%'>l>>~M] ;UWJj4%߷M܃[ƆKرAv*. !pvq"|`yg(E(`<3% [QǪ\SLWX;;ݣFM)r &-%W@iwvD1KoD Vem v[u% Xv˩wc{NsDxa |IJciΊWdl_C?ۨϷ^5j:f[L? HT3[Yih5_<ζjځۧfF"ڱM~XsԘE QR:H5GA|^t=SڿesY'|VXL"^x*ΖQ [H_ Я %}Πe n?7rE(bմ6֑`IsͫvV=gqM{zNxˮ6Xݨ~[xirSF$X@]\Ѫ!n 4-5e9^%-(x*"#?Ʃ=dޜ0hGS?jB2 @>UP,bTU|^A>s)P?1fa}bN$~|(;=EρNG38*fmDvF{q.{{J1Ridaf?KXT_ o[LAnzѱa#YS@~o1Xa#BBW㐞|jQm]x[y%*0LGgIv2BM RD{JVD*a0ـ^)êm%0y\*1cGNq!m6򣾴zPӫEI/1(z}+7}$ EN,]Y_]|,1wO䨎 ltMNɕJǍxFMRύFI8H<t^0}\A;;b^f] $o1hi̡ԨPyK.Ƚ{xIk&hN4G+[MA ]WdeKΐMAMKahgR7͗͆$kZ#]֗$t&V_`у+o*oK<ϽU/Xqzq8V~&뢙4߈y~q~sSj%~T^̂c(cvM#L3ٱ<9,NnDag-ͧEtM8N\`'? S>L^8!: ߢgZA)(JZBQ(q)P,i2gO`i(ؚT a۞"Vߒd%4 tlI5Μm4P1mݜW4/#8 3/(f#cH $ h a(tkd4[´&LKm:Gf[CF+K9W(f/vo{ wt|Ѱ={᛭b8wSh-E㴣ERLȀ֖18]nD巋]Q+^vXjhSI*W!r'BB?TF &X?(^NRIx:vO?{һA6k!Jԩ= _/ 2+ '\Ԥ8c1+J^@;[$RM9i^PÔQrp䑧Aj !A=H)~汶5h[< M;y maG(zks"oK(\:juC7tf٠i7?`2JP7R|e;{-HXqk6o^G vO ? &&,4qFy8Q} sxDX]ofa2,,w޸sq{+k47vNm^{.yyX̭~Gږ]> 9A=Ez!<l [%fJ">wj=>~ :}xp`ݨwg>-&YV%PKMonZjYƙѬz;.)Í)\:V8s9u6yVmim+FRSw= k4j$~l IrUWj8b9UU?sঠ<:dW7`ʢU EY.&gbrgq6u׻jz{Hp-rbC&1+@җ[$GWOAI3R/VoeX&>W{XAl9J2vYb}YPyX$˶U]taxy#[PXFp*LϽ{~*yo "P-_Z˿+EQJ}^HG\T q 8 pt0#et(GtL%+ Ë>)V&9p z: 䢠f̛ݽx,CU' yk.bMI氟G0OksR-5VKMNNNNkEku9U2O{ty]tۭ~;%w;G/¡#_ץsӿU+3|erN=ۇ\/OO+{HOX?d|ůLz= ׅ|R5,9M+BNQƜl4 ސMWV0oRgwH8N9FӈL+ U:S}eJRѭO嶺Va7ۥ{?_/)'4..EjeBD%XY"DSY@ԳQ N2i=qj]7&jI79:f,#SU'8PW(VF*\e6u}4Rx Vл蒓& aBs)$ Y1F 1&yD^E(y7$; kk / tAleΒDtD_'alk[ڋs#P Qֺ?k;ڋ>5= o9ss΄4`bFS.:qjlRtLq|M5.&GsYjTfsXVӾ,HS mzW$< #|$:,fbƏfVvv '}TEH^E|@AKFK^m>U4\asYUe. @!!'j;I8RG^_C;RH0`Sc',Z%&5򚗻 Kf\O>pEOԟ`.n@!"φ7,?ϜA@8$z~D4HL(2ɓ'Kɓ^ lД@nX^kAݗj0, "vCߪXzpthɤ޸te4)hfkimeա񢾱q@S/?Y$?ce:}#?y`\6N߅Nc|(<4 Ԧ;-~Q݂ѷ0 ;m~?cbw}g U997B& ~uUҐKv,7#(M6OO[Řdnhiwd䓆7<#dt/rRκI#kO+wYR l(ˢ+Em? yve]ŗWQ H6?)g˨t(HԽ>?fX=JBsԜU@Y @dZ{F/0S ! 0s:q Զ\W>6JԪ?{yvO\W]ni,tD2[R_I՟ק@=߷&jj΋j?ZFWU~J)\+{"ܱk5]KN`"j@[>C8HMh-frY fw b*s%Mhf M1}&9OQϔ )h·~nY7Z.aTW 69{s08{VqLmP7պẾ &Z =LAf" %/Fx-P x>uyuUC2̖Vyt4*8e)9|;rHz <ּCDjL.TMdbkz5yoM5kSDf/y ̭0^!PR[DcbRecmS%8/V3*f896Q,):,}4sձd2q s]nH(8Y2-~܅ѰNaPXu틴_n(3=V%ozJ5oIyK bV('h[PKA4XBb .org/codehaus/groovy/antlr/GroovySourceAST.javaVQo0~W\*5tϴպj6uTl;Z6 Đ@Y@w}sv!G1C0vf&ǹ(]:,W^a'+9)Fz4n6R*kkŪZ NO{p ?b dJ8BFfo06CzjB0]ssn|Ay%t0YASQ*!A~n,|BR}Z\A4Z`sg6HE zE9Q28 L|s7f0-jbʥ\%5[VjDȮ%po/zNˢ@CXkf/Kkg~\YM|42'zKoLXb O#^nbtޒhno*:9Ⱦ:b"48p[W;ZKpj;rΨAB8E_ZP^{0O/9Uݤ"hj;3.W*) WvSBjIbrU"-"lKƘ5WBıI'`~b 9%Rx5Ju|F/['x:C3/8<¹t <5z37tNAAdsN'DDxKӴE:o!{c>vۂlƆf̫c1yn7G* 5P$NWjc5`sO: Hkp>ל-y^yEӄ_sGWm;&DžW%;ZCbL6BDxt:O?F3,pO]bG4~:^'zryIBokOK$PK@4)org/codehaus/groovy/antlr/LexerFrame.javako{~OTUP4YqFahȢJRy"3d;iQ!p83NlʼnTp!#fWJǗ%&VbJe={d!{2ayZ Y _|ΌK׆c~z/>IiΥ ?[1 6'!Rb~2a#̬"SXYK&6L]{J$r XE̴&#ՅbN@GD\O U:q@๚0pr_3'o9B8Aqb[F>ľ9K-pJO1`swPڑ)O:*dDr\AՅW\qFBxzK6quv^G`z/F*m"vsRkKʵWYL gU' ;cBW؏K^*χ0cd%r3pi,xVMZ.HX i^$#)~*M+dQDcɢ sMy??5-p۵4/N 9XjMQlǜiQK9,Gx@ڔ%v3%V+lEV%<\q H|ɲc"&>K8m8G}% kZ&Hm};KlY:A ݍՅ7TkV]075z/=5SS[ |!K(b<b,We sI>=靎9!҇>( |  (tSoxvEPW3Z<-ѧZS NPT)[kH#s0_&@V~/[κO2Ble]_5S+voE 6O.Yy;5*0*x#@%e.$W. 7<JJRv Vw -}pv^4r -H-l-5:+?67UuJ6V?:FpбewhކY჆%AVNf1 KKj`G}~u n|0嗨r): 磻d4wUZ (qYHu]Xv\^; v2٩J5?vIy{ 1r;n܎xb/"lcg7^sk[l8uk? nwCFs3]6'42X˒vV٭b˾ 'E8ED{\xE?h`p7K"vH1ﯝ`OcqwO-n(nǭWw9#w'f9f |8O :W xsyj-N6\ZX%R(yKhVMQ,<@M -Mzvt]!g VpzEp*",]^UI`>!/= U<m 'D$h{wp6f[rUPK@4q_")org/codehaus/groovy/antlr/LineColumn.javauTQO0~8" !a"´n2=%ڙTsbDRmw}wNt|7󳳏 5.70aڻrlYLҁ W3h;بlRY( 7pO1X-sfe:G斑;NI3k(Z!+ɆJLt7܎DKƀƿT|,'B1M֠4T#٬rך[.5`XmJ;bLBПpt88~ɤ? o0`<Ά@߇ Ey)׮ɝ(e"6($dryc*MKRB-"Q/q5Dp`_rlyWWXixZFjZ` Z&d mr/1$I\KRB w}Ya3A1KƅUUk9ep՘ˈ] +?\q8$cʋ9ubH;3k\MiKݽۊ8Z*L5Ss>n*j /KoY^nlב5Bag+%=:k3f0q1;h Or}GаrS"JPaH9AÂ#峅#Z>0r 5=X?wƞ0rM"K8_Q3rH<`b7! ֑k[{gqs|yse 0س1F[Έ_6 2dʘ-щd鷯k48[\VfKTކ)#]t+C@K),ɁčB  -ARJnq'!$}(譅#ɼ-p ? `NLC["UZ4;T޿/=]@?b$rֲ94zl3*H>if)L8Ie/ʭ(?Qr qS^X]i坚4y[mjL2#:.W6. J$wi30j~y)" (a/wzzZ< w# kj/i365678Q!gdsZh  l,ƥІ55"J\xtNr/7n#n)]Wӌ3~1hӇ~2]` \J4n !yaJ;]3a  jR+8D;R' 8NySbF9'ݳCqyKo~҃;?:t{ JE^=u]/O@4N]lfD(JN JH @1=|hP@OȮcd.ꙃ-Y*zưs 3 q|ӹ6SA0kEv}C}ܑU:ˤE].m]: Î8Ma.$mG)I={}su1ka ?PK A4!org/codehaus/groovy/antlr/parser/PKA40fa-u1org/codehaus/groovy/antlr/parser/GroovyLexer.java]{wƶ;/rN£ $'v,B{lȒg{όc,AE:nښo!{g휝~q>i~Ӟ5Sx>5u>~(Y{lO\ݶM#A "R'P>unEhv qۑh(ҡ$EF*.)@BWw1;'D!nZڄZ+w.ӈC z'Tu}{q2tM'ϔϐ,BZn8_&~Fnu=D,.mvx3t\:`f#=%/}1[D8'  !9wK%haNϖk7oPvjnAAmQJg˳~;Yj{j"]~Fiސb$n˒` N :Fǣ[N><sS}1k&ѯ]~yxa_v 3{ϺpKnQPCVCgzY senKߝc>`vNro+FBԮ:09]s/lԖmm'r=%te `" d=pu}#Bx39-ѓ8h3f%\)Ke{Z".:1%Q-" 6&:Jqt~Om`j׺DŽHeCyê$m&~`xC6*6J;l"lgSqB[ D4CB` k)@&fqn +*ZWZ<@cAdڐ9t ҷƞ xNƬ>BH)$OPBH"yjP>`0y\"GRHt܃dH=໹E[)d /g'n٫~\lAG"Ei6epb?̦<:weʶBQ+ԔogA bbpy&'7уh]hHPZui5xnl,pԭUlIQ* Q6U@lȖ8Su0Q18S5UE+6,MSU݀lh1T- lE*c2X&S[)R$;WnLdAxj`Uo&tj:VTlrhuѝ!SCWܩj" bէ[kSrvtQ1aalRV&W*S4r1*SJ ՠϚ`9 c"|DIwbn V%o8TK-`b@_ ,!=2\3'8DPA)krѸhFG0t6c[rfx6W!u\qG&Pֺ!m8&—Ckd 6Mc} el֚w0mn4[ψ$I{&jç2._EƔL1\wwy7tطT^0TJE%8gI& v]rچ{NF8V+=]<ǵUj4C+PL"8a+K[J*lR\cyd+J-;gdNA=E qZmjŧ\baVc!0=Ft\_{|\fEsraؐ*Y,ChfۈžP\6%f fsPLnh2[U \efxI/4݂C&xj 9}#´ذ/ECg \e H;̱Dv?b 6}|#}%ɚp_l I&8)Y*[2EY."%"|[6-a5e+/yM5 6vWJǨ4$q̣ de?$e2nm*qn5zEZtSHb:_^O9u01`kMLlGg;8pgshS(GzX^r׋!6cduN>윽^vu5=*c*@z^$WK?̱?/O;ǿ#~#!~c5%S i__%W) ZDa+[.u86czg^٫YJێ;ԭCd8@a(N\RKR^w/J UI*V%xA&yo,sLZP%[ݩYw/ޫ8j) bS2T asR^l/O^rhvO˗uKdU=e:/5̮ۤ?e9vvsq$HۈLҞ)UwP$>J (3Qe_./qX]nH 喻N JjEI8j~IW*܂+%R+%/W=z6^=ގgP(\9Mak1+DTZbY|rDvVlJu}O+(Mt;x~yKgyhbs!Q?ƛ2!_fimbҷI-!ޒ #l§QH|`}kBF_xL_#HnsESP8Y>[k/` ?S /ݗ?d @C(Q,mq_/ZLup|&VBy_?[@<ضT4P4v= ]@a="WHO6j!?Y y7{_ PӼxy2zryw)/ z(u;ߣשP 7vKKNvءy=z^6h;I<۬nl̕@..c{Vs&xh.f=Q PӼpQp)?D^ ˍK|`؁ynC=N2 W~Ӎ2]iMVGKtEӧ5qQU펾x/E7 Vs /N54j&G90=I]T^ ǯ&1_jA"Y{VI=7U24ZRp^&2~vkvUN&Nׯss=0c_X PӼPy&R`W0XޫKq^=PcaV PӼpyPp)~!q][P JEv3sa2T:˚H?V #}!?J? S #} ܨ ٩y(> /qsCjMҏBUH<]+!S8úFZ% -k6j_VZYunW+do59[E7W@"ƖGFӶiOǘH9ȿ91TLYMuӥ[/o~)&dWJ"͕./7d4Ŕ /b<=C W`(H%O?:uȇ9p _kQw.Ǧ?!Tb|}jbp tn}]91wqdDJ)¹xZc4hEwex"}.kb5Heo5!!rd;27|eI2B:ti;܏7Hu>1]F>WEcI0ʍ=St>Lt5+ +JIJT k5~ߒAW:8Ox4ٍr>+3$fg"5]$@*Y'tkIƑ FZىXrƻNlfS."Ȓs+4@"ÖI 8FwZivϑ+ K'G&Ԥ7J ])-&jQPי(c$BX#l'6`ƣ]~jt1RQgXHKO6 LN g{QTaThϴ˫IbFu]q`bԇɣj#x_f3Ô)?8r%V4?N-mV8)}y4&W$<W_'2i7ҦÝ|A2nF 3l}d5g7:&/mJ۪҄u(#$P]'mrԸ泬VA=UeKhQ.`͕ٗ rfm>Z^!nh" |ے/PTp+I?Jp1fI"XYe^У,)/■ je`:L6vw дӼ T06^äuVeG9UA4,pg'f5$!~z 2ɭR 2p I+,AU c^zZ^x܂_&X:b(l'6N7 ]%:{SBbMGZ}J5ei =fgs^- ,Q1"9,*9NKpuPTnuPg^JY$Y;.4&ooA^YB7@Ğs4AOԳ ɖV(NaU 9缼 -PmH-r6j\es!~^ٚn2 i&,}on_iܔR=nhy jO`*%0ICN:ԣQ,۳ ~OM=y2c5qC "6Fn”o@ʲVXWTNET/>Sװc*B]R4{Sj: sڍY8<,n IEސbUx3z## G"U}q&^%D ܓsDս2)g6+1P,@ H m H 클;; 4 PA:jvBT0$5\Ph_9]*Cf @sXb,`K(`IKRs, ,hD%`)`aʐ *\S9U9-VX 0,;#zMAN^ 1l+bkiE]^0S P%0uPD»}@ Kv)1" $w Ӄax{$ՋLP*G>%b{Mxα` QM2!&ԀjP$=3Y9h|,O@9'J,ѣoxXZx[0tXU^-sd}3˓O:w m-I@k\ϐ7_x̼t'\1-# ї{Y:oʄnxWIvB1P%nc#;5^2r~D͠EaP5Wy_rM' % >(< F'IS ,`7-SeDPr+ 5Kj/<v+=ΟaHS(6"9P $ ;MQb({;/FRDTDٸJ@5B (ƍJ;bZ}\ύG@T,QDc #/IۆcAT0$# )n:QA CQGhRW(~ &0NI=" >& -)~kpn;L.q^-(9PHYÿqNLsk !u+ U,6*Ƥֲj!;zC3:t=8G ~ 0`pmӊeimΙMd' j;?F0_T9FMJWAWOWaF c~h<1 ko:OӇcPH^@_YuK/A-R}3|2E}Y#2"jKA:"#n;IL$ZSmC|HdFĜ:vFX ْފelsGePSj_xPnП<ks#ȏS&@yjgHtzI3mUEgXlf{z*J &J&0K.ޣ,UZ$ 5ꆾBєbM nL{Sc+XmWO$-M:P #Βwc]4fUBY-*sR( ZFVQ-${;&wgɖ Ӗ+25Yps칻n53bO])U_Mj/pmKŒHɳ[\l1qLD(s 6óս=G{ x< .B{ Poe{hT-BJ:)ھc|2s5\vNKsC9Tog+C[uPHm]{\LV5m !m=b{ts?G98ä8؞F&֦1 G&Hk#}yobF1F!Uz'^,[dF$>dٖ/ )*;~/./Dsb8B)ew'h ÀhQ)b>R1qp1" 0:F Rģ12Fl">XO $^R'HOd<92p( L |-30O ! YEa,] h&O%X&Cb~&xs{72y5D;% %{dj RJl]!rq`ӁO6~*2xyd10pxuY46,-qo8GkʖXr 5Wo̠d'?}<'%#''6WJPvy 6^;xE.-)޽8줡dru RW??Ș] t 3^}an;ԇtr;w[PVIl3C÷ATy_wGB2Ƅo Z1҆C  ">d%D(X+FrE\WeT Բ+n pX#+A|/Gk==a~0 |ESx{w,li[6uѰ?O:@$j ×Xw_s=kjfaCswVoZ璘u< }Ը]a!M V}T&3%w7JƍYLZo.Խʆ3S:z>hdnU98N#ȵI96u6(o_mW߶ЕEq|ېKm2f*敶 9>h{E&ITDmIRCapa@?K;i_B^(7٪ԛnaY&1ߊÛ"+q)u*ؙYBSꃈuI$;fbgezG3%Y°`,(BRS1\|&sAC-W%|Qb 4s~391i1Djg&LRq#_& SfTH ?k> YbIdJ0^BC~B2:#6FVIc0//|)ŠK9?xӉ6̖lGJ$ c"F*s[Xڅa&p1U[[` TߋT-*e"J,np/+s'(~h3|{vVŢWYnD^dD$󱞊RQآ򊷣Ss  *2IRڸ~aRͶ!31[X'@Ƭ!Kȯj"]r?9!_:js/2=y_zƞrrfN&:C+|nb h6q Wj,Xz8NA|tvs|=ɏlPSDpۖE,)pҴSb`ŧ0 ?%A}'( ~rG"8^`mܞ8}L^%XҥK}XFc 0GHt&Sk"}؆İ7] ?o3cFбc2VRNe+njHS fl{onX MB!vm330.DC F*氼9X%&ZINȕ('F2՜L^'7R mzxvyNZmnaPN_|AʒPYb-Bd2ʫ#&jY$cgUzkufiXņxuM(Sn$mY0Y|TցaaMYd0%Q8Q*bPnv4ݦ~tG[8ooԋ^Sr HWHC]α-&%~rXlm4p)0g޹lɰ ݭeT-Hf 2{ƺJ?I(}#MxdT5줦s;2R¯(,85pQҌ?2,,j.6ܷʦUبң2% `Nفpƭ+ ζn; sk'D iXȾr57S&askUNe!HB@Wl T*)]R#'dprN#;i.g:WvAP[RD8/1)VuK 7PrI[WNd>BюD ۦV78s <_p0qަn"_Y.6XRM;\(c j]$N[I(]Xg4. ܡ\퀇Z +ߴɪWfDor$lh^z]\QL&Oi33vl?|l[_y5ڋQd"v sW'OkjP/ V@%YNmO+5&lrԶsgQ9AAGag=2o唹>Q<1##J#Dz. 9DgD&FCA$)B)ഐ AzW@ }GS=c JCpLE83mn yMW sj;(ހu-0}("!|KwzO@ED}s7c9$[g >[۱KL#=];䊼lA.r*ÒO_WܽjC%%7f)|_>w's$e$0pPdLG.lQΑyvjeL#2С2(dP-^)tLrio)FQ,fy8<g IKvA4cDYt-7o_^+}( arX Uygu>=xP(]\b!L`xB8m!Nw|qM ㎐Xcw5)_sG+ZSRYo")?+FקׇX.IQχ,3NDt*2;MSjh|k ϴXj-}-՜x]7"7&M+@87΃NCN1o&.Pyu54Fg\49 iCG6G0P+4]U9X뺶54t LJg{ 0 'ܸYoy;M][D|"g62Oc gk>X w-45'xUU#7]]ReSX5zDmO66mPc|M\wDA i [L-`fNuPń lkFt6u-lvBKT\&5^K )ݺK7d)9RI(ETSNp~ ]H7m$J-*87|5[|dP֡ ]jУ>PDDzYdJ.jfb&W3900[@x  _^SDCOɁL#Q_ ?`t}xr#6G{Φ6%j,iTRTӢ]qķIdkdmk!bS>&|}4]Kj:a (lN'+[^^Dy@Q R6dT~(WPf(?R(J wd4f[w99hx<DYQvhz㯂uwiAnRҊ_4KfMW7~)ZcR|h{FL-*{.anCIjcou{sW%U3 #Hcg1ѥؠʹ&@ifW6.SEWN_4 PRXg9w2 YW̕R@ I֧o"_ʅ ̜~'k5Y]O A{j&^&Rԣ'N2T749-b:U]+4y ,c%F7~bʉITDa"@{$6eAFgktR200hĜ!o3_(gWA/Ou%IB/U:DJH-|1ˋu]|?2~Jj|;'3|_d]ǽEH#LK'SJ)ĝӳQ>$ OqYܓIB4a=NPKV6ywc48wx-Ū&qHU klqV&&0]rIjBک]}M.ךʐ@*5w ]I#mAp9 9eP&WG_șo1h1/cΧa"*CP6tAִUu;13 炖oPVn>O{oƑM}jy-Ҧid")5ov%@FزgUYY@eW&"_DBx43[SWLgo>a<2&z@[e=% e.#z7úYqM%2tC,UzA+D\%~At~ 7MIZ}:z)[7R"ڒ 񀺙jz H>xD7gsSm!0Dz;<8 cL.O3,˴@[ ~õUttzO+'~RI:te<9֔J>&Ҏ~ {?0)+;ً0}&/떚Q7q71b{.5C!sP, }Yzy7E39!n 0N6 8 ?A` –L6eĽߐw[JP]L/EO)3%d\zt ^+$qQNX7'DT0~͒^Qpwd8~D aZʇx4me?-f >M鶶6;8?ᅨ}~KO %>OfVshMsڶ\ s,{]b?hmivB,8' h2f ۤ;?M#t*Cd@!2S'lîkEaMON9{5q}\'SЇ\" "` :J`l T`/A d@0 07Cx?| `!* X Z#2` ja `":@?Ap1"@qIE6VHv,R3 4Avh;TץS m Hw$$Hfg!h1蜃A9 9 9;#;C=c:=}GlDGsba6,5{  d޴2[фނSsxٻ;z;bԱkc|}?ӚlJO>u@B1%72{|ꂆ_]\ӥ8c L-ltXHS]luBOeJqv`/@7y%S OmvR"k)9/经wMY-[SծcA5\xn tUfM9V=z@X<@}}+ӣp[b)7 UdMTpF3h2sHS]xCt}u`٭m@*1ZgMʸ<`f}MWGpT? 0_D=] Tk&wi%<@sVoE߈ΈP-LǨ7`:&4(moD3{`O[mmlOH.'5mR`ߠ !޻5V2wpnߴ`;&k`ѵQʴ)Y1)WOi '5-0/;gK*֮b6QF0\);EqVq "N^,zn-?v,y.{YW❐,+L(+./f16̬!ନ%#ڒ7:_2\Ҷw;bv6G݉ې Or8A ojſUXx.PddW%$Nyd; 1c<p?Yd >W*0YmEyHE= 6:O ƶR\Kgɠߔ": zPvhrε弩aW“|{S]#5% UT=)(>?re4vLui.+lջh#a|z M445 z-m&(G~ KN\1,4&sQױ:"^Zȑ{=r/{ܫiVasV}y}V ǹA֌i=l]k: ùWC ڝڻ6! qzeT'Xm̲%;"֌x \5ZpNj]>QTMb> ,) {^9/ղ 'k2JL6m%S)4FvRZ ?amtgɭձ\;n.cw@)m\CH>tEmKuv/7(Q5׽siJ/1N2;xpٗiBSi] cVtmDɝP҈ݴv &˳&hcI{NM!"[qU `iX˱ٽims!d\* ڰI ~>xq6E%v.!-qw,IY @ANˠe] &%a6Х]ku6*g tc&%G3A+K`^XcqJGC/tjo6&FY\=yQu?bqfeLuEQ7d1k&f4Yf,̋죇c+&*fp3| +0.o`o %dõtlt6ݥph3,g6ܕ rd`'6Ѕv`s5u r\zH1Iq,?LcSlc~/|jz@GuHzP*aW+Zα\^`b1d ;:# >c<ج:ܜwGrarйGtxG~mWmrT*m#'ӖBD[g)SJBֶeۈ5'b/Vմj9+oތ^t{K/ߟ]4mA5%VF}"JG/ 7]"ij ZM଒]`I7FV5圇 , H#t -¿v'g*LW xr|~O`sN.5 )܏Х85\i^tA}3ntgNV?sՀ3;s8L!C-'m :di'o,ĪA%XeNfeZ}%CN ꎓ51MfAb|c]hp8uF*qZkGbg-k4ive}N-S)]M~KEyjD!wf:L7xuDw T@]ɤ9#Ǘ +6wa ^7Ff"*~EH,Qܠ{ue9HY F_2}[f̲{6bq%,}U1pa_Š-/u0zh|l3 lH¶榿5>Lѭ'P۔<J |-=JY6OX' =zI]Şp=QiLl,mIL6Mx?r_/Uy%0AzN׶~NR>BA^%??go>744,#fvU!<>ɩ@'>lms%#&8HvHj| =#F Tr@^p7@>F"k3ǎV*Cl+9eS2/85~\\ˇQH0^Ty幁Hh5kZڇ0MBQr,[38}[ህQDcJ Es@dGr_U.^wkm>ds- jƆwren,6G Z"A 6gtRj,Xb ߁6 7 ЗDOsT FOiZ6[7Kv0OABNg͈!@y!3Dˢ-d*RMhC:U2IA<FԷ~Ldm?!$fFGN'Y&yW,CJEɀ*M#"t>O?6ډ&z\0]fDOy` Hit6 k]$4D?yDl]SoߘHKdD?ǣt[=%*a2%VܶD0m4Ј;c@m*څ>1uYobn_/,;|ɢb<WLLv)~| Y[b7҅IYSM*pP|;w>=s"~5໎;ղ٪'dۖSyx<6ڠ$, J$$ H{$)u,XqВv?x%[SuT*J ErI"Ýd'ƮcwS䢝3-p}S4\һ"_ġX,IcWJsF-L3*fzw&j^"-8J]ER ?d_-vHR²m, ˶meF<-F~ ANrN' ;h'Gr 7&K.h1jz! [fuyrgvLOԗC_SR4\~t) M"*RaJToSgXְ8[itKQ)jJz5 iv29n@Kl!eaz.2AOe 0 IyZpI Za sހ[On???~u*vr+seo]|ff6c**&Wm)MRJA;#a@Ww Im&]nfܠĘ ڍhtLb/6+#,0'-oJd یywpy|z|5,hCd|Ǭ} рnt\S =Dzuqޒp5z{;MLjX9oeF4ZِMӸ#1['ULyT%8~J;T&3]?' R=gi?}كG*Q.փ''t[==yAHy};ȏ [Ulb{3_ AϤ_~%?SrEVȐOIMtzh[V&i&\u ]|rGkI-~/ycB13!|Ү~yS MO:ʓy24kDzVLC/:#27IJK ehZ 3ٔXVܟ-2'H3ʏ]2jE${~*zic2R 2d>u z@a6T 9Y9YHp$qq[n3Z Xdf5k,YT9QE=7PxkF ؜?`fpv,MtamD<[C 9sս,4bT5: 0@ 0Br@@" F^h# H&H2a @% . L h` '>a Pa@()NA T0aXYW l,hP[rr ]B 0 a vO-e1+6y;΃-wB/`ewJx#齘@kۊ.-ʹswS MX,MYԆ5EҊf1G;wŒgM#A8`4ѣ''5S]1~cM"BM2Mɧ ؔ@oyGv~ ^.؄m|e،la<A7aذ vk ?nհWF #4'>-7t1q\D%3H[HΦ^KP)gW"8o|GAY)y#2) v3t« 3L?rcd&dTOޢ|Hi%i8[zd!O5lgMHV]ˍpdfa{sl#_ t5 →?HZEw@(lC$#c$i\WF4:"Ź#g8# Ic篳hJQlo8k' Zfm- BlΗiq讇X;ŒWoNN/ι~/NM 8%qxMnmjr"d7 8Eԃ8HG@WrRh|-7bM]ّ^*DqyЬ *6ff+HsL>8 A}Z˿ &oɷUmFx쟰T۾4FO-N6B}.HB=.+zc+"ߧdv4Z[>!̯չh G h+~g]"2tI"%A sJυyyI)NSTf\7fیB~<͸%]],E4]n, ^L;;cCVR@E fn@O ߧWߐ֓g2Li֒MثW`hi$g>g2حTīVK@gɞǷ1l<&;{")M!Yg<#Ch/\>f mɑ?_0eh-ĒH` j !#[9\B3+;}R+N); ӷNo^V-Q.[ރSwˆwuu%SwGf3tCt9<%Gi,!Pz/W/b&P+P xB:QX&D 22],6"=ӷA<ϵ>?PAq8,nf XDW x$0P =C%T2H O_Stwǵ7 8 M׮ZAAA>lWMMWMWe)kv,ߡܖjt@M7hlShF;K)X Lrlj0|~ 2W/t˃o0W Q)_R=ZB^XAA(zD(:8/pުv E%5tw F2!bk 0p8 ρ7uz#:&03OȬeªs6 cVŎWl>W~rvrjl۔,w"\q{j|^Q_`ԲjR!9cZ?s\ˊGm&!޶Oy0 Q_Rqf C1> Օz!/nB>"_n{1o+ z}Y^=~.gr}ܑryOD!h<-e'( lY`Ӣ޸ֵ7/}}&Ʒ1mfx;c覆5ѭܾnpmlteNies6AiÄ:CoHųpbH^}&Ք_BY êf-3[,ϑV2c |' 5L7#aܠn $nV!vU $b`ɛմ?Vj്k<} }Q}PW~}@ T@OPl }<>aI77F/`r?2 (\7?ckAT^E~-ܚ.R WQ2B"=eP)ǦZGX" yANuoi4m D:^ 9'1#Y&5T!ȅ<fr͊ťȉƥꄴDX M`R,(AP#(@! Oz@"' 8yp6a L iEfɀMٳxaUCM _߄Lv[Px&,# 됿Q JR2J&Dx$A[^,BiiX ov} oo3kB00x/\@\$ T"ҀFejIcU˥A#>Cۉ'd齃ˀK0מ7j1T]?i&\k씯SVb`%1rɒl;9%~tU^QGB~eQ^ԹN>.Ըu1Uܧ.B{UõenWJ5Ux"C 9"sflm4}mK=;ͳմz 9fr6H6іsmZth۵"z?ķMо)qܺ* 7k8휐(S3ׁj9j l T6Tkm!}eaCl''p3$j5NP-pK2VK,l,-K澝mҰ]ZhݩڪKՠj.@͡R0Cw'-7\녌yLofT:`Fc -W/!Hǧ;YQR֋gM4k<8=8 Ɵx]dªWxET ՗Wy  p &dK 0eE=9VZRO@t a™ Xm'|q߭z2:SstK,=b E[1+0UtVPH(H+0Y+[o+tt}lU%x݀ g aXaeOSWuwwC-3f-YxEgp<At.`V+^0ʖ;ԃST|=r}ϒnbW!:g!OIOV@zel 5Y$+ s@M}PSWƌžV/bn[;¦.PZZVTgcBĢ~? l5|/zG/<sɃZ=\֋T8~z-sb-1:zF [n}ls(pŰ}}o49 F^'ah?~]6<2bEw?b3dz:+$C'eW ofZעd(u f}1a@eu}vd+ 2yc:JRYId&z^ 4Q%5Zdl253tzͻ/k`zs&3cMx.u4$N7yh0v@8ژo0| lʁ3mxS=*ی^3V،vD`ǡUx;j;1g =iT'+hc`UWJ+qSVت r k=JxGj rXy+Ll}*oX867TA]pS{+P^i8bN]MZ3rC*E>`2N8N@2qN%nDoNߜ^?OɦYޜ|=2b `CAjPiv(Bv ve{ŝЩFZ]brtMnќ~&~it]1&7vڠ#Ӿo^O[b.gtX:a *CX(^,O_7/zGFыWNK _l ?',V3B^%wUŜ}l3'D "ݛb ZI&̒zբ`#c+wL1k'AUrUG]s "%|ęy[)os櫞{"sHZA38WeEe-Jʘ-HGan' 5ۈ}"Sm| Nj[l?hlUkKc=| q ,a`E; R%p* oXe4Lژ*3 🡿 T B7 AXwʿ{\}G:htz8)z"iy_ޠ1c5g4cg˻BÎ~ϵ„zO#9b='m.TR[Ju&e.UZ5\Y)&~1WnY-֎Wٺ^WnKG]9Ƿiʕm+6 US^k=YIy.O]Xug?D9*mINR\Rp.K%2F틻r@wr4TSCurtUru%+o||@~DRd zvBe;|o(--j}/nOZ Y*\Ԙ},0rn- }d>M<=(V(2NJ.#t/:_:ۋnow"JMoɼ]%4ZK;xrMI\&-R;zO`9'U2I8J(ڞ'F[t2OůN/Gr_ͯw7d ȗs:]DCwnD$mi-))k.&7"[lT:* Ya1ih}/:H_W\=FQu "Jf&׽CnX4%tת̰g3ExK$x- ɏYZMr 8s6 z懼W䗉w3mJ|HTE^$H< KNs(ALm(jTa$בZU(O^8#CDmi܀RR5W1 j:fhfo #8"UG0Ay Yg.,h'DȘjS̪enK,Y1!(o3rik"1dɚ&Rt'}BA4)Y6Fv pGW@rcKTjd5q7ݛ͹u3߷*Fu]aM'M/,B{5Z&u5!yF`D{SGf̼͙ڌy¹y {93'j_[Y !S\HL"(=P ~drzb:٣(/TL͘c7v{3# LA_P^A$-(h|0p֪}g5%>/?VI{x` #A !& zjlôsBfzNwbK'=T'Cځi u`5%Kj qdi1aKP>xLv5)d;hia4|L9>Cvh 6r6BN*C QsZ:zq`ZԄWUV7q]uBNnzcC|^U1Yȹ46UkNUQ^=uIA}%]W} F+yCB$H_|T 5K:UD Yxz\sAD zޛgeϲY#m& !hoo^]Z0 O˼v@13k7\I8bDVezHrn9P)4&&YÂ5Fp۔<oI$GYJF z\JFLoAKCβoEdܷfϏ_X;a73I+ࢡ_ml{wPt8A3U( j@_~O2P>x/qtDpm {CaDO U6qۖ<"Lz4aG0?ʣ+0ED\C1㌚8'dۄڡ{Bmw F R=%/Yj^7|00͊W Sme+z:qT/RvnR˩[hh/m~ dϦtX$et<&.W|C *@oiǻ$ɌfV&۠إ{l w<kUvD76kZGLQ"[ _&U[NVdf0 e.t>b:3Q{ C9dH=hw,?Փ=!B3DǛ(RVMުYʗ!i[){Y_'* J#5e.n6))I!-AU)-{kT2Pb,~HuhY[eâ[0f`sD53NZU_xCPfgFT ynҰ'b ū8W64ׅDV[ܓYJ!Z#ǖIUi|-֖I7K/dϚ3kz"Hr?hd (GR<=VPyC*ro$&פ{A@v(*3?褰ҶJ=\AK[]Szc@+"D˻kx>h*1+u[LGɼ~zm!>ZWQ*a|8blx?pg]7r9a<1-)V`ZAN РROL|ä#zgLQ8NoSTDo_xm)y-jۄ˘1U-rԫ](<8W܈!??A-*8U*C뻼i3F fv)UyRm`lx`;s,ܱ%:3kN+%!ر_2L>7Lf,xI=T%tUBå1C#Qce5n[aX- 6/t6D;Z91KT@L&ɣ'F6]Lk?Q9u'ZZ]̬k?ВڏT~]b~& uHh/rL?t>LP٢vw<;# 'ʎ!;[! t{@gg` ̩ s%}E1PI=a1X0Y2. ߍh8ț"ˠ *C2A6 yG>̹Bq?Jo[2c)}aG:d0b7dHR@.z2ZccMei݋Ԧy#xNOŨbW $w*! П %%@/!)Oʁ G, HȚ&p]LFx5"n\Nɱ",̈]FQp2ߑ)ilhO5~|nt;?{~6$+:fOHRSj4ʙ=n8F澲hx=:|C.iAM#ƞ;OAY#̷I|3)W,>x2b (ٝ\Su2{k"yµd;6 @:ۙkd=px75pI{ߟ<]ꐲ^e[ NR!R%$("4&NzH: kp q8, 2P8RuE,`:NP߬G6 P;{'3 -Pj08Ńwi|b&XKxf"]yX*jt/crGI2'+UGO944d0Sr3oȱӏo8o `'=MLӅ8_dtFA2_Ĥm:#G6}̢-K[/Cӣw8J㛫[:AL?:/$"L,zU谼 3(}/ш]vVT֡P%/o%Ѻ?n}Lj_fͶ[_6n]ees_w[>_O-2t0+m?x޶s[ES*9dQվj]\\ev>)C7xq_Xrx5WiTWH}B_]מ5E_KW.9_Hm| ՋVX9 ,LMZ|*}ż( $TrHZ*ˉˁ.ptW}݅{GG_%,"ٙE:ٞKN%r(DI_x7z<~LeѭTq[3.ˆf7L'?x.OIU^*Oۑ(|:KB>RזhU 3VT|}s|zR4l9L4鵻K2=lygt~0odY2j%'PRy.KfvdgPdPUiB5 ^#')Kߑ]SM1:F (H>"F #cvS0@eOQ?uHB#0aojsZsUKT[eqJt9NI{'oU 4|oVw)]B2/t)=O@BC$HGF0fısrl$ 'e?xTy>GT@WT|h?0t{4"t8PKMiTfj>mP"i(tk0Yԫ, N~aTHTCg^moAϫtKGZyR,r-MԉJ_|pzsC Pgbq[f1t~tc7Ģ̯vF5Q췒V^Bٜ${?M/}gSzO14o< %!θM(nFeQ[mvm6&A\ؑ]2af͢Ꜻ;vU8RئصE˵hզt1;A1C|]R^,ihS?*vbE !Ǐ c1H8` -  E[UJ&եx_ޜ_'ǧH⴯O9>Q Vc @1ZVoN.C ^VQ,9y;2^r[4剑U(-ʦ{8nl%B/a΁2$0x %d5`L~Oؔ<4e9YY;N-88k6/˳Ƞ~]potv!# VWFƘTBjn6ŌQ[ZOpi|hu a@9A+t;"}y[1?HP67 o}[ֆ#M8L8LТ${+Oܱjc.sXDz& dڈU0M'\c~_%j@y*[>NRؤhZZeg3@3i.ܠU.% q rYrUu±iK.klwZ}9K.ڬpu-sa5_syy|L?0a׀q:̚sB7aI i&C|YL]j1y˘ۑѼ1J"6#ڰ8\аv,sG z>a/OJc(0fg0Y>z{+!ј_x~m/#8k.NYIvxYO{͓L?$bzhFoQT̆m6%{IF% 5&K>G;GD7"":MV4K',,&1kPW{eO԰; /a4lV)lssnעR1_6t3Vh\ N.X{i*+y;WoB$oVqqCϹ,‚;H"ipgCj ޴KΡ`Vir3O={2k/m|Z膖Y*lR~8Xq5e-h<;wv [䜓g䇟#jꘆD_#{O?:OV^A`ZV4.m%[Z,sYP+2M h: ɘ_wx2dN,,14w#r8Z1C%,HRIq<@ RΨ])9ɭM_`)^} mU:#ESQQ*T!Y!G'* [e<>f $ p!Xv^W-'G^zbO? EG'"69!7UgVU0&^)%R(4Зsvdc) ^>g˞RK^1ȥRKS ͬc`(:/'&۷K, a{f) i#V| atC̲^T*vk q7,f [x6޶{nY i)Dބ %p6Mq|3 M1#rČ5$M<FuϾgaژ{s=#lmڛs 2 "mNhJ(!fCw5vM#l{nEW2L-cx1FY Φ6½B4ӨDbм0ϖ%s7+x ޽7н+| ޹"7}+3պ1d :D3poΎ.1+s='}wMqhw xw͟{w~ЍvdA:tdzxp)d~dy:46h6%woxt=9fvMJS#iE7cɐUǃIf|`&WIt&<‡x|ˈ".&s};g4J0D ux eۣT>?&PE5W,䩵$Iټ}K}H"RHdѧf6NҧQiҧcϻgѧ_~%rϯh;vH˳(޻e`ސOlLo7s@1^r;0zͽZko5*$x3wӫxθ$]2!S!z| M=D՘Iץ uCJxv7p=d>Է<7^KЇn">f ?9Rͬ<<dy6c= iX#,h8іl4wPsӶjZggި\KhudzF*˹謢@Gf)ԚSo֚sfm,:ߪӗ 1M l \ ڰgi˰wACj5T@Xw\[;Bk20ڕ\5`҆]AG_Ɏmsh<5&k༥5Z`4 p3׏+Wlu``=7OlR{;MlJ P+x<|M.ɛG ?GrUd% %3%df(Lbd~(-e%앬STz76sd6OFRy5#|dřDQ??2vI?xfjU:yVKN`:KAmN9'MmM:2F ON!Ӌ:F)KG|`,YyvDTP7ŝ obև&[zdn:U"!`A-xc6ܼtDG4_lY.n>Jx/FjKRZ{j_GDio)pL̀ 8*եz'S#Q.ډ@^l8O '68Dmi_XaaXdmcеRsf]etcfy+Id7J{ND~~Lφ ӏ~{`6r̩:- ))~Q`g8^cf:C81vnK8*%UgiBD;r}B1<#^wtpqy˹2 vT(:+#tUe)J 0>@@Ls+rL(yݘ}aJ]Z+ջn C~ql\ q0ybz8S-I&gWhp¬OijvDqi:_pQX,OO.~ ;i]ӄz% BIx]40W'q?G[70QfqZ2 E{N`h tIȊ9ijǵ.5g6-D .|`Y)7(YZT!fMbT-,r<]XbN(Rk9/[ $9pY-)_ј:p^{=ѡ=}K'La=z V,X1YJl),-5V70[SWW'60ґлxf$1ovl5摿Yp[x|)-78xr d92[(e;1Ac"AoC$H!Rt}[BK6krdJl"bR}:LE4o~B쮟!ҿaVXnAԸlq]A.sm -zhhpJt#z4ɣ8ՓPȍsXܷ$a^eyi d0Gx 4(Ƥ(36GA)ʣZ\D֍ ǢP;ф<I5hX(Ӱ$݄47Af[w ͊M$'oխI4 r% 4)rqi 2&zh6oV%a,0l ؤ<eMPԓF} G(=)w )Jб>3OD8 A\Թ2; jg65I` ]5s[Ax0TPEv 1<vՕweP]O'LJ#͛2Kݒ ꍨ27(V F7 7%g&î<2+79 ^g|/Nr'%uZid碳Sn͡H@G6g["75ͩU|7zZ3KH?A-G죇 DDr+Bs@YplfmnlJ Ŧ.NF)ss׵ `|>$,ki7ѥO@gm!8j!1GfM - Y y O>swbpZfiI@ZRy㲦 X߾ 3AW8<f+<^,Tѕ/`iĵR׶ĵgmH:Հ55a‘؏CVq]iI[&1nIUlɚq#`C#mؽ}0+" @,n gGuPfME' J jCrzn@RBu!{(/ u |F>3җ(NRBB ⹝~0ť :|uUOD??NG~?=9E'Ȧ ꦀ2Kڠ wJ,C{(/K{j`8[FyIķ\e#!zL/ >tH:IF׋2#j}⒱R9,1Zxכs޵%riͳ|/pz~~J vtr,64јV"ˠ/AkzL} F}тQq?`Bj;ay-:9Ȕ9e껍EV hcjr $(<S%|<>=Px~ql?Tf9܏̘gӲ|$7e&qИ%ЧH+r/UPB ?{P^m%Qq)~Cbc(/.0G9c SvU[Fy9+Pl rWeDyk˱jƅcz0!᠍m@"BZ@( b@( M(hcA hЀ(!!Hh`BZ&P AA BP‚ A<BĄ&(P! \hC @& 4q =H0D 8AB(&DG>tA ' j!k!󞡨?UUt>KJiTJ$ stKkuKꖖy;֪26([#j0r0+TQ[)25tykLiEl})4a-AYw ]mʢ NntI\=kٱ=R71uW+z-Ʈ89 @G!|0 `[' ^Zc3|(k%mN|e_+u-AY׿556פp60|Mh2phJjDt9?Η{` 1J@2_k`ݖ,[3J ywJFyegC2SI| ),л `J&;T6%1iSցd02D|R:b8[2B8O%k qI/ײ:mw-"%SDE؊Sk3SStKVt!1薬1B'2qxPoǓq'.{aFPD1)i'A5O>&m64;hAA av>F- :].K-ѐ-Z>:Eϴ-!F$l9d;s±ulxfem0gb2/˶Xj5p+-g ǁ6Yskc!vx {-}q{/ )x<1 |vpkɡFsgQv,>"DK#,8_)|z/QQL'$⭀H2uR6T%Q0Qضx*0AcȨ wTd`IեFI~oe(/7j؍)`W?~]tz{G]@loFXߍsżXEqtf)̈$OWβpE4&|mTi(J~|me10JK_NQYptAJKsAoTV2`kvKWtϽK(ZwĤ:Aw^dxň{}E$IxD쾉\4侘QFWw't<~$?$\;f)5D~F\D?EG ^`w0ҷk{{D&п|k)&>ףڗbcO A5# J!*5{r=5F$u__|E(]^o~/7jU R'&DdBwKfV?$(IKsgHGV*}XLh['ti jԆ~BB{|^_7txd .{9֥Yӭ:sk8mlLx:x-HV( 3PZ/kYPPE֬v, CNmN"CjN2&qLtyyy훶ȸgK<oP=4il/2y()Bh$yK[OϚJC"o$(5)L _B9壘C>,>&Ʉ Q: 4L$rD)Iwvw)iUgi-77> ǝ~[*t0Rkc4$2>K)тM4Nw *sbbBG=<9bJϧ7td8n1jXҀ.aH >tfvƸRwբw+c}]<-2b"+ "{6-/q`)]Y`hLoEIg'I:ױ9!R+RRJQF(\`1l-ƒdy; xY:ोE "8 bz`htYn|S"u`rHmIu32L5dj_`Kx7V:w 9r_!Bȕv)_ aCz9_9, ,G-,/ W2},t4AV>t@1¬kl@;㘱'~GK'}ݸ2}ĸ`??R|:gїewEE RGRE=D{{{;T ׽(:dR)8SCZր:I' WG'A2]v2ܓ7!CҞ?I仧O"[)SǷMRyn+,݊u ?p ~=ֶ @D"`h d< AMyc+{P F(4+>hPѳ(Kt[Ӵ!hk``ޑ-Q Ca\N=r^g섁a-򚃦) ~y|gAz@˽JK=qc [N`֠TNk;5OX1D4?t}Ǔt@8+(HkarOF>aJ3hˈZN Ә`4ݛ6[懚u5rX'g:P,M>-$XRFMa0g %Ynn2;NP aO1]Yn6҃A8c2VӋbA-CGi_Gw[2jFL@/Ck%4DXUhQlח(fZ( 5h&,aC0s?l5#7̵A+,E75{d@kX)# 5\-m6wPRz! 䴶]dԻ>XYȳKܵD4b칖doKS)C 'ӛX.4Fi)]Ĉ'K"ѷͶV4o5'$er90mhZo 5MfбcsB*z&keډ;qr{hkd/W2_՜WQ+>" )4w7̧ieJuIDOE`jdSGMICLU!!s d8P r]gA=\N|zJCz*]~! "zcd‚z,=?TjQ4!LFѿ.E"֮g ~L? jAj!jY摚dShֻ1[ag|E t1UA~GzyMm25 OM07ٮUf9m'X^j뙮K{%I?<>?!Kљ6^[ؑ2S4cXb:̧E֭lSi!l/*}^Tg.p^s:ggN \zP*^itް iE쿏{gjo^u o8|4[D&lێ&jnfnm$ُ'h{ňggO~~"7 e׾=Y$xLno&_L>-P{Ɋ?eYlq՘P@kw &z}1^W?=nƭ&wIb¢O+`^AX"iŞVEZi,Tif'y_?>g|x&Hi?%vHRY//DB28auFW, 1<gqOwWS9kmYSmsx$51Ea(3+fh~evu;*n_}.֨~ɿT/gw_s??֑ȿ~W*?r1/_B??%AՔ3E *-j({-E~"/?i^rc' X6CTZFko2 .̹^E#Y? PVL^v48֣9PC ֲ5@:EcRc1ʈK>x0& ۑݙq~u'DvPʏ(}ʞ^F7"=c2ZvfhEUz}F5|>g\]Lυ5)SnޫhS<ƋJQNhVzQ[RZaOeҗ /F HЀ5T % Of%_)ʯjުf֓O>;n^4ZլyN[iT:jѭ5݆~U24ǣGxԊGR;V]i7h4V]UnlWkxtk5252f٩+s^1Y{lT5ڛ՚d+2ލVneU<Fǣ]l<:nӮ7z٢-7f*s<:xtG׃`:F[I֛z.lʬ;%-.ޕnA<1Mj&cjcήfUxVE1]!PeյwrdWuz+ߪ0~\pf.nQ'XhU-0r{BCMS۩T:AښUDQUF}bLltdz0fԐLV)glT-~ԫvh֪J;bK<ЩZ;UaTxHd6 vUiZ:*rêqXiAbՂPZyiQtdA{7,V-ƪ0[6cTqՂ(l j-"J. lv2] ZAV+ /zy \.u6FYi).|VիV#Z$8Z@ZAV n/ZK{Ъ!xVm5hmAt kT*VjU;5j ȚMK|V+jK߬Z#*_PZAU5pQ:FY+t.E5qҫ5Q׭)< VԼ*vmQnIqiGjHwŧj *7uȨudad;t+vQikRn,P/B`%QmQc:<(^ C Fo*JBf zҤf Œ: 3VLz@ .V*m|:zJ+mxUzA P*>+v"!^1L If*IGAfm2w.7jv^ey`G cTjK}Q/9L萉җp4 8l֗V ԫ4 bA2ѢZ4c4(8>A8a {hSP0v]-re^5=Y4+rtd*euN3dۍ uk 5ڍzAO &:DlQcn;fjLPmw"XkMWwVA ՘6 m2qmaz_~}-jiD-m h t"GѮP(K=.^>mڔVʡXKybզ{o{N iRlhڵzZj.>Dec Wݺ*vA.WJQD-8pq-R%OѰmkY!jZ-,>訹eٹKp]\Zj%G€qu ȶ. ¥;Q:Qj 0Z4CfŶYiNAJHJMH`NAlYۘ{"E6;zݬmw}[iƒm:MNjm2$:T|4Vr:AN3d+ujDrZy}NA)ˣQ6VQ5[ *wzPJ J{ժ5|e6g!TS 6N]v;QZ㋇StZ1vAF?=4e{D_ E/JS X3fWzF:-ci'BGEU $^FIvf`vr?_Jp̨tR[ NPnBCE 2nDUm ]yk1Uޟj'67P]J. Oh&tGmWTzK }V XFc,[lƽ sluV˅#,#![Ի4{޸e<7x,Aʍ_g.@xfhv:u8VQ aF0K0,Zw:QiI-*Oꍤ\82KYt mO;iKqz|\ q~[=jP-٩ p\8qnNpn$Юb•^k@R@Uoq{G0c?jD˅բBz,4hfո_/rh(* 9GԀ>|Ec'Wq_,DR$2JP,g J! \E0/ᘬZ4%=ͪ(բaqvsGNXCǹZ4sllԬ%j0BnS) b:WδPKA4w=E6org/codehaus/groovy/antlr/parser/GroovyTokenTypes.java}X]o6} cЧF$QU}d'Aȉ;)L4M$彗O$Y:rчmFma-GimngV}~Q=SRUkkß706oQz곾oW\ZWORjZ]1Y(4ѾnWmR_&K#W_GG5 d#uC7>]L]+I%h=z$`0'Y@dO1RV i,jqy*|RMJqN`昘\C\LHMIpw3O:<yW }6]O"_V@D w6NsyU+rA6GRvG fLC 爅IrhsI@]ȩI2E"78zV5¢kX0K9;Xܽnz0@C/P-EG[T#-.F!:ҡ- m)us1 ِeKn`kGZw@hinpj-i}DK䫡-?n+Ҷju{_K–JWB^ԙ;0Jܳݡ3CΛF i b/RSV,Kɪw&N¶p2%~Nlb_$qPg'ɼىS_D.~۶InA%cG@Z5 #hlJoj+;ݾٲ?` ١O_ q~HpvUK@IMQz6ViYshS_Z.3QT MQ/fA%<7XwbC^ &@[{MHw )xCNPXQj*tR>^mz^Ff[(%%^Ȁ^oo/8`r(M=D||rR#ѦG\tbgn? ?|TϕijYWTXڍfW qyuUIPx>DV TtB`m0m"Ffg~ǴF}Z(j9י@Gj4pW(UaXН(0ZGxKD Us9L(+b$ݬ EPKA4^A5org/codehaus/groovy/antlr/parser/GroovyTokenTypes.txtuXmsH>U6.pAuu2Ƞ(rZL?=3R{DYhƅ}aŝ6TTh.گ3&Q Z}lVki7Z?l;nEWbo4 ҌlgocoW|;IB_SDiD #u]/} 4{6e~rdK};bN8 )q83?5U#m,L8tѧ'C:3?5I )@KÀTq/1b8͠ S! 7)\' AB-nQL*r"V)7 A _$^-Hg0`Wq"5G^qGdBa2*e|d3gff|4!ߴI,[,惻NO(Ajpko$p%rn dsz)iys,RdEiQ:dx^ssHI.v" 7=[Cigҙw9 _[9dέKtyR"Kxu֘l!Q 4|+=չ5=gj!,1\ qߞ|VQRovQW# dd}4uP~InB\#κ-6mqK{)Pƨ SZP!>r$C{@5|55&c?UoO:;|w’SV$lKE0' ̉RN_•0&yW Q:~){0Kxڀ#GL9B^"SPp9O bj Qa-c!$1#ԯ[3pSP#lF !z/$TdL/&NpXA5(N7J"),6WHsFZk h93k\ŧi䫦Gp4xroFgA>op G77 \Fat ~_Rh+U@4$.mt񌤉ysB%H\ۊj"[/a=:Е;f2t:WR6)PNIe/biex^RJGJaajCV Jx8 ge6TlQںDJ,),r3*$7YYes ђȗ^k%>Q|ѫƑ9WdNē\q%?,US2d#GoS*bƦWJ' 1KJ)6I.CǠI7ڏC!\6Iw ]HhrS>Nr~NLɥDl7ZkwOۉk^Q=ѣ?n !I-^)9*njw>pXo#} Skk=njLGfnK[Gl$<^?XUj}ub^Cýt1<,em1vj+i[&)T짥u飅1*8xڞ^9[RBN{_+c4G1݋0W  Ԣz2C ޵(k$&t=*hC89(H ˡ(Tgg|k6wPK @4!org/codehaus/groovy/antlr/syntax/PK@4ߌ 6org/codehaus/groovy/antlr/syntax/AntlrClassSource.javaVaoFίE']QZ5Qbre!| l0X [;$9UU!v7o]F9U[ꠔM#ΔYnSNN>N~?B_ľPPX<6#CiR,eIh(V{HU^4.mQW$֍Ǣ~hJY![S^g륪Zi:<}K_jmuK:/ƺdVJ/t)r;-)z˲ZT */LVc=SmgHnZҪE3ᯁbe7nL5Blj#I `\0FVzr k(EQ$v % >Y欔RiCkl|"5BKjh@t}2Lm}R޾k~xGfI솅 ?9ϫ4P3h3 Y`(y_`\sps>2w`"Mk禼 Ҙ]0Bc$M]EHvHL\,֯T0oq*u t(,._r vWW=wg,T"pO3_~~0PK A4%org/codehaus/groovy/antlr/treewalker/PK@4b)_* :org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java[o8 Hn}iwܤ)łhSPTl}IJIs]-QߡhQdgώbgre/&X )aMf2T& +&Owٝ0Ԋ`#'O_"vbkcJ[V•!K`b2XE.JH iJ2~osP  zemdٌyYflzz~?wf*eɌ;1^8P玙 ӆ==xcjyJn/&5r^A}y.ƸbO& &OػI2M}!^e&77y®ovz}~`oӫc&\mma|)}M,T["Ā5,D*2ueŗ-0E aֲgt˵܆5ɑϾ,WTgbūr4Z\܌ ? A~ǕY׋ $2$nlH kv^_)l~KyZؕ5El@{˛ʨc_!.K\UuP3~m|萟 %s!u*d=a~6qxL,xSUǡ;/NBGd?mWӃWD>[e:K-90gVF,o.&D.O~4N?_B!MӍG%ɽyrtTTsw ;=wB'](b--9#~fOK[}aww #˺ĺ-XҿRqs_f 'Of}ןzd);jnZuEhy C0U:mcqD)hyQ{ sJ|! O3nrv6 4XR*n-;gBC6P\&b!uݦӚu%1 ZvFq ^eu\bxK[D&o#I-6Oy)*h{֥"CʈkLiPΩw^O{ nĭ&77 s󜘽W L([Ҏt>:V~X{j=ÍRǀus;S0zS|-$z@*&@˩-VTreo1c̚ګ?+N|SWޒmg?TBeiΫRPB*&@6>jwG2I?cd y!Ӈ~1< #!@%q_k8/FUX|tbHHAU!H{=^"౤N-A;3$H=}Ǽu8>ln(*AA>4 qtΧ~~z~C6H>Qo4(fZQ> 8>o(Hāw>gP/oAFP/G"zP"G5 Eo(8ֳ ~18 UA>ݗ ECAw*]#iD \,+G/8@v#xVE=:h-},9(H᪔ShQD2r X{O's/DA=wwص\ VPKzi |ebe bT/D% P1u&=/{`F6LoS_@ɧu [&`13Շ@_~1nM|p\H?pwYk_5Pa VUWt 13_ N|->X35)PP~amǀ#*RsLzǜ~VU+qEk> ݇ YDZ ~vj'sp 1tz\k3:7{J 8ߦ.ȧX0MA+ܠV4`EԊ&7b)snn=Q F!Ȝӯ=s@ޠ]TLyA!ԇ@{Sw<{|-NծP7q[C$y VVǑؑդɗ(7srE$UHz)= xOw&oLM,RAFQ˝!SP[ư @ӓsFvAx@򔸧*pX>YF=om!COjzD#N~cQēE} 0]s`:]" jyAt p@/@7'd>igF"h4:sb~ dd TOܨz5?jJw X͙ި7Ls~F+fя:WT#OK!¡{ף ] jt&>hwG9h?&Ox?S_ PKA4;m H8org/codehaus/groovy/antlr/treewalker/MindMapPrinter.javaqsڸϧn iSH;]Sc ؜md7D؜mnJ6 `<3jZ :/_ r=?dA6ބ$Λ U8%1J)KYSÁW75~8m'Lm,K,Έò4u^_8'm_xmoݛw?wymiNW|(}B:.ЁLr; 4I靧[@W }]3z6jwc)-H`4PlŅ3)L(%qBW1{T!>q֖OrZ;H )Fpepe=fQGyʠ%mͳPix$ ,aUSè/%=PDR+^ 72H͞en%%ñ0)F3nf\hÑ{9."㡧B*[Hc *,Nmץ0]Yp̒-Lq)ia)ni#Dar{[))jOw5hBN-J[ W_k^!B G[j`*]=(FHU㻕T+ "Cj$s=Ŗ1,k+!:;)24-g;=Vk 鳞!}3hV-u7cPR],Hkɐ]*J2)!nya aM3Qiτ rV06 ϵ53,r)ʄGoܩ T!\%q1 D`y%%T!۸ V#׃BSaDzg7 GG#aR w7z.Il ᷱ}#Fsyڭ o꜒2Q O > W 8wîU\sqPqlQx*#N" Gu=&b^ Z6 rʯq q$ %adCRrB(@ Bc,A\7]JD "Hpu~XRWF_0l]uQ`Hzܯܫk{܃R.ϺSQתG8vu@`o/ c濃?>r_ ]X!V8 dg]5 (r[;]FUg< T p%$2$ S}2ARZoR"gT@+EXRV#EW>aJfE%hY !Z ҂$!/ªOa~0NU".j,*|KV#,YZH.A!Iim4O(eegxBj(|!ĩ(BC 9¶VLhrmBVl&!C^$AH朥Y@HVKRsY aNqݝ*V/E:tp DYPУ!aⓃhYpU'Ȟ/X$!qU!U Q0ROʠCӕK`盂9lVF|o`ZF)6p׾ؾt&gV'Y?{Z!8m(|e#_+x[YcWWx{M;E<%yIzJgUSEF|_I&N6c:kBm {,ë][ZL-pYtCS&+' nN>K  vOݟmH6sf>wݎ[O9eyv5ؑ%(j6gMKSƋY^,/%AEjNPKA4 b B;org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.java8W˭ltj:d`L;Z'q&l p`f6w{&&rG: ~gCZnqл7o~]oK61ͶEpN.P/h؊"9rhIߠs^{u@kAqPS`9ZE9M c4OixNsV>[J3(NB ߖa[+ҏs${De|`ny/ x[aG4QF]A$As2# nj5pYɒ=r"Y>_;y`~Q{zh=û/k|.|C"ͶFo|#lݣφ5@dܓt!Qz ae8ǂ>.@h1'y"0;Y3JQcQKlN_)r'hoRb %}닦o%AC\A5sEˎ;?],pŏَn$3V06tstiIӡw؜遃 W 隉]C 3&-)MhK!Fꄠ)1 xl|jV@wPqBhvS)kzaO&=sjLGACǒ%\=k@߂0bU Lh4kc[#TQ cb49;ű9M4 r{ O m;v!᩵>uO)5dQ>J#MZf~\J<ՑulalKga)alob,mX#D}$K1V;Lc@ԅ[ v'9Jy$EfyDPռ҇rvgZZ4W&˕vL(7N#cAIڣF BC.&E0Y~ZKBcv/E0SX%MF`y5Aqc-!I93"L3]]Lou%|1̑QV7©#4v}m|5ӴJm6"h/`hL2=ajJ??EDHRoT <S!<$IDIB=HɊ j~W b%Šdq %B0.hw‚.F%wUION)JVиX+dΌV0&QtZTL;BR3,Zº.َN#PwBi ہ3~1Yv'T۲5fK2 Q?i ?न"5a{G0:J;3J 2ʊ26UlGTȋV\+ByI,7h8]d[A:ɒ*lMъ8QlG8T"!q!<*NkaCzj-AP~TnM;:~kPl"_>)NE9rts\9MS+!tMPV鱌W[s PKA4v2{5org/codehaus/groovy/antlr/treewalker/NodePrinter.javaTn8|W,>8#%蒴]!(-e6#);!~KJi}(aw8.~p%Uypr|^0XB+J`7b )ܡ6\ 8aP E'[hXBZh 75>,plT͙(vn>K8>re-PAZuǻ.b^l$u=ҫ,9"Â[Q1ߖk2)TɬViNNsE5#v4:{y=#c%IiŸISG)].SX$2ayv.yF_o!>iv=h|P9 %-Gܓ$k^5QB GP7ܸ5$t45oeO+3<qQQ!KܰDrELZGܱYP-|c[q}\؜9۫Qnyѯx?r|IKbqP8P p#aDZZYy"c C jw2ؖ'pZ!sY0^[yګҘ#)o‹v O.ӫ:uR›^Q1ծ)uF|h-]()r@Cie¥ٞ9Aٹ ^d~&}Fk1٥b0G1`䋕6MbZIp ;R煅ӓ 5-,X[[nx *C @KWppYip#0KÉhe %kj @^A*K%8RӫNא+˨EwF`.Uga4M#׶aLƍ|Uym~%*F >EI}:]}XDe||*^}hҢyIi0K3[a-;$0k*Y B]rި!^rˬWex(GEa̰` r- Xe,%0z2/_M"kb,iH.D`K2-ь |tk/$Г%mAI3(4?KƅgZs& rxb_‹le wWg.xT(HCQ.wd |EAïUwnb(mR&_H;6i]'I?^mzޅ; h[σ}䄜 i5VvFH6h6ٕB=-\ӂo4B(F;GσPKA4^ ͮ*=org/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.javaXosFOqe2`a;I#cQ%i2gCp J== >t{ޮZGH;悏ƒL>3&sҥlJ{,ـ$ "nj4W&b\;%uPˆjKT12s$1<&C3X$ N"cdXiPLGؗSi:bdN"111h .TR[G@#5/1Mbm$p:h }I`pFG&.h($NHkt.ڡ3OAXn_V=8a"<;1p?Q {>$ q%5%eđ0ۄ{_1QMD҉2W*)&"Ř=l顾L9e22![iεcQn\hT NbSO|x.W?Ykjt0X٫2"ol:ڈ.b){R`YpNmH,HDN: %} L6o N*|U!vYA/\˥ y[G 򁜖MXs#iiˣو凒 `e/l4 y畧(+W uʺ-?Le}*Jp޴0p?c.5>;Fk?#ȊB5zK,~á#Wn_cj~Lc:IWQ^w-]ӺA ڮU*jћ'C^Et/zZ%(͍o=uyv]Gݽuξ_[wmTwM 'z UnAIz㙐w''i Cq_SĊU vYuH*RU bzDUfq4nd* YK7V] ̬QcSg|8ġҁR.tiZU/{a~W*zm7?Mf준t+c\tz@']kTVe]+v2ԏ׏-9wwW mӂD yF{;D*1rT-HƷ6Ș_LkO1ջǤӠم+ ^t\hrWvΤE23a lѧ6%EŋbvչEv%pX\*0^ˍWNp,,ٖusꖘ,^A.KL֡ݒ _t1]QKn%ћ@nT993ª]U؜s)z uC;$K;8摠 A,wtLy݋fyz1Iu3U|p*dYʺϚOxqm?[]N$ӗ&*mE[YNZA0ܵ6 ;ڪA0lHgg/h|]zt#BR{=!M|Ǣ/-.z>PKA4RQ ?7org/codehaus/groovy/antlr/treewalker/SourcePrinter.java[msH_1r NI=JR[4Qz`$nXL<5_<"po۳ E~a>[ɐ]CmHZ'bHۣ&?i;6wkq@-~T;9Gk]  h#d KL&#+[%4~i0遄XޛfsZT kptaAGS8p:,~Nքz I' CW|GW-lw @$@@ިF޵GQ|܎ɧp{ Igп{>\'o?U0@ {G @LdmXF)D j j;ؼyIAE2Mz),c|6d(wߐIёNP0.)4&\+ wmzx#?PyI# 2X篠 ֧ D,=hA'lɜ`+m7ieL8w8V8fC f,f\!X vDȚBrj\ wx)Pi(m1 `{dn:$FRtŽa>!&?"xn38Z̚s6{[0qq0c'!"cxõĜc0ɧQ0nwp";xɰ'a;X!-uCWf2VSsQ8?RJ)R4Vr"~~(3JԝGbaE%pfbέUHۇLvCUpղS@)X Oiq<4=+]j}ͮhe) U`ʴAܱ|.*)R,G6QO`nsXj2$!mzsŌqW8H狯J kȂR"M2#A[.A]t}H1HeNa\+.YG8*opڞ{ێ]''Z|iW8X7yB%,0gj 9jQg_C豧k4m|(R\&=M>aIZ z*aH >l*r}nzt73wyy9B mg<^5Aaz%o\Ҕܹ\s1t-ZZeLnkCQV~]KA1B1]p!wGNZ 3jɜ.Xmf %L`'z.D7=MF)ն]Ѱ*4iCZm'PzG}JÉfS}SBbVb/CCaDT٩H8[]A=>Mu+JJc]|Nx#L~(A*b;dI/5O@..r=f Yv!ʄ~I۵𨙔6Oȗ# lN燌@^7Ǭ5!\ _%Jߺ >ΌVT}~~AKU\F]#@v+}~jj:n]^}x=B'u)WͨY*;ݯnlh z_O) өܽ0P9H/?28j J%qD-<$.b$*^0BUT%n))o{<ңŁ}OLᖢ[]jooz8/PKA48%ӆ:org/codehaus/groovy/antlr/treewalker/SummaryCollector.javaWmo6_q <)vHP`$,˓d)DʩmInb='/yt ~$aeq,:+:u'o^>}>}e,rI5Gx/ l 7(,p

Ő_YXTPT C⋚0bA+(ʹ\eEc"UFAC1@vlY "OB{bJRlBQ"Tc1bfӰArdBϋ8(-Ji٘ w DTy3  |"֛  H)j* 2rK,\_9>swyQ_&hsgt4rhS7 x<7Ÿ9\S΁|481G_1O`7lL&6J;[@aU~{l`Qi$dH7?c#N 'C0w7$hgQ7a\; iI932{BF"`0t1y7|3k!m W k|0ϛN=ro y`cSwj"CwGVnQÖcQДCbЀ Sv9l:b뒙[3Or|׹MY¸ef&/ߠZ uFW5t^.5\$Lu\X)Eq$ {ok8RPRl*Qwxe;4{6 {iɅzVj @Bc #Mv ˯?8k+Ic$/jfj38&0jF!t^k!+hG7)B>~nm/7Z#8UZ`Q֙x]V gv_h?mCnw?k)%80E0qZa; _7f!O%xW3I mZr N#̴MA 0ɵ0O^|WrT&$: , m@^gzO///PfvuTeז95lg~`G0˴V)V頁g(O8xPm w9"~I< mB:4|*򖽎Z7@]ti7kH"_LYy}m4\YjSǞ[M_L{AZ_hKui6V6R ܄V-` -zi5Ìh3&D>A^~kR676$@kE6٦=& Σtc L?_\4 hba|)80ss<&ߕH't'](E3 H3xyCs+E J{N\\I.0m\xlk8U-O. D0˰.0wm rSSe?e_3Vk2~ ?i?Ny}qOi {ZP;=ppmrDgC||v-?Ё^Īj!=Ԥ~b3~3 ZUr٩&yR]S$CK]6M3)BZXiXvFk:,zno[+_撁L@Tfeό/u:LA<wtˡ]׼6.;D[^ÒG3:>ߙ@L}A4gZ4ڼuHpMS]m9_h Y\5BfMf巠ٵnrhWTL֮֙r ~(liX*PRY-Ext]CAv\c3:ep=ЧIWKw E w, C낏Az s HTA/8Q93lAksGN)4vxw&Wh-m&rMVwX-tCȏ1hƁzڴW(>: ~843C[> nG$Ieh iykz&vh.Ů- oYCM48/^Y- ÷Лծ."Bh! ͳ{AgԜto7vpV}ڤ6:+9Ie 8 ]Aw{F=m96t__F;7\@;O|ZAm͌hch p$O?A|MtBb޹c }~G?EB׫ *PHќoC=]XByн ^@E!&eÁhzxוj-`6pϗ$z۸U_N[h{#BhlqhѓK''OJ/;/80zԛh `QxZzL%}8av'IoC~@\9,Ztn|Ν: ܛS}A4nhdHTeL=ߵM4$7wV=7iZW\qwq\vt=ˣop&ZU6ZBY`Y+_sKCgE GB3MnM&{9Hxˡy>-,Z \e'ؗ<#Bs.V;*L;AǡS\eў9mtУ[h9n< |ÏFw>珎DwTh(F+s5ss6kSpf,FݮT4i݌j>=<Ӭ*g58C,ˡW c.Nlyơ{Xe8H^&T yi }Ƣ:kA$4qWTWauǣ{ %rj~YA[7`ɣO[Zviab!dU(4֗>`LAz:3|颇^$+rr K/EUQgܻ~GE=yp)4fM!ڌ9MarhgPLG<)]bZԁFk-Aj =8=ӀGO}V$ w|_RK =E}_1tW^ib?Umft@v'S [[/B ${ j^ պO}~I@Rˏ [\"kˏO5$e-:Oy'ZW*-m\dkb6vn4FZHura:YwTh/ʊ V[]1O+Gmڀu:Iq,Rűɱ⎪wKe 0z_'kdt6imfN#&\o'ٙd(#g6N٭jc'4]GS{iL8Φhͦ\ _ott,G ہmBLFfb'&mkRUB*ށ3#Q+TfBPV7WWPv/)䲮znדk8o(}m D늁)2itf:1AuDI>?Rioߵ~r^Ѣ/?6ub]kމ_z~Ⱦ`6ׁkeoj<_GqgY,^2? BwV,^>T)-ep6>*.8p8)QlG t%+pRp%#V:>DK'х0:Y!>A'8,k%b&DHPTv*^;[r e%Ӳȋr- Gv0Zi55XmQH2RXX"d(SQ @0QHݑˎpLeYw+=J=_;NwZL/vثFyAEy(uJGO&3Ӳix'r2O'jٙhD$[^ďRv޾7Mu+|X nM"ּ?ވnl$'᤽Uh/Cݞ&[6Y_ ᯔ>WӰ/nLj;q|"ψQh%U[rRt'^$(|FlNB A]/*vSG(T#Ȧ aMqL!c MNeCkk(4kKjˉ: -vVcVkN7 (6tL8;8P*YL8Y͉ UJe}5׹P`UzXi) M+h4bq c̏5`Lw-cy| h+=>ShfMЕ䱖cCw, ge nȟkWat:Sȶ'xXph5g򍌣(a3=#qz #p>e>GC[BؕjCbP[˖{O: ;Q2;g=e>^o] oq\[(h"mkts*NLV:kܦT1bަ+o.#pu(p4 @=5#|`5(ec<[= `tKYGcwVprO`z*T5Y0K uyS;~P6W*-B]qD k?ʒ3,VŌ2U`p-P|o3[G߷ [C+a$zp .LEK/6<q_[jУQki 3V+בYkk5t,;Ѓ NO7*藺kxqfy)ƫ*j)z<ƨ:4&sa=FХBi;]xq!i4i.x,4Ne~a LSLs`p|. ^*ghO۸ZOu|#vauL´ZL/PKA4 =4org/codehaus/groovy/antlr/UnicodeEscapingReader.javaWao6_qˊn\9mn:L\eR#);weKX޽;O'OMzgtOKVJ !߫Xj'ǔ鱴gz$mCZ15Y Z]6qg2;S$l(GHL=)M:T~ V")0#/.BIUgާ'rD62vI 5y? /pxNsdߙvtG"X3K2+=m3VrުQk|uUސzm6 }]_7!]]ӿ MlM-G㜶5S@rDMO3145 i5"TڹrQc6K[qEF1f,g"s6gBDD˼`)&Xh:EX]"tXNΓI2DQ̬Yr!\H Wz!iF9K/aqgAOjT0^G8l8i°lLvҗEgB =^У4\KxK=vi4Wj6p^UDnG$ !|6D$N>Q Mfc:LU<|qCY썍ʵW)2:ؑSYaa{O\N q'}A@,=GYڕ*t걳C]^y.a+F{<*b$$,oBr^\, jI5[maZ'0ib<).GXء;Ïd3~i+..ţlU37- ȻA'UcwK&rƇ[izϡgY;r\DG/(5Y|t^_Y3Kgžcc?۲x'IU0ʞ+dƉq?Jф.I j8YV]7  [`ń~|pt;yхqz7k#$[wavz?̶P9D#ޠP.rwȒ.̒YUdn06;WحyB|3yymZS.l90h@rp6Os _a[CO??GG[}avG:s]m^NǴxhV)i犑X좲.ʾ"?= c$Nu9ZmĸrȬ0VrX'hP­`u{|XSI vdeAT,L^›ﰀ>LJ,r4cP_+o ̓ xP|e2[d):j^*\RBJg/ūDg ż)Z(Qu.ۣWU(߬,hE-om#Z V2O#%KUKZdi8*7QkY\Uut e^P)>bY_β3TeP @$ϘT`!=eJ~CIzcLQAl+4kN*C@NTwyӲ%$E5 Z7(kO>h2X,۾]T,% He$8>QYQѬJ1Rƪ]eHhn<*aWu=87{U`"E.\%؅fzɥ}ߧ?`oZ"IdJ]FR(m $@KԼeÎZ?NP}` gUPI%,Qf UQl*g)ѽRFOv莝1 ath䏝{{E;E~Zovo16{&i!܇#ۋ\'&(y~D=4[zp=^;qgNiѭyGHg"w4Mgn83F{rxdbdQ*8ÉSAc7pFG ߤG;x10@C38Hcs c-ʉ&X,p2g0rYНE<#'fC6`pF5׋ M#O436k{\(ό:{t{l#HFQb(x0# ),VbRB/[AJm&ۻ@n?]λJrEMu1"c3y0Q[jnpjU;ݛ/88Ji) Pޑ:mxsm8a)xi9iw@꘸]V||Z}ltUN37n3h6s؊l18M)t=:ݚ$~4?q5`ƍ}^%5fK{&|b u e4l(VP֧Lry㦺V)nZ n.$8s1@ʾlc~jͻY>ey8%f{z~is#B3yS0ڝ)@ IT6m=K Զ8Ӳ% ]k~EՃhϏ--Έ*w;geq@8MHE`9@М!Zn(_ U}s'҉G>|'oPKA4S +org/codehaus/groovy/ast/AnnotationNode.javaVmo6_1ɛKbe[Ix%$'ͷmE !%EqF^(sg;ݐWTE2k#}u]Ǐ7Ef/wCCyr' o%ŕċjNe%u%K^SdJD)Vd."ɲr^>ֱ.U+YR nT(SiEC5EV+RWuEkɅLm F赬 FD GBzŒRUdxk-Pv߰. R:p`XiQqYV,)Xu(]:Cx33?$Ka,+*;L KYz;?,પ67~=wɓ4 > Ñb$bYFCp68wL K G^0? و=CAИMX$و~ďxl̒gҡ;Gwԋ6h>F,=6Gh/ &~Piw$Jo adA4A6(Cfo>hg#lțx>d윊r *2EPl',%>݇Pv(G6[k=H< Xf1 h6MXtz hBdk6](F`Ӄ#U˳Đm!"TLҤ{?f740O,Xl,XCԙMT Ql1ݑ7zFĬݼJ0_myx/խF[..q-~p06w=X^&|saq1xdW~v3aDHW8 s4 g9esfqAKY.ʚkh!EkiJ/Wk.JQsg\g}sjQBۃ]$Ҭnl)B=ey3HԼ8m/]GCbOwȅs_/*BFk? ۹mc_O`KQ:ǀlj]|I%6ӝ{ phN2. v> 玵V,-Pyb~=y@ȴto/ڹ˞sW{ʓ 5; [HtIpY҈4?*@ƒ6\t"6!ZHX aYZ>+tO׬0dL1U(j%4+N2BnS ]ȓLs),ɸU"`Ih:G!t>uHr{߆αɠ1Je:HƒZI)y4&Թ2%2epٕ;! ݍ;w CE~Y{Q-@ 1AFY]QH.xcsA.Nhzx9oŷYôdޛVtR[l`X?οPKA448B4org/codehaus/groovy/ast/ClassCodeVisitorSupport.javaXn6+SC@ Hd tf -6gh $n%%K$Ea}{xқz8J3HjL<T)J o-{SHl)j[V``G]nǒhsQloM!kl 孡U,APP&ޔZSeVBSa^3շ\+Whb]&/ˎ\a2o 4n7 SӨ\\,VGQ/Zg~\u/y\FU^&́mE[B yVJ_۾I}OZO=CfYZE**}2T0>܅+:;A{NХ;~6d`cړ'RqVgCZ kKcOuigF *`Ú*Y Ү}AGoiD[;huN.4>i]IG4@n<ٙ4&b@Udm};|$Ɓ<l 8Inv>%ZK)iOBF}.jȶ)=ثTx.&̤Yy F3aؕIy&nq >6A| J./G|$5܅%ЛdJjF;թH3[%\}r\+gh]g6 yT܂ܕ^%iWk ֜ 69uKrQ龇VG4>T}:510G.إd/z فc/dTg>q"aN&ҏv`'LA'eX&]Shm$Ȱ/9'x9Y'Zs /8l-p-~Q,Gnr@v;)8~j"poՓxD\podVwiNIL'5ܫ3vM@:{Ȕș >́&e'{gAt8#Yغ&7LΏxe|7~zf7}.PK@4w ,(org/codehaus/groovy/ast/ClassHelper.javaZms6 \3SMg.>ϔhYґT\O,z@@%'q$bw/Ͼ+`xyRUW45yLG|}z$oO{5˓aY&+%_IM7SXǶeZ(r HTIN K2bw:}Zge ;7IL iEGt,+ˬnWgL*J=YE*v_?%% `K3В -{yl^Vٮ&'6Yr%{̖ti뤆-)gyΞbERV,3d8ӆo-Ct+Եb2]UIV(R5V%$yP.'A~:q}.+)7J`rj(/cSQ*d 9T'ҒsI%nBL' +%rneƵ✊ `7i"/W%c/))ЈZ,Y)Q\Ga-8{ = ٖDPRUh8 dhB4[ZKiC柡&ynL<O* EdI^}LP'ج ,>%$eqxGfbHKT&'ŭzDl討:*H4o'ycLF$7W""t _q,_~q#KNo<g! >НƁ$z8^XYL&uY<~ldvAл(-h]v#Knbd'h8\cT0%ӘDWdbiqIF>h&ŶL' <Ml}/>X↷6"YG?H oר/8!Z8O.g1*lE~.Lfw"m!v y`alzl]n%#`ΦT,Ey\PMǖb\p1> Q$q@ؒ( .󮤻} 7Ya[u S#36[VD>˓bx9v%=3]B;m\ ᗙ+Ej^2*@@Q_;l5iI3bPtEK}j}L2nu5x&җg9$jSD6O0bn#@X<0⣈|A->Jߊ/™s4ba+`wطUw4mTZmE[G 1[} L Q%&K%D:nuPHA#!3ZU,!"fz J\743i&A);@)ݹ\Ut=6V +vⶒ^ڬ/Wlմ1 [k09)iv[mZ6[X k+Yik gwdij vT[zE>ixḾXLsZ]hsZƘC!YH| !3GŇZGPuw$ rg0HZ RtW$ z1HfO3|rlMVG?PKA4o&org/codehaus/groovy/ast/ClassNode.java=ksǑ_1lB@9N!* $!G<rbI.Huh;UeSbg1===//gK6̢(I>ݳ5~z|<2e+bjSw5}:.SL*6(r vRypuR U*>Y%«dVuuZpuwiŪ~ʄqɂ-xL:B(9{H;VoٲX7iL{ rֈjUwQ DwSdY,.Ep-%69cpU.t]լL([cNp҄N( q 4 T.刀F h^'zxz<=E? @58eRbR%[ ('!VN}6/r3vp[怓#eFT$_%*OxE0Nj]рOP=vq(=Y)jMs*>p0E:شVYU Y\Gnoc X?٥\ȖFGY 9AlYZ%BZӪ]\ TD5 DN"YF Wt );t-p@bb2A]]^&OtzjttN×#6lpq .fWj \G|?_^S\lA٤G] 0D!5;] l<{O.Cl<>\tĀ.t:iѻŌMlJq䳩M989aGW i<YM/G1y 54 jtfLOz6bo&S6bލ;LkQ: {,tL_FWWחN!ctJ\{ċ 9woG K\ / -W ]ޜߌ.#vOG]x Ƽak"%co \5"Ơ ӱPb>_ VMݭ2b EU}i\eij,oodc-B(x˓,)O>> eBd5=zYO"0Kn0 n^94\'+4'ѧ. ZemzZL[Nlyigƻ?K:ۨ;V L+} / Lgo+2ZM5XO[Wq В&6VnҊF(r j-R!7[71ƀ)FQߛVKpՄ?TXueǑ/&o@G_wHVwtѥX ,3HDSu )w8[Uk䓁KRP(%:} %,`p_Ýk@6\T\,$!yA xCBݗt>A]]`chL<50JuKԸYZWI3pn!T`VI :-o5pdD&2Jx#zyc$+I}ξ9^xTq}s>w/y_x,Jk%8Awqr/XGKӧO Aw=; }0}SpW :iݣV%x; Xm)EIwd}2_dCis~Lsfb!אJ\N726!dG8iowi{KnMai9,&8_$Ekym!n}nIҪ{Ѽ( ˅b٥]>j JKn2! ]Y XTSZ *[Z NߣZ%˿Aʾ`ӳ| њZ89%LᠵZTbYr 2RȓcKTO3%T!RҼ>&\ 9 T:{ iauIBI)ȅg5qrF/ _I뒯M l-ANI_$e 1ѠՂ#PPG|QCN),`5=~q~YwG]{do}3S9Q=R {O<ÉQA=BxmpTl ݈0fKˮ~YrJӒrv !^ H}v5 c}n൐zg0 'b&EX5[efFWe#eS[u*66?y8XO"hoPU)&MDVZ` X葕B z]p;31Q6i@ՠ Pc544~XtI92#)e 㬠-G""D-H &3Ca4Gյ!0wP"neS_@KSG  "OܠDCaS[ǞΘnNUzE{zDDa$p[{it[]܇lwuNK~19ګ+1(e%_]v=bjk l(r^FPmMdVt7?t4@`^6*%rG\̲5s!MTQ6Y _u-:X' nRs$Ȅkd՞97ڍAFNzk儖RvF^f[g$"Ef޸l0ų$3^M1M-^9#Qdhd7*.G&v"M+*]*@tz#jh\;@l( RȆJCbdٶFrTa&t".,A0rXxJVD nIw2M7QMD/Nu%t y3\Q 1]ߟX|[cp°_:G7̏Vά—?B+2hlcEd'&x"?u:`˲>'S*g@9<O63(b:Rqͳ,YTq..@c3)%&#J 9`yH*j9( ꭇLh{OJQk25;i=bD(3O]$!$M4ꥻ6\(QebХ6Z_ Fk~V*lQxJi6zetf FE(@l$2YnIp* z+7I&׾7uZEP3D'YƩL'ZF a 9-v_"FO[4ILԦgbKKɦ#tC]3lS-YXZ ZjS A#xnHUymgjVsmre:h(&!ي LQ&F-TV "5F`a (*(H%qJzܝF2_I{ V_;-E^pnYkS.v&b)Eǥh XxQT5[6tlڻnr| ft .g |=UUhކg,fe `P $*nCq.s`<$N 71F/vуUmD4ũc 'Tzӑo~1UiO<‚ Kל7doeuUnccm~b[G"K1, y=?޿rfe-6lܤ9]mam#Hg(RQ̱ʔteT@`@$򓖺ɺ\߆^# Ef9K?$U"T6}!Q q/Hx^Ok7(Ë`UP1Po'Vŝ DĎ5q"4t@+^kϞY/϶C5{gVmc? %,P0]W^]i]44۩Mȉv_4-$H0Hla n8UHrU{mDSfUy*>FNXuSk C ~ "(!vW.2i^Up_5`Wbr:iqJvl8.?ЩZ9W\tew$Beړ:omHa2vhuGX70 fAw)U9%p6h+Ǽ$72]uyDi3qw%Ā[x{ZhuUW&5oc!14qUؽ۠U˾s,H|B(߀t aRsaUc:B.T9'46w=WxCOF]: :ba"'Dςhh;A[fjqMֶ+"-١E⨱ȰHݞp ,8B``NZF?!Rwr q+YTn6L7\ev,]s!SVLSث9D6ľ*nr}|-]dmK$Hp%Sû)ye󆌈BetRV-4ecu`F9﮵5il,"(%epUGjzKs Ƕ:5@$=Ш!ޒh 'ےsɃa-;q ^]CSwԹzFjIsKW ܆d6@|1 .mK*ηʙ 0yq(n!|;I" ZFEʿaWy4#*qT@gg/j8 ?t\#>iZˋdž#rfЬzpPN߼=Ͻ8o]-7 Nyj[EIȂ~s۹`׻~= riFfF蔓Ut4]DrD<;nVGѶcݴlFoYMs閌n9܋h_L#٦Kql5m+On:_p[̷jƠ֦(+$Yf}HLw'!xq'(k {o> YזP;Q ɱ.by}?  )(ӿNz[ :ny?>c6ЀrF+9}N]nܓ_ewΰZce:簟i~CX<3?r$zTq8biBNRg++娃bK_[_}ƕ!qEl veHgي >4+T9JXa2/ _r {ag{.~ا~L |,BsX5J6N_-jbFݸi+1ë+m9TRiq|낿 BI9; ~}塞"drB-Eͩ?LE;H(^LO%)NJ "JLQ O jx6`jh(C &R눬T'<ܓ5;?Zcp;ǥq˶snN hԌ joCØhZH@ܑ"9xIKKl8Cp+%HfR1 M& %$"/Z܇,D`&,丨$.d )M lNWtcbk3,MoZYɨ_{8I`6%pØ> ,f/& ~>DlA׊fOm[wPኤ!Й8`M%v$6wOypc{7v{Nt>Mt=`0<3a=LG?{5p ؞=\ow{EAÀ+7V5\9^vg4n0Ldd{mh;]~oWN;Ĺv/~? -äOw2Kmn;!X[9]/p>`}c7IϾ/PJl ;ݱ\!q?\ =(]]HC_Gn;-<@6\wƾƣrx3<h!RC3bq376Xk1c-4qK]^%|Xe% ɟ#\>`І]x)tw6j) _u:6ג6B- ͵`ɪtX:J6g\vGd̿O¹ +y\K?nuULjĞC{rl''8e8s2eJW@`vG㯩t]$۬3h&g+hK$dOG c%ξ`mt :0uk\ 5G)hn9^e7Ҹn񄘖I4~v>*kŏ~){9O}oUZ6{낯߶|*-֩Ұڗ C Q<Pڲ*ne?)Hl2l@͑N!x KIeT`Z2UjiVqA9"i a?xƱgߖ-.ePY-@ N@Y'\k [Vyeh\z[? X8%BX%&{<nð_ˢ\wlZ+E-֓z &K+4h\=U)O|$R5 Ob!YDIH*,^oUnU@wt"]IsT$5~xϽj J2v~vvj ԳZ+ 6KfA*Ρt]ѥEAD֤eP:GT@3ajk+uФpZ.kq.Ţ# $eP\;dE"Mid$`G'p«4 e6׮UL΁ꎧ ê(_ 73ICE휦ia3/]S餰;WEQ{,,/͝;Ja̮FR&JUTsA;ÜsbƍS3;Ҹ1ޅI̚R<)ʍH-U kP"fNZ}9snmkMLjw|JK\ĔhU-2 Ծ6,8U%&^W#Ÿu;5ֆPKA43]m (org/codehaus/groovy/ast/CompileUnit.javaYms6\&HJԮ;e,H*ifC!P u|Խv.vntcވY-n{xF=}7E/bKp6dXnvJ,W1}<?S,\X\Mx*;#qh!LdS4FP[g҃!F9̾@=熴F0!6Zp.4гyI.0O{F&,|Do%x ca\M+g:vhvF>3@Ϲ>fO\OCc#گ^}Ձh1| F/3:`ufKJuz[ёXoʠY8::UMF퀕0ܰhw0)ǖM-r0w t̸;X&UrNJJV֨L2W>Hг1zj;LRRݘ򧚼zhx4z@}TA(S?fYd7U"D2D>"7Xcb>EEGFW? ;뭙3y U Y+Ej%<0b?jA[ ^z|+Ĵ/MXR5Pui-P$P p *-XO)Y+mѽ^YP0_״"ʁ,w>kWM~z~C HŖq<,Ɍ=O;VC BtਚNIJO>5PivJJ(2zWbHx`r?ăQ{SD44\t*KLA^aP(_SXanPO+L;l!؄}0hA}0qQ<2Ooy#T%S =["Ɂg@3]1`S\  Kl @2wr,$ІeA;jmʞ>&NG5]^S azkӖEˋ(t?*;U i_bQ!\29"n*um*N9{;K}(Tes"ebb?RilC=80anqiq7]oaJɐꁮpmaTмvJO])ʞZMYgfm$Jup ׻7МhuBuXM+\zF1tFUEg\܅X: x"]4}2^UjY鬮x؊F*Ԛ4jiFK_ϋ3ʿ#{uQ#2{+Eob+2ы}Ya#T,D th.PVъ PMfna_m)aB@]Q1O~1wkDђS7uuW[4l#4D*!bs 9{nM#܉D+@=;nqNז^vF.-ՐV 7sz@L:tT\fŽ) Pvٽ4VU7-YִC\F;Ly^=eqӦ"h PR`Myzܱ:];)>=f+,PX0^-:Fb☒Dm2SuF5K{(lOmvV1m}X1fZ*31;h$NPsxo }fX%H4_/ףBNb؝1iޛ/Z7/G׼V#M@c>c1ib\I׆6T!_ڽ~/\f)V;'JńO^YokQKR|-|_c˦A;VkZa+Uu* K"-pWtw%?n e U`݄,6bgqu?o7k 0F_d%R{M A_ K_әimk.fx T#jRjt(D!WvRƜ%g&Nҽ8{󔁭јA.|YWZRuGfk՝Ju5ͅetˣA1<8j}nT)] -,˧ζM6REnly&3?IwUQTy9iUfk! ?Vj*p )iD^bb#Gh vS}zх,H6ܣ:[/$/z%آl"I;L:C6]S Bi!T6qD֫TXQu!T%\4,>.dt0SU~8,MmHYl(uQfMgHƣ;,},KQ=6֖@(\l.w vXHe].wֵR3KWFB =W>V@ ܐF"fYz5pnөsM:yBIt1#Gqt{GXdԍz ~i/i'}$py̭-% p4"r)gIx{ڜ{^XVʐ}?, ;sG1.){zm 8pƫ͝{LXLQF\ɻ :jvr- Ki?t;g {rY$9&E>% 82MC (ӝ%V6 հAfIo?mZhA7`?+L?r;֍Tߧr.Wпu&/sBee:툵Tϵ=>)d7$RﯴM3>L^=m5v!Qs|i9?orm.2g먽7c|->//PKA4oʀ,org/codehaus/groovy/ast/DynamicVariable.java[k0+1 E>-]NhmC¬j?c+dEv,Ԧ.%\;qcP7k$HF~4M0|evj{epʔ>X[ o-+t C]zVߖzPѤcjKyBlDT1z,7 ^( ZV1BL+&]/7NR}81*($:;W/d:ibreus /RԓOpSM!V)COà>% PK A4org/codehaus/groovy/ast/expr/PKA4c[D 8org/codehaus/groovy/ast/expr/ArgumentListExpression.javaVo6]!(P'ۊ-i)6hp$OEcEC3޽{wy,O)0LUusnr)K:/;'_O'4*SnCe\`b^~>X4R2 IU6>Qg^\ sD=&W nf,sSpnj +D(T.n;a{X*iժ_Wm&ڏ> L~:e .RlGJnJQ'9nAAH&2dÊLOO>` &e)Lfj:pZNgobvmx7aOqO\Ô(Ka'G>)\?wsAtG i 8z1rDY(6Q?eQg vYvQ|A"^58av!=Iv 0ĩ N~^+č2J~ϒyg^t.18U Дarf mJ@H&H T>&\2Ey *&)Ctxfa6]q){&qYBZaa:(I2daztBЄjG.]('w:8t{%=aEZ$lݬiP1kI쇗" 6L8IE | ХUհѳmWL /(]F[nݫ輔:簜6٭:3+fsmjSZ|?={6L;G2<;;t6ՙx}Xʼq.cC**,hɇT^ 45LeO?~;ZRc~77W,aӳD-  ˳2QY OrH.--76x,)}T{ª}G_I'hl.@RU 6Ř_Im]N(C9y!?lxj gxjX&ſ-;w= j\̨Z?Quap+7:+|qfLݸX wﴯ-nf݌UumM7}qT6E PKA41org/codehaus/groovy/ast/expr/ArrayExpression.javaXoH;|k$>ގtd& 'N6:ni;=Ln~l̜NUuU#;Yi_2`ttj~NN>tONg$ 4aP/Yr߃`!]&>?4IVJ"Z&l"Y*%3ʟdFY2˟T ˒ rRLW kny`C2$U*Eʙ*H2gC4YP9 %Q5wPg 7KVT@%*)y c(2WĂg*8Td&YT&(K2(lnΆ&}TP8H_RؠB HL`:ٝpot+yr!Rv4RZ]$JT "p"oJU c$ci_ZE8K%P 8LR..Y CD E2\:)G\hsL08oW&)#dH4/F5I_M-M AyE˥6.?c4GvD[v|(AyObR9eaƜ/] >-|:]]Xoѕ`6;}OX77#kw˱?r=j>k{G.9wZC߱9`w#έCu}=]ѭnh]:d]9 ,\KwcnA7[rI=ɻ%Ztiu9 ?vGQ:#m7wg>v0z?"[:){ #k2d/=ǾMףQ!ӳs<س;[5l+,r95gۮ;РxL`UNGC.lyPw{UlY|]ICz\Þͫ#6x60X㱄S8~u,WqlG%+0(QSVwS[k,197y/}d)0 C.Iu42{hbIڰ4F a.p-ku^fR4G8aty8P2>1 V*=Ϝf Za&#zeADxsx~ V)} )"Q}V%"J33yc7UYCwZYqz_j5䔦 vÌWsJ1װ#m{s"umJHD,Ea&ǧgжw̰NA%3]( 2uXx>3j-\\ī(:dUF4.X]ǭEkͲG^A_54$og/m_en\sQ>5[lr43޶@t;^b5TWZ01ϯLaԼҽʪ*,[[:TWM"SkHZ6lgwFEwFp\HĘ롗U[;^ W9dߠ@kr 4+w5˯.W|z@T99J:^Vwj;_8*ݛ6;^'_P]HMIYP՚H musek @yB>Iu+S}\5b$ !sYߍ NEq_7(ߎmELݝs`n\oM;7t1PLXޢJzePLΠNK6HHÁڲ]gj[yX*6a2CBoś'wU;ՌK e5)> +?LR[i{NV;ink{ks֞pM}#ۭFmv-ڰ:4Dk*D;n/R$O$#&k*PVY!#I7WPK@4j(5org/codehaus/groovy/ast/expr/AttributeExpression.javaWmoD_1N"=Dˡs5J`;-BbcosѮR!;3k'@HDj3άo-x㧗ŵ2w>-pἃϿ_ ..]αȠTRn_zU8JAIy*"kYT0]b7wu/T:#XQ!&b% +Ō3ͫ&TK [ݚbMXЎ)G$'m6R!NFZbv#<)_3H{D(, ;K)%S 1*`Ptt b|G7zi<#oO0yw,w28gqF_=w/Ћ"Bch9t'E6x6'6 &A cޏQ.lXt?K nxݹ0unY8 "( Ǯ ݹՎpQ+P{=*?aEO%E! ~07|0g(0r[iI932=AF"u,6Fق ]8 _ȳGhm\_"߰Ob/ g&g Di01"CADVÿ w>QÖkaܔCb&ؿ&Cv2GbpC?" rי efmLo=Z j1 j(XlImy89ap8+TTw2/O F,:ϱ; ܚ%E!ɩ5xW8ZQ7`ǜ~MLZBD@ + R:LBXp`ﭙ y:Y9|3M;9/z?(? ؏Ǜo.UMy9DRY cDEUŲ̸*LGZhb{E1 yRy7bœ $xJUd3 ERI) %R.,R3M]1F(D͐-v|anO}cprNb a*_M68ry>&]=X nm|:x0=<{{h Eк5'>?C嫯<س|ڮGxd= l Ft VZ;;\v}=ri<*-L^`&#ӣE*F}g Q^d[N@9T+P[hGVqm(J)Ud F]V/1Ǯ2 BXygXM'`Yw 2'}?I`эwo,FV>S pe<'Y8]ExL` uN]G \QYUDGJ>l:A;;~˒别w#): *L1phfߏ }/Cglz^<ёўؚ%J/7R&?lg?h;kck.c"?G)Y^x ՄM11=i7\6`wav(Fڱώ GRr' RK!t-|j҄JP)N'y,|FCM6ov]MCւǤjNve^dMP+C%YqrM j?չ`q*{r܄29eP66i8o*ke3AFΤcslF^fL*CUz va6W؏_{*8ٰJn}yRc( !H\]GȺ~`Y'+h-c {]7U7(nw̶: ԭHA) c3j9טh_/讒CQ5t[Qb[VǪ,[,Z޷PK@4? 6org/codehaus/groovy/ast/expr/BitwiseNegExpression.javaVo6`@Ӭ݇*LLԑ a v&Xb&$mB,W0Jwm"Xd/(hn?ܛ㌥d$>arx`ot{T>.Ѕ!)] E"*BnF݄`9.(7C?a˧!fٚ+kwb zp}p?u2&tMw>:=_[cTT4ƍ"o;tmw>%.^jRw P).~|Z7˫Q8}r0a5mo{(G]8UuRK[2w溱mKZN guФlOznhaLRχoI kkj_uHw|d8PGG:lq|1^{ll~tPK@4&Ɏ 3org/codehaus/groovy/ast/expr/BooleanExpression.javaVmo6_q <9YKڢɓcEC(ۑtf 1Mpy.gsKb! V|.jup?Km!*H@"kY+Ei.+XHP`-cT^ + (TZ sn NX9(BC;.PԋRV벐TUDzA$/^ so 5js.-(k؈~ "8Fe.]QE \ P:[HQӴ~BJzE"E.|m2Tҵ@[g0s^r!5%JD^=,\(.Mݜkq{C56ʹR맣AP d](M)BfC5/0%6=g+L8H2NFAI2SDjp6vˢ a0y, w>CAĚ$gt:'r]=XeVӪ!'j\a5^(x v\M jEMdw4 ?/[+#mV]gcvr ]t 9 'ɭGh 2Ey V$$(頓f<d .K䚇,=^:)0FЈZ2;;x$3G oP:itQ8%T%ujNe FDZ`Qh5&2$<% ^ 0MUB^հֳ+&s]H[nRtJG a1m}7/J?k4LiU8k4…pCڞׅ)">"Cu}ѩ\?*Ȉ"xhx/^˻ͩ(&V~C<BN?/m~~Iogt:$rQ=X*eI1ANxjSA^Dm b V 7>%&ێGXTF[z ]a6?ZZ9,g4x!R>쬵*r󍴡߲z.kz5c+P: *uIxg*!2Drj2K2j7N۴fܚ䁖ݢ<rYzKsy/Tæ7[}z<{$cSաf{ /a,͡Z!b68GlD']5trw߻[ ۠s4mjw݌jX( ose0zܪM͞?eʸ=ZI빖]H黯+v_yFR4'|xӎN`S?PKA4H.}tM 1org/codehaus/groovy/ast/expr/ClassExpression.javaVmo6_q0<0+*L*y $gw]Fa4u4(}uMzsiAp#eYPB]jlRFK 8$}1uM )AD",Bn-^XIaeS¡.csfN?[]*4#ȂLJ]) l9VGZ2/R0}1+cW%04kW~ Vo5@g%U24M.at dYa'9L.Oz>s?HNႥ9 G|k )c.i1L&L{}F8 "%EZ$C٢mQż&lX1Mg 9)Ȃ7B:iSW3ll)KZcd|-^|+:-AsXis?:%'A+mɿY!-Ke>8[4t{h0KY-`#6 ev],Bv]@NGU1% IwNb Xykg)T mv#7Ҹ~-]kq6h@[A*7FC:hd_T 3zw쨍^~!Zkٷ8'~#V%K}V6m}ʆ}nGj儂Ֆ.-߇a=,26?~Bj;6}Xw9 H[FOB߉CvvѾPKA4X/`/w3org/codehaus/groovy/ast/expr/ClosureExpression.javaWO8=\륰, >tuf7+)>>tHPמ7CЁ=vυ*%'_+̖c-<:z9>?_v$gɗT)9bq/LWlDZd `E gb,K<()rSm<͔٤Ԉ*=(q)%iB*r ͌h%:h]g H,m0\3m -Xf)O4p+\eQRVku!OP+WR&UR,5 X(D pe#*\رhM\ bր1ag͂!.*TdQaiH1TkMĒoa0+94L *,si)2ZLiUH0M YZ&W.ĸ]`Ak*X޷p,L)%|:Y n p]7bY̔4QTڦXl& 0j,!u9,Ƶ0aH. }bNcF1x!_{ul6YB\ղVmLVJ j馕;a65t>aJ !7>ϱO~${aA2icx蟰}<—PZv]qY!Ku9_I3TO0$4d⛹Tp怇}`lt'n$d^<MxKx`&ikβ\gsI %_y-noW:콵Dt/̬v۫ʥYbw> TAm^3["n`^&-vi5 fη*; w~`ܾGl[Q8݁i JdU\ _kǫ 9wBX, <վu-~opn|ԲEQ(3x}ޮpP-ea9VXr֢Z?^W =&6 [ŻMksl*׫7_sFKD 6VO ~r ExQus^Lq}GBgڬRwzuDϻ|tPKA4>I4org/codehaus/groovy/ast/expr/ConstantExpression.javaWmoD_1D'‡8ɶ5J`;-B7oޤT3kuiN\zyfe^ tYYYZƨu};ѱw|L {k)cf䒠D/:lL\YM$ת9_ɒdPvG~QPJŪRf2XʚfkSV* {+rk \ } ʰYQXkh&G)T[apl=JDQwiup,(.8I6\>Qn! &Qxfnecr.Q\,0I^-A%د %+U'pnB8߫jx4 n\<8K%`{rf>qU3{P8$Q@KdG>2xp3=֣C8TvqKYr \Y9 j^ $:MX8 bLkl Ecq18(N:~/t{~xMi,QLt` @$} d6³>Ca$RȥQY|G)]xt?a0 k6١ aNaΧh6ciA26I\0ܟL:dQ4NDmqXRe6K I}h"~A4/3{Iy 22]lA:KEј]P"`$w4,}H}g XgIX TlQxԡ M .QCQ|ͨ̃OWcfԱ;B6JrVIp&‘݈aD?jW>\؜%U/[5wɤ%@P4 jq(t6咛\4DVSu:zԨ5z w%{|@/*/1K]D}qsS|mQ21[\) {ܢNʨZ'UOi*4R{[|]ΫzyQ)99\F*j}n"x-p/`LTv{:8_46!'xܣ8ܻ-{&pZ|ts^klvIʆnDߛRߌ6E7f,]?V8jJ];<Nkޝ}7*mTgzN s;` NSn'k; c$weup ۄ=nwm6O{xm^tL@lQP6x/%΍utoA7EO=kʪ)IߝPK@4fR4;org/codehaus/groovy/ast/expr/ConstructorCallExpression.javaWmoD_1DW"qZ"mR;NKM 7Z;)9vbi KM6ޙ3g̾tޢw^zBcU$ck-2S؊ᖎcч7t#"-bApwˊ?P<JUZ$KQ(R:Wt<.3]ImSI,V( IJM2qSJRT-JP= -̈́(Kd)*٬dQ ߋ`HY$ͷTRi%vHzU j2OT\=fłU{k%P>_.n6:pIa)+ҲYX)X2dT*KdiyT`!JuBYIMhdEZ$lkP1I{9.]l0^䂃z[xu[Q&mxNM1ɻ grtEc[nFt^JGXhENDYgee՛VǨ4C^7Y{\(ޣy>av$~ߋ M Zjp[,ɯaV 2WpJUWoG.*YbF™wf<:/j6yP‰}!;6Ϋ?ȶ83B/aV6&u7{zZ4} k<إbgpYm"npʴA ϋi7Q!_;ӶHӎIK-+wV;6qNV~UMJwm^1&Ø](JTu|aej]>(w|qlvNCo\g4FH;]q~7Eu`-b],{7{dܠ*U^ UŎK@l?{p9,p85&Pgg Ŏ37?Ky }1Die PKA4DN5 7org/codehaus/groovy/ast/expr/DeclarationExpression.javaVmoHEJ"$%:6a+bsIo]/]Hͬ18V"Xvyٗyq+i.*[lD{xqsqٹ...>]}I.Os@ 6FO^t6_X|V 4[- Q(R MR{9D2I#F9dɚx9HP3̀Q3,t 5̈́)j^ºlI5<9ksfVk Kfll@VR/3KVZmT͆]A%T笘TiF(PKiikZO%bR\ ZZ8%17.Bl* E,#< N5 _0)habΥܒj!rtHZ  #ceK), H`Qh]:wE(+砵4\r?$qFq#;"Lj#w!!z ,nzqm@/F&0wɷux[ܽ>vy༜r:nn/+AutE~A ˙VϪ(ghr=4.blTm[%.~b;MTw dζ^ZpD3wyc 77yw>J'GiU7ea)v^RDbYoiOO{n:3q6ZuW`Vd5v2Y5ԛNj-3 PKA4: ,org/codehaus/groovy/ast/expr/Expression.javaVmoH_1""4}.Uل=&i>]F ܩf8MVg)dygf_g[%,s xu\zqwXb%UbE>p8ֆ_Bb#5FZ uT.xy9ij/S"fڨl3::Ӡ;s/Br #SHn# #ˁI\t{p5/w6eeKkBJ mUR:OpWyy+XE^i. kMtuSK.)% P>K"mFEi.e]7(0æUݬk+ ~.drpRda!eT HKEuSf2jbHl<*C4ͲU(*ojTH "cbGu< {c.Uu+?,ZQj\x8yFlYI#n8"SV:?sl@Zau%Tn{h831vR +Lz7 6f{W1ݶ\}DL<8LngQxGl[d#61x_$yF>y1<{fYt68D G<8 L'h=0e?Wo'<\$xppl-:]AsSJ X+yd#ܔi7+yL[Hsm_8{4 4FuZkȳ%LMxBָj_>=1o4ZrvX!Nۺ-ȖLC>#BOn{NA#5]ں?lS3l_%qHbuη6fsCU)}cxDO?\ 6ZКuݱ3-<9ԏuYz͚0]#;q0d8@GVu; 48͸*O*,PfTM8ncI;mF5ue}[ cWOCPK@4k7C 7org/codehaus/groovy/ast/expr/ExpressionTransformer.javaV]oF}"mQHۇe5f&ټ[AcCU=w 4}2x9޹ޅG2cmu]J깱+m?Vutս˫G__?|ucUTөQ`϶X,Og9Vdo&Ӳ _SM꼋X $(7 `9M̩Y5f<)݆k9&۬t($whdo6 L^̋v] Z[-r{ȧ|i4OETy^ZWnm66paQE;<§bkǨ2MKo" p ^٫B^EǢR{T`oT]Dhsf(+{߃TȜ@?qZUثX纂×usG4.x\da>t5 @Un,+Ӵ0[tiЭkF{\ (E^k/EathhG\ܥa\4T#w3hV\c\6ͺ9r1Ʉ&cAXONŐDC1g ?4YʼnG߿ \޽s{~@4I(&9%a*E!PB(viqQtC#r,NэLCiǩ fc?,F &5I0D ^2DNw"L)%NWDi E<2An ;LE y! FD66iO[^FT$b!D2$Lg(2d@$h%NY":ȑ.5b@+lc=%ҩ&Tl(O 8m'"P)}U K-rRE٘[8zKIQw+ݜ|y}/.pyŃQә%pb.kHLT 2VjHd-J>b%P5j9.k zvj #݄k+aeΗsYYA^vҵa @P;.B0z YxOX'aR߫j E^K{O'k[%h-iZ,𩑱$˨VaAD @p[u6*oYXU<`JfaKd:D1+m"HJ N*Bͥ$WKq89 af-AS7Jr{C+l2L֫NARdUhCcumCI5/0$6LpIp7fYEc=ƛ-RXXR.v-nXJQ˦E]&KqfJaak.6:H 8bbS etq 6# -|pr.̟{~{KdB˂Rbի:^!bvSH6Hx7p~ ¸ϮQ AǗ(K(ԃo߂]^rsAt0aiqz88D$2.(<x 5..p͒ _s>gƃ 0H2AQ2ST ׬# EW`=ΒxgD!|8g',̰)yRf(t!Ӏ}eLu ASpupPǢi G &(D::O32q',!K`NQʺ# \h@p磔;x$ 3GG\ŷ DX4\P* ) )fm;*f4!b~ɢlL0#mr{m|DOE,q2Qɧ\ﴩᎊۋ\R&VϏ#{Y8HJzyR吓>OHHwʢ֧٢VxV&37X4O 8! F'֧6܏=ЕVP.pwmO}ʈm"FI-05mx-ZʥRRX7RLe0b>Ѫ1xN ؋@ϹdϹ6ځ_~XkTx@Vy/3=Fhr]`[/qq;7{l=3_] l~xPK@4^`3org/codehaus/groovy/ast/expr/GStringExpression.javaWoFOqE*y˚Wi8+mFU;jru2؈.ŷ?۫4I8s5UmC9(RlBd$nԄ/$/d@jodV Dd]Q\kIjF"Ѥլx4 Bk5MD!ctY!XAfX 6 RV낖*NfȶdL 6&e܀?QJSh8a-mK jpZS k]P. d(j>%&LTj,"ՊAC`s;v*ȯQAid""|YBH(&j#0KLm!AvWg+=U9[]´!.Qx4â ]K'Ȭ6+" kmJM/3ôRUCC?n)USx02`9bJEqg hȜ >\#=ޡ!;998_u1(Uc}:u:! LqX*ĮLAuY 7 uu=I)Mᐎ5զ~om-٠V|vA@SIHi@|]QOȖ~F[Gx['М1kN}^:Zv%[Bsx~G^?jҮG=Z;Q *TN9+yOQkeMo?U\f 7Ԏw.C f@Z'7iGv9Q"KVH[!^oΠdFd:Mk9#dhާ\6"8|[ְw߁q DmKYH;gŚ߮B=/')j^.螫b[yqTb뾪c1ݢ9ω).a)#ƃ w}o:ڣYQ!&H`kAՆ%ge&LSja/-.)+KT`#UTՊ]))b@sWtd'K8aFĨ, h]Ӭ^M:\t~zo :p=Jh yyf[Vď~auBt7FDiQyx7$at娗'xn5܅ihҁ(1\cFAG0Ha4NGI%50WcL86, w% 1aX<Qsl(.)3 =Fa?E1d#4  a7!r V?N;Dd^G8&Iف,L~uadqz#lh\׽qY֢8t<ʣ$n;p< /yIlEnCOQV` ɐ~ÈbHf݄q?$iBn,D AeՁ:iSWlg 5{t]ȢmX[(8+|ٜ.\l wG,WRW3sY'^*/?%{tT.Gw~t~@/=x_| nş`_SZ' ~N2NɓArs^Jy_zMOy?,!?J)+knrs=,5M{#EH6e3rM݆֗%Qp[OX.㞝z_oO LEl>xi||')M _! u) =;6򙝧GR۱\]nwQtWT8P@sW-4BjQo=!)q[?MĩP5jRd  XMb+s]+LXgεaN66 'Y`_Zn˃f^ۺͪ؜*Pߓp}p{ylU ~ՑsPKA4ck 4org/codehaus/groovy/ast/expr/MapEntryExpression.javaVmsF_x&K4'8kAo93(:t߻{, N;e}g^Z C`Տ쯅h^kٻs+[<j̒8b. $VL :Y>E19z%3bnis\ ,7`Խ}Za 25YeiyypHֆ&I'RSXqD’(\uB3ܖsA! SQdNR )̔ф:WYgqJp7fYZGS{75*bgbIu|26+B #N,r>M6JO)_|vsu"6:H% 8bbS\;q 6#5m\o{~[zKdƹRb%ի?;vUr12 b85tnqA7~0N {#LcQxK˫Wn-o},I;GCD0,iqWM@(Ҩ"At Cw3Oo)< 1\bFAx0ǣ(a@Ix|z^<ĘYBo7K&;B!Ǡ3`U̳cM)yRf(4!.0 m0&1"apP]Q4t1e"wU y%08aM.4bV8N5,ǣGuA빚FK[B%M3IQVIPnZÈbZKBv5W,2Z' 91OȂWo:viSW5l%kX[c$|-Nn-:mӖ{XLp>> VWnH:7UN}p= ַN#. 0 od86=M ̴И<$+Y(0R>*Aߎw4ķa9yRcF=FʸWQ=R;~`ɪjp\r` "d4(64p Ԭ^>o \?iKuQ=@z!ėZPK@4 Ox/org/codehaus/groovy/ast/expr/MapExpression.javaWmoHί(̰&dnWZ2N=mV[q#!Sm^ t鮗4?T,?P*{kj?ͫV]]oעqLi0#лJ:rI(DH"֪PmFٜd* i4Ѳ bkK. -SBV/KTƱ|MdFBdm@n'UrNTBTFȂ(Ɩ ᣀX0p#JdM2̢6J2m(ܞ L9*($H7)]P!pU[ r-0] ID [(EDJ$NRi)U apl 򱝠Ȩ:K\oy8Kc%PDʔ'e 0y(<0pW7bYN\,0 $σ \l䊱8T4٩tơŠ@6X'AChǃ KR:_Ƹ7 @ h숔 >X3=AC8Hwr3p 68ϲe}E?yνla=t'kuuh<2]1]n;W~3= Y_yv\Þ%,-AuC`Bǧݷ}NC{<#yğݳvY{ÝICΨg4Cdz^g}I֓5{4{q; ͻA]۵:>lh^ձya}40zF!u;`1)g #k2Fwo#ߢ2 ydw,zyV>|S pcFY庣o;zg:.r5oЏwzͦt6D>:exDҫ٫D~x B`=_n)RBi6Jd>jb4кHZFðE|HN L җkAι/u^̊4[,(Ϭvv}o }\z^ hRwM24P&b=bV<TRG7E Ԭ/J""uۺPJUيG>Zّn5S5Vܭ}.DIXR-G &|T+s5ん)մ[*Q~^@M8s V(q#USD T՘nYǏoHN /Ÿ|k`l"esؾ}͞ZeܜEbƘGUz+V;b/ IZQlzc2D[Ǔf*PK@4>6org/codehaus/groovy/ast/expr/MethodCallExpression.javaXoFZd˙V:ҭꀓD0Mtj'f5n=¹8_ . ?\SʒO VLӁܾ(Zkz3"XflW P+4ry՞/ȵO;]A.AE\g9`y.4_B& 4#QI=ók; K>-WIVɽXE1qX4"[A" pmΑ9˝J8,pkP\3Ŝ ύG"'撌0@T(ߝZLO"c]R*xCKU#==,mRHl$ 5')H-q 0$Oa Jq39$JI)e( <[HEHFe|*1`Ue nJS+2 َv][1,E,/I*Պ\`݆T&XHT`4eha-gU(2hZat+~7L}:C~p`CXhQw VfFFZp0(t:6\Du, 7G<`[w;/8qF7Bo1gfE&>Нƾ&?J4a1Ah<ptWďIexչ0s'ny8 "ȩ&1)ޛݺI%G GCݫWA?~bLJZg7C4F>xy>I0 _H0va5A9#2@D(yMD^x&AdG^uĮQ2++f}Qc.ߢ1T"Z{6czoBӮ OyB !%DF~a;T ÏԳab{J(w2?7g#gޅ|/mXl5 vOH խ9X)㼲O g BL̛̈OR GBؒXнIqD߅q\.pԩ+zg;2;74_XjJ+ۥ{_ijߊm0 OX Ǧ2َ "G``98T/[p Ēh4cj[4Ղs LT OK`-Y2f>iy$-Q쥠I͖أEsͲ%{SC`wj6iqք }ѭHԽGǏ3﬙̆Ɵޒ{lj*28S"BMG}]f27+ Ubq+KZQ4E^{Ii"8MV{7xͦ_ԴBe}[_5INRif6mޚ}wLq/@YeTX]W{D4 FbV5g[)2j s·On:nPe=Nz|9^dpNjN-gaUcfӷlqd/^g3Q$ORܞEn+9[,LFTE6e2W"/0)Rg֊׷֋6x7.'լeҚ ;X5EcA@rݣ>pXb{X|?!?S1m^@>Ө:ƨ+4ek":#ӵg1 !Xp{{J5,R`])[赱2'!x wwX ɐE8M=fo̔'أ IHԶmk>&Bc!:;;/?PK@4'~S@9org/codehaus/groovy/ast/expr/MethodPointerExpression.javaWsF+\[ᄝ\Ud1u%Nv) ' Wj S͠~u,zNG:+jU_Lr-{k?חWoh䗴3,rfs-.e2"[=ugSETV PYUdUq\UyVQ,UL*T'*j^EE^zN4zUB4KmmEV3в,Ux?ES5+f"ث2^ U_ӭL\RJUˬV,T`xe2*t%@ȼLIp[u6*_$+dņ2NW`T l999\W B$Be+{QҸ. D!m N76x]lVj~;kY(nҤT>%.tlR)Bh&MleYf:%GxsJ0Eng15j eO6qji-&D96:HXV\*)EV3-(I4 Q%/ynhDFq$z;&401GQcQE3tM o҅BA¨ѿGCVԨA"];Dq'Mл+x6`g/^^AԱI^Ͱӳ=SL<]Z"ЊKCZ3fuѮYն‘~cYb˚ډ\3u*n}P9dcⳖf)Z3\K>kHs - SgͳZ%s\gxP4k# ;CrƐ 7U9a{rBڄ4y3Uݧ1k/ؚ_lCxtmnYr&yPpf~Vy՞i Z+3 oLp-#IpB4 N>?;D%j>5}w@jkU[|ca;9lJݐQ #* zkLrչ=XT^=?rg fE:K>?X'{]vAWP;4\r]MVת0+ |k.Ml(C)xtņoee nQ5,~ d"/Ԛvd26VN7|\3?z4tK:Se >Sl(Zڕ^:?9> :;>Ke7=EM˜)Az7pQ׫~kGRuxWr(tvEAx(.iJa4ď(K44ϟ.^0!i4wOFCDN("풌PF]B8 vY_Q|Nc .3<#pʀe!#]H0`: LI bRCF!KFIJDh5-SRemNa^otip^ϟ ꃏ=<:,fŹcHi;Uk9(?M_8{WӼEt~dt*Ǘw+0ۭҭ̭Xx{O u=~ V;)=EuEۡwږhm=T߃PKA4o 4org/codehaus/groovy/ast/expr/NegationExpression.javaVmOFL~tpJ*q6*ةׁm%qx̚P@W)d;<̾u ST5ķuZIw ~:I?szҖ7UI=>]ћemkAŃ-?ApHRi,KeG~YR5%+{kDEbIU9!;jfEMknAյ r-jW9ؗ]/Ͳɋ"s]ba5"Ǡ4ݙ4E5Ty~R+f9̖uCV7pej9QLSd~TYNaH9F[1)*e lDIjbVivm:UʝVJU-U^~Rv+o vxHJ5O1 VABtmcvnM-SȜ#:Uk-ul:da =Qv 9L-QܴKRZrg>gkGc}h5L%xnu˛ XhS:n\Y=EYe\?}D0+Z +PDYzm%{.>R$G"y 0.CV0¢̿/@Ҡ28W5Đs8t}NѤH@3ҩ6 a xa$026-#J-]OXXZHc3!K"  tJqʅ 6:,;\1wzJu5F3q|V}wuՔv)<WӵPRmuKP[kuAOܽ* )59W툰3-&s-XJ/9Bx@VQmoބ>;HZl'bILwQL{ Ё{hQI]+ T uf  5ʷ|i|3F N7֘^ ;E 4lmZRz8qeBVӼX=@"SۭSVJ:whѐ{' X-* YUŁX~![% {L" Ϊ EY2R~{{6CEoPaCjCn?f}`hl8dK.@$M2:M-`~AQ`0 g)Y 5-/ I jD43x/8'p[L}]2!+FKgb,X/uf:yy4Gb;~þolqy:aw]O3>lRq@*Q| ШW2x{&9 N:Y_{+^ċ/PK@4.s)org/codehaus/groovy/ast/expr/package.html510 Sxfp.`EbpӘQ=I2\p:E|Q@KI$~Ƣސ|r#q 7aaٟ.WX`p]^٬#UcPKA4jm 3org/codehaus/groovy/ast/expr/PostfixExpression.javaVmo6_q0I<9iKڢ$ɓ0E;jdѠh;/rl==w|i9p3Ҍ/L˲T~ Z<9y>9m''g'o^0T 8jɽ!W1%Fѽ(@)tG6R9DTB$K2u1V$Ӭ4: rRJ(< -(K5ʄ)j4rوՐ!/1Y CԁMag[/`슥56@̗bu󯖢V:j;3ńf_,(+J?wl:S| pGvH&+3w='<徸zh$zfT̪p1Cɍ>9V r1Yng:CE.d*BG۶xo,Ѐ"htf:a`D쾍*i 坒- 0 {ѝo-nEZ ϗ*^sC$z=)nY|2ҽnT5hi3sqkk0.wcBe)PmLsy)~ Hé)MR,+|ZٌjP{YvF |nJzuRؾ*1}|3*Qkt蒪)'҄$5ʳvfQ&[d( }v{Zn6pO3}j/PKA4:  2org/codehaus/groovy/ast/expr/PrefixExpression.javaVmo6_q0I\9iKڢ$ɓ0E;jdѠh;/r $ɻ{>rgr}e_gZe XN_i7899;y{=ZL}qW'M ٿ,!6ZEHp=zϴ/!""YJXLl87:K j >+Tc( ,(F|* #ˁf#^6[{P~Jq6- LEx? c1+&0REWiҜ!SjG]R44"+pb))$ͨP&҅D !R $,Y@BeNì S+8#SL"Z %V!G@ WWy|7RaQ.d*y$ Wu: %f]kiPn]Hp&D+xjT YJj$@>PT4QCbW}nΨu4GQySحBJ|/TqͰU9R*Ƞ.cqrUzB9xZ:yF+lYZ1I*Etq 6#5mOT?L 92F@R`ի/-1vj#brcË֋7˺йE~eW / xgQ^./^5/8F0~q"r gq x]\Qz'h-q f?B:pE =/ 1JckvÂ+s$I(tr:=V<ϡVAZ#lh@pǝA̭jq%^玓MgJZ9^.i{defGW7Q@#|oDόc^ O^$#ˡE+ ܣTdQg_$c“t i Y:"љ}T·y62Bx>%Ԧv7J l@$5w/C6"X~p9MM[-.uA5s]@90n6qԸWc_RʘNUJ/\ez/LMG쐢'Qo3LV1qB @5 [Zk8zܬ4}PUi]jUj{Q:u"Ms_xOX,(ԁ7#}Vb$3BXf,kZ(͕ NB@J98,e/"[A,DVn6\_ srb* r k&2|Qe~rD xn"ʤ1m8hL4b٩X "BȘzƐԦB';Dl!4(;QAlY/nϬhnۋUϟ bi&Gf~)}+PAa#hLle-=6':" ih֍S}66*{Zm50+ԲXtBa?@yPDF\#` ;cҔ9F'4 /x+ʞ&ؑ8aHǽ48cpAʒg9 5N5Еqܩƣ%x8:*E]&qBqrGYIW 'S+t([?kaET1kф]%1)C aSMmj]3_@8$8koֿZNI[9,Mދ{" $WJ۟z]%t7) N;As8[52Lg ^O)=|tOiiA;d}K܁40\Ug_i{½7 w/;BuUI3w9lZN2~J/NKʋd+^.Ӻ ]ȯ{bKFԁsV26u׾2v&vZj_J{8ڜOLdaRPKA4$ʄ 1org/codehaus/groovy/ast/expr/RegexExpression.javaVmo6_q <9ibKڢlɓ2cECwGɎw/X6x<Ƿ<;H.WueUt?o ^N7gOL`:jP+GX bE%2iz̵( TRod"V$2: ru%A݁YT -턨* 2+YAY6Y T婍^冀ZmLfpBRUf9eU6k%R>unjJL0 hiD^,BƒWVQLʅ=D !J $,ٺ@FgIy)Jҫ-+TZDq6f˩T(u@GrZ|%5%3ڦ] Ԏ ʅ?`<4r,JZ2HJ,3ihB])l$ąw8ܮbY뜖Q6ٴXV!'M^v 7lN}HJ/Hڏ.xjMEQ`[D3GRl[kk]?5@HM[pgr%<څQ187Pa"# YR \> n׮"&cC^$^dz(#6 N2{`Ić$b>}bLyy 1flqȑ$}?xpDq )O0. ~0e??!J:p`E /<15?pykbA؛L*w? C5uPGOpQ2 MϘi>2E7}FИ: 7.{jʞ')QF#0Nx2O\(;,>I[1ciji1 aQ4%<  D4 \t(n|z{DZû'IQ`&yX^Kp%73v$|cQydtLɵ J*}؍u]vqe7:R=C;nk=:By}Te_9]!mPm?k\ƚ^w |sPKA4bN 2org/codehaus/groovy/ast/expr/SpreadExpression.javaVao6\CIIXe&H(' e$jI; Q:@bZ{޻Q:0JV3~Y[&SdN~wgoOn&OSHGo 9_\YA6 LJ8e"g3)B2+UEwK\|*j V߻Giߐ겖NUPr9WXX륃!ByhaT`={=ǺB,ʝ!+֖Z4” ցQN ^X~,2VDzEvul;Bά&HzۺquFn[ͧvd7x!zAphdTBkl%{lnf;, Sͦa 9ADl\R.;a8SҪC_r͔?˧RfWjl͑V[g-(8@S2tJͥF0X"c X=He6ԯn[zmͨkW! &zg|пMI6`x" N#-rޟY.1ߋ[`9xqyx&^(Y#~ +W̓X g#^R.xb=r1d0L0 Q.Q̯NjX5K x4 ^$ޅx! 9kYRPt$eh ,`ېT&0K64eH2QF#Ĥ/ ^L Y6 _se5,EK#z۸O`y>KoTlv] ,^5qNr]t?.qȠ3l;$ wFIPea,%ԥd8xpee5(lD$&v ąj˽RwL|ibA;\YPZ)kκj܃"!4(K __^䡸 u ^$a2KW;~t^ݦfж &Lz&|Ȇ0MQ2dWT@K|0͒Txs(0kƷ>MR&f')dqig xC_(I#>e*̃,k8#RI.xc=r!L4t0D0 QC.Qlc p4$ޙx& 9k!OYPx$eh &,` [T_0 %CH4M٘(b:Ϧ$eKy9 c,tm\;x4N2'\%7 D4\t(Io |ppsyJ:Bg@ۢŬ%bv9,&sCaEMUN6u y5/ ^#N6@8ߢ*vrF?nbȪ瞧+cxƸqKZW6=ś)4t{h1ܝV 8/)r= ̧@;^}%xM6j߯%I@ FYyU]tGw CNa),*h=)z'< -ϽWMP` %gkiTݪ;ږA]U湱m}JRNϑkA.^/uE U]z8|+?د[M89aAj.wS;P[PU8$/tA¦d8N~~h#GBڿq>jPKA4v?4<org/codehaus/groovy/ast/expr/StaticMethodCallExpression.javaVoFߟ}R+kv&mU8+bIVO@UܱZϽ{Ï}sJ0V}Q+-P؈WOφgoϿ9R~˵|㐯V// M}~KY#HT9]G=/ mv+KJةDRod+yQ]< Xu-I=Y5< -턨k5+9j^ʊRC^N\)mRS1b0JMAQ44yhLp0e |!ԦUfف-&WhivͿiEqp9onh׉+q_8N\)m(E5wqϿ8f#L\/k;{WԅQ|h7DTg4cx6ϏbiM Zh}o)Ҩ_yV}Cnd;n%M{wC<:יnTl܃H0=? +iC깒:{YAalNuPۓ>WZEKI${o8A>ҳ=#wp7C?nU2Fj+e־rg`&'ju|l;ُ:Xq*3ズFݍœ\.b4fNTmocl[|ZO;郍BlS-naɽ廓(’їs{n[=CwhF5`oXX 5Sˎ'6dKlR{gQExcڥ] ~9ܧ"lat8?v[F PK@43org/codehaus/groovy/ast/expr/TernaryExpression.javaVmoH_1B )gZH;'bsINpkhN7`F<3/s ܸ PWyWK=xߺl]w0J[, rL[w;Bx3Y 9,QZ(4rD.J6b"NrR# YC.'+axqµ!\dZ65HeR\$&By h*Ela<񟀉LSdS,N+7^sH>`\.XK\'NŲ?92D<7eR'cPA4<%0@V $*+t%TlLI70xL1UGr%v4לE)\Y I)OBQXqD’H\QuB3ܖq-A! jS%Vda$eRQ(BK],RFc \,ͶY*QYMb )ADX_Rݮw%f cLo㍫TSJg/`7ϛ\iMpG7fH>- usiP\c#)vZ6h~ Ɨx<)acmΓTW:SDD*LڧWLJdpVh@AJh6B(M0&!GbCik}$+]sTs(Yj/0൸gW+f>/uRUXMeWSl}â1y м"~/kI ^b^r*)|W&Mr=-y{FU|'ݸ̡OHL3OUͧ^~ގlf~^v<+zbv.thWfYR=֞ @oP-A,5_.u(𬢵Y8lE\Vn2ꦜ ]<9z{]s3ړ}{B'1ZMGJco,kt:K5=;h{,j{^+do-7߭PKA4?nk1org/codehaus/groovy/ast/expr/TupleExpression.javaVmo6_10u&mQVɕAQEle )b{g(/+@bYyg;.*n %V\k!+waOSw-\]\}%Q(w~Sb4#.(6[ XU@_NqpCPk6+Fimu59W50L0 (^0rdۅ,A*-k+Yٵښ0Vr# ^8a.Rj3YZqs֚jYGڀ↉ _lr?s"mF4bƵgZ ,٩@B~8gNSQ1)Վf\Sl*7@sk"HJ A*<+XqEaIƣWK"Ѣ P3ܗumA}!6tJ[I”S ) *Q٤hl;YJP(jf[ ",TBq,9Ӽ)̠.sl*ՂRnvXY⢝6R,h^^s+PV:EB h኶ ~p|g~7> kd˂RX`ի_[1^!be%ws4y/h a Ç`AGQ'io| ?0;I!z"|D4(E0QY&Ya<B3>'YdU%EZ$Cy{FDV>!Yy9iъ `ԉMVzA0|Bjl,vm{-p[v0m|WZ*tx~{ᦽM_0Dřꂩڽ{HIha{A=EGs i~?=πlI^tXjæ8j<|`ΊțO3N7z]7nPQbxi}:B!}՝(I+JwQ|gő ZX"6(=; ѽv&Xj;ek _#壸pP ݣ~@wW\ sqA_jj[܎ie4 BiR֨^@#mbk-e6796̩FƟ$"pm M>͛Uv^ңH#1U*,R؈.oz?w^4oa*'jVi4_l5u3Xʌ<B$$nԔE25Ȍcr)#Wf2+(hAF;3IjF"(SER/,SA$rRR&`u^i>K/H[sZ0EdrZj2l!񟤙c%s TFi/A8`1L@%:)(j>K&G :B"@B0VJcVpFH_RX!p HU#͒SՕw'"2,^ث(u !Ћq-AQ7ZKs 4RvTrˀ"*Iuf24G3, V}mUqI͢ +D,y!\۝qͰ[8Rd(`C1\U:Ծ1hvKZ8QlU)TK9nAAH樎LyʥH;Cr_12ĎCNa4W݁yF]{#ot?MxGo6Y}oN<2}1]f\Ebzp fiڞKxȮ933PZ44pv#l׺ǟ3pg٢[""Ick20]Oȳ;50rI=ɻ7~͛]A}ǵ-M G ߠKض~>w H}!cg_#MPkLBxwohg-lѱl#O5.b he;Iq6R0hSgCXb3 CG2$9LGK{ATήKŹ'"1fXAHda.}Oq60.;Ӈ8ib ,Ĩ 3҉wʁ*qƷ|pMY?C )/ 6&.Պoc??֛m}q5B~6|l8U '*K< ]OeWtM+^p8ۊ.px܋Z֩8+Z[*Juism0Z!8JSX6Ei(؁exPmvqk/\|ip :TO)QҎ=!h[!ߌI 1::R2Բ4u~x䝣9[WiV 91@=dvؘNbߨ)̝D\+jdMPD\]8{\ݜv9i]3AQٵnShuuHp9_MCg9!4Q-~̪ND ]]̓?=p_ ~ty5;\^^_~,~$[y 0UMAм"%x4xV"IK!YUR^\#+uNps!Gwy,FE#bNsQ&8' @(GL9 wvjoNQ2Θ|ŔdZŒ"TG{0ieR6maK K4vJDV#,@T)!cPnʴΰ|-ؿ XXrj%g>(a)#ƃ 94V:#+Y@&EްQn)jaY?kJ:ֹ,IPAEa-gu)bNZcuG?G*( S.qe/H~b;C~`A)B\!DP?v?؏hd>kLp-ys^@Ä&brTk$ޣ᠕G3#"PH떿%/]aSt+%,vK!pd"8 0XԯItw=5KՒU:WCk_|uoҡ.6]x[,%w~^!ߖ2Gp"P}ۃw} %*7U hMy}*o-sHqQ|ij+m>&ώ`s ޿W2D^է_|;q,Sl!wA/=b]57"TǝSKׇ"}ގuP5p}M3t-v;~jBx/t){۪=Rvw9T$Z͢q>Uϸ=Z9l6ΤNӍ9P9VGમ{C@*߳,|7*Qvnkyߚ-\x2ҲwL]'숑IF-!9;&gڰDrYɒ/xu~ x|ij󣫧pwaT7COTCα!ZVN]Z PK@4 /org/codehaus/groovy/ast/GroovyClassVisitor.javaVmo8_1*-8vw[L .ۚĀwCC:ZzթC yf+yu$ww]V#4uG4ۻdwM'K'  sE- 0RԵq ̆2j^`Jlt`EhԘ,iVTc\9uMα\] 0ei@7Dɀ™08Ky%P˛7~/}LNR#aq&h< %8`' `ȳӅ0 ӌGqtNH !1'g Fx5@p^5g,Mgӌ'YuA& %E%m1?%EZDlQvlQ&z̯Y1M(- 1)dķ!fyT%,z |`W쭱w-Et 6x% ӹ؟Y 5azi Ca#ۊ7' p?|C("81,|jZҙ'8`* S)wЀ@7NbysVj!jz͜jLwF o'aή/gq:Z7Q(Bj^jU--~=coPK@4SGI.org/codehaus/groovy/ast/GroovyCodeVisitor.javaWooDtaTD A m([{,u&̮_R BDmofx|M.Zp~xyBodѯ@}>..7;xggOTB7$%006L(*F`)HB@% &L*x/) J=Anj(@fh+38 g0|`b=b˔ ~` M4_Vċ ZrHAISb/xbپC[ӋčOFS>g1e7T8G 8 Z Z5Tm9=gNqNllj5 )5"E;=TKVW Os>9 7“ _jxM/ kPx5 ˉs|I5jr^ɒQ/XSҜ^zgQ _j(MB@uwwVhFUT_HW͆4~3;ЂK`gۘO$ZҐ{aCctU4N0QmfkZߙZr/kKE ףBz侥qe[+ܨ/5#yޅ W$]U<cWoaNPKA4L 'org/codehaus/groovy/ast/ImportNode.javaVksF\;gbI;c"`moKTv- Z@24=w%@ĝN[Ⱥsν:t$s˕KĺEmT{Cg篻9{M??{uMR5jNۊf'E/BR.TF*g&t=_$yiJBw+qRy2Yׅ&3rTYyrm (4Q)6Rg([a:i}R..iidLo8JˤDlXh45I6℣ 9 u~@]0¬FH uQRKdP5/,̔TzѦPiaMlNSg )*ML/8^)ڌjb6zԮ*HJ6v/*OS,ueYƃqT-16t ! w-fC4EaȨ5ύ<*:K#Pt'KSV0+ 9(ĕ;ËG~:"3ks;FCDP׋$p q6'FP14pKEy :!Cp ##A?`"}ZơhF`{oJ"Q$}ġ+&tS߳tqVߦ++jr !dGM?TQ&yr(/l9ͭ 0 CVo]T[%^3۶$yAI07 XW輔N 簚6߯z|8=ԭ|^O`Zvppb!veE7Ź1Arh `,_ ׬U]k4_xM@otjL]7@o~;wJ$M%7leqAnm+q[K@:lF}Nd}ˇ~s`2>TT ¾aA *Raz(XemD[-U{6e&dF5wq_Iu6/y3LluPCO4wo:NZ?>iҞ|zj7c]emUDFJƣPK@4q9 +org/codehaus/groovy/ast/InnerClassNode.javaVnF}W  sj'Ahimm!*I1"Y+ E KJQ{fIYTE P3gΜnȡ}smz*KHYUgMkz٫q>y/4KbԜ%;Iۿ!2jzrRyBgń.wq2 ٩Pڬu+IZV&WbFmZRY̪;ebJ'Bb/pCwiuKUE"Igvі,ҊXNShYVܥEUZN@utbe. WeEFW*ͱЈ>%k&^ڌJtPYY0 ,=Q|&i=R2 +dZD5)zKԩ#dpm%{㻕 JpXqDEI 뺀&E%f][ipn/\honb}W42 UΓpF]UMN'ƣ67},Krnf)KJ0|V\q˰S;fZ.ം.tZ9ҥ?`P\*`FMQ˥VRJW@AH樎67> eU`znH3Dosm?|?*9+ Ún2PKA43g1 >'org/codehaus/groovy/ast/MethodNode.javaXksJ_ѫJREcw8,[\W*u/=  9ޭ==<;fO?Gzf't%һȟFо;wW7ѫ7'_yK{K =thmby{2 izwnHny+NƩ5҃,fJw׀e _&i,TF6( %*wc6$<'?k.su׵sn@2(VmJȗ+)1Fk2&v~ exK^ŵ T~5NX$ƞmR,RWXȝ!< 4x, Tz"QAA U Wz;V`ZЍ`R.T.ث4$dqUO@w*HWEbٍ1!+5KXX br$mEnfRЏbNQQ ģ63)eKN#̸9Y'X|n9n{ c ,^ ^ŷl[濠}(l Q%)LR:l[Bu_B.1<8X>[h bRف&̐Ue+4ݜ L!K&{v|->f 6 ƥI1u,|,C`9:R{aYd^'&^lS4d16MgM+3(|4+]S?7's";ta:Sȣ i[9ZLt k> bƦ=1FzS$ژ:d_In%5C܀αi#IiNW n~scdctf,@MWGn՝rDd+Vc: Ǡ٘UmXȰOi21 GW_a T^3aYcΦ]>/P~0*2Y7~PЧK{TyKWᶑSDxѩIShLGiAL)L'Rl^+9;P$5@956lQ~]Nb٠\n"?'nv:r┸k(6G$]yy=O;y*^,AffORjR1yy3WT-vbz],Vgݵ+4:ʅ U%EDp%Z(nW8;pY{f䷓lyt G$wTF?!=DC ޹YNad,!چ 9ԷF,\cdơi0xJğЦxo,&;7 k7@=l WځX!=]te lLvկG̃'6jh2,{*^=7h >h80RpԤqV cSjF`:ZPeWx\iwn3e)Ca7V<)Amr s_31g'\O(M! ^ Y^~P@ t'R5Cu'F߃X4竟qȔLAy7w'y;~ ~vt1a kO$B%[.(B]yK_OI%Vmxrd'(G6c4hqq+;RV޲Y_|0I?(4;2|F^VYn?Zkt<Z"x\֫) fhZtPK@4V &org/codehaus/groovy/ast/MixinNode.javaVnF}W  Fr( BIkD$G(vE$&KJ{f E̙ٙ^Xt&4NW&Yn%+g2h$uMErf+:o2WJ$z*յrV(P[t`+PIZ:ol7rA**lȪ*T*7*jZ;szE6妦LEYZceAhσTȑ뵒TPWFHȎ|d'*=C C8,|1ub4tC a= @ 7æ?Cg EۛF~ZNg̞H|" '#KX/rEhGӁ+y~D#wF|x|G E#7Knȃ?;&N h2 &~(ac1@y|(¡3YdQ(P `tz#A7Ez%GڀodS8}@0N00)Ig x' #i D^4tlQ(n_oh䇆i(l6MCװz$r}ܢ^<ɩp*`n(=`F [!$m-`1jI ̝ `p7d q|ԄYf٪Y$raUFZ ot>J]k9,ܖs;'XVs`1b͐YH?(4 c$o6}TrY#Ay_s~Rm̘a^>t—N&e76эho-n%gHOklc:mGv aA4HgbK  : l"ܷ>!BΉפ֕u.nPK@4_k2 ,'org/codehaus/groovy/ast/ModuleNode.javaks6s+M&J>ucvdIGRI=77-EB!G.Cݙd".v/ΘO?܃?ȇw1>\{OV}cwC{!c?f"D/&Ncۺq#؊y Nia bф@ˢ~qҀ ,I uƔOI¼MO|e;.buֵ%`'A%,,KɎ:8l =wA1;>;M?J, Cm"?@chz "kR'(n²أ`$D0 !$ 1EQN9 7L +[ ) ȍR˥ $U9EwSB TK9ni*n1E3V\Xp q.~㨊:q`8 #MꀰdE1d@(Fh'F; 1`sXB5L )e:1G$1XK cpo7%!u*`5x۹\W C9E q{bnoX\ xƸdӝir?d$ޡ*l@"8m/SW5έi{~|Z5dN äAq;\d8̱ҙ[v7opvO_aۀ=y 1 Ox}T:d6wԼ3s}αG7ΰƷ9SӹGrc:3Gnݐ,cӡEKk1 JML{<w˜Ob|2foi%E!29 0&к#a jZLn3jU4l/-ECˑ1|"wmX̱a_ZFx8Ch`GKV3gaY˅cg`c}:quBsZ[k bƎ &Gc66pvd>2 -FS0<K6z J3yCO@BBCئn4:.Agu`r۔B7I:`gqJXF}@6${=`Mҫ PƱ{H1w&;w2cBBpSLM OP<1̙'} nxABОĔ簫'Ch(\; )C~.'*K]B}>i8%g"> +`B=2 ΃YB'с}- eO.t}ݹA?ChѴsWi+|{W"d0_2 j-ώl‚MYڂkчֻpfevɁr6xW_\VXg.DB& 3aF>*e6n JQgkmR0O΃yHί4– >y.:F" :\緓 &k LJiMʤCݰO\W?$Ze"UZPԮD^Gxn#hҐq{{,A;Xg_&˪tz}z"E^JhO%'m Y&_ βdΟ3'c-]Kn5Ÿ=5tl 8L c RsN0EP.ocY4B:| uKh:wʰCb冁`]0HXD InZ:W9lY+pzjӁ&plr`~jWM+/@GP ARJͪHL?NCk&h︄*Un(~OKw@u b@ϙeKJka1ktLbXMQC$+ R.ni tpCq8 BhT2//&/'N x΢HhU4f)lt!)DĚ\B@IKv"F)pxcoN0/ra7¾'DI10llGNwFX74C(њjy%I )G?P̨Br%U{{^\*j\uXh~e&+3Mnj"r:h=|9Q P+ mW _q/j S=[͹_mEQu1Oohj%3EaW 7AF?`n㍩a7@O\Z~YȔ}@urB<`.ڠ{-l薳t,*~Z]GY p4WtUGceUD,v> YAsb<[ہWԣ]*ד#jF9%X[s xuR9wV-Mdg(B)>pTވҧ?%d~W垐02T K7r>Vh+W[Veؑ@QW54J[z1@.@+1^sG6a.>gھ{AlHU»F^_# /.otiK=o E]*1 } 1Jw <7~ͧkn6 +!4B@Yō&.3X'=As"oGmTOLИ,իˠ<ő./;PU3|X9A}7[Vo_ׄh|=3 ]h2JoaM}֑?y7V An$d NpwFk]{xd!)q*cb=-$b%B֍r8mŽVq_<y~Ī^ A,aOfS= nF ]wED~kʉ !^ _#y Oj/ Q^pjy/rp:L8P!cER!GUAH s|])E?qe0}HI]OF"hbd;7>Ky)1ݱ cBk^$@oJx!;  "hV/]\J iN\6W>vPKA4m9,y$org/codehaus/groovy/ast/package.html5A!bē,!0k˂޺6AўL tRf\^ x[U0*l md{q:$Ԗwuo}@1Lz*r2q*WĒgQx*6E4!D)a m٨B;FI JzAQj"Z S̐ +ߝTK?m@ 8 )A3zKpnSl bx n'wC݌=9( /ݛQ8/̚i;AOð} ]'hQZ( !7]8h~4Ƿup)t-Y4еG}˧T >8=!'9Rpo}; ҍM)g;DS^ [ 'd,8?`EY֝E9G!D0 B7 =ܠ] ?^i!GhԈQ\/t|4 ݁wޠtLLM F=;gEZ$lvXCFh;dz^p'7p݀-2񓅬#C\cg[ޒ{DtEeܪ[n}%:oNcsXyw'"˯xR:͠-?tv \.p^4bsjs! <01xhk>*2˪qƱԊHKꑜ"Wv"y{0 y$ΨH?cAQ -]7"Nr De0v*w:{g go|[qޔb$ά,] &(p9򂄒w J0!} %c+Ax $קC<Iy0h˜5?`{ky$A7vvUI#9z!`SҠy467t A1^`c ExAx;#`('4'p`(w &#I|0~c`ije|cj]ABh|B_&@vOE٠<=2Z &Mc^).p,t;ak/-x1ybxOr) feg&-pR3gy%? M"mE.Mq\܌0 o]0q3(:-z]wRrl@`%X%7i8b¹]{dfc/[˻5 g<3N<:g߾\ F=&:o{/#B%oRᬤhmfTmp6%IRǨ2Gv,"%oΙu쳫@5W&3%/Mm NN޶OOۧΛ Llg xDrulnk8w2tJ`e]9n.*p:iH9"@B%&k#d-Р孹c ]@!kKY/[ְuÝ0s}˵,ĭ:[,ڊ0hF03í\,(g0e!v^Kn:H4xZ[ZՔKkm@qD[<ީ]F4bu DZZ9 Wg &dSR+̸X#SL![N~a6\] } #OL,aJdX+ʹ.Q%0} 9Z68]bAkܷt,Lm$%T}E]JSѬRF X%}l{mm%almv`\3+gWV~\0vKvu 4"šagR? 1lV+e;Klaro譑1 c/ ,mU̠.W> K.0%Q\A DIqaq8Õϟ ]^rka|(%YI t8P"r9%4/}@$w~\Q]: c.Q4FtdlR=EIۋs`=γGB ǰ; U̳GSؔ4mf(HD|"LA3pz0$(cQ`EqJ2 YNqN2IzIhDs$kc .;ΨS9I(I|A?F]&@zIEƢZ>\ ΧVQVP(aDT1 1KGĮ&f9)ͬ_uҶUB^հֳ+& {W][nQ+Jmo0m/ih4'+̳Vnh7ݕHu_J])4+ ;'~-ðҼԯn﵏rכޝ1 z:Y,;ښ =@ZS,+:wNxZ*x`֒/(s5XH<:uPrG փou[*zSS/3_|.,noo{ NA*0i֩PDee^z!E~vذA< *fd)i36SHQsؐռTu۩}?ًWR6fa=>Wٮx,7&DeTE.PKA4[0org/codehaus/groovy/ast/stmt/BlockStatement.javaVmo6_q0 <9}dI88'Ia@iʢAN}GJ嗴f 1M=sǗ3 :N 3| b+Zs7xqz}w8==;}sr6)6eO<rtfKhvOO6x `E9L(ÕACl4\s♏X1τ6JFq9 Р3Z %ϬFR6NZp/ rri`.31cgj.Z(< 0y.E1,2ass{R9dh7L8Q~Zu2*c}8@t,Ғp@X:k/YHL=`JjfgKd:D6+YqjrJ V*<ΙseZwJdX+ʹQ%0M ʺ9Z6>8]`Ac\=4t,m$%T}EKS,SF3 \,\ͦYJQ=66 Tbgliv5Jǜ3 2׮RMmj|9{X:fyFk\YX8ll] t?EB hn~kzKd€yfSbW~u3cgvӯF&Dm nhsQ\?4aʼn? <}ւȇALOqq$-a?AЧ4E4j~]5W3>MlH.hbL&ZApzupIP(`EØ\[(D2$)M)(Y$$]C?J^Ä0FЈZ2;Ä:h8R'\E DH4 ]PYTӿWcS+p$([7aDT1 !Kv],-MrbX Z 0Хmag[@/ vEe Ъ[nݫJtljv_Tik37' [4C7#k-ΌTGJcl.nE1( En%<-DSLɻƜȳOó9)4>T޶{B{=Jљ{=)_r1ߴ{<Ghf3_+VMM';;".UdCcBFs/B˅AnTq|}N{V]=ٌYჴY?vjVT4WRd`[4:N^6ɱ Sn6z\@#D1#n=먻mE:] dp4>X(id987_T(q{\,'|ʯr/WШ5HJ|0 Uxϥ%߮adMQ-!Vӡ#vun#&tQ\*۵p\?_We5;9( m2L{<ߔf UPlX%4/zt+hnvݟ:~\9FPK@4I)s J 0org/codehaus/groovy/ast/stmt/BreakStatement.javaVo8bTUڶN]n . ۚĀwClC:~3Pt!{{;Nyم{愓KY7 \msy u}YgD5+8 ɨx8]K)Dž2N6U)%YHf#6bTX@MN&qm%`= #V iPbMepvmO[z`K5SmY*G@+7efPTe}R.RjbmkSHL)1pm鄪qbkV;׭WTk ip!De5@ܳ;;cV4U0O(,wPqF(#[NBTn } +PKi,xE-Ѹb|0 >oAo>uOi{ۆkl287O'$ SI-4ȺԆRf#=/$6pfYEc=&ZRN7y!ִo7/{&f .U9I{׆`O;* +ȂBP[ggP$$;#|KQ{߆cr`vU9ʬipnt}:xYr߇)Yz JlN2>&yf|f_ `_)2NR09Zh8@0#c\|0ɼ_F҈^2{{x4s {i4\t(I|~p>%G[7$Cۢ|?+L߲8b=rSQo ߇Xue.!f׳-o !v6 nE(]t(9nb-݇ P˕6n;eS\2x7 raY"R˵zJXcࣀO'K*OƶkN>9|gtrh/(i Wo3 Vn`{ NQ)*1,7hg gΛ_5P§}ǀ[tC ;kSn*sgG{kjWJPKA4Z oc /org/codehaus/groovy/ast/stmt/CaseStatement.javaVmo6_q04<>8MQYfIr`PFblh`nas=w|zpċ> +粶b%+8/zgWPsؗyj̒k8OW1RE>5ziVj+AUABNi^GD|XR5K#A=zOBK Qy (T$<8kIJ;ݷZZ|,sgB[H=/--Z,<',J=rU%y5oXkR] 4\ ZZQ8eT+[p Dep@V $CVPB?cJzaKd:DVrGsͩDµ@ߝT9D9’{%"DvsBMݜk+ NdЙjVϝ&$ ZI)u4&Թ &eԼxM6B:ڣnY,P "bgbIu c%q5->W\2L&H)mF&b((`EIn2 NiƳI*Dك%ZCxS|JCmuO|%' xix'`Eg.ʪtL\JdZƻxpVh@Q"W%s|^2f |nfWE©IrdK2i울{& Ҁ.g Vqb.TZq;UGDηDV,jc.yx)}׈<:V5mذ~'߇δJNfŕl8|PKA4RőMM 0org/codehaus/groovy/ast/stmt/CatchStatement.javaVn8}W uMu/,3 y+-16[Y4(iPw5n5gΜs8"9]ͧVde/b)K8/ٛyO8;랽^q)`pyQW O/15ֈ|**U==qƇ,!YKX,Tm/M⢖NU ~H7!Z iP|Aey:JWG'mxTv ڸo0ӅzPmͥ)K@stYGUM U(vY3iHƺ&^\bJڂV ?)U}8@t5p@Ɲ dCV4V0O(֬Pq@(!^-vSD@*^ny)L*K6-eupI4:C#B%hͥ m|qMG騑da,eYPBil$ƃlf,su GdS5@'H< ZmN`I,eE_|̈́aZk.>J9b>b8q6WGzeo|!g|=Cq>kI̊k7pSkNA욧Ɨ]00oyw ¸ϮQ AQ(ԃϟS^psAt0aiqf88D$26(=gփK,0H2AQ2S$pvˢ `0U, =ހ5uPg',̰)y2 ڐYi>1$mFД= ~p\1oʁ'"(a7DHG4(cp}Aʒ[- 5JYkd+N7JsGK0qtu| MݚƑ=6]3|έmalG&DjX2 控 9 O)7:riW3ٶ[Lob U8*v9bBd^Q[3leTX1E^!VVf }7uNqyN<ܻ--sw,,9c{0R} ܬ 05Lp=E.eqJڣww,1J'rhuWŸT9dʳ{o;~['j`#d(1.mb&_u~V|3 wyCV5usmv+yB[1iHkK S13kݷiiS>71?:a[PK@4}Q R 3org/codehaus/groovy/ast/stmt/ContinueStatement.javaVoHbEjq&I[݉Pلl4ߺh&Nof TR²;潷]w/<8yB]YU52RV&6+ //_wpW퟽7o[mDN=!OF-WYxE)kHwʡg0?$TC"ki62+jXĦ`WZ/0-ss!<8;I'xTvڸoX(ujb;@hkiJe hmF2OB~Te._XD֍KL1-ipbkwNQڇ#D!Z $=s>fI3U LcT(fz#_hn9u R}'.*fl/aM`w, wxgP3G:?Tc6aOl4ߺ lkhFUY!%UwH fw{okwN=89\2ʅME{ ] ^~v;7y5LJ/cσP/-ſVx!FsQ \wse4>e %ՐZ,|JdjkdenW=;W5zjnCԵ. unNpqzea 5Um-Y(K@Kת,fPUHº&^\bJڂV 6fyzzUڪ\> :Q֚H8 n2&MT%=J2-+T\)JubSP" wyosy)B*K6>ieu%wK]F] =.W8dp43Z9H&FIiU !ԅ F2z^`I.ۀ(DqC~3ⶫx\$ϠLJ<\,zpI0H`4NFqʀDy~8^<šYA:CJ❥OB!Ǡ7dM 3Jm.IچmHG,t0$mFД= ܄~p\2ԔO#8aWDHǽ48cp}Aʒk= 5NYkd+nuor2$QăA| M]OEPn rԹ8CR-"Ʉ]%BF1! )EMUN6u y5{3v~AAp*68)L-lL[-9,ft}"jva{Z,/F]KU6-CX5f 9wS|ZLS~wݣJt&5(>K>9xYx`!ײxF~%ѧo:Yc`lj\+:w/5Ǎ{IrT]'aAەѡָar~#:lp:iFs'H6zti%ʻG}UmT>͒7XEO^rLڃ~!|ZG'vܳ~[Q?7:=xPKA4M3o 0org/codehaus/groovy/ast/stmt/EmptyStatement.javaVaoH_1"58h>1؜$ͷ.^^HSͬ!!N:RyޛڽyV݃pҩJծCneg x}E/?2_د5Df`r(DUVu3I~)ۅ,!R(UERUh,Min1 w/iLv7D^RV'Gbxtځ{V`6)B>VҎluI,LY{]/!7u)Yr}|}!\aJƁUN/ ?+ӹj CȲ1DI@p] #/^¤}@IڳBT(fh8u %RC'>*RWRYY(-1c}jFX [ͧ mﺐ ֘Q+\ ).Zl%ns8,kit,GfӰ4 @'HM^ ) &J6m`ЗS]]v|keYb_Fh\ܷB[o]?5>"!(K ~/T%Wy(CdA˂$,QfM:L?<ʹukkv!b6Dr݆)\Ow JlY,IE߿S޼{a|4eB`vLqƙl JqOxqY_ArF#gwT2+X\0x4)Lg4 HԐh xkaqbs;τ€!p0fm9)2J mC~)8-7bC*_3 M𚡍'My v$lB1gu r7x;p;bx=%G[7DmQv@&z̯Y1M ” mμlj3~Ap*v8vӭt 2)t-}"m\.@WkcݿF]%t7XL>? %<=( ">JXYtTI]:A' ox* (MVw=l1ΛTm5պ:|4͋P*q=$_ |/sy, jubm.Wε׍=E1xxj*'( h7r;PKA4C 5org/codehaus/groovy/ast/stmt/ExpressionStatement.javaVmo9|+F(RI$Jڪ 8Ov:.kd~3^^6GN)3qe%)`=#Vg lEyl$q 6[,t*- 4 hiZ20pOT~P 2]押ZHEʯbm+Itpe*qb#V[ϨNeҶCj"၄ :[Hׇ^ty¯;`1Kb!!"(,i]QE) 5O.Z>Dp {|; OG.0\0Ny2 cOq0<C~^|1ݰQ U8O$i$Q1yx)6%mʆ-HƬi>1L&Z cF:d(c(`E]e"e r ox%0$a->4bV$^5>JYO)F\E D4tQ(#T߂+1) OvULkiˆ]%Fs˜'d!FJȫz  `Wl[j#:mNW1m}"k[pAKmZ]!meG C|K`[-ZxQA\"43߲o\lP2Qnk{He}?pUktV5MfHo=%d͵Yߴ! 3c`CҳL;lz8+q]ݧ{, A ~Ɵ{ZN(_?PKA46r.org/codehaus/groovy/ast/stmt/ForStatement.javaVmOH_1BH E:h:@֍$nlބfyqqg]8N0r*g.]©~?9>9m''g'޿Q)c`?p8.Cob*+HD@r\eB=bJ K{˼.F S:qQIPw`&E3BK@T C@ Yp_ (mT]Xm.04jY2w0O*Ku_ƐY^PVeҜ!S Vj3)9.*ZQ,S]2E&+-(+E$,qg>+L3PY|LQE#[+Nn]D@*tysVaTj*K6OM@} )ޞX+|8 YI$@ri|4Ni֒K>f3,s]hYMRU "6y"Է6։N}֩JI;T=x_aOx6.U5մV@}_&-~W},ТG/UhK<ÿ,/ ~?kk6jCܳ m4¬9nl8MaK0c_zW&rohz河Zk `W]cqbU1GPKA4fh_ -org/codehaus/groovy/ast/stmt/IfStatement.javaV]o8|ׯX:I{H?PYf'IVZmhӠ%e;J;irwvf"?g@ga/ymol pI y5L+V|/CσH/bK!3 VK)\w WUMҐrՆb(1]!ĵ g`B3sw LkY]B)%llxpÝ0 }˵,L.j)Z)%/= 0U%D=B֥Ye-9C'/ZSJ \k&jؚ~u҈:UZZ9 wg5 f%*.:D6Hso*Th˵@޻GrQ1ʖ6>"-\P7ڒa  JA#”ۖARx]JeGYԥ4 F2z^bIldcQ; _ [#hF`.0 /{jJܑh+K&,$'p$CKك4"{%kk+.x0ɨs9I8I|er M ݞ&%E>8}$8ZG[3$Cۢż%br1$]M, rS ɶag}@!^#v6 nqE[tVx=9a,{˕TŨ 7ݵH2 RiV+Jc|8k5w _GPIgRڿlǒ >,p6`OÔoƽ%u<K mo )Hi׌v# *Y|iWe-`wU:Bu+& Ǘs0FQ_f^6T ~V=z@׽97^Ջ-h4BƓAv=q~No4iPKA4%#t)org/codehaus/groovy/ast/stmt/package.html510 НSxfH.`EbpӘQlz lc2fe3Jӛ&.5HͩsgoCjt@) jd\x1E_zr\PKA47tK 1org/codehaus/groovy/ast/stmt/ReturnStatement.javaVnF}W ]sj'A(jmoA*/vĕĄ ˕lȿwf -hZTw9gKvO89,taLV*3-<=}==o߼a)Fr-&p8.&SC?L֐-FSQr!܌6R%ĔT#Z]Ċe^FÅ)T%1iQCAhi7D]QshAe9pt;P)(mLŸ\Yahղe`=a🄱*KPT*/(Y3iΑú&ZĔ-(*2kkRڅ=D !Z $,mY@FgIâ %ٚ*ZD1TKi*HN u*<*E1ʒZDY]lmSgh.PMljKi{B+28hO$ CI#*WGLf#=ϱ$qͰuAi<&I:AD|lT,oV`I,eA_h􄤽vafiu$>J9b>b݊B[q#52;>3塸7. 5.s0AZ1n"bzH΋zGлM~g^GƼQ8勗`ʋv },I0; KD0, @b\ul<.5z<=t!փK,Sg Q€Dya}/bM`,L!yx3c:PwAGA }ƻbhsSQv a-YrAXuF҈^6{Y­kεoDe@K{P\^;; ۧ!]b'wZDQu/<; KY*$mUc6aO`s^4ߺ hFYz:Ryޛڽ Nyv JJUW ^˷˫;xwZ[#ӥ}_AW&_,-_YpRՈF*8}Z*( bU+QYbX mu@.j=O(!Z9 KD'xqB|.R-<'-~)OyTWYNY*Fʯ?n&Uaຶ`yZOb&fG1dqȱ&0M<xF 'DW8[8OGC~Ě:sc$8}k<9 4jᤔyaW:VL\mT'_G:dNciu;NY- xJe5/= P z8L7mL:;lh?utWa8H9@TG46:Ϡ>V)Y z5>r*$mQfIr`PƢmhP߽nmH,qιwyg(;&VX9?h/ /?98__8*f1DT+ACLN%IJf)3c2S5za=;U%zlonB)AG /˃^2o6[/,tjl@̔@s*:*&0Eȫt^3i򁿃$^D #P?Z1*U#Y !RHnZCTt aQ!lH(Rna0 9tu%w+fBͤ$cDh1uB 7%\k4KR.`ob^Ut,\KjA6>δ`VQ Sb'+4(jCQT,eI,P "Ołv5+\RVYeߏ֮L+߀n&\G"hT 2و#s)֥PIW MP$&XihW|&g|~^[ b4VJ̝gDa4 W~v;*_3@Aqt{W8ɠY0L {1?QxcO? a$A(~>s|q%ma? Ń0JyvivAt,kp<4|pqʻ~`9a{s`a Y{M;MD!Ϫ<ȳcM)yz$f(!.! jS` ߆h ΃S2<+ 8Iy:LFQ {wYr(qz iRc xpSAʣp߃uA빚F EE%m9Vo3 OXg{3r?~1Lr)s_kdt;g;>Rӡ0=*,[d3 N%!X݄HPt٦[ɵV*;[B8NaWn{a`V?[o"n(ˮ0h6?4Asa*jszqmWCjQM]8&v}^QzMr`cve}vوQu=6[5[WoG}siG}GYFEk5*׬R=_|>zDn+M;D"t/yrQ7\Kѱ11p޽)MÛ]&SnB6E`Xw[جPKA4.ĸK4V 7org/codehaus/groovy/ast/stmt/SynchronizedStatement.javaVmS8_0S`rN}S`lʷ [$9VFRB 1 ,>kIyuCSΌnʝpr.~+[q޼~|?~ ?{srnkQV1}A^<59 !"B(gT0зpYϔq҄5dd!VBd3vnV7SsH եBT\yA^ký+7m^:Jݩ̕#+U*x? wjPRe\|]R:0 ZխϨN҆!Dm5@ܓ:H7V5<`JfaWKdzDqWrKsͩFu@߭TKCaIg%">Ds(mݼk' mN7d75Zt,Jj$A66>Pڵ4۔Q Cb. nYFQjf@%HE%lk1쵎V,r?Wmڻ\"! 4HC >Wr.o;~KdʁuE)L1͆u<̹I r9Yqe p<+>dC"8hC %)2>ik˫W~-Jn}g,;̀_GEIYģɐ'=@iG .Y_k4#^Px`<8pde0d4g@I y"~Ɇ^ͅ>FEȕ5nD6lJ/>y6ɕщ-okUD־|73CBp@b>[۪#vm#!!ҁCG@5;Ac.8SXx[Yo:aΏD.J z`ym,.pe e}M1PKA4x3 0org/codehaus/groovy/ast/stmt/ThrowStatement.javaVo6hxr@e98'IEle i}w+ $Żw;QpK(F?N8 lo^w_/ߜ_^C%J#8 ֫' Gpob)-ΈB n e4!DU%YȤf#2Y*zX;ĵgʂ3(Z=UHROD^PV'G6-@T35 4KheF pOLW~T.eY)ŸX[kL%tBxakV;׭WTk҆p!De5@ܳ;;CVjaPYXrLQGz#4:M \ [PKi,EŖh1>uF [ͧdgVBCGs騑dA ) .1ԮHFK,3lyXVFɦaTD$&/ĚvnvJ +N2ӟTm$Mn)vZ0h烯T# y6GVRZGϠHHͱ;-KA{`1X9X*Ieԯvέ.ݦfضŐ琧W]18Ko  t$(xRY/Q)^(y<4~3q\"r%gyx&\wQHFW_0+aY<ğQxqO%E E0ǓQxӜ<E px5ݲ|FKĻ_>CQĚ:s38<.IچF,`#h~`n xҔO#$c7D'Ť`p@β[5Yk/n?ɹw'˲ɸir0C_&iCivOwC3rԻyCr-.qX],Z2!a#~͒nJ0wg.q<XcཀGK*/҉! r#+' k>|x=|:Fҿ7ެ*5|Y xʕG}, ^6-5/aO2aP纬hVKƒ NVuY, hZyM(H:AD|lL,omp#S%fRjD_&NfJ޻0:YAR,(dcX,[7HHbw- Bo1XP`,% SS ۭjM\Ⱏz|F \$?+oGDbQׯ^)o9/e80~=p|D z<8 5O0. ;a}f? >tϓAy0p ØxpykaA78*w moЁx|N C1^t!`# Iy%C[xG&hD<a#,>a֯Q:X#li@p/F1 aQ4&< \ DX4 \t(|wxDZxUjWki+wS:ܦ}'(ݢ玣 mJ[4s=c7\5\|iiިB`J(Y텆u)|ɀV&xeNͅJ}.<5+i< 7ѧW]0W\)z:o6* TEq&Ô@Q+jL͏Ro/t>wEw:m2XqP&r N`*J:XRո6Mf!~ײUiT6a*]V_Ж&oUDjE؟adȋ5a?v"M޲UD"Bk/zV3^n~Z_*O#,[gwtHZ8> ~M@Nv3aKl$B5T PKA4DyYW 0org/codehaus/groovy/ast/stmt/WhileStatement.javaVoH(RIę&iI6gƋ iT5R]̛ތxpċ.T)S+_JWpo;s8{&ȿFL}_AFMgϡ_b.kHLT zz~Ƈ,!YKX,Tm,MⲖT H!Z iP|Iey:LׁmWvڸo0ׅSm-+K@ WtY{UM!U(vYsiHuMtk4Ĕ#P.?)U}Ct5p@֝ d>+LJdVX"SD5vSD@*>YR4Tl|"`K4:G#B4}s;2H۹.W8dp85Z9H&FIiU !Թ F2z^`IkI̊8nw bvSH&H(yw ¸Ϯq AQ8ԃ/_S^r{At (aiq|8pD$26(Q e5Yq5F 7NsGK(qtU| M]OEPn's+ph[aEt1ۑ Kvc)CASMlj.wf 5TqR[x6n簘6}/_۹}yjƾu.馻Vڼ }axU `;'R(NCk3 Z1Jt 5(>%I yp.Tiu+XxZ!Wx@~%;Ya_G\)7ƺT9z7+?SCp dߌ݄'$+u X6dhF`c|f{i%ۜ-aC|Um S.ンhQj1vo[߷<>Gl n `׆W~T{PKA4% %org/codehaus/groovy/ast/Variable.javaVmo6_q( 4 4;Y__*L‘ #݆k+aeKYYA^ɫ{uã k K];Sl%RYYQ,<CJxeU5\W"9-Sk&Qݺ`PVeSirY CeO`;a:P_RBb:fQd54 OF)D< v(n]"aܼj) %xw y.QIߜ<zۃ VXYjnl_5 SI*dAV6T4@:M(vjٕ(*CEQ9g P.Ějo{`;RZ6[A;OmֻL~Rl3l(v☘R?s;:_`3Ng5aY]8_.9snW+A¦5oo jpbz㋠n(>sh!b/!ʝXI*Tʣ45ئ J:d|`o_ϔn 6nw}!A6şiGp N5zF*Nl mu7οې(Ёԅħ N/-M'.rr_Mڤ:l2X*-:F "ݙ7ZPKjPKA4s*org/codehaus/groovy/ast/VariableScope.javaWSVfΛ):?LQ&A^+ LnvM@B#w잳{wc;9݉,DZb%:+:~OO?Nzgh(3?/}PjųyPLBjLsH#TS qˬKVN9>$=$QOq:PQnڸ-d~n>d9e,p`Z28dďFڒ׆V8K H!8$Jh֢ffƩȞA,[3@ \Zɗ\:eq[q~ D q`V,v6 'Y黀hDoQVn1) ~ӥ)zfR磒Abd{)c܅ʫTK?BT4"=dnM,(^I+wn T\\-NHeY0:pY.ߐB< "I` "H$K)53#D7HIf(-A$"h~ץAa? \Sܶ }Ub|yq۲ hpWل9{@8k5Q9|8/͡5z ױg>]#=k8!gNC h: cb6ɽ[O:DŽТN2<OļZέ=@9#%Xáa)5ti#Krh@uxv?uF3vHq!l~: Te#mֲ]W ҟx-g 1ɥ8$u4@|ۻsAC7M|(ezϗ198p1@n{L=0uG2Tre-L:tc{e5Y(>ۆ )-4ε=|2νۜ9>8e{ q': [15%犬P;*s4TmcTҗWa-fеQn52_m3v{^Z\CmOw f.ށGPbC@!w(^z?: $uuBfxIp:6mXSp}@؇RqDZhfJ6gnׁ$*&k,* jkhN4C9^eF!3:gV?n=ǴH7\"^ޏ/ZCjWKpg\l<ئ2]$.}cwCmN*CY yM`gVUPK A4org/codehaus/groovy/bsf/PKA4VF<+0org/codehaus/groovy/bsf/CachingGroovyEngine.javaXo=œu]{ݪMaL*v'Ubp;٪Ru*n|޷7?_âHW2vn)~e;f't~ypsO?"aѷXO[蟓mX R cCPH\nǵI>) )e!2]%kC-G&`yE<8 O FZcJ7QkȤlX,EM -QVf;X̒${DA \mxqNΉp2X ybݖ#eNseR"1`IPvN >BL>-rSBcIَi:Ojz =h04݊) 0HؠRa`)r$)fV*{{$ N2iIJI-E7Ǹf*idgV I9sb FuJU& XԄmYuĢ~jL,؆=VF,IνLrga0|a-Y7L~;VlD(&0q$&+0j b{1xӫ]̟y#wt{=$<ƻwjʞ<w>xCI蹁 Gā4w(NMdFpM^;7j>up gCϙmfs6 \@inݑp]pI=-%a6v"M{8vi!C{wl:t2\ǣIN*f}q Fƙ-FgazE|K2,E$HHL#uh>ZfdHtt)VdG$L <,/e߸ɖH*^Y"d^- 8\r1?[v@hFI¶ O X*1e ׷l{b;WM]w ?l$QT~b%5BFI\$"T3 ϥ8oog];TKi.~E'>|@3 W—4~cN\̑'IH=٨#bj*:MO<]I:S遆~6+{ mrՋǥ|q%&J)W612{5j =7tpWPHL CN+ Ud׿lA*T ^0hoZ%-uL2IWA0b9W ʞS{l !f=M1D:Z/j )org/codehaus/groovy/bsf/GroovyEngine.javaXo]ũV4TQytEhȒGRNaH+ E|ν$EJӭÀ Esσ ^E$۝/X?o9|_z)Q$RA }0pʙkb18䖮w0ejE2SFd Y ,O"Xd0,Yw"Ȳd\$b-\0WWv{} %NI.¹Kt,h&0ADI%way!sek-0y`ufI%XYNEF V`d3Q\f&IT"D%l$WS@< La,\JוU8(`)\Um{3KZCxPA<ZalI'b]4utk I>nH2.Uv;0n% JHAr,uL20G <VyS'& 9uRNXssd{$ؐ!|O kHLsH+$]kߛt[]\D*V0I lB ? hȔ >8\I8)(`p3x5J*7l5Dț-&\_gd4Kk5w?u̚| kyxi{v^Q:au69r\{#)Iyɞ67wm~`@4 0mP0AD3׾b7;|ǟ6]L#6C8C;Sx<TCc\(8gRďٟr+Á! HRsRF6bGK<'BisF*#@yI&~NKzCi@Tyފ7ӃK'JqsBز5dY6pFp/09D,Vh _T]s jJQ(8>J.гb}ijh qU>CU~^ 64T7HZM X-}?sR¬C Zvk oӵdcx.1̗a I,+ugM-*Ox_esr7TUĦv)Ro$nmUlQDTZ8b3yX˅7īF 0^eV+`kg`yk1!RJK%^I}rCDncGB`@T_z0vX!&ʈnQlte.=SW]kP5qo FFҨG ,.7TcT']]P*&=g| <&:(b8TD\ 2g_՘fLYmhEO+Nk'dwb9*i5146?L׶#vWXnFd=thr^p(\Т;*7</xٖ)r֞X3C*c8C`N&7.i]yhW ?hTίŽ֠jymA'VԚRPe976j"*jQ])z }]Kz¬[v|Ta8mGMi4x4z0]찍HW oȚYԝdbVX=DE{죝۲ L싌Y4%IE˽^o }/ x9LTdȗοPKA4$$org/codehaus/groovy/bsf/package.html5K C=Ŭ U? &0QSR7vgKMŞL$e庐^d ʉ[Qa45Yu3o?NW9Q .;R=̲V8xtp* 0ÜvXY2:ޗ/PK A4org/codehaus/groovy/classgen/PKA4GUN3org/codehaus/groovy/classgen/AsmClassGenerator.java=6W(Tb6\dRa s3{[WW{଱90n-fH^zTjRjZŋ׆- hd'a-yW˗^O^_޼3ɍ?׭ \"oL{ :䝽11vv@%9OK/Jh#}'SDɔ4RjMI6rMLI8'ҋIΓ';NK٬h؈f tɓ,I&!@i­R,XR2}?|q)fH+i^,r&r(`x*EAZBǬ7Ax{BQ8DXLUevDL$謻1HϞ[Z }D%)j$2EJCH0!DDt.W=/)}X4"E]w$%3nDHt&LF[P x2kMdyh0EB{J@10K{uS ]S;|ܜT2v20Z@#GwY?( @bql0 `oSG@wQt1qwHn$7aOTEe&1'7T'~:y4\ ֭N~0I<ckj\?X?&`| k?oS4y2%Ȁ@x[nv1mxbqgXfM_Lnȝ>12ȱucXcFnY1xaz?1u=`7!ؔ1& EhԒzB[Ir@'TXݖ1Na@c ܨK{}`o:?E@@H[li>HY0~̇k2K'o'! 21K2LUV1'h4f-}:}ɸӺ}s2f]L(iK|d2L("EX;2ぎ0N?5L08}R񯂥v(@cJaM#5m^VY{nlQLljeaE-> 8bCB X\{V^?&e֎&U M5⩚.FF*=q_ bv8 nqQ Wkϧr HEƣq0 "s{;u)9BgDjQdm)f>5!9 M?# BTQ 1Rcrͱ'/chMvsE2kƛt2lqXS!1tx+##&Ce)ˉ$g5Ea씡k $#y-'aq?o qM9> XBϱN/ t+htz`m`k)[W b817|qH~|j*%qMqBƃMSV"X5D Ƽ!”&\M#dgo6D)N;ŎfY,ypbt"o\}^ ]؟{|yڭi,_<|%lwUXD >}F{ڹιZ/^ &iL:(2|jco lorD~ګ$|+~vˆtK}\L^@Or }tf? LmUkd? % 0San2Үt7khh73s^WIo-Lbnr #|OpAM7 1twӹ)@KQ9l\*t /iq6Q4U?Ywj 4R%2HPװ \/^,M4q; 9$,OUgr>ugIX2ׂ$hR&<Ms`<D/u/GN}ǯ!6D#/XxұT^EJ~V=cd4#sa+lU wl'=a%qzə5Ok+H:K9}kVA8Uiqʔ$>uCRChvlϜꌄvRGj!S"RRvEx͔fy&cUT+}}*W̊^!{]k?YNj e~1dx>ө5> LF@#xv͓*&,q6SU!Zd^R:5lt∭$Iz{*Bg#<ĹL\A2M(d)apgGZ3SlF|۞y3jNlaGK-eR ʸLN1gGp!+S.9;Fi+<>>VxVVd2^?INFdOgR٧ckigQ[F >oWٺ+;:]&N%xQØ>O9Y38Fh#X.(୬rl x؞OF)yyi=en;T˂n!\}M!oTK "0̰_O;19ZO$&M/)(Uei֑c54Ijq\Tq\d,sE1UUɆWJ%å۴`yr̺Lo? 3Ƈ1GX8~֧ Tp%՟Z9Nz.b58P=׋׸P[>cvG?}xmB`GwX4- r mA] ǡw-,nM?ٮ M)?Nؚ퍟Sg*ڑKl.;Ǝw {//s$~ɷ<`e{WXkXN۪"9Q趚~c0Z'.zOvʵŪ 3U:6Lw%cxg-y`uU=2$:UǛ6;N|Ɏyǧ 4$u L+n"Rv/çnَ?v[Kl+w){GB W{SHc, ,*|,? ,יKɏ/`w.9IQVڧ&U=f[(a+"4!\');ȢEdFj[UkOI2 ,<KPMcjXvq,ʾ@@=<Og(=vOKe!%*9^s*[-2sG×={Hk%WJWPD׻;sxESAVƳƲ|_iA7Td˨bavSORKA/01AHyjN`O<˃e% >sqZ %_R9zQ;/:9F|I9E~QJVQSɘȑ_e(ߵ9@-b,]g,m]vNveZMsgpW:Tu]hG˪pFM9!%" "N%uZAЛ U+#}Γl#yu+[w_yL"׻j37_BuQggz1dѲ$ϋ]>BwW1tt̵Zwo'Jj<ۤ+u)ͅ*\ede=:lϚ V^^;6wo|?Ng~;@7,ǘ밖h{aGÛ3{%&A#}F{mIKq Mٽ::%2 U~Vy"jǺƻB-v?j|2jĘ3FXÑcݗ~7s-%{wA\ue8VSRVAa+ `FbkG0CY S/n.i0^jɑguBʧΣ2%?afH؎ʎ?Pn@\d~ZRC4W]EeTWaN~] >D80 |բ XyT]GlOiCf{<`)hL0=%H9uq%sY)~r_6vVEԎT" ,/S(.R$rYWu֔HwŎiLjI*YK5"GҬ)/_t4<(Ω#h4F?i3j aNI46oWYxxq Q v *pCqx#qW0$#: KBW=ܴŨZ:{jxQ%6n[^M)N5)_WjGOv]87A_\mTfYh mkgh&H1femhm/}%gdc lj.|:f8$ e<`JZ-E{#Y*zSk,ktbʍB_V^ d` I}9y- 5rvdP\(5FVH%ЫpEVq(.wxp0'ގN+@?i%tJ"F,m%lL[T)lD֮rSLG7'B?ǽ`|ٽ5$@9\#A"9N0 5xPȑwmB^auAjoh)Ύm#gcli+7GWjkۂh{zm'_m, $s/ ݷ/zѸ?^+B`'NLE:i*70\5 $g1=v~rCz7!Kn$0"\Yjd'h J&qE.OQh`f4ky2Af. ;-e̫QzЍڄb3НjlU( -dm"dݟww& ]Z^`[L{.1XlN vr"F'7q!!G;}^5g/O_ 6r^*_BC@FkӠ~vx#U})m6{Wo7{wE$5NκefALrc {ob۹BUJGARa㛵*]Çz: OeQ>q}L3GKfƫX3_OmfKm0/¬my9݆[}`ՖFGfu9w f\RG>tFo2q;KTx kq!R VX䟶:!.ݱnPxnqWv\pVur/di*A0tFZ9MI9/=B9w;ezIi{c˳O^4A(4aŬإ>so&e40rJU[0Nzo h !6d^쮀[W/JVb>o֐W1CZc:Q*ck_.OE{wLxcM>+O8GݫjkKv}0&y}>^drd>.\g8/y?Q>~??(BQ{7cn8tݞU+ >E:R _[:<(y MFcd'_k7GzvbOX|Qc~rz6 yn< =r/ـ kVjƔ VkYc7̓ Ƿ(B fYW]*{n8SPt.γpzVVOb4t~+pCuhsk!_/gE8W#䪏ɔָSQOcJxד2Nh l&+eJg6X'2sjGE`JW)c"fك}Hs⁊=ee3aQǔt~E`˥x ɮ@>:MjE-WNro &1߷ﲏ>Z_2PԱݒtGsMg]q`5JY Y9w.Laz& Or( eBUg^ ^n֣ʈZɬjuZaw4 n? \UE;Ր;9#1TiD:GnPHe΁{Le %˵;w2tGQ\ }EYٟk晌&DFl>*;-s 6/oNo:a3A}zKx2AnfSZ "5*ݡG2,ڥכ=(Q-!'ed5Uk{Aܵ,PmHT[#;coy`-4­wim*t(*dE:}܊|EÜOmaŀ|XBT:v7E L*>ltHx\x/o{NO*bV#3@`ms. h:6LiNc .!wUN=ny5$ŇXyW쬭%BUpQ}RpxTQdVEsty%DOoZ;WAL[v_WR8RFKIf(iU,oxd`}c\xtSr+zja/NzJMk%I"%kN+ja0~j`kL?t8GY xkqԴ9M-;][(N5!Po<6uihKچzg))^ 'Z5lP:Ah25{tѪI6(KOa=J҄Z-%u\ /K52 jvzf¦ViW0qi^X#Ng7y Ρ6[j4Md D˒Ԑzd !8luN0reb-g+բt%d>hX_00ψ2E 4Yбbt}>-~0˲M;+9{]~ J ݸvy< LN`;x1x?iٿlBsJ,+YU25{.}6Ctmckp}l .jb&'Q9,մ vr1: "Z8zG$T<-ڋ:Z ߨclyV   Umg婌q?<p# >O[zZ3YΧWgG&DF=R!PLj,uZLW 0B: E6TP%3Ձ؁0ևCV#/zwYsA{H6F,_զʝ;;;;Z<^}@aZt[9iq^,\ S,cQ.) % Po:3@e3ekFect6?^n$q2iҍ8ȗ :1Cegl&p| ȹ ,jK2g|,|_uИ}\oĵ YoIFRkggv`9bWYRO]ƈM+}'mRw\tI6'"JƘcg,6IZtesX6^C()m1_ˈuG$G_cf)ζ]~lq2Wh4"gU; =cR;kD]* ,uȵ[5s0bVʂTgms2!5_Vnwd(_`4ǐ*ʓb9S[QT% }M@%d2X3F$϶ ]%Dc6t(ZS\/UP̙ ·pղ81 ؚtZ!X/yWDE?T=6Y䬣-&*[gj3*Vo.U\E,EQ3v_Q'r%SP{9]+ 1˹9f:n<q*^hy~~vҪ;UqO(IO2<`uLUgixȨ+:LDRt Iԙ-jyvPYID٣FRGGޒ`!h70^-N*$6& ' / 50F e1fzV!o!TQy4UaRT[$ws$PP%OP!px¬;=d5AG<:r۵vDBE/b!ݤ2&qNK} f!y9D*^,t*tdҦNLe.gfKuh-\!;Eslrag0euP^l2Cw}2g+@ 4.ٲQƄ@)!Fh'd5K!HQ!]!#P|q[oGO+gSK( aI(ɬDZ)&6;}: :ys,Xa4_qA9cgFE6XDmJj!Vj6o킲wFvWUAH?[\)T-x9c\ !bNKV"=kU+%ܜo }әNqkvPrxfbkG(BS5T,\1ӍҾ`-#kKrlg}ع_*Rl256Qؼ yKı8?f>)'&F-."l ўh 1s;,5` Z 1 & kP-fdCv Ʃq=[~rKYoTu+35|d~EՍNQ?JIl0 DSΰMae/q)/7b!Ƌn)/6\,v\T_e˚32z=hS(C_aoǃR0Dּ+MUeY&Y,jI^"XR`ydpeH(SoA*Lg[Ǜc=ʢ5+DbKE$z=Y9D`uM;^uFeټTUf*Xv΍ڟƻ`f-ME-ǟSkpZXn{WT v\YBHd<{4V\%v|3=Ӕ'$R8 fbm 0)\oAJOGmZW7Mw]﯒&M`Lz5v! l&H ONL -:7'gd#D,O^N1iE^c)oC1ߪœHCjw{|X/^I7,hBw{*=N=}pa|5|cAm>0*Ԩ촛`*b۳h^|_BU(E}-N}+8| 1Xdx+Db0x (Ȧ,gKSñ9X"N( Z8崂WLbULbFE!4 /Oa}z1apST0evϰJOnL1«~zLE8h-+6(@043:E}0/7KJfNOC$a:5,HOV2/r]c*?Y_!)OCw{{蜒UP(R|=Ğh5ɁD#b/U4 Wky9x)`i4!NJkh {p[vZ&_;g(6>f-G{<8>!<,)c/ amDE;7aP>nI3#'1R8M>0'%r_G~ڗ|_2#UeK<1 ^P#bTU 4f!6UKFxj7^3Ek[Ƀ^fTNěRꗽqi5y]/Q!z貛y]`U5Y ?Ǝn ƃ/l&u9w]Z`=' ̽'X2+;>؜hrhTJHU)@xIdxlAmTأhub˝3ܐxP5D8's':"kQ\IP {#Smk_fY=/$GԖ(Y9h$ .۳QW?E0(1l6sh?XWBqT;X@jSk6:N.LtU10RB$=.O-w*7:.{6P>'.ːBĕ s<ئMMQXoh4\{9xeھaOW{5%_}NZ_Ӝ,3+CK֒蚑}MP+myb#fx.mԉ5a7qXPvTr i[(T=R *jکK9)guYiv81ؖ]LmNiSƅU*$fsvzfȢƨq7M4l@uQX̓CS1l*I0fݗѿN;aS2YbIts~$(_Bizo$E1ל2 >'ѧw߿FqE1j}jG޷ʇ_Ӣbꀩ' |!$G{44DFL9`B~]2ĀTʊUDd;x}a8j9p? ¶4 )F Ń)d n$>s2b,r/ҏ?.en#;vlZ,E__(#Xhņ7< h(sv,.vCPj+j^ݽ&H9MV'}sϊ6Bd| )^//K2zVI™Հ!0g*ChOR _t\g[|},^c"~SNE3q& 3 =-!8brBDDd0[X,q借{pG4x/x]TޱwF2Rj6 6iK_I%M:j! zoE2]agz[yb:A|]$ҵN.ͣ z6$aA) 8s1UwsEY Q ithB la1a3 V.X>b{]iNb%1I}Cp?Ѷc'7&r©s{li*Fݻ:QHno%Lɨ0T1Xq*[!q0ÝuHy`aҡm4}/akC"nD`Wi%yf.i2{2_k|)]E:.|n nz ͵"o(mkq:y ~o,&F% eDۙ ICiQѨ Nx0,Sewz  3% 3b tI ZT J5s]J~C!qôDͮT!zs HVMWdhPWmI )_!8:Pท=IB x ECyz4CyxIL*Φfb[xnߤ+qbqD!C(MҾ-F>OBY3z%Z@`zty*+5Yo`nHtX ++Y1ӤvЗT݊ 'h8Nx!@誩P'bJ %!'I&$- cQv􂋹OB+}3SFO x;qp;&&@H? s9MSQA$ݝ3?-i"x;ud3y#-gb&ıLIk,xi )7J6IJRnv4stZkV~vPKA4LK 4org/codehaus/groovy/classgen/BytecodeExpression.javaV[oH~8"5Xh[՘I l6I Ѫ}CBJ{ s8eNHknFt6p} _~;w0D4bA^=X:')|9#h@4% &R'Mª,JecT5_;VTwH?!ՅNPb] (vA%hAKu oVިR$Y@R^t}|jKp^Bi :0 Xc$3jS]8Cj =S8DNsLC5"E>|i3T+wRaҒ/JD^=,]k(dTnuq{Ӆ_7dp0ZoZ:ZAiM v-̖2j^bJl<ɖoeehZojTH abMuz63촎V,r?;WmDm]-w\ QUhgj<#V+)vPKg'ǧH`-:ВW|)ka!w]1+sW%QX ͆KV^ݗ K0ei!'DɐYa$W0ai4¿ဏy~G)y Ӆ0 ӜGqtN,|†^<ƜnXC6 %Kg/€!p0fm9)rlJo eC|dSq/ Ʉ]cЌ1C#a8 xRM",eBdA|3N!A c Xv $z2ySc q `ܢ.u`C_$tQ$׿#SRԫzA2-0#ф]5#F C a3mGg8E *K^mCӭOonU ʝԭ})K˺<[JCE^a֦G/PKA4aJLY0org/codehaus/groovy/classgen/BytecodeHelper.java\}sH>ń:c'<‹+ٜ+Nn/z]43Ϊ'ݾ |PwEollȳsZ^|~q~Ni}sN/+SJkAS\ҐQ`Z #g?% "BڮKF($#`C&`QLבFПEf@Y[%"[UIfytҷc h!*7M*3#Cw]=V!k:DvCX`rF$x@JYknUr3|r6AZp > *ʁɿAh|ej3 8Y(ljn] K^74= s@uº| m$5iB0t-Ln!t4Vu9G6څ&9.Ug'hvyZt/9 MU0jv.K@ޚuR5Xz"8H;m\e[ߨ=)/}N7\!^FߜRuu!XɌA¹LW|d_;\2ɽs I]ՖFoaZK7PhT{^׻p/_oB@ND "?os!o)4[,$NMkCPaÊ32:$jdc0<h,YBdn;6ڱ>w/l@!, !tdžD+dFE^43= #Tg-.ΌG$l9}TOwZ~^\O }Q"N:  y~?{JҭKL}.D3Q0$Li-,ռ$ǢM[h^=WG~o1n$(ˆ <Q֕&4`uNOAkBli}}5yK:ZAbh凛R'٪c'jaRЕ 0`%3Ph jor)ruqR-?! *$ӯNUe|6V 1J9%,@( "n+s5V=%)΀$D٣BM|RӐM Lb#VSh蝿JVpQ 9oMn't=>C6,\@.0weA4">3$U+[mwNGIV'Eenth,;-oBsPj[;`kGuuY+;4l#"SpYH!e@d"p(@Sn^@G*\)KC>fO:ď+ᭊXb鲦Q򞒇5F0ɷ£ Q1f . DsS>IBAu6z)X{ߡѪqrIEFW)r6;pc5N2Q4k`~q '8tG Rj 4^a,5*"T"F is*[KYt)"BifVFa[1B`–j`_! ЕkZ~ڗSp՝6b1_1̂P=p;Z= 5dqA 5ljY $tML)3AS 3; *ʼAJUaKqCtNb򢺌Vقivu-? ?Oq?=Sr6U•|;r7^D֢o<,yN.gPeYILi󒘪"%1_KI_|Ye9L̵)@c'>tO4\EdQW^Tc9nb4qt3e`R(;-8vm#@Pd]3l<Ꝺ[7O 7n+yaɉxV)^X." / R3 Ma5sA'W#倕A/*,׸2%Fቨ,~I)eHY8w%{ q93齤߭+A7NGKݳܽ[g:2Σg>+J阐a!{P%{[@ 8jGk}b࿰5KtClv:ht=O[RZ,ce0D22f>6vT݊`ք[j;H g@z zCuȒUFtv̀*"r%&!!c#ίJh?M~BQtݎ& E@Qfȕ T9zfbmM2 Q p0#uerNfĤ hCe$+!nyl¬=SM^l(i qh[OCox@̠7l$eRٰz)Q-!g7<_o ˵9)oa2k AVJM0%W6[ KG Q |JAR#,={KKQ! 6,ξC6LJ%@z}2;o"V?PKA4sIy ]#9org/codehaus/groovy/classgen/ClassCompletionVerifier.javaZo8 *iqO7K^.pX, ZmJ{o%W=93/Hd.gMdBޟ\~aYI59aRqp("br˖1!q)XK 4IDVkQ$B)T2Xɖ.RF|ɤaL2/ser劑 MٚI}wot"uVn ~tՏ&"oRYs: A׌q"lCK8IRkF)ױd%:(|ř<O@-8[*q9LAe^kAވH?SH\(ٷBƗ< ~2 ʇqAA^ eNiqx HQʄ},퐋 Ol dNr[\ htZqzL_`crUtTحk3DL7e3O 1 ɷPKH1$)f;4DW@h:Llɬ#ſst$ӥ=v m_-:ǐEB. :\wrcɖjÒ?n.啍Zdn9D'G-91JJ"Z$d47T1M\5^B~2$k؀i݆nW܉lNNq ʂ N%:>u;)l~de?d4ĘsIX .^ 2Ԋzc.Du!~=ޘW!ܹi?O˟[yD,pL%V/].M.G9͏5-1օ8Й02t5 v=jMN$+!F Ff^-[B"Ī4ŮO ujl2(ΓGlml(ݽ_Nq}7uQ '꺬DB.*pa7D:X>;lO9j`MEwK*!ı TLmeZAK{ EL:`4~9Ԡډ'DT`&P+T/&A`o)F)@og?^$ ±ruUDh鍨u'Ξ xՂE҆OlqJJ.[TiF0+a%D<5tl2 3hG,_ @ :%!&jBiGgh^xrhaBޠ-Zhk"W|9 B>o 3,mE).Ay7.@Vʻ΃zwx.\>*c $SҴ!7gը 4/`#ɘ%!iD}/{MI|@:),X%pESpi[*gX(?ˤJ.ӐVe(ULk06 Y7v ͳShtn^!Sgb`5eťNQ ²1Uz,MZo~Asq q';y ^tA*R:XuЙQ ,{ͬy~EsBQp$ >g؝uS$ ;B7-Mh: a-jt΍l({ý˵S>{ݳi[V 9 vUw!^{`!I9dǡ;Z *|Օ?|TX*p(B+81[Th , yKIJsTa@ay,^a.xה}Sۆ1xF+X+ᥧs9MJVUxÝӲLFb>U|SbH[`ײ~I/j>usw[2Ѭb`!ÛS4\ee9woYomI}27mw[!-$|:.P[U/7s_><^<o.n'8;qԢyrL=d<cFšΠ VuI%f3B۫ǯrqbϫG웮{7 GIÏ6"@F{JJ2Z@d߈ |P>cya 1t#J815mb ),@A|ԿD:lPK@4_00org/codehaus/groovy/classgen/ClassGenerator.javaW]o}j*e;M8m]?ݮȕ ?%)W({fIZT^\ð)Ι3gfg^y99(K-B[F 6tj;'wtrr~w4OE%bIkzrVb7t'ɒJx%ryBWŜ⧕ҕiJRL/*+uƸ.% VXTOBKED%Jd^ bðzx<'UQWZ㭥TPk]lTj%* (ҴxR"Oە.9D Ec "-+ Y%3/MHyQX/ H˂ 0 h8\Bo:B6AaϮ3hS౯ybLwi IMM6"V4e_+$˘ E>GRf{D4\* T̓Bsh͊JR)dNg&X+d׋ț(KfDL]^n:M ,qgXE?Y4߈ebE4E 6_Z^6GtϘ"N%"5 E"34{kѨSlS(r8MD9g(jUgA?Ҫa4l{Ctуi{#wDWXtG= ɞa,~afɞ<24p~@t؁=<77qƳ7phG4"`\f $G{ѣ{E8kijv@Y0C#ޝ;~ɽw'x)3`\д.;b< u"i@<0(o."C6ta 3ξAGEdƙ*ht#h{f;6ɰYIlynhcᎌ qY=ܺ>`aj6kB='bNxQ/X7cƝ8. 12煼k]H]vWGv5l[GQir0*e;|P?jزb(.(A TmZ*O$T=OU a?8i~zi;*_ё@[֍6FȻX; sY*;}o@erZ˧1iL<6ŋp}?=~KYy=G}paB_n[hߠ v3a/)8vxg0Lxd9IFtMyOXj/8Qsכl.f'UQg9qz@k`Xᵭ ) }ےZoUdm:bP"r.t-htYZh6gZj5*|& y|; Ki<Ҍ'8uzc3rL-vgɠu„T 2G̷.Kc٥+ ,dPuOzpR|߾|Zf\ƂmoZ^.]6ϱ 't\0rM5N>NN{n:M9_PKA4Nܺ 9org/codehaus/groovy/classgen/ClassGeneratorException.javaV]oH}"5XhmWKUY&i:pxؐF=w ٨ҪH 9ޙq̣c)(U]_J[+ez~U[қ9~}{{֍URU$(0[,T+]STUN3Iv,lmjuV]u^@105;jEMk&+TsMYQQs<:},Xm6 L^g[k*Nf[:PO5Δ/e ]J7}@~fc3!UTx#|j v*"K0HQ ,KTdW{T`oT]F57[sV(*'P9+UҖ˲ZQ=b] B [ͅ`n]J}8j,5 @Un,+Ӵ0[M8l4(Ĥ2 ƾ!KIZ)%#mp˃f$x$7 iq輕zZen}'|/tzgȯHx6xpǫsMxA?V(g.bեYQw+}|~詏.\8ۂW}rqܲ"a+ `񦰩)Oj N"vz'{{OgIռtvZ߽PKA4[*2P.org/codehaus/groovy/classgen/CompileStack.javafg1#p&N;vQ{^vO?w~W?ȣ >mozǫZh 6)h~,J<}J)hD (XW|%)l(ZtxG^p|kp@vX ;q X;Y + 3Ey{Bx_Wb͎ɮS8 'l2ǣ۰ Xo.7p:o/ |-uX8Lz4f yN`f7wmXp4e*¼M+]%|힇pnMm &`4!~L61Ҁxf4ohxr.G/MC'D.ph4X6{c(qK zSs\dan GG}8 `q8X}V!QJ/6 ۿ$r6($B|]JQ8Zu[UC㊧&Kn&4\FUy] Ge{q/p+v乁75*Ny08O;3 \8>l|^>[wь'{Ư8m\ĥC=o] LQ Ь[w<b( a,o A2(Q|ħY?ADHI'HTGSa'[/)`vBA(JCt/ENMd 4/&D4b ě[d๋W6yKI`f-ʜmc7ن6Ғ%q 2 0҆xo}R P.T^t?)Q鉆K m!Z#˅-!mI،#qJ*H@ۜU#Dש7JfXX -ےlgI<LWDpP@ _z:@/f2^+MsgeOEASzhOEΖIdfY ̷`P$|9eYHנY1N6 MzHZFG=!`8!p^} 6- ^,'[=A N4^NƁ󡏁 IB3Ad"֔z V֌R 4\&_'!ylᲣcp4;S]-(p *Y޴(?i5K90XHrkQW~ao՝IVTJy3G8K*2 ]HCY1[^[%Gs%_[vF'edȖvmߕ`f $Up(~Ĺy%oGCf3%^VF/ٱ ̱x OI9z*ε+ij'nKY_rg=ӲUNʜ U)| .68iQ:T zf:O&n E ԂPQ{t`CP*p;u-Ce^ V--<$5ޘP6K2T)ֶki 0.sعPu99>qj'&/E2lCDq {3mg=wsJ|k=ֿ w5PÙ4UJ䚂/-kVmRG^TUFB.BFh0a$R<cI&:D:Q1wh( S[o'8]l9,UR(q1Q? թT5`|mgcZdw$ s*Qe9ג^Mґ~#bΰpH_p<`(u&;`Wj UuTQ(%5UQ$}%GgZ֡:"n &V % QZ'm&NQfmlQLybsX!_b l[hIܐŜB:FiM%:S펩0 }&7؃m 3d[ 8{9;KI~[fSM2Sf[R_xn.OjIg|]?uༀkhQf%=8N~p~.^j Fx#=qIco(xE3<%-87 60w!#vUqo3i{o^8{l~F}8sLS;|5tܗK:rgNK}^xUH d`|YM٦g_j;3@:hmDhW2ӦUG&OWVu=ܖY 8x z+JٞIV̳9VUÜ Ɏ70 ox=}@}uKt*7f?]E2[1{ZYSyI3|\Hf(EeG3Suc0ssB>A7gcZ]kQ"$R}YUx@{Uǯb ty"0CŨjYe+jTFU+]}k.;OrrZ{uBث{Mn}LICuB\w@-鼝{E6 U7hfӮ0>k6EC-T53 zڮcu%{Ҩ9G>6ݨt)o7x5'TO|.m# jO XQ\U.q)Q)oRմMJ9+g b]ea4F-K 4__s\K(7vZI7%:kj9/jyQֵ`鳿N&>({-t@IY,b:,cۨ:b yZे[]KpM\ud9W=G]MM@07^ƻ>Փ. OZOpS„ɣ@K4"|Rݩk 2o?Z+_O׼]gdV̒hܶu vlqRe[j%|OK $XF,Ix*]qyT`[ _C`dQ,],y>5ؽ+KBE۹vðKeFef,ۃhI4gnr鸖Թ9ـܧmf\1_uhu Q7$Y >жuf' Un4*Cv _>V֩ QWx|9 LŅk4~7*&'v|Zur#Ǩ? ޷ߛ8MtuQ\G0뻟_6Nw=cьpx;cB035Ŕ=ַAzB䏶rIdyuhU^꾋Spy.Iϫ(U-3=}7mz# +|0@H6{a ҹS'Va'S=mY탷cv{,ݐgkїcnY?8!rv,- nauRFwÛ|\ ~"җD4pٵcy1z#Pƅ0ߕh-ͲIC%mB/!˜Wi}ɮJusJ7u JKxn;Yj8ѺXz,{"tX*]ed'/2 ?lHEF\D׏$:M𸎄+% \qY<2)\F3: K }DL47<yk?H!Kؤa=r$AmEB\521JVI\6\H,EQ D< d.ʜ4ϔII*g]<,%B!9L QmR!46QI4Cm: #@*=ihhS܊ 1)Rl|aUX'`[4{T8 *OTPݤ~p*HӶReVD/r"ّe=:taT,H]Ɯe\G,e1(S2&̿N ۗV,I*z[Y0QFp0,\ ߺboM,1)Ei+0\ ܞ z?aQkovY [gl6fcZx`MeŸ˗dM iڞ3%bwlot4Y3&΍#?- 1%av 7;Ưօ3q{OqC,[˅<.B;hb97Dp_o޵5-%}m셍jZ6"<1]{MjC 'ȡYֳ@&$*ͬ 4~5µoHkt|_6\fcR<۽uFwn[j{DA! Qș}ݡoagSe3zj.Caw6>wɱkC|BipOa,LseOG6Qgtxv#x,a2"e#*\5uT"jfL)Got]{hÓ-6d*Ky~xr~rmPb+vDb?|K5d=2ijqx 6&n,Q(JF=L,1q2|{ +=pvnkgz"mv6,Ҽ%K((Gu!8f+xKjXaEM+;îNc,BO )K, T)ܣ+̉de9|d9"5ʽmXoXM)L}hZs8oߊNMiVbJr^|L /tq! ]gGl -b+A ص{*z+?o!vż! #B⬫ޔc "a@$Z}_c21*Qt RiPy,s \$ED&v)k?HmFA5J!JoyKXUaK72ѭNWw?U/YKbóshJ?kYMZm1FK0a(e>mU'՜my-jbQ G:~;L<I*sAI9ƗNZQ&5qf6*Z<;FEp/$"7*IUPJb:M'aHU֋㤇wϩ1m6dlA9s*1(Or+@ > *#'cj!]`tFwDX #I(jOVwS:%Log?Ս9՚Iͩt޿}R{˿vgw4a3tgGoSuEBrV%<=h8.<[VQ큩xvlq%$ؖ)n2Z:0t 9~}P0#MuqRߘ n꧃/szK"+[,zlvj@+ azi6@+dK9<ro wEVSt43J7[G.JF6X=_[uU j8}1~ *Al;+KU%@EVLM M j')f6coNQq5Z֣5/;Ơ쩡?q-}>׼mPK@4}pj_2org/codehaus/groovy/classgen/GeneratorContext.javaWmsF_q31Iv,d{;XOZZZ'nܖis= WD%Rv+[޼~}0ޜ t_\t8UK]~sQSxEBMP(-K^YRljE-J.bVRq\ւCQS-+a'x]ˬZl9ˡn'YvNzX~˥̋iYPB"x\㟠,KXT3dƫ^s@y Z.U&pYkRBZ,XͨDe- -{Rg!+8W_oX!| H"{[kN&B @xo|R!rVb. kd)$3ʺ!*S YV&.dԙ))W_:M: K´ HIU.iePR74yhn[aq,ESLC1۸J53}/\3^0`#U`aLዅRJW@AfPf9W!].ƅܤ0CWہo^ML-W5K(.[/8Ȇ.0 ko1Q8^c;w2$w{aʂG,G! z(a)Ҩg#QtI7A_ջ`#ޙ]4DSiV6,'= m8L7c68GDE8=(1}ߙ7 bXRBڭ|ؽg%bU3{K:jʱ/lgRE:듧XOp3IKBhђ5MXݿ< Zi W0 "kaqYj7 >6O@^}ek~)ibvZ#zUk8ۡmq;ՌYYݥMh\C;nVj|vK}8Ŕ ckTwI8Gt_D7=OY~і/(_v%7U.>Gn稳!<>/Z/ks4_|#.g)ɧoiҵ)GI,,as]:3\'6O88H;L/.~G;~kT*p1}uPK@4x.org/codehaus/groovy/classgen/MethodCaller.javaWmo6_q i59mW Ka$lɓd0`Dleѣdg;J8ۊmFQ S]^3t+B֧uEp+2D WU FB8Њ~*D, xeV<8hC6۪Q|s T)R2 *d)Rŝ^d(0 *7;0sVҒ{%">D㌱ (d-AS7ڡAzpMG3ᨡ`NR ( ̵1ufC51%6Lq!m,1eMRU y.VTqm )*0Q.۸j3#j_y0 t ђͷ:L% 8bbS etտ 6 # -BO~H"FcUC(̐fI:6༮~LjO .?f86[dDvOӘO(NW?A/s~x q̒h3 ]H,~bHƏo] Apȿd(co_M"$f#B$$$epE@k Qb$oSc |pSǓqʣ؁uAؚF E-E%.\1IQoIP aFT1Є]% F C ~MN,mj;=bpA+Zklbu Zi);K}3fuY'3Y9Z,t3rZȬgAqGwŵT_EK_E/-,LZ\ODńxipTY~2"7XHB֧iCWYmo/bVtj;/iWwZxݛ â=[*jgE8")E"g ʃQi.óNpYeF-m2kH);vq#9h?xYẸ~`IvX$Tddw ?`5^VW]8жxwg"ۂvvmhz3YpofrkQ6Qf~Z^]z{L. lx*{yy]@R'ˣwꭘ:t).8dWEѵOElc:unKrx|ڂApFo;-f_;TUVV'g~s{4j]~VKӝ=o@]Ov[FL.wk+ݾ>#xռG7ԓÒ(RJfm^aܹZwdPKA4 M(4org/codehaus/groovy/classgen/ReflectorGenerator.javaZmsHίR脝dk$2ȶv1pp6g$٬>*1/O Ϝ | c%<:u|:z?9-`.Yxq,#Wh7'6)xY‚Ec8GpD+ C)Oycy|,,e&bupr'D i.GdP&q+sPYq T*'!8Sj*1 n*q E"(t H`IS E[η\90Ic>'S2  C$Z %ElagkWDB~wxBW_x|Βϕsh&t1 RɄ)7peVK4uZѿt<{˵n86z`:^ ~w=_yxs5:];gkwwarAC׹r|X=s%~Μ 58wʃsgr}=Z. @Fuݵ+P&vvkE+Io+ g6hum%81(^H!l_o`z`cd"nBǺ.lQ z=t+RgC߆~C*km{{g(÷hX6> =G|u5G\PMH{\D~ ߀6D˒x[P"kfBϾ:vmnؼw<u\# G ~oԡ4zG-f Lp\#sh/s*=o,̦ܦ{'!)Nk51_IFȢyfxO ]u>a{pG&Kfx_T`p08]Aʧ{(lCԨ2ATu*RЦ}ڦ',ᓷ9a|9_04 ˛{'3=r$;(@¼V¿jy+k#)D@QসYUq.$풇h [Mi-ðY<^;f=D4\\DC!Q2uԢ`}*g%fQEHp r $(B`Ny.S52NnLL)m1D|"m0<:mx!?xÁUU h(T9/xdeE6x ȝUl%Vکhl@oD$wxh^ 6l\k8Q5npDɐTNPi޵ۥM@CljVg#Q@*Ɏ 6M ,rMDXoh6Tel>Zl {|W٫ Q}NM9.vڗcuY]!DFUGN*B3k2vMw{}noU9z҂-L}PjF{S}S=B\]NOkq"@ңS|{.x*ůe T[DrH.67`5f1Ԟpll%PM~EV˻an bb0j% QlpND6y'=nu7rD5^֚F!8E)eu[\a1G:z'3^[I13.ϖI-0۷2}n4QnINաJIo /+tI^nӋJ(lף[u.,=}xWU x±zt츿G{KX*#YZ7UR4l IIPQQәv%k~{joخT$$:r+!؈~⒣0cƔWnK'^( .kK>2Kf u e{gl#k$c&מq|Pǀ,XJ{wlwY նC~SzkvS!P]].|Qe{2 =SVUI'PK@4<?*org/codehaus/groovy/classgen/Variable.javaWmoί8Vj鋔4Up+bS$vxx=Fs/؁DEJ{ss朡CEY"{Ntw}?_OD̿DXu:4P,^4˟~kS31_DѵigZf=|Vɗv2/8Y)XI.R$He\>[]+],B\h"nbd1N\,yQ 2@Wby 7b"E.5xY_番ʖ= tk\:I) U*P1FHȎɵȾ!z41cM9|'D)竩@+7~פ (n˷ ;C{H׏شi 5 rxpC߹t诿*|c,?&|r&cKX-7tK;O{%X4vr5Ȼ;h];c'|dqB,X~ c˧ԟxM c˹(/DžOm7`dǝv; Zҵ . ΡۃE#m7R0/?lc]6 BؤugڠM'`w D tihӭ rۿwvpIc/0|M e\619nht:{֡^Y5lWk1?4j4Rd\.U*@81 _ Śξ)+">>L9d|uw@y$[92uv eUq^C٫/3{o_z {HK\+et8>j]!_ /YPa3f1mNC6JS6Gyɋ=@k㤬aW%@ܕKVz N²̣$xx73|xv}l4b_/fQ(}M?3ows/{6gć[<M ?Oo*6-Ŀ h6c|G_|!;읿x 7bwOFsvw?Cn`< ?1ћ.Xa4tl)E` ʮ=qt=8 ? 0J*oQ2P7xaF$ D>jJifd|?nePDp,cgdo{%} `ň+ OZ o>[i>>^MЃwCs:3RE=Q)$&Z\b~cΐ'?$6%n d2|"` 𥵐q)xBWVP$elyQ1CЇBl$O`A;?:_߆z/aY Gb /Oo2 v[?Oo{7gArޅ8 F!Neq2^JM ;MKfA4X"=c`%wmLi$mN r\ d68@ )Ž.vbfݾz=b̷|Tw PXRMLZQ֚w_(x A͵ ݃8S*W";: { +LF[pkC\ ݥ/pM1,#p%/:bFGԘ*ITP1;R~dNG@P?b&Z `Y$ YZGKS}[":TY#ȩ9J9thJ*d;ވ@;"!|-( !=gV2W g8ΉI|]MUAMG݀pU\Ÿ˦/sӞ&mv^98Le(}Dœ18og;Z.~Ie(O7'e~Av2OIuٿZ_V D(!GȻR7q LVu;BU(ͣ0sZ{,7CLYo43mK%)qA緉{7L`n)#hnsX(HD;• j*SQREXj@3q-aW]6I1Sn2cNĤ/+AT_"P~Պx+u^?JG|eqklQm[I DE_խFvB75G[uuiUy?ݰwuq5yXWcY1Ц˼uD{>Y+Io{W&dv)Z4DE8Xam5H{wp't{ܢO*qwbhu. ԡkp1gSK)Γ<ė'pg[lKMהV5%s3lMhPҊ>[^'g{ηF*~S&N* X[—TYkzl 8"cJtLR09`5{ V.nha1?m0*;PjQ ؊r|I{펭fv̘hQ3əSt.p*t=1ΪZorRnULxZԶ<yiBM']>wdɀ ܶTk ^5v>A29l'~:ۖGFnk]rK/][VtMsrɏM#וS;_6'ÉoH j~YWCX2//7Dq&..[^q\gydXT;XkNN}^?=QZwo8-sq4u8^(XP2O(ɳVTŬ3Կ) pvh]O4ȹZƄp̓N8B|ZwNzI~=@ɤZ@&.ߴX>{H`45_M=$P번Cl6#dǖ|s,&ĩ2I@~?PKA4]+U4u*org/codehaus/groovy/classgen/Verifier.java=ksFWbJ%dDSr\(EZr֕Ji!a%63 AK-Lxb0{ކi4´޿wE7q?nb?0K[f_^~HEe^_;MnEpza8f$.u$EYF7n}aS%c4I ݄2@T,IQ}RĺLrN&gd>.Ar ʲN#TcšQY I !=䅿q;/+ 0, ycP&-A(x 8FPMp:􋡈R]D%R  S2pK?`su(Q2;! K` "/xU\Gqf1o|>;3|9;xgYMc|M'ӫxW_ѳr<Or8yM}l0zf倍S6\ n:nS&vOvyΡ.Nհ;aW˱g `}hʼ7%=*>=y?`MA)#9}6.~t'ڈz^A#xκ}c*C&0"IIAxWt0 I>`^v{p쑼~vki2ƣ{3 dg4 O!Vɿ~zӇ(IK@lz)N6٨z8xth~x};xb; ^8J@l Y- A[:N[4n(I 6\:8$͙xN/NM={M7 6?C%n 4ع *MǝnCg0$~8DqƳ"M-(2oƦ5@V'i.Σ0j4VaZ]ERK?Oא6x5ڷ>7qAuqZRxzi{JQPI}/|{ByS¾'=+S0 _(pY;q|Lt 8 0 Mo/U@ h>!.Ñ=@3}XYɇpN/H=pc oegFL󎾆"_(AzSg"-0+z}ob*9e7!^!10(M 2<ƿ?}8֓ҏZ!T0UHA+Izќ5}[<Yu]S}[cSb(Zh¿C0%ifTd68L7Ym¥\3sY.hn͒W9H(N>ĥE` #ן5۫M2^(8_MimId8kȥ֊+MyQ~3n6dh50[Ba{FG_*8OZ͖>DԞ8TB6U\Zj|tX Ou%' Y- |N }n(F{R9\(p6f,Z,(`IP I\k^ \ѤXD1WAm,/4f8u0.B&LPL K`@ꖞbQҞiWd#oMukj 0Z?P%ҪUlcȮH0Mes-iF&{˛$n2:ewҿ |"f] -,A,j:"gw#=F4=(&TenUL23힋5.#s`&ɿ4 ;J~âmrʸyJBo'݇oo8s%'Ԅ.M,۬*аxnn;oAHgZ_A-TuM{Q}bwE8[ؒ(FdUw܅pP U'zLς3;0~&&&xpAߩ3N,)RlhnR2OO##gWk1r8Xr*V p쥡=2Z5`}?.(;vM Ƅ`Da. ڲ'G1%5:W6VȖh€2Yqf|Љ#kWla7_NA6-܊>1n4rC.Zm%.c%Md6ꝺws[tܟ#l.SSb{&|Zl Ea}W4TCdEi|T\ϠALmE(_JU6*V\ oMHW3;a˄ƕD,FW_F§W]A| TVRS4%]iꯗ/KVwLc[eebN:CnnN隍j #w:˜Iuѡ6y j 98ФY@ `Z6E>BW>/9{a_(%A "5c )#կإ 8n{݂ZYo`HU|fwB2q%ԼCd\xvo2,|6` TX Z`~huDSMa*vΚtdLnÎLSΤ?Q}Ǔk\6RkV8JKK?Z 4'X|h`׼y'W88z~>n1n`EE<ڣZpL;nWOu &XPr; xb\j悑峕\=«FU+,{5h13PNjq( =*=,(O`"6^M#̖l\XRc-V^?tT íRR>A \)5_R`„>6d婲*[Vαfz6-Y95S}YDS(uB)Dk|';ʑVWNWD=9^m{miWq(nU, eXK%a0ZEbQ}KS cJ o.P!<^{ 5}|嚬YɚOpfQ͞>e]Sh *E<Oq!L+,H:S_ߓӥ<\[q0M0m9c>THJ%v!UEQJY؁EN$Gmq=B2'LYkq62AueV#_@R=kq2٬8f)9h1/w\!M3/,.9  q~;Ξ>e.# a5n;8(@lť8{iU`u9;Kw(Z6+r.T6')ZM>3ղ;}zfd!KK!Y~A+\~Ho)Yip^/VAQǢx Ӣe y".s ]HD)哹̕ D <&~T:": zdGj Z6c#nS0eZh:[fl*F•rK%"I؎EOOw~g8Z[1沮tc k;8=mՉCS\GG?"/C)T Rw\Q Ulo!UaCOt!fʠNľ_EkgE3h۲q!@W^W;\w[ċktU1=<ʿS>t9TyRG߿s}3n ]{^Cld()t|iPDFmZRE q [P4(UuiR-<{ W)*D5yW&4u00*?e H6V 54)o* W mMdW먒^LqPڢzA^ݥ4|Uѳքۗvpw=Hl/(;ArHu:Xz}9J!g:xmf/9 ~i ؞~LB~$?t4\Bc6s,)*T]osNѶVYL oT 7V#/4JE&% ؾ{z$@8GUL=O̴}ՠntFw2SJf4w*W:ͬb-:k:NNN~ꞜvOA''g';;9i,Q&f<.EAt\jXȜ|p.IDnÇʴ,dFaDr !ZQnPB%*הI-T#bɁQjܢ#Ƅ01lX`"8 JS &* VPE1MrfS 27;9ZȌ2{)b.Rb%3 ) ܦțQ`lo, 0Ȩ9t, XJ.L4"Edp% XͶXɸT^4k=9==Ƚ\ aٳr;+ n`1htE׻}=lЕ ᏮΦno2=OwA]7[rIΝ3 ȿ>J;ҥˁSξ9E!#mo!\89c{;lF}a}>)G #r Ÿ\LG> ܞ`&Ӂ6a\aˉaxdaA7waor:`hg̃Cn{̨a6T,4t39:b3\A ,:19KVjcI;AU(-ֻ)IX3>f}'1.ǙL Xl?bkr_-Y*^h 侪!ui(44'n%β[5qJ8V;KngO+-ohܥc,sCԇ -Rw_{rs. W75Xa.晼h.uz/ R8ZTn%R7ov|mZh%_5*$Su'G\AQNFR (sFm Һ5ZGmXǗY=^Tz-SCu%ت4wv_/;>Uo$&=N*r#h5zS6? :&G$:X>xW>}ƍ=lY>2n"G"_0hBrBׄl:2j=Su'Rn,2OAPFs|-oך kN|l_mZCq{Q~nh Vo%4₂L,o-ġWYfIqܪ =;|86c`BJ b'qc_Mjjʛa o2 ;•8i5{iDh~ruFMz]?65j0fՄz$̿D>(ՀW~=TR @Sx}3l-_C6;~wL&P6$Gܡo$LR-Qh2y :91=6t5ijE>OR?2Љ*Í7DsnETXOnf;#[F⫍#1ȋ}RvEޚaaUs|13uʟ{nдLsɬࢥiS W@J /PW?5>5 PK A4org/codehaus/groovy/control/PK@4b ;org/codehaus/groovy/control/CompilationFailedException.javaVao6_q 4m Hڢ$*˓VZmhPR`;JvF$w#{G=*e\fJŷDg쾡W/^ѳ?ikjķ=sZݛlx1uQ.UIQed"3=dLLCEBCCxQ%N%xqh4QpNW"_wC:t#ģsh셱ߟ ƓpDCϿ?BLbSt >KG{DLw6M(JdKX}Odep&؄ExWޅ}Qh'b"EObAA0`E"":aY&p#lhVXlV50c?:t@b`s,](uts)0V- A~bCFb_Q_jnnH7N,mp5Ýum2?'op 'v7 j/[(W圻`lJQ:N\iSQ;b޽.*4ŏN#C/Kfx*M?j7e :lFlA(JZ5{wAOL̇(}aC۞|o})c/~4l8qͰSf<{=6㞟%%E+n%*}pcN/$ry20%BZ}Ȇg.{ be)FԶڎ[?E@8Z0 p͖Q+^[>N$%.4̒C6`D MƣW`o#1>zOd,^!]L6a7BpFRZoג{ҿ{QWJQpj] {Ϗz7~/lYR0VOKC%\} yڻ@zޓquUq_45uwx| ⴖ;q`8~%D^nz>ݍ ^izct~䀺djfK^'F\8إ$mG?cKVOvNBGCm 뎘,,]2jH JqZRT8 26H^J~{ϸ'1vyÐzM;B8P+ {-EzEXGn/LwAS%0L (zshJE]N|sN5QeK<7F?2^AôDx$<b>wXT8tb)<( ` 04Nߧ($+JlwJAcP#(d!73D^96\J`bT@|7R\Ԏ.͂TNTMhR-%(0 .T>Z h7BdpO²beFe߈1&$̥bA$]XyW!>_BXKLXIMl9tQG5Tt)dtʌT{"vBkdnU"u|+͓BCT[,}JHFC]߷,ljv,ϝxWbehV{ZW.jfBFoIW6Hzr<~ (<\x)!%]o{R2Xĵ JqXc@bLD΍n\sI.g03ZVi^ { .i^^ͿB餱3D/I9K<;_^ 'Y~lp+SAwgNzu`؀ke($ +֦/S9_RxHG"ݠi HKOz)(d0z ˫?vTo&.1"щW$d +jRkXWR7i+.{#sL|$"XŭPZ ҡ; ]s#\ wK7_^r&QDc$~__󱐙6]gk#ԥ]⑫˻7ZG,"<dM`o!V6$uAU\-гR8P6 ew*ZI\RYwAQ=%zK;Ο"|2{!U;Lݧ+o?g)1%j;)ƤJH LJAF3fqhF `cLy/}Ьk];ua+.-dS;1#96'6=fZ%grvAGn9VXb  {>=I̬x)!S)VTvfӁ HLQoE^u}؀i:DU$1,;!Pp~avsKxNg2H>R.``x*'h㶅$bn&Dz@_ѣ+z Lx?Kۛ5]e>[Xn"w=sM‬y #A s~pPaٕ%;MIn+#t B2%R5Fq fC ˪+yXp{[ .mRt(J[^bªiiLQS5:BMJQƢ*ܷ"$cӍԨ"%%RRq Ccj[vު!DeDz1@5,r'Nժ@ò8x 5мFZ&ƨPD}=NC)RMH[(oH1 eby/]5s`,pI&5y $!VCW~!^ QꫯL3o"! ]`c4LH2IX;87NE0#TD̖ 3WdGo^:{C ! FyJ!&ܻ,,s1\˛޺tjmƳ K-Db#_V9^]VLZl!=xgr V~sc) kDb37JpL04qZ40-0ƺ6n%aSmj՚f̚1פ K Z*#ҜeR|kXsҳ>n[ #Z3؁P"\$h<{xaP)]d, kc{+Ԭ)2+, (k]XNi43O4jk. eYS&ҏGa#NɌ %Ev9- cxj ܵ-T>h/Bߴ^˲v>|=SGZ%/-K׼,R2>W7* me:X&`5>W~Vy~}ih8AUK.TR *Wh%0Jy ŵ`1.$󪀂! Q+w◟q1b{>/cH.cd w;Su"& f _ob RiG5mДs(Rui(nwbKV܋m" vCmem3 F]&j oL!h$CBlޖHJ<ߺRR_bs]/mƱs ¡u Eݙvę(vաų'dZK~.ˏ-z"ĻJOPC𕷽f =if;:P}.8`~(Db Z4*"ΞL"yrvo%T\0>TiT*MABrÙC_E?l^RAzؼ &QWx#dW] ;%q܊-+jc#1bWy` FnУNo#V3=􅬀N!(]5If„nx=E>NK _(R5IE`ٰm%@%Y$"J],9&~ ʹh<[Ӻ~)4:u ?59b,*:냿}ۥ^!NwSv&vϊpoTYY [9x3wc<iLΕ?R'+; '`U-z+ G6@o{Dfg]A,W.T_ͫVՔjtSoILovS)NצYl cQrLTF`cE1a :%-Q~Qc~ySUUD,jI(x:R<4RtfsyBդ(njd,(U!֤?첦> a:n95q7ﬢ'!WhEƋqUqa.rkˁO_ 呢I]G0C4ۆq[4b.xg2ثV.w/T[#Y*S`rWcČ9G9r1+m\YzeXnj*nSsv@@JN*_Ǩ] td7R_vrU{"eoW(d-(qG=)t3}ٻj R⏵4{śV/2UY'@- n]j4ov1kiς@}$# |n +1'9%ŢiN2 ?3F} {إ9B_c\58i0z^Yz|Hr0hgie3}w+Z6fԼuޞL@81 7elDlqbB=3Lz@T_ 6lyQtpjחW0+u-kdr~˯|-SJɪEoUp>8]H?jQj6?=}&;oRY=*in7a5nX lzYJa7Nwm?CĒ>Gs[MM R*.@g'9j9L' `$<_y^̮JȢZ &E 3p6;& Fuunw sl#lGj>TZ)ZUo.=PGe/> 993 yvndY/xD%isŮM݈~ (nH(uuEx!f|GR#1#qIs6\I^H䫥14v7檅]0qov)۱_PKA4%j96org/codehaus/groovy/control/CompilerConfiguration.javar6]_tZ9UiiwgYfeKRqB"$1H$wf2,~NNWGߤ&~ޑsGO_rË_ 醘^&9O[c1qNW[z"Z PLl3~<`ӘhM8Z'3@8Z4aUca"XAQ'Cr'[q3J<!Ah{w~<=MFQD~!(|<S;ύ1G)_184Ng CB GO 3$<QXlDqD@T@pt2) oR~HwUH+T4 %"$l!* cѢ+*SV8Ap8U &@ޞąC02({KvXdh2@TDXE͇#]H2% sP5,J3ɍe}4h,q\$1(yKSeq(L*p\Uv4dAݎ>dhLST\8tg4Sυ'(8 ؎s܏@1lC6f* $ٿ8=8Nr3toGI=gM x&'!~up#6r7߈=1MǁsX7S >d{4s-k6.&jHJ.Zז P`l#Krm7šZ{D#;|Ѝvb:¾;&A&3kse'1ߙ38oFi%:FɅ 4.|N,`L}D@l@tHsl: dt=2AP2y$ ŅZ5|>A{1wt^Z8p#``>_,KH͚m/n\k>;7[ r0'B`$4#Tܾ1{%*5q@lc0df^M+s66qu`n-FK"օ`tɏ% e뒌&X XZoѕ! FM G"F圴t+>MH&>GPwֈ@ ڢ^`ZA7,Ɂ4H?rYޭ^Ih@B +eYPΡcEw3]F1keH(*%DNx(~~ dT Pj 4\5ٸUDjځ(ee+ [Gt؂`|Y*fc0\H,E ª?G!'@ +4 1t) ^Riò>A-yּ@+-}Dftr|[j0?_eS n-_6!xB9W]pQt0zBp:`ak.U&qt n%g5N!֙ubkї+C4LeCoB 2:kyxgUa0LII%n> CVl/s7=@,%.p>b-LG'Q`i;*ʊb =9DŁWMjuǒj>?Q؟{G/l}]K)P<)h|@*:NP4CX4\U'G5-x, 3 @ DPE$1eHwű#1Ke)dȧ=G5: Sjun6!N5}A[R*b#:EkJ|W Ǻ\Y"6B[dn&o2iAĪE}<]Y.X6L^h2eE'O S^6|5DDtZpqQ LF f!_VGbM Y7M.gر[13U/Wi\c(br$i''rĐ079/=etG\E3,g+8tPy@3bD:ьT&rgLH.Ş 7jDkRF1?iuPOulxmGrQ@yBWM8Ijc2dŠ^Uhڪ&&HV'jBӖrJ|1vU88ԐfvuTɦ'18Ah#&n⾣bSiG?~;4 ͑3 1,6AI&ڂ< ̜LXUU}]I's/ !c4[ 61⤸Tq$Tͻގ)=n9 :`F :vPe/x2Z.O!Keiv˻cH8Л:qZEM9o)Z u4/sxUhm8K>G{Ґr `;Ow$w:'kvl(Q*n4t`PPKA4'q. 7org/codehaus/groovy/control/ConfigurationException.javaWko6_q XRv_ðL0wV Xx2u f@ӯ@R;*tj`8jjW t @ @u%++xr h1),@z:pt8r"b~)3ʒ:Ja!JgH"єr23|>eSK_DM#h&~4 ?&H]$Ɉ!(-,5D9(F hif I.t6e29er ]:Qi2 tPpT!ߧK)+Ԋ dC;dMXlae&!JeK|!,*W7<~(&sF]Fdr-Ar+:/g*P  cPjl3uFkx /n T*x0FU7uU;EK?=ޗN ^G?K nP.AmLA8扰?b/,q9ikcazV#)z  2Ym;;׼.@[ |)u-NOƁ2 C|R]׃qE[ٿ, q7;Xh|B'oF|N?nɇp|5p=ܼp 5+܁>u/sO>6վuuq=>9a=JVOc +-*Ƭ\HS Zɫɼ %ԜSIkę]FބBWO kJjuAl3PK@41y ,/org/codehaus/groovy/control/ErrorCollector.javaZms6_t9IM.DȒ[iP$7 "Yv=7wSž@9yi|o`qa,Sn~o-6^'_7Eʗ 0GUN@ox ks?X I \w猛0cp(e߲4 QȣTt* KϙX, "?g!iPYDerq|)"uF([@6lxz,4򕟣H %%iFD 5O u35K 0q_YG (2 Cm) k4b(8q OĬFV Inh_+ذ@5LߤlbP_ A@K-H(7h8 %k!E+(׈и z/Aـv1÷ F-yISPSa(Q , SNAÉ:ͅZ;Dl5i*D6< 2A 5ە_.{}A3?coA,#fl3$'AhG0_ iUC=P],'\k g9|ɱq9FHPG gN'TDg|"@חwLԀpoCy[ab}Т)q]8Kl)z2dj%H /}G12x.D@6,~_%,Tg#yFޤ<*f3%5ljkFc>Vq|aw"V(dbP̴lCJ9{8 ?ID=询z,fB9t TN!8yҀLnD}ڎFpTjP32 Li k!>& 3zŢJϓm^\rֳV'b"LwKD+_}Xqx{8OOM!gDt WLz&r~*K,<)iQe\ MqGA":Czdʍ6=V:$)E(CSK0MѲU';=XN1@57< l/(?Eg+v1;ꂤ t#}M3"k7ކ6vJo0Gs)zc\9Z@z}җ[hm:}**^g=߀Řv8N~*V`V\ح0ia΄0CJ)j)ˌN8la3UtX$!GWŰQİNK= oFQ zJx+[0xs?މW+<5yIV ]{)n[q+UwѕQq:lùh*~$}*o }Gsl{%e_J3LѨh>h>rZAx.E=)To9 N`mÑ_ӲlYX5l~ EDH۶DN}o,}m%vEPe7|1R-HG`Ҙz{is_%o^T@4x|O1hj +fT+/5{C[jT6 ܠLݟ+j[Y/hQ$iTҾ\mQ׵_*!uIH1ޕvx>yoFu൮+/6+{X`GugJrXhG_b|bvcn%1e4upteQ'qǵ͟ cy|'.+nEn> cqb7}x0[w]u!/.yH}@d*@sy}f(ɶ*(8gֆ!('ќ 7rT'[wM T?GitI,U&fm[I)t4r'?>ߧH?^;9z̿-w7OӶ7(ySDm#/f2[p`(Mtc=+ЧQ=:UŪ5%. ނ#72NZisR騱K5q8kRWrwmĨaPI vwUs[p)$vs`e}[[{϶*=f2٪Od|(:{uӹH&ŮRJ4~3PKA4+rm +org/codehaus/groovy/control/HasCleanup.javaVmo6_q 4 4i3 MlVFmn(P`e;e؄ {y'=xË+6,fJ  x.>»1jeσ4OV7 ~jAtVY m;eG%BZeaT~;mǾU`Vmt Yu*!Zv}N'bgxrã6`5})J([5lu )X4^CnBW*]!?P5hطXI]ポX"bE[Ǩ6U;W]Y@@pu*_B]KlG"UQ>zJ H鎕@{g0s^J]a`ZEk%1ckBX %\h#qM'kkd`AQ (.2sV9͡Yu,G=xS-@%HEȞvl|dxZ50P]],J>,hT# 29#F})uҵ!(@ktd_J_!Gu-. F5~p7]\Cѱ\cM\gwA׋4`r $b`) #OY }طEʄ@$>_8.1rge0qyvY⻌ 9K)>=g1kL"H3.gA eH"q>g1'[g ldI3(Lb &36AOYaSx$f( ,` {cP~]nB̃2&Xp9AF!r"2-37IdKoy'%YRc q=Y Tqtxy0MP:4]T(I)*nyJ:'@3M͌߰8dP;.bR.Ȃ̺tJkX `W쬱u-Dtw~>Rw֔%r+Ve>E g&@MHS5<OPȆ^KѤ"цqc hH[v|,WBq4(IA9|1@竭@/eQzʧݦP0 o%Oo.ʙxw1 ~`o9T~Ѭ9[rn@{w=zetӁ7%Xh4i]{!qx<ԣ%]~ ΅7[viѥ.Ρ^:t|L8pxAx/((wJ.0:C8C7o92|.`ˆa4p3i\;]%d?k "Ez4tx<`9 ǁk]6q1 <Ú7 ]ߟNBo<:j|^<Ȅ -[e ]rgF [!$m-`1lI#.̍^^Ɓש \mf&]3#ZxuW5鼕^"C,-cQBNԹe%E9󆭎eo~䚛V|jRU6O34YR(@ L$/ڞE 0EDK?3K1U3#G]e1"&Ń #Ih~ Zj9pIZhH)Rpq9_jI'>nIm3MU-gi$UM 9{+dsQz=ڕE!,cLp!.t64cAmٕLoFu@"<3UP|%sJ|@Y-!s-Lޓcr!RG/I`g{`ߝYmpR8LW{_fx{Lã!}+ǒˢԘՐ'P X3QTstiBy6f 1Kf8,-͞4?Y30eԗj-[`GC^w{h#v2Z-0n(zVw^/ԦmQ;ēssv>IhE%> >\|[>j1DyJ|Bt 0I,<DB˲>Lq7ZVJ̠F&nc]wz-UxM|qv͗ޭќ¿m"C-D)\IaoZӮd?4lPW\wNȡã!8 }X\n} ? uЛwV{"ZvhӴI:..#M[8;Ա}ƞSFy;_%r6ɮxx,uzۦYtOrx,շK{'WGPKA4UdSL 4org/codehaus/groovy/control/io/FileReaderSource.javaVn8}W u%E"3 y+-6(PӠ [t-j,rΜsfxy'p KKdE,Ew z˗}{^y1dVFIk<]5[:!%E LO*+c_SP YʼXUm4V6%)عS{'tu9:k<$]SvڸйU,%ea>aKTS 2]抢j)=b]y!9Nlj FZJ|2X)*U{ DQk"င ;k0hJaQYYA(!^-n@@J^nY!ӒJDQ},BhQpSn.tGi{Ӄ_dp03Z/Z9H&ZIie !ԅ-V2z=`ul2ZP{m45K] tXhn;m`!E-f}:TI;[LNZ2ȂlU%ź8_ԸEBhՑ ~pr!?{q( ds9I̒/osv#bzHƏ( р]p?4g4> y܍-O% FG1ѐ#"~rtp\axf;T%>l9kXH[otZJG3fۅY(5)}yjQicu|ѣqh ƵE9Ћ ɘ@S5khsz^,GKeBb4( 07r`!Ta1'xZnr!FػYJq]j+L u+ny }wZLnP `uf%ююݾC ow$/-u*\!XGJxeUYmZ p˫򱉝-.‡D56aS)2s'iȪ2*0yVe-ʣY)IK2)\NOmZhcͣ.T!hnV+,4[UjK@b&&jKWĊW.:WO' psvlY`"/NQhKi]oQ!R<ʙyT{~a B|%ZY4(:5J͙)MFg kYLq!UrX6u M5 nf,u,GZsTg&H"/eu+([Õj en>[S(N&| J[\(XeGlܖB[G]s @ @u% +Pki8Cr?4lʺ W@%Ѐ:˺\mLbd  b_Mȱ3$Isn{A ]MK {e}x00;CDIcq3n8,} `(e | ԥUg]S0'N F]8ێt^Jo!- cPښ{덱5~ϹnD N ',4^)r-">*[ eϒV?^2m 6~ [פ<<*pJ8^Wt[==iRpXkxRsYzsOɧpCg+;Z^nQ1(oxfGޟjtcwauqO3x82w9JXUqz}Yufv{SHߠXtK%nQxPKA4M.` 0org/codehaus/groovy/control/io/ReaderSource.javaVmo6_q T/&]QYfbIr|+-6[Y(ɩ1.b3[{y3")2ibݘTp7 ^|y>Wo^CZje4q֨&7OX ڈt% EC=aL-M<* ^IY"6jJM%A/^ *vATNeN,jA^Nɩ ^6W75u*.Z)ZTQ'jyTT"ze}_c]j.6U FB`'$ͨеJeՇ#D !J $,T !_B*bJfݱŒbQF>qr9RC%w(FNs&d|R"`I4F! %hf]Ҡ!6,֛IARdiCcuf2j=`m]웥4ZP{75KUQ+Pݮ 1muYi͒R;'حŶ5yF6R,d/(K)R(cc{P$$Xi\ yF),1͂u/,મˋ?kɘWɝ1iልY ^0› pQ^.ϟ5/i8F0~3pD bxOf#\(a~KBF< nX O)W< 0\a8^p6"΢i3F<'a#l/`L`,H {4KO!Cp8GO)yP67q!20/w Ac pFލwPSQ4e" 'u1nKk3c$ .psEiԁqx MԁlM =V GU˳(aDT19Hv=,scdwFٴJȫٷT^~>=[Zє?cQք p8 ܒpXYC\ڳ7j2B#ۻSuZcBuۥ ;+#k}M022LjWin q6ؽJmٚy҃A~=8Q\Oʆ3 |!t\6[:w[R48Q<犑Mex`.RU~Ig_?_<q824AAabW iy%hpܰcu\kE6VO8 ;;.D%Mݡr1%݋c^ U=Տ s5 e4D$dılz@NS>1Vm%PKA4 6org/codehaus/groovy/control/io/StringReaderSource.javaVOHb*PөVu@֍IѮ7vB tjyޛc^ ڨjKKdUEo 'xN?޼;;=lQ^=X4-G(%l-Eagp/_SXZi2#V,seҬn+Aϡ^* V{aLZ)eU &^KM \ennm%MjZV='j0E$t+.R>?cmu^bH?K"nJ*{BV $mٸ@FgA3U LaT(fz-ivzm)ݮ{hf JlLK6>)E $G -Pm\ )`a^?r,$ \jC[d{^a[6(jCQ,֒ tXhnw&B +f52ןM6 vڇ`WLN2UȂlR(㬳S lVGZ2Ro{q(>dU s9IX̊ಮWgAk+@]~'qtGl;dD#vOӘi'|';`'1Kbד1GD0,t a˜_Qe܏Y\O<\4|p|qʃ؏a2'Q€Dx}~F^<ĜnXBrS;M!Cp3w=FЄ=I8#ڿdhSS<Ә]e4"Ӕe oxsGkH}1+45,GW-46r5B';B%=b>&G[3$AۂtwfD1dah4"[0<M|c֩MUB^N\1_?An66@»nqW鴔W"&-vTE_sSJ\}\nz|޽%<[@+UHjm:w/t$mLO}{K#JZm."r#E!+| wI;~ >nqҸ-\|4Beg܂?twnï8tö&q |X֍;T4( =*AB}]!v3iQpw;dlT ~zPKA4<: 3org/codehaus/groovy/control/io/URLReaderSource.javaVmo6_q \i3 Mڢ$ɓVZmv(PӠe;N P!p$^ȃ8I2J(Iukr+_ o^>;xw''Z% o5<u`|a-CC,e5"_ DUu~PJCPSlYX,TcVαm$؅j3{/tit:o<kÃ>+mZXBTl@jiR*da>aGLWr]絔!P7qZKmcH+Tk =?$` sYQv > \]" >N>dC8Iab]9 3lJ_ʆF}H,>3$$w} ASpupPSQ4]d"&8dRg0S$e}̑.5@p')w(cI2g<=oQ:i9PQT߇+ ) )fvUvhB.GE!٘! )Y.mY'6U qu;=w~`WR[xv-Ĝv.]JyZXs|oi7=ۛ-ŲYl[ceJiB]Լ5y#.Vt~@gIx/`aRSA44c0cqg%~m+L;-Ux6x &[4LI;y_xnf$Vu^'ZL`5ݘ|67Uc~\ AYCT)C'ӂR<XL<ܨjBAu2>هv;_.5Yqxm1:|pBO9>'H A%TAwDӯ2:O5zv3VApVpU7+>e.ZĊ)PK@4!R (org/codehaus/groovy/control/Janitor.javaV]o8|ׯX>94Eeyp$$'[ʢAN"8=ٙdģWR(iX+ϣ@/j:16"[D@uPG~QPl*e%F=`2WUmVI\WꅪҳA&DULZle-lGdxtܥU/HWkZ\TbdV,UmVFoT.sD$tQU)elV岖>巽_XWn&Hj2ċYXZSTZeE- $kٹ`|w Ir 5BCz#in9u m}'{l*gPK Z_,cI4fK]]f\ }R.dt47Zo9 KҶ HiemcQnh6yhO(.[?f$n ipIFA4d##Lc>Qx k7wľLb$Ȏbד1ȱ%]a0yx%xF)5OF]W0Kfq0O<%=iztr>M8t4Ɠ(adE y}~͆h/&{NBiYS:[(trPYTK#uԹ;Cq=1baldanyyb#xSGթmW ^vb$xt6 m8߂t)W".vw?RF瞧+mjz;hjp; O"ws"f8v\ΰgcs.[Pawvq8i- w=-*0,ث }0rvq297R,q؝S0؝&ǾlPnkӘ/T帅p%U{zCGmm#'as|~]7iρ]e@66Z>wAchvwyic?oKw~Eu E߽l_!;mto!P-Ǘ9TsA-Tp_$Qs kzn&Wv"~>ϣ -N{r_PKA43.org/codehaus/groovy/control/LabelVerifier.javaX[sF~WqyJfSk%lA Ȏ߂%FҀ "Yc&>f }_K_YK1M~58;ggg_}YO`4 |"2'o7<E.4+>y$R.˘ذHG[.,cC3< A0rAb< - z'^)xrڇ8_//rXRdm*ZMHCA1$qQLZZC>;Qgn 2TPr,di #fx&7m[c<()nk+c4Ʀ8Gk}LJ./ ҆M̡E&1>F) ";D{mRv8N]BF"[7qF[CӻIG!] jY5MםN|˱O5u y0GrO[E><ܚ%F%[$Cچ~S="~&غ1Iy<c0\# K9~0T¦]¸e#gr3ctF0+JiL*E6-IRz?85E]:IsKMWk.rcMt 5ȹ]Xϵ>A/}h+$9,_`W; RHXɱZƏ8V{o|ibY`Y4MFIZ,nZ 5!QOV͓'%k9Sm[`n^~i{OtAYa8{StxAv25Ъ@Fl|זkxWRj0u):<ɖZFoc'hZOC􅏨_|Z϶prw/mݓ/^3j %f]N9ToAp B[MD")fi 1˘[[QۜݮzVZDEɡcf$ U"n=Zɧl R,_x6|xX\$/ˋKĎ=+8a$zSȴ8E|2=/m1N k 5X^XQ!;#UŊ-r70c&jZ2~T MDSeY5esiQ~uҫk[ϳ=s NjKmMʴyUT4Ln{eͰC{hDS >"LXf@(bѸ)(u7uY jr e'7(сFp0.@U9t){K. Wz G䤊ͬnmB8َ9\|?zE3~ `麯/[i6VWnÎ1sʸr 8PX/Tߔ/bNpMQI@'DG#PX{PKA4G8org/codehaus/groovy/control/messages/LocatedMessage.javaT]o0}ϯD{HKd@hi4Ƥ :nؑP;v4s=Mo\P@DčFrl(QE= VRxkD K1C|H l&EO"\? "{+#81gXbMp5"qlw,EƔtTt5+̸SRKU7b@VFx(pcW Ү| `CrkD]NcrBi:Lߧ@L.,Yut=}2T2km'j% % 3|3$ș#HB#aS2Re3:y(/QitFnjvS2:JlA|A ~՞U%af.W*n}t$Trr#8!ћ$pEie;{ueE3][̭ ɛJ/~FEcdU;x0L_lDo ;}s{jg;iٳUGeY[B8nS`9ܣ=#ںbPK@4G1org/codehaus/groovy/control/messages/Message.javaTmk0_q~HB&'v!%aȊN$>8oYS s&X^He/1bMbῠcgN$63OtVTWFFSքIaDQjEk ca!c[Au4uŐ)tcƍB2ŨOŹel9wL1 pvΒ*2\~K v{ ]tWuwz̹ap u(sFϵQH=E`mxlLF,H J؂f, n(ǭKl2l COvf„(YI'uEF<I^2,EDpzatZs`7spVۻ s4/\eS oC[mew yWPKA4y+U<org/codehaus/groovy/control/messages/SyntaxErrorMessage.javaSێ0}WL> ZUVhZmUQg3Ď%KRTK09s|x\r4ye؊n,hØYȢdp&5{"wiD+iv+\ZYeK+rr`>ȹ1Hw$U3xJN Lm,{^ٵ&\ .sԒ$}F V$ <͈ qc6F9Ja L5Gwotö+6JzΥhn-n']:Gp 10gDTq ={hˮa;)!s%B `fFG-4 ^`NJ7>k_VLJeHynO3[דvQ8cR{2+ ~v nm(8ՠAk8mL;ӗB"ݓ+ya@ֵ-r|G T >1Z*y<Ë2?TaC:l̒!e?7 Ax;Գ~WFɫ^-;>,?0r"%]@ֿ#?_PKA4d| 8org/codehaus/groovy/control/messages/WarningMessage.javaV]o6}ׯˀ9IoX= teHE.)ɖ=8-nAsyxɒ AU ׬2J+yoia\/J-crk.sT0ɭ"g`URgIZEL( _\pA*1+ [%+hń;V5n5gªaZ*9L#+kH57p_; jÕlpգ.a \?9ë"0~,Mdef`Rf1k@׻<NЅ|)*HقFEM Џ"\VFˇqyu%@,d'U2ɍ!WYqjH(Yu=xfJUX\dB=`+XV291 n* $9d̥M\RsB`reV֙ʀ"P![aIWNMDՃWlk5%Ly%(G/7Pl^#Miz;kB^_ -6ISw&aݬr)-j kMc/hDDq[~̖uփhz|>j Sxv #q5 s]*86j b56eDVZ(]]!Ue F]z \^!x%e-&/ x`HFl}᫕H\-&lq`\,*=C ?GS;~p cV~S6OH:d $uzp<[6tH!tOބi̮i'g?oݔ4i`rOF ah tQ #6f)N4x_KmEr5a) #?4D h`1b![ ш)dO$\Qd_hSEXL#,\*t ɍaE, kqɊg_cVnhU\"+ 7vODpxDo&I1|5 >l7S8BfGzUxj^s. r?x4 m)ی.Z &9Yw]^Ug^ă.AGdpyL2vz39uR\60RN~jP=m]abR<;NKOKDyQkwAD &oVm#cas_^Yl, v^֐sע{Ki|&IX?HYu{謽fVH^_eڻ]a;~#Ϫ8y!/PKA4͙-org/codehaus/groovy/control/ParserPlugin.javaTQO@ ~ﯰ*u)C ,+e-jMoewj/ ЊmjU_&ZY=/X[k=J ҎruN @|#pa {<ؚJ܂6jGC:XIE@*R0e$jAHnQ㾏a2 GPi =x4M-b:_%,a[9Ͷ1M  XXb7pc3+ߠ&[~OGz\.C 8$8MQr,?op/lLS/`2]$d>%ij{.F@硇ʆ JRʖQXHȕ\.j, !"Ȗ҅:&0Jңo+4<X! k͖֘[g+mLJhAy-BWo:v^y%5ev |tmZь=#i)|.a=k2R04ixx2 n YtPe^M + m!e}+x ;-uƓCɮ7FӃ2La֭gAW:L;b4_)e%U;*+4f7^ ߛGg!LJ<ۣOL_PKA4o4M4org/codehaus/groovy/control/ParserPluginFactory.javaUmo:_qnD:v1 !Qʦ24njYVwq2HtcVUyys3]m ''ؠ3"-l.ebЀ+1|EcVp@nk_fWɇx_%4i>ɇc@bMe)ImܠP4? c|.\ :my+PySju,#uugsu/6 q&XYVD@n9e2A;MAVZH=&'ش֓.G[PuIr[?n<̝6~Jpɮ,.- ^vdsO;Wz8}@oX. q2t_ ~9G/1񦏅`/ " TDƼg @JO+Cfg0CyD\i^{Zw̯F3iFA0 Љ7 OQ#G*nځyo`Q4W[FmveIlsHڎB(̛7o䌎z hj9x1ys:;zɻSJ kף^,[k^rR$˜.{ɾ,iRPX(!5kuFQ5vjyEdT)nVZꋵavIqUΜ,ZJ6ՃUC<◢yU].(\[yT{gK:)0욖j.a-V4`,eTVP:@th*KI`lTBӽ.yDJfaLCՃz4 pJI*D Wh2zP +ƹ p[_7纓R|.d_zxt@mHyelZOӧ sD>Ml6ڶQzo,McH"/egvdc8Z2>d,ljCVqk&F\,VYJnJ9nAAH2vJ~H!;0nA"),fi@s˶F#s+5$6H}x̮ (M,ѣ_ \֭ qBf:xrD)gb@< '1EqJ~SإE˅=OcQT}FG[kU l2T^0rvdF+:r Ǽ݆åQ0k?[`}vJӬaz_(q8Z.lw93Q\^S8Pkl"*v+sN'kԉ%Ҷ/5)wEt!Wo!pFZ~$6+K~''/bSOںG0|~G k1m*YveU>Gxt"8?@#Mfts?}ؚo,z}{$F?K ԨBeٳ-V] $rG-#;·r~VW*nmF/L+Ws߯SM W/W髻PKA4/org/codehaus/groovy/control/ProcessingUnit.javaXas_d&ːt:"! dЊ)'Hq(Y@ ڝ$wݕ:_\HyYR %E|xrszHEkŊO[ӡ>d.xzw9Zd$EODRISPN̥~|'y]({pKRK*INZOBK \E(dLvOu{z}zJ5)m~]A'$2{ֶRo mzLbwO!iT=T'|*76A upsӑđwyAZ"$C@,xn"T :hL4W ۳SD>FCI&3Bқ "w@PEfo=0Lwu@5DJV9:Aؼ087 :lz|>,=H @)Y4GՍ*,L28£%mnbꄥY=b}A`qޮk`*E.m,OQuTÀEUHSlx02-{rv+ED1ƽQ ّ >9; 椠ӘCX!̌U?@^ N[/`v;KxG,4[g34E8ȷߚ5gܟ8=ɻO<<²LC MG؛ V:44Yx<>Gks-:W ?]{;~ǧŸ8&w!/o ~p!diFɸà(]\M\q=7-92|>sw`c hcMXsܸ$dd; "Uz"tf63["p:5l+,jx5ol&xp&  ly0{5l9>xa-L7Ɲ\^{/pwx 6g cM}L ^$+F,V\V(YUI6[ *ߧ"[ n(E(WmW^AF E!Ц4*Nf nd;(c($9PF FeCNsOb靠˳HB]D[Db-ņ F۵wCx?b\$Byf)J鷎)I*2+iF5+U)@sRm[$ ,.$KuYR=(V#Ac)`mze}ǵrYʥUJ-S/xeGI*ulTѝ&5.<GZt˛!,n|Pؼ#nT6;Pmmlǽޯul<HR(Vq4z\ܽ:\T6B65WݚagPv tyI3(OE3^2GWKC0@͖AvWٴk'T28ǓH G5 swtz15O{dO_cO޶ ( ӲorjYó_L=jj?jsB&'rZ{kQ[uխ04~V y*#F[Qm[W!,tK~(B-*ښd4ܛ)p(_1y8K Q)Leީ8*'?-Oiŀ1wDf!;_f&}N3׮2Q XkՈOjOZ!9_܆ߋr(T1jzǃ*Yg:޻Y|+e_]mh˗ۜv[Nmef2aitb70Jh]O }}` ߟ!V_ r/LW\i`)ZaJ;PKA4yt/org/codehaus/groovy/control/ResolveVisitor.java=s㶱? 'S9Gsݩ,wؖ$ӹ"$G*I&߻HL7O8/,v s 5rfcAYww|_'w?o߳>E_5 \?ebY ,w؟JlRd|)i==.YzIƈ#"{QEEoX*M.b,gn<"bmV"-8b!hA:]K&3l%xːZd@RL>|)?e8]Lr[5w r D ݬZ, <'RY37@2fc>Nyd+mI{ \;]E>z84"J=0,JdL B@,* dߣ)\O"HI{ I&Hf6]B0%)9ȪpOfudw{3] Hm2Sv5&. 2@TdHLt8鰷} .Hѣ45@C;cT,iSbA¨ϩ%,xw'Xn8A}{ \> Bh`/p2OM6kH"v?n\xrX&e;Oųwrd7<^t{/k~T!H^+w<و&ۈj7`Bgإ755\VK%[O ѝ ƥP>Nǎ LiF\tN  E齋4 f4+xQYmR\SR[UGe$:K8'ޟ}nY"Eqﲯ2c痙\{5WG>﯑3 sؔsmcˊ3]?ᣲT!Bi[ý( 4&\נQPR^fP/EaM+S\jzϨDS6UEfd%;V '^1'>m9.Qa_a0MDzrBD~x' Wnf1!j=)n5 l|:r!+$\oؿv#YcIM:fRw=ԽkԦ3V|3s ԣv|*Uof7dkݕjةsNS:5UBu~nki h:xcetq^Qp"AM-+,Wk5>Lo'XSpx]dO5uFUn5dڻ*;2慶.g+ǂbʐRxЀ2D}P3T[5bUF<,_fyU"@1Ꜿpn[A<tz,3o^u& 9I|aerG3AN8Ng2XN΂}igJ<}|yz/E"C@VQj )Ų ~GADp|r%`ݏKY?cRhըHDG_OpiѠKB*#loUP;Nm欲ΐ5zǜ +@Jx+r-.KDqOB zt&|{Vr"oV"}NmqYo@{!mjʎysr2]^HEE*3p7S39`9vFhyyy~SPxBX2iTM\=A)`rJ3XN1>mrrI8KF$g%U= M8Nm[W65 AXxQF= )'w&0 3Y,iNy9 {D4 j:2.ݖ򭥦EΚXYBj<:vG502]{A.|ɚԅUQW4N͹xiLkb1ouO@*, HOUl| mDs)Qs^GV>Kwf[b{MQF%IcSg_iGZb'ko u>Xu60xF 2aR#f>Ǩ՘ !>ŒFAs|s+g[qi'qWbb+ɤ-5(=%8#}}Yyǖ*C6mmw`H'rgZ8%^9'OYD߫36Ļ| n!?756,==GJ{pӳ桹5m)zeh*ꀙk,# aqvDGp{?y~wR9= Zfk"' R- mpRTS\woÚpW;k8C<% Y*)n샋*[<-L5 ~aR՗gk;_Ht,No-ZvDPU{ :rQkA;;T6G>K>f -jg`vDzxU ˶Wbqs6 \_at-ۍmxF\[Mknk+糳mkXnG~f +)9^9$r#f6)\ƭc^Pic,SykS&KHX(Mנ HР9`@y P06'5HęuP2[-ҜԞtV[/H9ӞF'k`IP-4SSv8Us#LT[y 4"Ů's֔*n<F_/FYb 5۹kaM'-ܵv:aG⪄e\&qAW9Obv-ɰZ1[eUa9(TbZܗ<\[}2wNw1Ie$p/W_3|M#NVXP8WEZ gIi2uNNNTy*`| !'>}s}otP6 (΁d&z$SS_Hkj[ջ n:9}nвNp>;K/^8P(rq9ևK5^Ô"nfC#|TF'A-68hbʾx /RiIMNA¾C^CkxNx)FMQ>Qtx=v릶І[zyk~n g.e+Yj=r]өT~)ksnm)Qb?IBO%ƗmO!SO8,Jy!ǧ Gl?ӣ I9Rzp }2YvCrQK[kEi]TP&mn@LfuRM-`/I9hYs tتֆgɷ8,4-ic2(I5G=YW :[UDj|k##fTN}_"zrD5y3١\ɜrK: )MRIK.vsVcӄ >*_ݘ>sV;*g8K( +vcz,iY*_^,u(MXT_S֒wai U̪XZ'-epg`Њ lHjb-j}E.ud=l3#AT'/fإ\o65HQM$*WΪvҌ'J|մܙꖏ  7ρ;@L!}{4hmnEDa*#hHz_]n8 >O `sh hyNjt2\{ȻHI)QI{9eJ$%#re~: { ,RBjX<FGpS5JIGj+NJ1lcj4vp/~&Y9YŰ̫asL42㝻Qʼ$erhhAJXx6U<li%b7w1f|pAְ) ',ſ+䂱kg -vңOEu'ї`{)q"'AL5R nk 0qaỴqgSD'a|`}Ȁ>MvǗ3qA Idrn)^ {~L 5S|j)Y7=r#Qئ둑 $эtd0($3OKtnUF="zJB 8]ژF>{T{'c=$; pk‘$!WOвCDG³4P`XL-P;;7%vspDz ȮgN%lix爥%d @:?ٽݩ!|.Y(@ahveD@2xm VOw.(uCڍ b㉰.}wgcAuǡ;3.F4{tؽʹ-lԧ{s4[H!F+XS14JB|G514haDI~rꝧEcr~3x*GGː:  +d+^ߛ-"׵Zy;6P}}""ɱ|%+@tD>!n;}ɘ h/j)h8΁sBc>yp0G9z4ܨ|ʙQ02zcR,ƨXB:?oelfzn{ w x_XK[NJAjoxڂH} |(mY+cXpWBpXy!QK|zw}.P{x2ϯ̸ 2|,4(. j|0)27`F:ϑXm_N4Wk1j_)ڤҖq-_[XǂDtAeAfdMWʽW+7K|(0Vp6߈-c.7ևhęe%[6eH ֞ƄaNl˛PKA4J%ip0+org/codehaus/groovy/control/SourceUnit.javaZmsFl^2'wW&l(GV|vI ŋd==x${}C,LNO3<{ޣ?:FYeoV o_/g^{_U Xlx?z4ݥ<"2!7!pMъ26 3QBsVM˵R?҄Y")PJMz'b>$<_rM2LS`Hw~(V,}7dSft[-=) -yQ*QT{/͆ (dYR,Sx;Gh,YDYFĤGBIJ(FB1`vw /#kk&B+XΠ)LU*G5sZB, ]]^ Y,6ELu)%V{8"aa9zi I dQt{@YZI( Q3}j5"xGm`7ebC'55K+2$Dvu\8Ԅ&+Hx˦}o }a' ?(I!!s E1~\|%S($@[̎yŠ_˽?`&]flf<_UV1ܥٙiVuKjqcml>}\ڗtmM/%krb\,ӹۣrA75yOɹ܂ܚ,3͐Gεt$hzE|օ3vYd ,Y3Z9͖ԵtrK3LٓoW^5C†r`3G 3o2 76L]?ti][olѨ;h9Ye8]^ g\f:d{wvi:y(N@![n(JQpCD5ߨQ:^0W~ ϻ^ K0A3?zm.Pr>LiyH4ia3GkӒq].V_d[;#ˮ"Ikd@N h[5z*ݗZ~ %d( "-1/#G&)n>pPEAb.S?1hD9ډDVNo'׋ MwX ' ``P/ڛ\Cb~ bo꪿;{!C&cPPI 0ߓ% =bq;`6hi]̲* )GߛYʲ"h͏4z"?e \?v1 L˙!~tr.’V Τ*=8#V@Nؿz&|=Wd-*<(t+Kʕo C傈cb dR3 r$_9%ف$,- )f w<4, !MS!QOTc! p㞩NM1Ь7`=U"_:EUF\AX6xTa6ǐmX #C6r4Trl*>4PA"J UmrZӟ xa -we5UO!?kh}Yǫ̋LŰkއ*0-źb <(P8ŏ{)l .c#QP`H>i@{d(<~ύ }c qW}b'dbD3C;jЧ&y0ljRsWcÐk5 .] +w>kETvY~MešZE~N?i`z'2NJe%W<"{gkZgJ*ƀO:NJPMRJ\tSo^iNJQ !E:ki,ȏ9 x; JՃ=^/6tЗ8CD>`?PjyusB(]ܝ aFmDž'L) ~b* aӶZ˒4긡X a"[D@w>)׋^%/d2oPL;qH_˻yRm>Py>T{ư5+|f`..19+.InwcSymΝB|Ȃ>S0I_IdvgTatgJ3u>ьmJ~vQѸ/ҹĎ65 ^Ơ> Iil[}jōZ]E*j uOZ~G'>xB_ ^hL-ARST<{5mMM_CffzAPcBFZз _T:xU j ­C[/"9h8#)^G)謣Խ qi+|jhs6E (tɩG; pP>9YV 4pFKKNI"uqbK2W*9 -rm,WvʭՓGmގ~VCkȎU[C5ut,b5 N5Cr&1@Uۛbg~PEMi$%>,w$AŏCWL[d qe$P|_R'oouF@[51DZND1W0J5]e7˿ET0n?̍oTے}H5 >T̻ؒ * M·?曁 |0Ex~MѬy7rVx5$J4J!k$PɴۄB'!'Nu7PBO~j̚zL]\9WOuNs^UE&H6yPE7PK@4'z'org/codehaus/groovy/GroovyBugError.javaWmsFίغӤt٢# ('D8q;=@ ˓j6yvow5:9\*)oUʔj'[x1| ?^z ˜ǟS`̲WY.I%;' ax"\U|T)<4B u+e"teUf֫rirUq%Z/E(JNZQ .+ +62VYlD@ƶBmlX嚗RJ湼ˊbY$)ie~ȚbղR@*]% |eh BY,  <גB0v8铱1-HO!2+G8jӆ` Dd/BlsG$`ЍjGsm"D^jHixHs e4{!DʂTQ #B$"Fэ,M5Z$;AXl³\[-٪ FQQF*DkB$Pv+E'\p-%RVSa m}3yB-Hb nos)Úov61ebZ;zxӁe  U Cdhyc|/B0z YvCvbف[@`TcR&^=6&V#ݦH eδ{h-YRKPߌ75:=^JlZ~s' hb(Q+nòJ%+˴vۯi*JlCsQذGH2ԟVU2Ӡ7'8ky+lH ~1 Ab!236DqsP_NhA"EjbʼnC M+@ЛVInE,"kv KiÊ5u6*M>"V+1D"IpjnY9naj' !i2lңC< >O{WXy G>DgCEK'BS]mfIԨ4PֆNSkNcEӖ-mvUoԷ}yo{KTW㓷#jZ/!RZR& {᰾Fe8̌s8jպ 6 x*_o? gAè)UC{+ \yS< \\RX9_ᦠwV]%C5L|tcωP?!نXoevk#_PKA4D (org/codehaus/groovy/GroovyException.javaVao6_q 4)4;I[lH1`LlVZmh`#e'NlY!Żw; /z{Ǿgj|[o~잞ug4̖"}Moj%+K]}s2JQ+diȀ&U庶S[ԕnZdx$Xl~XuaGQvX*%K}<mbQm>U +C&`w{,K}p*!Z}+Yg~R=(I Q2`j%o c0FpѐA2Y~&/p4n9 tx^ #.}GQ҈y4]yh̒pAxzcKz4iz4@&Ap: LI,YQ}.QǬjbQJbFcw* Ǡ7bm)GG '1a!3 -0@k ,R? 6?6'H8MRb)O)8[ \O4k*iJ^aϽ5,IщG&|`}8rrPXTߧ!: !a*@&Er/Y2[k.8 6T:ٶK>̬I|@A ]4@ݴ8tu̾Ʌ='c#II8U:ޙx% u89)2 %NliĜE] b `/Eצ)90B,""ct$#G9 ;1񅦉~-# =4j+,zܻ㌥b$hЄl{^.JW9 !Eibv"bv;,[M\{.8).w!P^xu'3$>pt"C4@ôxߢt.A-r˾ɗ \9IV';tgIyxuZ[BPO ;tF4gley~v+wKu_PKA4j org/codehaus/groovy/package.html(ͱRPHML1̒̒TTtԌbJ=-}"N}VJv` >y sJ2R|m :!&]PK A4org/codehaus/groovy/runtime/PKA4$Ks/org/codehaus/groovy/runtime/BigDecimalMath.javaUMo8=KbraOf7"MM[@ScȑI {yd+(-si DӤGYvZIpnhPn#MRWhv ;B= 3Z,kY%VNJ3}2 ZI#.GJi3wwq뻛ί>Ngik%q=,y_s2 и9fC3#إ5 i_$H@*9BaiQIk\tYUVzElGTB@-(%-[&۷X~+t֪_ <}fWh .4c,A/P#6p$8tMdQT!Oj*,G\,mL$o@gN50 \1ºf]-Sۘ7 3To+SNrC1_ny՘׬[GƱNQ3oǾً=b^|>d}<t3h?'x>ۅc<ǻL^PZofzOPx_oo&f3 T|Wsa pأ9w%Vsn|zBGܐ-1m?}ڃ_=^sJM88>J T{ҿ"s0=+M9wopٍtQ9'H,BI1#a<${s°S4mHA|;dVQ ?d$Y2݅KX㸱af}v. PKA4f/org/codehaus/groovy/runtime/BigIntegerMath.javaKn0@)fI TU,M{cO* i҈H 7co"Hx5fmI%8gl62‹ 0D < оsh9)rNy?"cpf~эX be-kB-6y$PJYD7Mi7hD9 ℽ lCd$S^n2L,Rn5Gyuwi;_Q)P)豉YF4.(:pU{,rAIʸy@14ܦn(Z)Jx\ 9M~ T*M Lr涎#-z]\P_%Tmb.#1g58̕h oޭ !_:+1'; ifTmۭrvbİny8^q_W ~tyά=/#z{>h#r`M0€yv6!>j_)>)jԲ vU hnU!Y*Ydž6U qU[=6~ v`Wki+w f_DY²Rf'UytM;}χbybZV/ حs␀ռ6>v'g4}J\j+ID5 Y $@x4MR_-%`b\VS͵ʒ?7y8gh!D:iiIZ.!+tۀ?:@P@bml@W*!߅n`DZ nиGP֫H7eE]'1Z.@*.WU[ -vzaU?/jC/Q"B&Ay4k-[Pod;Fk_e(~1m@g1%]^5oC}J/ah?v#/ :50~5ޑ#CfhP5g/PK@4z0org/codehaus/groovy/runtime/ClosureListener.javaVaoF\'=mdQ%Fkq-1꒒kf$'ŝy^i\k-GYYBj؈8tzrS])gNKYi1[?VaSG;ס,)nEҹ""SI,i#UZd%zZQjJz)J[qmt!V늖*㭤^fCd)O2ܽss"د4~KY!3%.Z$RˊDf͞d+AY2ҤT*TLaHFkiDpwY!#rˆM 4Iܩggt-|<@׭<:ElWv +H_gHl)qIG/aԚk6- ҝV!EH T$)dNg5[,O(lw%CUbJ](X]ZRVlVA{a8*=wCGl),g"ϑfX)@f&r#CZr)CfAϑaJj<U׳]zpH"q#<-}¡NcrC'Qp>M(~scxYrǷ:8Qp=xv䎓t/ YvMڍᶞ^еyW 5q/dtx.M( ȍh2&aba{#78 .qB;g̓x?s4ρ3s>y G]'Ѐ_0¢a^H?Aei_3kO$HOa8dڌب6.$ Hew{vuA:Ϸ &Lrpb,{[V{);Iw Uh77n IO(whd;A(|Z ?cG[izMOMW[ ϭwad.DB01j2q%ve1hǏtpr*/ڭz0 h}b~ob'pa|y63`w2̂o~Mбwn+?eato Ql'k4[1-޾="ٰv:۟PKA4i/org/codehaus/groovy/runtime/CurriedClosure.java}KO0{LK ܫJސx u$?IڴKxgqE9<&Ks6N9h_* !Je {<]VSө)Hئl~Qdޘ_XuM沏638\r{yR)2c-b?aȿx|`}D?l/PKA4:8ƤFS5org/codehaus/groovy/runtime/DefaultGroovyMethods.java\{w۶?ն(#8FDmy%9{i XS.I=@%+I{$6E`x#X|r/]ݩLgjx~Z{{?ſϟx\˩.CjqYJz!~24G3?~4GRnfA0}JD_&2cqqpLj"YDM?'~*bF˹RO60]k ҙP1VT8#o!yE1ҙ$t&bq@p e:@d%":Qx$4FeX~[%O*Ri0*>F""ψ2X)xL*\߁xn)%¿T2'/s4~01hDXPB! Cqrˀ'h`f6eiV@d0H UL޹JЬ 1ayb6͜5Nq@VeDFȇ6: kS,B'RlB"fdU<\sC&es!:e"IeBV ABKeOoCh)#ct܏*"{x j5cpLObDjrAS1Kŋ]= j@ zoZy[s,~GcG{ǝhٰ=~g0|/']<wu6vM=k\w5PtOCt<#t9~='< %[a}qyo0wVs+:uΆburR(u@fC> N{H_Q G|Q0_8}GSa-lg>f:T* .JlTŕz1]>6e^q I(G׊cnC@ e\3s?nF!# ~HR/'ۑ\P0Z6L&ѕL+Z׼w+_/n7 b/9Z—y򇤍#&9ʺ#!XFC W t(w7w@lZ:mh?u(*MaW*=Q2he$.'Ax)C$oRzFy@9hX 3J(A8tZ:UIRZ. 'cN5l‰b#YnHm8I&o%P/fWzEiZ 9!^s뗻k/;" .Ηa}5^-C&N|EC4r_H0Nep_c^_ )k0w_H.q &g#u@O/{!ԡmj5#|H4&v+`Me"5t:a%bX!lxĞ-7}>cN_Hr3=} 9]W(3C=(3V%sG#QZ!X74o`̉'J* ^I ޳oE"I;}1R`0xЋN5&@;54Hv.#4a[a?5| <:dZ/+nъ&aэt#7Id01I,*o8Xv(PX.hms""Z,+8-86W}Q&h"yK}Tpb{]nZI(N2  Z.+a\R& f&Fӽs|zS #VefAM´$-q*V-BLQ_ eAyM2€V$|Y+-jQjѨ]+BL+ƐX"4T DjV|HD$jd:9:ž)0;)ڔ[")r%3O&kZ<3?^xB~AYǕ#LݺXvjOϞG \;̿tXw[굗5ǥ9'⟯&-t>{}hG4rjW-/mʗu2򪶾O Krsoh,5% Nm 1~lh}jנ.yQ۪_Ig~wmW7&U=eoEHXSَtU{zV%^|szleTd71xi?_2? ᣦ%mA<'ziI꺷 0 В#<[[q#E6a/cӚq 3VN <$6~\+ m3=e9ƃ"4R>yqxBJ ֻI4b8zWnkxi"E3yײ9I""{8,n1%Wsu7d{R`R_\?e}:*X!RlriՇT|Vl(|fqh .K{][].h||/A^K9د)oS{S'Rp|A%D 9&FX6Dz/TmvMEIF2񚝊h̀) gX{o8bb,C\L?[8PdS`eu+%q+CaDOJm8$b8z?W$ xL)O, f9_`ԆsBji*quᵌފڨi'!FZ[#M)3 O )҃C@8Sc1zIgn]q%@35fcTs`HFv;s.eENŸ5=n͞aCff ;<-9NKSJh63hn .JH^_#% ƯS-$pª!sAc&I*b!l&Y}.,?gj4y%sY$uuY޷^nWcJoz*!z5*?*-jAjyk]P>!4 Ba}V2 ;ơIVDPO?qVFݕ 9 +rxFʫO,E,M} uQC US|&⣨묉O4,|hl T=a, 懱r4r ?gv.=(˟OaU|4bػ Hs-Q D?\ޥr |yNO;LB.-3-+d`ɼgKjpV d-kj-ᘲr1Fj}z.q61dw2:Ϝcp+Qb=:tog'A3z$Ϭ XCL^1MB!빦?Jwy?* `vA46?J_lfp}X5迎ѣFu.`/Xߊ?:el367߈?Fu -3h3͠1ȿ_ Ql`:|#1w\f.75{uoĢƾ-.Kc2۬aFQkgS0Lƾ=mp39ߣJt͍Mv)ֻM]Seq(eݥ=!=dbgFݝO4i!>to-q s01#҉C^ʩ֔ s9p8n'·H5+8K'|->V2,e/KlBjz45EÖA|O5z榈95 #?5'r!LNeu~ [W~wS{e2wէѶnb}V_E~ŋRᙏ3Γr境adۀv/qt#G+y72߆M 9Ef=B֜>c*_#R!Y0=Í|ӈ.՜B7tަbs}nVgj˗ڝ0jxz\6 LwMRg:M#DۂD'~-pj$a`5zE2VśFR@W۪(i.b L[9Ў^.Ҿ"`'Ⱦ/9mY.N0XK%o|6nKڃ=X q[o*98StEDW0SlÜTKo7r+uS1sϠ菝Iepp_kt6+M)${`S*9cld5%UW' KҺ@UŔ?!P5E<܍l*caT.\t*~XULKڮrEq5%7ٵҼa'sv씥G VQߠj5oJd%O|1[h9 Dz\4QTY򌫬+w 3TʸTIV}c؈l9V"/hubkޗq cn (Ҏ_"JtU A0(:u=.Q}>ꪏ|U(XBX]J] >]ua7/mgf`L?!֔2 v1R/Gi0fx苊uEGҳ!ώw?T؀#I٫7uMM !l`z{4J@OnA={'դOLVG'T~0_;^oWc BN$A2jT '/kݯUnNA>uZvK\sZ $ӧ^q RSzY=KZg?I]ŀIH>r:Q"j! ֎.U.ʠcFt&a 2d|qV.+cPu4>H+6V1c롵1ln|}h$Pa"hܾi?`j߿}k@fēa4@?tfMNyЊ#+u5;)n!Ge [qWE87ƕ@ }Lܷ"+bËR7\-FނQmopk{SD$$nE;5 R 3Dqs"RlE  DHS(lj+SR zyQdQAGuN~`vI䯹A(<ӎ^Ub*m.0G~dPe m#QxT6`eCMa/$[?-R."7x0-a'Mt339X[ZZk8&ʆ,oZ!ى/ݨFNwHcMJfw+n]4{c̵CB`=_NR1_!O@e yZ bT/;2ϛ *"ƣ~45:~di@ GlJ@ս/Α+, Vs<U=,l XkN1V~ t؏1-]?3Т=]Z>!+N,>IRuon'Djb60 mMOMlzpSe B-,|`Ӊ!vY(/jLwA3=;\|kP6 yiUT 񎝱= hY qGUNasqAâ- i^QAzuz [VFrFDhk{䫠6Us`PF5e')ƹ rd2PvAp=B)`{]'i!<"ei(Ţt !kF((qΏYэM{DN.΂K좝lXn@Bu1R*ـ_ 0oDuwZbi!㶥~QoǠ\jŏ 2vJlgE4֬4׷ a@kׇoVES:0ierbBPq^V ͉4_BS^m崲4u2!{(3^_+bd-[5*0B"I]>#y1ܻ) Ę}b0UHUl 54s֒ٲѼ’[斊ZCuSt=78(Hr1N] ZCIޛ6r:$$x%AՌOgոVF;ڑH dnY:vF[S[Bp+t,lK+D5vvh&X81</bzqK'jo@#kw ຂM;OP 9K qd\3@y%ZB״%ק멙ur0Ȑ0p3A톭;P!*ejB6RDå7n(/œfZoxkWJ[˾YZGE)?Zh+11LOղ`R9@WJ[{e wRY,!F!sn tvdw1U:gLzcJsCС@B¥(ƣdo&֍8HN(t0b:mmtMoc ygVM;2O FX?8 7~>n~?Z;H˜\89Tj6{E@P?Kr-|$0 I.@Q\'aX& vgj3BJkm:aM(Y9XH`וumuWZM-C pA *ʫ絆 Ǯ Hmc@~hnez~25BH/e ~Ts8B CIBԀ̊QM[G0[pXo $2  k?ّFE}m(5 e.dYL46aX|%b8MJ@IYzHEN#爵wiHHE)f̈́1pn6Ut"{$MNKT4/N,qY"7 :"Qу \~u~K1FPu$8 y p2nK!b٩Oz5p%kW0WVqڞdl`16 Ձb] 1pt1c!8!1dAhaf懗OeItQk>4=gBl;틞}B$őUB-Lթ?XF}mh&+5$'.`ţWW"}עHO: I>#Puv{Nvt(| Ywā^Cp\ژ^5wi~=^fI:^FiOglLf5<,m5,T,R.)䳬Ó%{?MoL{geyo>.=1I:\^=~|GOIAo}"_|! bt? W6`uOĀ&r-R ?Tyٮ^epSE 8ׂAr5H~:d߯ի!Sghr. )ISA"}LOuAfL_U 3Я*UP Y哬m\X,b"K;st495:ɚđpWK#8S1JWNi0۠P@"DJ& UC<|~fG5QfĢ )Pd$'k"[b{5@X<y} :퐴??K7xQۃN1)E?T &>C;Hfa7vА 6Q\#"y v Eb_g:Uyƕ͈#~Dޟnף?g/F6PԃVz'POom`3|*dv0X,7.Aj;))=UĜ)!Qw²V:bl2XGoly!l^yVQbwTw@x/ÂQS9A"%HܲpO뛠@IO:"aWpWkvRa׭56}VߡSb$Ԧ |Ȍuiq{fU&*_ͲQ~Bjkc.Rk Yۚw:k/VZ˓FG1 ^"TM,ꠓ?*{F-r'IvN^AX:vP )Oe =,oz }Iѫ~|,1pRut_}N[@hp a0-!׸mN!ڒ"Fbyunjw@ qh;V~MfX9j%Fo0(*%9zЊ)HF"EzjV1T3U]w q`u葍+=EHjw%p*trJt[>rP,QTvdRSR5YeYa|28*7zq=׀ιQǟdp'Y)>OZ> ;\cjg吼d"R=\WFӼɩXpDeUг@K= 8n2 H҃urN"bW ׇ7~pA*<*C<W;!77M&7ʙzNu@V oʢbٜLY];{Ѩ^C&ڦK-[#so2!?:C<F+^_,SWT\BLJdl6j]v;?>39G?3 aرC⯜oi\;+z5jۆ,^bNYÏfPVVebA>vhmKI*}nb>7$koԶ( 눁[ڏ>ϢlL_MbmvU XͦbOst* Y]%+.vh]\}WQ,PsY9#fPŔLU bD**ҎEd>#(9]x>-˷UE(IT.e44AJ@&7e1*6rBX% E0/x?R/je#)eϐZthn Yy0rRzYԠiyEV->- 9X\ a|Y~q>s׻h$~ mҵm\F fGsLϺq-ڟV:(J `^Mk{U ˊ"/Q Mc)bIYS4ؐg 8c+⢃|/58G?ghCw4n!6CԂS=˥iE xi7s]F/^2.n^Ax׽vL,s0- srpls}) \ۈ|hl(v餢A-yVB+E@Ǟ[RiW Aj򾜂Tc\2].IVco&fɹt]O%96#̩;A'̺PK2a(fR> +HhDIJD6ŭqq4b>#ŮT02jnv֘Σsp E貜F"!kwZ{k۱W#雐CȤPB'4h IYFx$\1#2 R,`ˌ% L*VlntcL mɨ`qk9pp{\h:]u#>&\8S>2#`˴yRB{ج;OjIMTi8d;[ Q o)DIk9@1uVF$/wD]5>/| UjG¡B6 cW]:,oE'hd@+65^ojQJuI{0wjKunc3v 8+ԇ,(miNgpiAV8dRƥ[% w ѶNcُ /9&kn 9zq>W-^aߗz\!WBw| k.I|I6)oܩpJՎV+x;=_e~k5,~ƵS{N^.Iy_41#z?Bw ۥ fc7ƙS{bۺxEqѕhP4 ;@n̥\yӈ_>MA5<ԋ`ؾEP J}KUfr1v*kRVN#RⓚQUMj6'_om':w Tn龆E5uLm 0@Ou$ \Ak zqZlA2փA|*a$mͪ~s,j@tj@Ve1-Yu[6D W%X 5-te,H*n*&o@FP۸sW{ٝM"&nBzyʢ6_[BȿqN8{POW"MC[}P ,!xłRlx2ڠIb$BcCķ_"b-WF&$=jWw]([kZ*,xtZ-n7ZسYakd >ݸyk\* vk˪FUڛ֗k!c&lY{,|]h"ʏs g%o7g+e3i>1S+Vt߂Q}ih_{\bS7~rW7b׈XS?i8O(V`1z֮!e4#Y9ډJo6qz[mC4=XwuҲ]c qŦjE@SL#S$2db+Rҗ0\AWSW#3 drdL|Gu]CḌ.6P$vcd=*O)Hٛb(A/"eUίy6Pu̸UK5ηj ;դ˴Tܠyvhń_c=S۔0s8)B{)GقMedttYBc{L4ʦ*|]5>?T`<'rNfNƆ_ Mӆok]Q,k-"p:SR8IY-m&rR7DwmFKG~YjAV Ӏ@H8>K{dyؽ*+CS@&>8zrM9jbX:Nq/Hcf80/P7*aL6aBm[zNg0jgؐC¦wvb잌pSp *IuVRd"pAV{׀6 W^>; t9Tz 1=_˂B0bKxÏ0 wFb_unxmp:OM#P[TտKb_p/;:dXrʛhuhCXHUvj`{]8McipF;,H8#i.Vyad|uZkNbh,_tI#^:Z@߹7:#\i6V: Q;9WC(勶Gz`\͠2dA19/^+ 1JW?󬂐.9(?8qFߚ qΑ(0#OfcJg]O^ri4pz\;ɦvW;UijH'RM,䠆2]lۈ%QtuLEikC|%v7:=-"<ӸKYv70: *^U8~,EZgf(Y%e>Nt!'70-0M * q3.Pn6t6@.NI1jx0Rnx$`rWzAg23;oEX?FT`!YoȗNGGCI{㨪SЈ \W`n$[Hn{f11]c` P )ƮIz_q; pv#,yJzb?":P0`tn=1| B ]IqۃV:ԦڇOԂoj' Ped@$/Q:'.:+j pdj6=kp>Ɍ%ǿtSwyaCaj?;V(t/2+4/UݟE1?˼p"<$SکkXEѦ3av,MhۖU98N/1-O<,&ШZprwZEq*CL& 5xӉeNj%l=QV?Rݤy5S6/*᭽iY!&ӁS^ĸ(?R؛Kck kw\y@]Ѣ| ͘ݱ@]Y5.l͍-NNe uMiò*O5Hb[-khܑG>avs96_i_l*4Ѓ.I{&B[?F vXM5żfP.5&6\&j=,/Gl[5o(Λcˠ5b~ewBъPC,sR@9  wP}6K6kwZXpO.8rF ҵ`~)&Y*v]?̀lbNן57@`wXK?AfGN8x q.EfgHQ9&r ݆B/D]H,ohda'li/I6mP9GPF  i3Zg鬶!ɂAq- yc&e: Sur^ǘ4K+4(o oT; $;=t^ Zy:VlNs {M2 !vX`eX !GF%H'[ė81'Ʊ-e`#--xLb1!n`3! ;$Rexq_(ȭ|dߪfmھ%\- xDK |ĵ W Iv͌}L:L̵ltl諗>nIHdȫ)`<zqΐF:m_2+Bj#]&r W~(_{\_Z3O@\d"y:a7$lObp(}6~퉾3nKxJ7~..%B*8bEYR-ߤ%0]$"qj.NI⊹>וMbtr Ǵ,ڃhjQ}CTlDЪlNPQְOKِUW]QPgMY%FU#YzjBIh Y:]~\̖WfT2e榉 Y|~Pgrx}YEC3!;묺&Y_8Yggbƥx;kwYf!UXvҥy;⿝hsNtxq'}N=MwwŠ]uk:9uW:̺n]~UckG`v{wÎ&a.kwٷ͆N^QVu̹j ۾m[kw۷ֻܻǣٲn=H p_\'Ks>5Z!dRx|cY<;""Daee۞`^1ˡ!;F5B# rq!Dx-ĽLJ}#A|鄃86acR=ğLNs:Vd;@2k3Cy,5Xz J#8m=aK bs^q;#ؐuEx<o1ݍA0MxE<mmК pgWchls@p;Hİ"Hbk 'B.TdGK h;r>ʵi\O7ڰleCn]S.ma7ڲ*hC^6P k MwDl7[1o&tbE^b\[qw_OO}~䇿o?h_?LryX|ӭã7? %80!,8V7_sЯĘtnUOJhzF/x9޿&NZkw8j#'iQ^חY8UcnO=?1q­vjI~Ν~[eEGD`_w?UQ>vuYبP 8 u`?/kµ4|Ba|2dH/lK <+A>-8'ݙcOI(ɗ1b&X,HilS3_5S &Ura .ݠ)f#e?Rqm"8d<6oaL5 .KcjVU$^&TzV֟{X޺Q=ZQxV@Ʒ뽱t{W5/?!鎠|q &~N;(|(qtW5~ ᫯ ~~~t?-~c ~?V+D'|ß~?G#vu = FFɟS|L^{GGѮ^Ɵ/~k}=dq8Ca|߯/|34C!Wd/+ş=1~gM??D>D""""nņp!ߏ[IV5 ??BN`^)ؔ?`oWxS򶕳yUg ܪT`<΂e(ǯ6"n-omYeO_kZLgB̗^0:/P8`KMba;: R#<|NߧHG_m)SGin_jI:vӯS/qxNL)!.Uf©B}1`G{vv$"7!I%hB'=GRt3!)ʚ!F-cW.ӥsG/7 | 9 `'_Nv_yɑҷf ZE6r.s|iLxUf>kH4D+QV ,Qb7w{O^=?7rgļxVĚ_@f c KBj Xd'vt79ݺCscEDWfd3ԢOI^ehj&ch/ktR2ƆFT5Flƺ>eAAZ=)1<6 č,q A7Qf؎`\.h><%HY 8-U5|'h7?hj&BU)ɷYv4$Im̵z>8vx|#@PVd:MSxkŁxNT}8# ē\cJE'٬AO(Pѕچ::%SRR%{ =ww'[=Ĕ&d/y8,*C]Ls9 x[0r"ږGPYnQ. :?[!; G @"{ }H()PPP]˓O^T`9ez>[@5. =L@Q :pD.xXvhWu~$^6rs^)(+yIz(bE_7u!=ܮ79t\uӷCRtmeK,SqSo]Kk  9WSu^ʴ{b-b9YcM"6hQoDDMQ􋹺}IID pcN-֤:Jw&+f-b3;γDHǠPLBGH˽*K?o3s&< rr%~.`&a[\9?'ߋ|;ƼdRȨnz FUi9?Cj0(- 2NiDx@~q*+|HY0Y^{OL!3**4I{ܘOt3ϸ2vLla7N QFsc,Jg& mD6s0*/>'SB~\ܲhV ,}N"e! c] kmH0hƼ)9d{kxtҘ jN3J'ȦRQÐCqhgt'M)F)<HAy:d;i- otYb. S=fʂkMji, &^*aY.TFƈ\L6Nޥڳ@-jZVs=P mU[,B;'=DGuQ.'B ,' GDypPPA$F >)v9pbM6%mV[ yA@1$~J96ͯuW=g2/)`486ȓ S OVd[_\┍Rtrl^ r7TfI?hl>m93y&lȋ ϊuQ )L3i| >V` Ak m6M,r=&l|Ͳ8r"êjKTwXGxv wsY:Zmi/RjC͸I1Y 񘎊VlISd=P~;Y|jprf+2GI5 xiD T,ޞ.m\Ujm,j}l*gS-;IABJ`uǘq3ٖI6 Y[S6K-d~014 ŽFQt2yw=sT 1^A:Ҿ @y@ ݳRg >y"n&Wջ^:7Cb^;OEˢIS h8uӬǂ˫H-HS ͣIY-B]m-Chʨc!`MWGSWopCnXyB<Ļ; ||,9|r (W ; LZȷ>0(i>O{7!x9[AܢE5! -Cvc܁2^(  O7 vTptkݕ{Iq{R3G!50uBVPЮ66# 6)AJh?% #+'I.:j(h+?5<>)p?^A /l`#f%>0CG6P3U#eNQHVP}J2ܝ'RяqK[Ù2 k8%Jꇽ=nFIN-玺SgmQ*8mx="܉Fb10 &ƷX"Ggroi@&/%{W5(a$Y 5ݽ-ZbUvaVn mn K`c}YܛH&ڿ>=wr;xCY Yб l؍{raG%nK]Cy2lҸV5]MwCZXTbe%>$Ѳmj }j=įnu_jkܴ`_r+VLKWB\:ܯM=VZ)>Q$y*B=6F>۫Ձ)>le#Iƶ~P]m).J>蒝Mp_[#Fgp&0O [Zϸln'*"8[OPoj]ɲ"ܜl m&fQKNyiawGa򺉾e0]|by\}\sNb3ڶl^V+Chk=Ģ}Ng*nrH7H1gHj;;]!2GU $tlJ~[  lO5N͜`G&%!.( 6Q;1EYۖd*'K!&B o {ޚqLfq|m++nĤLWEe@oF)'gxlvvx`azfFNgh lvtaV$4FGȭi_oT#!X+TR.| 5pȊ4VXf/y4eԘdw^D.F2d23Ӯ33_Y5Iͧnns"fU[<'e60MJ/v/jҴꡩYycg\?EgYZuv0:4œyZTKH[ܻHð44,YkXFg,3 '\w,&D<&B6O +L No-!(sǤ&ZM3F'|Mg4A{j`VU{9 Hȁ EƼZP*8:HUE.Ĥ}Z r~'=^ܞW? jeau{8aQ>>Ͽ?r@#%1Bܮm#I|pwB"Bf X{)m5V tu r7 gOҜ[,P _Ly;)兀1D()ʬ++ ?,&5rpoeî[ cY_8` z/ x>61a{W3xիpO5KG6mϷ~Ѐv T'+AμXyO >o 3qy-, W'@\(bC11!$=H.T'XN& <V-X)xEhc &LbeTxC6ض=-QhRyQV_ HFOF9Y`^m7马('yV 7VN<(ٌ-RUsl]zZ XlM42xmU[TmtIufmՓ;,"E7(j S"51*?`N:ErR">*IdçAue]lpTIUq<3ecmM4WaܛӫjV{"vtg!qXr,w(d"E)c^EHx"Ey>`GDH;cm$@WPtyErO&ʆBt3*q/ȁ5pG\ēy"  F꼁x &SHyΈ)Vh J{{ Cz~}7bL^At4-mH%\ ֚b#:pJxT !g3<M^΁7]?Ѓإk~h?jGXv=#2 ƩI[WSkGVQnܸhgxR+fs{fTHs73. }ZwCFxA3:󈮯C9fTЇ"bvt5&%Mq9,8CoJ-RuiS~"j~!5?oO-Q;7oV?s^kb]6O뜍y{au:Fo6p>M :[N4+Sh[#n$ேyEtGr^~nrQ@ƢѾ_+El\B;qYBLI@ţ$;O'Kkt6/c1 ղ <we6iwxIw8CAx^㽕X5偃!NM)#(;AlqqHVx^=ko$Μi6FhV(jb61i*G!: z>ڟ.=6Nӯ R7 RY=|yee24#ޢxXk8ɊŅxr,2,:&Šr^Z.5v`.n `6)J MWBNcdҹ%I %);;D6qECZ L M-\Pa Tpg|9I &&rWIJA[%h\Q0_Crp Rfphz1[j,2x0^l#B~(8Mbb 9p`jK xCrŸU3,ho =xeABs|Zt"Bke5FQI\m NwSWUѐmqO9oX[^Q.<"غV sY˖|. X#+S6E0l #INI@wuiZT~nX 18@ ⫼S AܼPFKw/^q}᪼H,ds@ #y* nY Ԩ`L2PAaN\WYO*|tcQȂˣQRO}Mg1rwWP+3v+qbu xUQt{ރty~0 QtaKZJG*bu>1F~.I3̓n{{%#Amߥ9sc9~gvLk[1=sLoq>"dWsc+q>8w8_Ȗl9evz8*I2-ܰ`47K35Pr+@b*/~)V*G0n)#2)KK~JQtjzn5aM*jeXY]%a1 %g$Gٕڇ{0:& /!t #ņ?# 3,Tfr76 #'qB,]lz} $ń}s(a3v6l}_x w"IMB!chBYl0HEIW7 !2 Yd[UJW37\G`渰}mC:3Pc@UzFuk7S%NjfqO/zl P+B?܏-,pX۲n=dn+sN9'C/Ql.V]!r؉yIDQ9|3*FoK<dƴNt'.G/1U?^`(.%7f{o'$@]zJ+T#sRf!T>ˋq.VQ3k2S4X"}ٻ0;S:vjCuepE1Ց`m|fu0Q71!nt}-nͤ.,>}4"Xh" 2GRBu L(^Om#7fîIebgk GV] L,IF'/MW` RpRYwA(Y`ǷO܅0N 4BsuqR-fC@5,uMsU3хME,q4_))l-ݔ7+x1%]I1`Yca'[mbCuD΢](`OuJH FOkk&2H{@$yzo 3I ۪7`}"' >ML˙=ɣnaHJcy"9mXrz!R"CY\FAr^U6䒋rЋGvCp{lKBPEvb:BWN*UFuB[9UPլf258à/_7fh:V`{I~Qcg{NJ)!mRA"Zpqr 'đWjI> lqZ$\#lv_% o'U]f증mG7<pcr(#b5Cd>y4zkr2ָXU0 Up?~@S ǁY+9UM[PZk0nw&\/o9:Imıu}0拀GvN8*՜``H3/@j'[Cd宔9Pރ~ 3jѝ9ahaԚ'e7ҕ/+\HNe]-F B2+rg|T* *~3S T|gxkkm,JLtCvsKB܃Eu x`OB͆DAP$ ՜ְjyJQs?9#ؤ6 #(*+M}uT d*WU6+]GU4^b^]Ul:,ApfswUlb eXT&"_A.S/aV_|Q-z‘$R &*taCBdV `QdN><\Q-I弉$?]}C[L[򙴤:ҹ`jrz^wmC~;迦pnjb(ـɘli2#^K>#ȧB,zW`-YC5rC@fg0 Ko+ ,1 j;n{?LJі=SpaoYŴ^rh X͝l498oγ(;[4e"]#bl9:1R_`qY2ȶSbj 4C(eӌKoE)\Ȥ?{;@6 MhaWF $҈1zϳ}r>hpLn{zgəy#[t ͔SGƾʸaݓ<DWq|@z07d[I4Á$V(cx8 `WFFTb`!Ε榚L)&B7rLO]8'Y9.EMP\ƾ]9p޵W^ 1"K{8*30{`m3A0RCCt.+XŐ2VN˲\F)dρ `o*<P :yT+szSӬ0):ֵ juw׼ SO.z巁M@{W%n ~-ʁ[93h?Ɗo-zmb(Z dtsH ] vtzl5A0x B~@86Z1m:lċu[ ^?mkDt]ӗhN^:8KPKA4 ;org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.javaW]o}**$ ڸ)f+*I[WJږ˥.)R[~W6ŝ93sfvf4}ue]oY%1Lt^f;^;7w/^mq?V ӓգ&0#+x V,ݳX"} rsH\xxD4ZH^P˭~`V2L 26/)YE܊OA=HeFC!3U\BTAdLNp[A;He ҫ^ kO|Z6*娔hSkP\3Q⋎}zM1T)1'䄁aNǂc`\4 bo h2֝O#%ϓ4+t>"<1#K(CcDnt?!h(3w`A f[GF2U:& g6~!alX[$1(H: y2hJp91h ČL=&}D\"FPhLҿ74$ ǘ &ZsMk>e }Bp C` c1A[8>gӳ]_Rc#<;E%}ʝn6[m)6hWVL F]3DڠH{O]+`98 Tc7Pv9}Jf]U MB. ;Bxqꙹcu{ F9s gckIRWIAӅY^\4ݴ}yׂ??V1 )V 퓩M jʒmrNiViA:uڗGQHeOi ojhGo'ЖTgeBi,8}7/Vʱұ}Tf7Fg.U5E!ͅm!vqg( Z&z# On1ms v\Q:^CV[KڣD{9hKl`Dik' j*m~.7K9VzJ6ߦ`Iɗ0s"Bڴ'K\pU>OO[>7ilvڔ%xlIp8$8FaXEql^.ԘW}V)8q?9\hӗ++K$SA,'aƗT,M]MmL*Eqc {ssA*"LW!IK7/U60/ѰkwYt'PKA4dI-( 1org/codehaus/groovy/runtime/DefaultMethodKey.javaVaoH_1"T>HVw"mUc6al4*uc/xU7MzH w͛7/Ÿb! $[kQS0慶R/K@,+7x T׶Psm$)ya}Z a aeꅬ /i'S ;ݷ-,T^LY{@xK%V"Dž $MUYA ?ve!F:蔣im,hiEQჭl9Kn('-2i9QE$p@lUh;FO徨^cBze5\Aܫ%Q}ܹ4 Y)q#AȩQa3ۉ*F 4yhCϴRq 2{I *WGBY M8B;$m>YꂺFSgTMCQ`]6OM=XR,T˶JϚ^a!_bM3eFT\3\JBhל &53,Ԥ\姪6kd;.s?+*Ӿ skN'DW38nxw $?0yoFq> z<{q̒hOGF SHpx)1Od{ i!@"f̂rڭ=H,`fwA#ln:fȿ[+Lb6"(F2%)O')(mBKX|\0Jjy$]xDAp׽IxU 5˽\]_߿clo voRd_Člw^6GוA|yty]P,p2&2w2w'^ k9}sEiU3bxJ GiW=_w[B rUA{8ie^|GR^Js1jm!Ahzp }L! yB,)* 3i[@aZ%PRV3;KgeQUhȪflR:K(%TbLhpQ`&I՜p 9/Ǣմ`ziEMZQ'Keε(16l"e=ƀrםcݢȕ_./&UYxj%b8nE37Zql24_tGttv7FrڈB+Ql1Tac KX6/`VtgD6)8 8%5 oqA$D#e γ8I Ō7oR4KXb~M9; G DqS~3 bϕn XNg0SݺcEXX/YdrYA: ӧJy>;dH3N"<ԋ 3Ҵh2zXi>1T$A#lc.:fUpX;vEьt>L33q<"ڄ䚇,i:)H򈂖2;x$2G'0ol䌎#[%?>xp3a8εHѽ0#H~fb!bS~ɢjL@7Bބ!@D`c8G &"%m,)  .[D5 C~S72)$MJZY*q2H w#`I":/RF\$դo=x %X~M +w\Ry RCCd)$Nx EėHOɚ M<#&I!) uMdy"]Dy+O `a"LJ!i8 @ b}WA謿A#M`WS呮2/Y xP8USeɒg:(_bʉHeG"@6X%`.DLvI{9K_~LrTd=(B:We}(ϊw/ksj>Oι}g7i5>̙ s6St9!y?3 |DSs9gd f(FcJF N_ОZW CV6 .I,Het%q+EQIUw ,sˎNUd1 NW6W߸oٵmb͗pVđٗcX O3U6$)yG0l8." SkؠNI$RF>JD*℃gVHZ0Hn9!0,!l}K8)) upMk}uې_`Oque#OT_ݲTfA4,֡nM$ò+| alm2>E| 8WT<OdDInupz ]Pi*M*DłGm=㈳F!cuY V!G'Bh΋X1B=[bE[$ӠЖO'BNIE^]Ld)ji̘%{ kEb%'2hp`'e;տ-^0g5uJMŊQeHTuH.x&2 _;@jn0AD|/ Ӎ^Z/ S$oj0"ULʓv'R|LcX4+;ꇾg5o^k}vSwoe1>:ͥNrU wKu2U3۳mGҠzOM3opk͠rQ*{>1sſVC o^_`yӳԠu*{PA B- %\q&X(x<PK@4! ,org/codehaus/groovy/runtime/IntegerMath.javaMo0 e5N:c6`衽tq,P[2d*k׵}tj4va!A%(|PΙ#x?~%,EP:J0cR6F(pQ]L1sF5#dʔK7s笪6xC(/{R+BWdIG  :YlOpw 7T`quVy*a4焮^dSF I?Yn0-~`1I#rML48'ؚZ4yܞ\DD''b%,үEzy M [SUQ2UKp1ۊ[ւZ({7a| ‹Lmx3:>Oݵ7dIoyB{z0aD]ÛS'#tC7S_fSD#Y._o䇬D*߻|}PK@4=>%XI 3(org/codehaus/groovy/runtime/Invoker.java=w6? įSN{{I]Ŗ:OyL(RKRvl| N-_S03 `0ؿþa|& zWaݿ߃?xOG< .݊}41;c 4I))]#j@5ugS݋4I윣Q ;G'{;%> MG'T]h "=ĭ>1dl;#pqjT N:B0/'c(36%^ Qc 27d(vL2*_~pJҜQ_QSHt=1;Go,o0f|ۙ9ͩc.{w.PdL“Uʃ1`q&Oנ*;A!ȇM@\r23_?Zu wz~™ ;`́:0`\ #&Tϯ W07a 8i8]zt`EU.xooO4& JPUu+0P"@K̯M̑BoEgQO]LM) IH2*UKX(ʟ/.!U=A6=&JiD&{0'>>h8bϮ{y3AC[)Ϸ*P}2s t<#`WMK &Ō=1_Gm|T*;đWB_5uhh1, U6< M4I"v L[!XBżNfKSN(\h;W38TfT:2_W;4bTp C]n]ѕin hS:Ov hQRicf*sQy@t+(*Sk-mN$JkM3i5lCEW,h#_H:\qBe /X2 >j(`|ɮ뼲*ZξCa!~P$۷ߺ,b~_.6,""16xfdd _D'l`W4XqZLu>R($GwB?IYs?QPnF:nNu#9rt>؆ࢰ|Dk^}ckb>N /jn54*Ԙ41*~ Yl_ جƾe`v]󴓮3@1-؂A8ڌY ʹtӃ6u!wCXih{h-A~,pOjvoNޅ@gR1hwYE*0YtF]3st~& >%2M%r僔'ZIG02wۧ~f ѳL^mHe ߚ$;[?cFN/zu-v2O_Ke[5%Edj`o*ϡ>ewvMU%}NLCGr*O-Nb"~ۭZKi qGs7K'n/dLݦb+S3nĬts/=sM3%HWS>%ϓDL.m|쾐s#g|)y= bRP2a[KΫ'g9} de*‹ KbSwT2r\9׉#K&5w5/5.̧V_zіYYDX-_#. EYKjK\=q*Tsħ'!kCSFJp : үN Ag+ "FcسxD^G łycq-'Seq1d" f|F'M< `-vvh8SCc-8G]A?!gHbAewx{]Ƚv{c 6뇮'yurً AljVV-c?0ָ3o7gxv]Qz^,p;7mL./EMG"ǪC1>q⹷cq[5z}sbgf~.-6!%g:J{o td1t,E(9 oyq5 D?K5zo 퐕Dd\f??| f,;S\գrWi+iR<x\~Di/}Pxt` ?sMrz|!D3q cnNC/H%#Z'Kv1T{;{5u\\kqƣ^V }illP=:Xh4{4vhQܣ htNݯ<\b7`SniJ ]7+3܍fXmڂw;U'|CZՏɂ/C(cr3fDkF鯥FFem=l^=I5 !vWbxJ˸Ž#âwro mI NŹ*M57 yu55[eC[*{n0&nqoUk mzC 2`)y!-fH|2@YN6k=Y!W0Xv |=&|zi~HN}Ldb?:RgS؁bjH(6 4T@.ZPt{EjBnRa]&0GS1FBc|)I\2:3-A*2U(nr xxzxQtq]A+h3?D+Y%8q^-K*2Ԝ4+Q9Q`bV@4.hT+XgY"<ŗx}qREC b:2F+@k&&o{Kr"5A(_X5u*v"RОk'K {-j{2"zֈ!tQN%0q[͜B."fV3,qjMG#<\%/YP#رbFq u_Dk+I${MJtT)㯳4yUcOW,6ȡ챲T w!#?ñ'{2l>em4g(<@݄* !u˺pdOätJQzE _]ЊJS3~3HK =4nCO’Ea`&: 2ݶ B(B^ .MS:hPyxqXݹ BWsDb 5Bš4fe;ԥk,ۙOY! XnN7Cpb'5M ۹Aˑx]l*>ܻA< _eOŚ@zZ!f^M6\fnKNSؼ8ZߌV(q*䥰isIq~XHz=\|ed۽QEt_[D֟ϹTCm2{eܒT}6^g|>r{,a5X0{{Tj[@mgJoT(#V;c ̶`wTj[Qp&nPurpU^b d%{8@(BqA4y,Z"2xڟ_ ><9 8xЂ}巿sAQC㲈>K@8-FL>c/D [1cD.%OcRX-ɔ0+Ҫ*t0qnlĻ2iW%::*n襲ވ ǭ]闐wTv ϧT~|>[i D-gZϋ ?R 5Ϻt|6`ϣdZ0gehFf1y욳HtܵۥvUQ\R+&ڸX%q b(aR'8ʐTx.T 9mzC,1j#/2|f+FWEbW=z2BDP6mGьp΂6@84(KDz1hS ˤ^6K`Kt`b4*hxǚ|NunVJ#X'+Kr oB,9%Kk=*m}Xl5 x=B_(+"KjAU&:ߎ+ɕUƣϥ*=SS(obX5XR6/Vq}ڦƂ bs@|۔QdnV@^%Jϴxdځ97prCGG7\غGN+-u)//s_OQwhseyey.nmjWøwZ{&d9 1. y![юUvhZ`UsQ%eeC&Pݼ=@,.;`Tb׍lm:l;s)ԅ@.`im ڞ  `Zo\Kw!y/^@-.ʽWiפ!rY^YKXuvd\tY\rS؉N %YwRE̶Y{wpqnş_IGD ̏E ;p;um{ ,γ$iS\4XkEv8@xE| 4f x}Zxcܚ Tj掜,ݍ R3fh5*b]_{]qfq!cs?3}݌6tkfl1Y9\Ot8` G*M޽15ʴe z8'0|ݷ^wH56A#6lſj>f$%^"`l oazJǩdc>K nx^ylg񃈈-;˸wŽEn,߱`6zj(D, /3pAN7}XBVsgyAgvo02MVSC0˹׃ fnՕɹc>٭Ft p/rEmHxrS0pfdŒ:+rb]۟(E'KꡘareWD LD +j,E`<~MV`W#0A;?x4j _?2:@7ߎoy-wԅ$RU/bq19.N?~@ MW RRī5U?` C)E!2 ֥׍rdh%1 V]Y/ÁB~v6+p{@KٟS~@F << ͨqI .<;ߙ5x'G+Ʉ#|8 ݆Kz4 +ugvJH 9KC ʟ'Uu 46',I21~[9e#NYSIJ6&UWB}K39؜^vDDIu],j] =tŮemǑvۃz> 6,Tm4HȄNRj6f8 Twö́ȳ\?*CTE5{jJ9P/ȯJ2U8U!kX%l ?bc?Fj [B^NI1puN9^#0qꆴiZlQڜ/Tε(Etje Q̬?_oȲpZ4ܺtK:&PN̐0P݈|_I*1zU6E-C}k[Z\Rc u6StW Fܮ+EJPȍ$)ٳ!/9Eff/lO?i0ŃEﻈŭ̀\T'rA?FeRGהl|ǃ%L)5;R<:c%Y =5RQ* ikSkv>X{:TrܬhF T1X^ ! ǯ) }H2b ⸂B@ N P=%ejלMpy*,g 3qƟ*^ ?N!(J?m^sZĨ3ہ ȦuѧTR}/ g) ֞Ba:EdEbB6P^ $L}ߥ÷#XDrsd>WC^¿yzuҎ]:.U8JGyvmS xb:EG=Ns3)Uf$2-^d C#ƅI|dpwEGeA.|$ïj`PJss?}_b5PP Hɴ_b|ǯP(kn5 AA Cc-ȭ&M p@?#鴼t8C8MRZ`02Z-3OFF5aC/-Wo~r\Sj +Ȣ%7^Nh{ =B5a<,fuϛNH6%,|*o(ZMx6܉nr&F)mL.g*օN4[%7$"Mz%ڤV/ߗ:_CC9p)K@+~>3ۆ'!'9b+#Tj FQ#UL"DdZ%&Go57?%Fde{@P KN"Y^5u@Qˏ{JrO\32ɌkI(uv^,PAT;kk.r)4A/Eyf[kYl7.{,¾痐UX$!N)aA, fuBeFP!00/mL)t~~H3hi3Q$?ig@\.M\WL,d۠xqqY ߚyW[ CȐB;K.CF(KsJ`S9$0 5q robZ,S'.Ԣ8Jǥ2ZiW1?/I.=|v`^yFc8H8~hZcGꐇq#E~~(Gxf˂Y'C[2=?|,&2V |MGT-\lo-anF~;f6tve;ng#4;zma0כ e#\h(=qi[p-tVNs#ІsmX٣ٽrz]2@p!|eOۄ@e5+7,)k8SK֪*+&SQfWԫE-2Hh]H3VTp^f_\ [AȿMZEw͌)L1>f@k;}Y <=JFzR\s:s`g.[Ixkb<vx;Wu֊7F_E(t pK]Y\ќ&MuaqN= ,!1 ]tع7G|g-^iJmn:Gc^R)xGBx{Q"]|V(~/>l6jhM CnX^lgDld'nKmJc 0^ 8=F<| Tl H:'W96qkyƳg aЦj_dCm>a+$ڻu+[Exs3$@3H%/7T='(6嘳E3K=/^if"-o4'AȒbCRW؛8@hl:?j }0f ѲF,C_Ҕ?yaf7@lPQpǝ & Z L+sLH6_ <2髝ʠH܏N*.l%#kI21/?;8.k(n[|kcv*Q(vX42VǶ6K@5\ȑR17Ubߓxx?X{Xz]n=YXoQ@*v z2ib=gqlauT+Bk: ˹bVr&fcWǶ/ -a\` ͋ 㝴{(PgŸ|w).'>Q28u[խ"{XYoJUMޥL|?{〙E/r5 /xf4E+s{8"/tn2(g~6^mf 5^\K1^^ɋ9$ [^j8}sP`UchD'tW4FUCLJyA-ON.>Ob!ȱINVMyKMPٲ$W!2#PK@413p ;org/codehaus/groovy/runtime/InvokerInvocationException.javaVko6_qaxrڬ+>VfbIr|+-ѶVY4(i0+:3&=+R x#^lW"Lk"7f%ouU ՛"j$uCgCyrU+j%EJ$jNaJj<$RL]`2Jgpu)I-Ze%jQ=-(Kd)*ײڭh:CVHi*Y#Cm#: FmA=Q៤sKJTf&YkY@-UuY Lr!^ZED.=C"/!a0pw.#_=gyVIzgi j\mSД;uGP9Eڔ56>"Ŗ(h:4fSOdmW.Ř.dZjF\)EH6 ZU F2v\R6Te>&TFگ.MZ<&"V*„ȴ $@KO|*Byq]`ଢHXBfa4~ݦ{jWG2x|ȆԿ"A0d#oÏCޟA9! >MCEBcc΢q0 !81LjkpS_|]߈dږKe@6_=,m 'e@~ds' s N/a:o49shQ87!s{pqK &޺cB~/1/䲭 'qk=PKA4e )org/codehaus/groovy/runtime/LongMath.javao0ǟ^@iY O ! xDr[bؑcNۅ6ے~|LFB1)(xyϧbIPR fĔQ\]Grd>K¹cTgDg TD3)Jgubt&\h\!|a11g('eu^iIY׼ AF.էwLA n=|[RkpkV0 q)/xya#lBmB'Yr]Fp8䁅4xO6L7Ü_*│,M87\_u'l}HYNovPP TQE2bwŇT> 7Rk«aYpzblWMkl񕴦?iе7 04-(1AI>x"ӣ:z|?*'s?֙c< uPKA4sC0org/codehaus/groovy/runtime/MetaClassHelper.java=ks7_CBZ4%XweɲRMR R gx3Cr~ݍ9JWEFwh4=;GXޔfOvwWq#KUEq:yŧlOy Ȓ!UZhBOXErfb4eҜM2K|uZ_P?a*auh_3"Kj4~.ztgz£djs|tc@Z6)xU*-,Irf5+JKeuH_i!Y}LӪ.UmLkIzǞ/Gg?rS=;|{ zN~e}tb8p %RhM>%֝rn0+JՒOY:*s6/xElEZVd"ytw<V_",`hRLEF(nF*+ʚ0+U ק|.$Pc^'6(\%䳌OAY&7C@]&uQ:ʯ G``ƻ=K9}*6xb ﻲPHtdcd£sNQc g|C;:Wьk\_ g *5~AT#WŒPI '/p˅mܗbp%c"@l!~dQaVE*U|+y*MB43oT%-ldˤU,j삋͒HkHyl1V;#ՄjZ!CGv]bLǻ, C.x.SKxV?EtF}V0Xb.~+6w|Z̤^=VA܍H"OE&B+DkGD+Ҫvi& +u-DmޕNnG(Ƃo2C:vE*q0 {qǁU;~i' } yHi̚k:6TΨGvTuJԋZb{5AmkW\t}F@I)eJ} sst-:r*;Ƅ>"I+ݜВ6}|-RDCBWZd rM R6n5]ք"I`s#4L]B}BZd`#:duŧMmwu<=ê.΋œYEZ-jn <:* FFXWvܬQ-fUSk#\0(6+mef?mjut_ZA$":LjrYƆf%H斲%6k9txۡ.:]]; 8Y2Xd?|K{&ɁM}gLU Zc FߐtW5h(Iɩsx~0FPL|1(֛Gx/|fGm>f`1J=O ꣰3e{<#8bK̇a NO!4/4< =hqǏ>o928!Qfq!Xk5H4cŬ5EQT"K/㒆C$06!8wf[k}Ha\/EgT(@D0(VK(i'Ǟl\.o!E(wY1(`V2 * z}c+Q:vw AU6OQ7?[LH0GS'P5`ur ڒ s2ĢQ<)h>;uZib¾\,GX%|j=K@ȢRAw,EdǪ(ɑER58$Ƣz.Z-1VqW '3c5fj0f-BDv B 84*1oע[!7{'@! LT~@f`OY\0:RKBI=J NRfUcfa+Wr^]ۥҾvϜYdewAۗb 4GLvmVUab1 I DhjR% MVR4"KP+p&| ,v\j"S#ٷ Q :an `jPoL{)Y믱t缌I"md0'&tK053lz`NN* ;Uοƫԏ1t<C+'um.Mץ,@lBȘ< G<:ämgH! xނNS-'!l-糅*a bJ(EC5d z: ? !bx?-L󎨈.-G&!d{2.3P;v KV!bS_2y !הv=Gko0O),xL8buP>0Q5ê;%,C)?1U&PD3DK[NX0F ĉFnr>rWqeՈ!l!"4eyt1׶{Xո)ɥ+7`?_ zi1Mat|(+x%l?em֞dx'jҭ/k t괆5QWYxHUtPx:BBÑnWx6FaI 59qD8w8v y*d :^!\!@~MD ;zD q oE+zbͨ}%Nc~%j;kFlF d!x<>n4uMmo k>x"Òlu CPj# &iص!MLlGﮃ(7g0t0[^+3Tɂ o< g)_hh1C>y!AjCF |fdtBbTB7pr= 5AGw&h3}߭MhzT{RPH8IHDlSK C'ďl"RM&!W cNn{9E]4FDTQ&uLޖyLkj(s/$"*ׅQ@xgEnx#W= uV L PEx[ZM=#V7InAбHJ;6(5KQ)@QKrzv3I,8"wАU3J&{2n:3%lzd Z$Ca7n$cm͠j~,IB2,hET.?)^%v!FM*P' wE]!/ 4it\$S?wE02TNBnُ$2SCnY1SQܧJWG'/߻PSe]@:4U㖤J[8tsq`}%,3LXL='Oޘ\r9"wR1TfR Ж 679D<߹emEgb'lwkk˽ TǓ$m1k(Pe"QcZDǾkG7ԏ77B ٨=*R:ї/ւ 5=jưk-%(nI*yPQh!1tu9 No`87=(_`uֱyq|MF r]_#/sۗlbA#tk.1ҡ X|W f$m)9$ua;0ɜLaL! 랂`<lަsTSeW0CBGqG֪ʾ[Xر]mU-r9^3WJ !ec㆕i*xu{T,x/d)a۳_߆P]1́ >f&i1|Zn;`WWgLhشB=l%wL_AF;n({MmFP3iA{7{i#24@X➱@a}έ<)""u,qp)HNZBWMsqAugk! Ed4u @fOUʕ٩)_{@5_Aq@~ ؾvK#n:/`\n]yӨ.7.2 >E8$'%uRdSJ\{ VWћ%GՕXޘn[-jвwOXYy!3Gxg.Ly1og?y5wS܊2fW]bmM ^]ޠ)kǶhX|^ Ő5v=B։35ӆwUc1 +Yݫ[->VrQg+b3pѡm; ^r˳C/z,%}Eu(u>^:bQC$:xʲioWLi)-.|Ayn12}i$)nYהԛi-1\]dۢ^FeLˌ7@adzZ"~3kB7t-W/9'E͟rj N9h*r*ww @NÛ8s#x2I-S'!Vѓ<謑dolnir;X2O0d{HG>Y\+.&X^QI*>ZpWbsIs9Pr؃`tQ;|cnu8 < !x=IfsGZ7j\(Z։\I460g&}T4zEug*EY"d ҙ~hg%j>\C)I]q*:!X8 J{ }4F6nR8" DK*5y"&Ii\ FB$E,K#jhƜRFoX.ޖeQ_Ŕ'3p8h3jXqMJ+ˆ8pk ~"!!ժ+kBBt#{g.h38wg8+V 6 d`Tߝ+ ⭱5 B+x-[Aša%4Jv=d衿ot0֚e')uZ e D>ziж t5m>0бEh⧭{h׋HNvv:~7!CqA}3B"¿CGrѱq@@: IJa,&e?w\!_I8kU?{7%*=|7ʷ3/Ǽ=Ws;]ϟ[[kVF_igЧcM7 ×ӊ2S{[OoU<$a6'M̛U,Ӹ6nލ%]xQ66F?'Y:a5\FnOՔ+>r`87k#oG8"\r(bx?T zv۫՚ Řet%%ґMpYR@fspdbxCKV_ᔴ *ɢ'[)} { 0 < ς5Wh@LeTQ-Z-R9k܊EtH5'm42r\ВS[17X;;Kÿ؍ǻ$rn ̓{O|Cj#D r,'Y; TE?6P E;7.Fg|&Q0bT.E 3&Uţm͏Ճ$cHsp$D 6Q*ҩsw}݁:W@2)>yn"{ M5 Y kINiq|ccY.eы.WtV&(40 { 2tN[4~ -mFc*R+!^ۡ0Il209 hir،7ٯ'Pnb D*?ƹqJF]g߰ž7p'w)آ^'2^bJL>wmӏmKI#IOhƷ1]ԛAK(Ź\_`zh]kͲwW= ۧKC< 0HDH3:ya 7\xa1[yqSi[.,*my8芗7ؔx^W|4j",/]AlO)v~ӷQTO)r~,bbCcV7`nRvޒv-οZ\Hm-#ċjߔ*>щ]93_SKl7|"xWZs `ּ8B1^/Yg/f7Zxwr27'-Э&ۗPKA4t.org/codehaus/groovy/runtime/MethodClosure.javaUQO0~ϯ8UJuۤb{C<5qqve9qBZ4i/{%D;wwkɓG!hDʲh]NH6VLr1Kc_:n9XL*#ܚ]% Z;-%=nFBbUVBMĹԶ2>d2`wXEh\^(9Pْ*<"!!P~qG8׋Qtl 6bRh,SF/ߜI 5859'8Z38ep@֓R$ Z-Og*F*I,䊠7q +iO 1CX":q5.y/y)g@<^^ȩ`8YUq] 47[nH6Gѭ6ϛl RD'ݦDBixeUF<6-J~mf`YRBQ7yLJITh7XBܺ1Qqiޯ|$Y<!lz5KC=οܫMVu?"}_忩r7ofR;+*I(pmӮs)MVG͌7P`cjS,!mEu1~ua?LWyԂ:~e YJO30u] 6/PK@4Ғ -org/codehaus/groovy/runtime/MethodHelper.javaVo6kxr~t4Ee9ؒ'JIDjeѠhg}w8 Pl $Żw=IN=8E&.u1RZK8;읟.}+|mRXñAO\,ɕj@#e]@`?.KcU %5F*|JTQbrn7=,h>J܄lҪ oV<89NKmܷXX颜Ui hm,Ta=i񟂹*X u]ո}|uCt1”7,k|34X)-sAȪDI@p] #/޲¤YYKj dRzm+TH@r^r %_-epI4B#L ]7z ] FQ+LQ ) .1ҶJF ,slY֦1uM4 "!.Rnhn^mbd-2ן}6 އ?`O{* *ȂB͑뵒(AZ(C[? ۛ< 2B$,PfMu?;~!b:D| O8 ldh?4,/w\=3$]FP~0'aL[66'"a QF#D6)Om%wHXbJt_mU1ke>~[Гq%UUex4ͫӃ k#ůxxh ّPS\4p {|96ߘNt>9Op:nMIm _PKA4?*org/codehaus/groovy/runtime/MethodKey.javaXasHίs6pqvkL!d[{XIJniŒp+ J!~3>j|-ٿO=QOG.3'c]p&h6t&W]@XvJ^kjjN0ApL^XtM]oLgl _qy;Ms0aV@1VOmˡmַnj̱yA fƚyF2`pCr|X߇kfE## R۸|GLfq'vof!PNtȔ.Ѕk{Df$.|d &VϠ,L쫑seO,v]q|s|pJ70wçoV]Wp.~pt!X SϺ>_^k;><"S؈VT@Snl;Sga/ RJG\_-Nd }o~L_Cd c&@"]FT_H`n$JzBm\o(-䋋ʼn矩aŦ7<r#ɻElP: obZЋb!2 j~npaUbMl| iD: Շ&C @,|Q q͓rW{xREv,M,rb vʬ0rW M&N睶ׯ浫{ȏG~v\a{W!3Ð/Xi9"f. ^T3MA h}qd憒o'x|ʇf"_!G?Pf4>g,Vnkrڿp@T Y.1%u)PKO3::ra ZF}|+3Sq]xr:{cϿPC9+ڡ(J5/5p*g~ysp*yWQx MtJcx,ܻ+/jM*yt,Mg+e\j6qij=åa P YĿtvsW`H%e=:[kN^G5W"4!q^sщ~xW^J_9LKzsOy:+/DA#ݟZO/KԠ&~'/u`|φX,t w|uk%Rqoڹ7YoM?)eWHPKA4񔎾6org/codehaus/groovy/runtime/NewInstanceMetaMethod.javaWaFkUa}XکU' oRd-4H@H^BB^+/xyQ<Y ,֢^_۹~yo߽f*=Wb8G-:KvyG-~ YPXjEN"O&47TR[dgTP 2j@&iQt*SU9 IjJ<-Pr#4 (TR&xy)؋qZamzyզMZIiWJZ$n-^%C-Z ʹ(d2I*OR+BlNLP+K8%0]%iȝx PJ^pN 2ePLWge}I EBzcX"Wz>*D<ה!OA#3.戵G[Nl¢$)2;ovQ Ty(B2˙VjRSH.0R$Di.͸ UJR- C1Qy4Zܮdu)Wȫ) }Uaݟ5m2՞%#Tշjrl!4ce0K+Vrhwbb 64|D#P53lԬ\*ޢ la8K )MMzC\v:U4)TѣRGOvG=>c%﹏8${×axq!o̒=|fyQjm#Hd@dXswzFwajUi&Rjt^hCcߠWW*G˶|!,j}]k^3\fK*@ HQ>kTmn1 ^^r1Mt 'fw9$\njͤ4Df X"c̊gIMSg)4+"HuF4bC5?4}4/"Ju{6n 4PXICG|op0l_rӭ^UŲdHuv$;x czDFC aDϿF#WzgF6MvaJF;aRw5*)ƸBTdl5K|ZqJ?;\,[Pi1C%|VSj香 J]9}? ?#S s-b(XXBk!26ݴ÷m:%hM|=28jM) ٨-%w]~ >Q 9)FUyΙ!wRCtgV"kʐ&tNS,挵KA,Q7+ƨkSC6sz*Li"aHby4.U!* !D md͝U=L 0enݞthJjͦwm󪪷ml)62"Mᴓ Svj%vmDoy1AGkXYi-bIUMlᚠݑ8%fLzCX]w:UvSN=#{/п%<s{}%8${×axq!"+c6 0D7=<;yC?y;CC?7"EeRa $n^hz lA9h%H=/t7p{mp@^r߻È{?Ga]4nDzN5}‘x";xN0fC+w!F8#|Ǵ-t7C8t-$l( f>kf8Sr?{6z3zzw܀]6z鲅Lt*ڬd~Ss8Q@dsA'/fgc;dwОjJ2I?!qکŢ='lßBxMpwO2VJqsnp*/Bk[\yY]Z-$?,O'{Ǽi5%E;u7t _'J#jS.X^Nd=6XxCSX:?AK%]Bt#f'fG٪)Ǫ/sl7rW7+3|?gbִ^u6 ]6Y.lb=j˦ͱr9P n;? PKA4;Eo +org/codehaus/groovy/runtime/NullObject.javaW]oH}hKHiY Ǚ^%vv(}cbOɎ玝/DUѱ~sԡg~vI(gr%;+:ūW5]\\|uASYJ$.㐧&j~M !窢62ɒdQOOh>rS+%((b"U)RY"Umɲu㸬{gyEQvCVNsY2.窬%{9t|G'ziceMsyjm;-^5QtB?R]f9{UkK@>~b^T%ᲪɨZ%^b9 ,Ry.D!dQiaImYB^$/y%3_l j#ʉ^-SP U׾[9-d>WӲ{%b3DcX909nJͺ`nu&zxX(nҤLnQn`6yh) }<II}pyH1Èhcȑ$;`!CA 쒰c3QxECy7xt{O8CW~ ]!K#7J|o^.xSԮ YEE8 i䜏S#7P5m$bH<GH`2t)'K>M6@ApⒶ~\c_FUNնWX./W3fc,;+̶NOjAO)ҤZ$ 6?Ms̓ű~Pk̖֧1錍R=:\ 9y{-o=Ñbh4Œ_K܊[Ej֣9 /PK@4+$+org/codehaus/groovy/runtime/NumberMath.javaZm,DrdNi/P`uEčI.ԝgfvI:R( I\ G?Sxcp2]{a {%k>.EIl$hbTT6TSU^jWQ.\6W2V.zip)Kt(D&UBeQ(fMt0JW|% jgZi#Z։"`+ej+:ڔ!YfFOPTnʁqJX54l&M&B7 aVh2 .Չ%VxsP3+֒ťQDZ)`xBZ&'=2}c_ӎt#ԏ˪d &YleJHort]FbبdTZ4(Gc9(7Q8Gta'y}-̑A*N颍iT椃rWz |DA4BԪpNQ.ejMY XB3-X6yKfpU&ԶPhG:_-,0ft [8-ޅ@UH `̸Ih5A, (q,f[Wk@)(EH=yfABzhHK32hú[|/*1\;yB^V²XrFKP-m >h`J[gr_T*d]Mfq? :x+ :$I1k2bܒ oD|dRwNz)g//./ËgĢqU#c)ԥC?tI`&+HӐqZ&o, tƣxvY2\\aĘSHWLl$,Ex-T>Fm`&u,6vQ:lp,O*xkxE.' )b>9&?Q?3CG]^9N 6=3`rĸ'#~{J0Cc<?̆~cP]M,<:T80 pݢ5YbfW2eڗjb7D5{)-8QwmbJjDL 4aVdnƦK׭rf#$'?|lJBhB&4~$n8QqA'-%;H&yjCM=_5i] -:Qm(PG5=\mu8vQ!oMq-^mdM[ | }*Ǔ)L)`gBdJ&O(ۍ;=Ө1O馌_dP }N,cM!O61]dlڻ:mg- )֙$3h[?ok|p#5F3>7ESr,m8يsS1H{ۃm8ݣB}RKIk+"`M6;_K98V/NZ2$x%4*d$ipe1ylVyu 2Sb?nMP j2˘IyDU3BkJtaT.ɢ4 s(Tмa<)7* [YU UǙtFf̒J^\o_ ,x ¢߬ ou_XYkod|-OfHœfhMmE?eZ7xDb:ߣ IAQ}|d}iIAo__.|}u>,H{g/g;{WJa/N`9-f^1tH|\`܈l8zYNc՝{}E$- \ctk'&ofAj}l[?f2}2>0?9 3>ڷ]{g&܏$@!CwZHb'_G5^;[ӌHNutq?ٴG`'_0Hy# nI!&%:Ϳ·X^m78<)nlyPK@45ȟ(org/codehaus/groovy/runtime/package.html5A Es G-ʶހ qZqn/Yi;ˆ%Z}@%My&zu{QeC\z]ɴ p;1pw@ 0^Lb8&ao.gR1ͳ ~ !Vzh PKA4~߯ 5org/codehaus/groovy/runtime/ReflectionMetaMethod.javaVao6[P`NivCe&`[$7 %V+I95QrYW)ݻw'^"(djsURIlEw MY^vq[ؗ @ fʒ9tSCjD ̠0NVR{Ddz+3dyEse$UnZaJsaeJ, /čirݯ,U/Yw6RsKPyI[PwyTYN~  wCt*)CXШt^^6%Q7A4_9QE$p@U_#:DxP2sF4-D"6>*9 5Qcfbz@׹ .fpJmw'u*)e45&ܵTq0&v,pNn2}9u(1!DegM)0YjQ=;*ŃiC[bO3EFÜlW!N4wCD:f"k?? `P![4ͱ1p%XR]gXYhޡPfH<8JnQ lb'|$ϒ0G?FtK؇ix:8Dȟ$]`4u&a#> %aׅl , '.O&0S?Jx0Lg4`^4q0 U_OrDow÷wWz 5o;ϣQZ7֒FtꢐFD.+R>EA [Y+rΉu=o2VT-YjhCȢ $mWW5*8u)̦Gy j#y0;L@@NwpyQHQӲ'%b!JRaX 0 %puG4;2|.%T4W2U*pQ9RhIG}l1fkf%E^˖vs0>28BZ.責>.zW OFz Y0uJ`8rU/6V @ Bu%12Wi}@ cPEVYro6iWá5DN7CipL׏ iû`R1D\ϲ8I= ۹ zi)t"Ie"L$d6ţ(h"E,،(0a\9G7"n.idb4 Mg4NCbRc&h/!'(.LS;KOu$tys,p)EԽ23|p$%- yp`M`ImNEy *2%=C:D6B1C( ObiVY# ljĀV,V5ea̦s!ۚƑ 䑣V=܅V BQvlP1;IQx;a4 y60" !HD%~ufis˽ O6Dt1rExs[ENL[6|{l+~!˕o  4ktaۮk^+צjWk2Kfۚ~޲?0vC;e,.Cv48{Bb{-[Ka%vƴ1,m6{gj!Z"hFm0זWel14HЋNo?)m 7ݹz~ozsR@?԰ʆ eԙb <QLj'l_ ^ _1S{ڇxiT[?߻֚XEm;4]Nsxκ-|`4|ipm;qS6Gb%Jz&aBf;/3.i]߇P>޹]FC6j,Ӝ_OF{99rn+u"|Wnuz*6轳 Y-%.jTˑ sW/PKA4U 95Qfrl)-u6 e@4mȦY)!YRE8'Gbkzt}iԭ˻2sZUi jmqa?Epw}Y:/ɯq~+e(x7Dѭ:h6tGyR-3|eɪ<qۏzAJ4kCvEQE\YMAaMJj?2w!s"LogI|Gl[d#6h_4y'>} zxᶂY„@8>M8.; 3|ģ+8 s!n, 5 Oo]KF.1^ Iy8 , 0/BqN>e#9`\`,JAi<O2 '拘 Si Q2(Hn=FX~n:f4OAL8OؔXb>)O)8mB,!0Sm.AG q= Qʒd>Ky8AmZz:\ΨT.͘u@”P,1*$ +vcႝb E \s>U u˃\]_B0;cl { [,hWf 8/zry%ŸYK_|wA]tk4tY7q*oQn:A%XNe;}ґɇ<=983$q)U_D(/ow_qoS` 8"sb$wpv7DLD*Yd$TBH5@ (U:TB@9K (|J ^2Ny)Hd\E^r"ð=X3JʪLIki o!<- j2MpQx_&2SO!y^ E~ׯN_-gHx0`a~ݰgy,QX80#{w^boim4;\y}/zvh90tsG}'(!z^lg[ߎ<`\"<1Ff"ya߂p\ È"h #Ms`B f쎼F2Uy(bp=rB{. ϡQ,49< eQiAĂ`4<Ё[h.zhcFp nX͚C\ȞJK"Q+Xw.]u0s^H G:|ft^wB4X WϽݰ!oa>F7*/T%Еn"ܯl;%^x{r uON\t~MϞ 6nDHW]«G \zi& (*|~zJq* ca+wwVj̳ 7FwVUדI w0&0KYFb;njmot+ >q)18D&R5tL=?kPbLO]G&8K]k3b$}aʋ&;b{-4/B:ѯ勷6S4jLڏ,e'9 ]ڱ$52Ҟgݨi@p3@;Ykv -kx?eCHz6i;7NWjAG(Qz̝s>͓.c_T y m2DurGK$g#탞PK@4XN,-org/codehaus/groovy/runtime/RegexSupport.javamN0 E~l'iЉ@$dҤJw Sb{ ***.mWn]03: Hiw$ktQ0֡ ,a!Z=rqw٣+&}QWZ ,uWU1Kx\{d-Lܑj偰iu4CJ#|||;^wڰJ{xJoB{<1:եHOp[3ʕB ΡRoY>3!}ĠV,D!g g Gk OΪ ?h9/PKA4Uۥt6org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java=ksF_ѡR00v687˶0"Ll"tţoOg!~O;XO3NȩwK3G 8d2d٤lbo.C# gv@.|>hxclB&x9gnH, Xk4ɃΈ_o71mĶ` =#wx;%cϝX+,<[)d7*/, RY>p̐Kz=fAd0r >b{`S :Ip#@C;Ñٽufx= BV13p/4菈ut) JN s38ٗ( 5umtM0a0&"?7YsaR2:to nN9b08Ce ߘ]zMz2@c er1\Aq@.oA/&86bE=p7KʇQWj뎒p@8JIEϼ0][2дv |˄61yN:go xL-\oKtlJ/ :Dܦq_!|!uq1v-N˄6LC}ԃS}X.rJ!V,C/|~M! .0~i hMc2c&K`O܅L"`̂8 H R Twt @NtO ]B4O|vwRS _1TBAeag=Mx ٽW"FXmy(B.BAl@]} /,r"^dfCoZZcU}=D >bR$X @%!'4/+]o*㍆@2$EoQtR_6w+ kReiJ'$)5U-Oy4H:Cc;@]xWC1,ɺH:| }I*h؏!bsBHT~J.Ql:\b#n$ѲeQ8 H5f4ψ3a&Zt2g vsh?eJ!̜Vyn//=.|\oq!J_]> J=ֻY>բ&/R-U+4Àⴭ醪5SgYHŸ- tXL0px&Wt^LoA\I}-uKr:lۡ|r(Ԑ_ԧs s0m*-S/搾=3 HDyĈj Gu3vOOi(Gj-K~.-L+ B(u";o] 0|-8+0ZPQK|ݸ^x*.sZX^aW@W4[(|?䍢˶ak /(˝Hr)dG~|ŹW6 ^nD_\HMi/緸{puCƿ6?'g'R Ilм ךEMS0ݦy3W3*Z5޺"y<(f]!:m;ieRZB6MeR`5<0uA$;dṘANt52d(}1%~e30nbVЋ䊘UM-A^(ܻgD$InmFKT X`}/X0|L f~M5:L?:0U7Z7y 2uMţ($W8? *U8l z'.$+D53ϗÖcD!lܡܭ$pDI/]qljÍVv'`ߐ}6`Y#~~@ŘORIt6*MRkTPhH,)svD+4YHibSiU1꓿[%+mO|3sNvmAPqc2B8  WV"`BQBgNŷBx.deqz~jV6K^N0<2vǜٺd?e㭎6 j{C};ˮ­MfVm3OdWx>͑?%SR4ou5wcR#%n)5s՚7#~遨NTL<7Y1=SsFxQ-mш3%wdVc`Xk@>Uct.Oe8E)12 E'G< FW!P1&զ.MIObvu7?ƃ)/CAcҒvĻbS ?C7ٖ C"4d6<=ޱ8 Q=NÙ6፟=; _ZW}9_ Mb7r Ï,ַC ʂb|uY SoD"sǺ5myI+q|$U* c\A F^ʆ.K^ Ђu>70<` >v;K2Fߚч£~&%_"$\QuH?bˌd9PKA4ƮD)v 0org/codehaus/groovy/runtime/ScriptReference.javaVaO:_q(ecMOC h)ALq<FOÀ_ڋI솅)%WpViuNcɃ: -1HAAp\2xk+O"q̮d{Iq2VG ox%48a>rK xi{;x8R]E25BW.;j}pt{<:gHv2tL _ldiny !yb#x6@ֱ+ۮt5íb`ptEHx-ηUk}Bd?nn}O̲{/}^ro6 G!YB*h%eO i7ACZ&] }4\gvM@dTR{_w/ Y!nD\);:swƄPᬩ7~jwp[Wxt//HKn&$nLM$N4elO.MKxJ*9VXT{BI~{PKA42x2org/codehaus/groovy/runtime/ScriptTestAdapter.java}Tn0}W\>%I([U `KvHߵDEH8s=&-p .K8+%k٨-o-- %R3wJSn=mӅ#ʑP=*N [7.ӱW+:KOdZmF7Uh*%ѝP"~d}ᴘ&\U*~0I>7aw 'T7XPm4oVO@u%v_^W)3vXMQѕ>b̚2,N>8+܃͌.?<PKA4=E&3org/codehaus/groovy/runtime/StringBufferWriter.javaWnF}W SUJ'E6 YTI*Q\IL($帗]Qˮ۾@v̙3Ùeg~zJQb֫SuVI,VWW7ݗ7osYiEA%=c$f󊍾{B?,ك=.zjBW<쉜z|Ҧ۬S-TMĜn-^dC-Ze)\TO2T幺f"خ4v YB{K&\Z')eEZV"3쒍l%(Kf^ Ue, KAaFF>$+C,zBi D>;Kms౯]Ԙn$Bj^vب\(hZ |!&Yl'}gj$*gZݱDi"T@H,Rl4.T%F SCřb˦B:z\d9\ԹҌuxM\Rڌ%IcCo:4g⮉2y87 Jbb'6! &rHBkʅ_v_)e(r8S>Cg(UcAҼݮٕ4ҏ( k'Q|^z7 ޥ3e~oaDDxl9~^>ɿ |,:6Cw0Ë6ALʏq,ڌᶖӕ~2GHEF([,G|'S?&rm={M oࣣd˲xΣ V7ӝ%PxfhhRVh߸jTS>neγN 4Xe0n]?>ͅ䣨35 k9}Y^PJ M::gӳP2^3zBH~ENKZ6w"p8+T 36EBX NY^۾<۵D,C>xu~Cw< +f9f\@aP>DeԆʊ]Mdžj1 N<嗟uVk\5<ʆHcq9<~NKYQ`? )-(cA䲘41 06r][]))Zkg N157. [I5׶_kPWǭ4:6J渢qkr3}pk]n NON^^^ '_?=S-}]1bw:] YׁE.KJ &*Fj,Jd)F&/IZT&UsUJP 0R-̭Tq*L Qq"Q5=t65+PU\%"uo-uZkI\0$2uKUWZ\>`DT%:%hZ4"-pc'[%Q/)'*IcY>Ƴ"+0٩XF&-ޘw0B+z>:Dx)CX׃F4DKM+9 5(N1bLfpJmT)Hjd@}rCxkcg C٘wqvO|ȧ]@Gh]rFpOaoytmh0s{lEHCzcOA%F~< ';`H"<1Eaxp܅pXgWEP6BS3*ׄKz:tjp? aj.iz^D( KzFda.M=F>]ur<$^Grms>U Fwm];kcloo^k-/bIsnyx_ j۷!q82ű`/  36SKDu@kJiU}!ΈoG o\=EL G#N ȥSHs'śxgq6h@Iiշ-ǵ*MƀQY>+ldwé 26>ZhRd,϶f5c6$1hvp&~3]@} EeM_K%%<|$3vet}m;y(ګ~ZXJ3Yz $_<.b9,f}4[6EJD~m†0`?n 6jYG7Ӯ}d70?});(tlu{p_x f \KQPKA49HM 4org/codehaus/groovy/runtime/TransformMetaMethod.javaVoH?bEjRq8I[P1{8it:kXۤZ4:̂sΒ텙yͰ !Ѣ2+˙~7*sN8;p/rpy/ H7} 'Eh>|) g(x- Fj aZj DHE21Ql\VPorF5cTZf)eU "s=>s!7WM UZoo+ujg7Ip+U!֐*)ظRCr@iJ е15h;^6%Q7TAUSi~Ƴ0HXa٫ZF?#`2~V5kT;8m(ߡ UfC{0iZ2v>k ! J@XY/ƅ Rd KI*SGnj m0'N9ꜦFdTCQc_71Ջl )l{֨J}NJ۪޺0R+ȟ7SټW< 0!\a>^p1"/y3icaAěNWJ̓y#4єQ"z3b~B5+CS99-yѝCF̛yXHk#^'u6,>4j9$lzDAЌ"V<$,L[Ƣ[֌JNޏHXGZĨʁ'fE=b!`S~5$[3Ɂo=;a–OCn`WWo!XI~wd"&ִϭ{~tSո?:˭5t QG}<ߴqc]5=Na)hͫjVhP-WK~!nr' {q+Yza >Y:PHrZ ˉh,<<|yw2sX_GCky(iS~bY>NlL˻>>L?&;MvW9? em\s z0ʭmfO I]$t;=^oPK A4%org/codehaus/groovy/runtime/wrappers/PK@4C:W8org/codehaus/groovy/runtime/wrappers/BooleanWrapper.javaeRAn0ÕzH8.,FʤJRQ R Epf83,+#JKV 'TU7"Й'+M8ŕSt8@isH S roj)TN褫{s<:s>΁nʹ6 E/8Ԧ#FOlHX0Q5Y CZipvhXT.2Z@*'z:a:#]dvP)t8M҉'&xdblxHrGċg|O'kc)}TѥDv(6˝ٚ*[QJBF#4dW,4K'\_Wx0 \TֆV93,/]D>ϢuW|9X9\JpeZ9ai.ݏwcQy潷_Gp + rFW{jV *PY, !d_h,i7b Mm@i"sZ|)s@ }Z@5㜉ECd䆎O%Dq} 9 q{!]|EOMEk_O *䁥m@trX]^ 4%Ygݻ%S fIi>$OE ٧o6v:V>ݥO_ ɞG/91/ X&4II j/kZ?Q:4GU- ,MKGrҍW (.[Fz+j W(zFQ_5,l E+pgUiwpWdOxƫjX ??W#XC[PKA4+;5org/codehaus/groovy/runtime/wrappers/CharWrapper.javaeRAn0zh.UUȅȑV[TI*Q]2࠺ 7pVՍbL%Nh̃uI!*s$Ѹ T]qGh;bP@/:!͡kВ0(ߌs&8p#͟= NKgBTDo$T$u$U$[u/jBmjvAU2L8Xѻ<ck她f}úܿ [ޖS;K9zU)-ZHixy=Bׇa tǎxVkPKA4ܱ @7org/codehaus/groovy/runtime/wrappers/DoubleWrapper.javaeR0Q z^J]*dс%6ͲQgBD7oE3,u{2k/!Z1ceNRNdjB܊ced S݃8Gq%lS r}l)TN襫9#K9G}pZ>@7_\! 8Ԧ3Frfw,zlzR Y C:iѲ\Xj#zhQ^to)uF:wE";pjBagH >Y=>}<8% -tMʧψg|Oĉzmw2O!FBϒlK,eTՉP2%sֿeiQ:ᆫ| {.;uAlX_N锓G {<A4(:Wa3v~`o+'ڟ ر#UXпo-7i)hP w8K(8`;Pԏ=K}>6xx ނPKA4V;6org/codehaus/groovy/runtime/wrappers/FloatWrapper.javaeRn@#+K㴴S+5<`[Kw+ʿ-`Q7o싮\cۓUp\~w]+| Պ sR t WV* "cV {l*ͮn=Iw8v,1(eCZcHrB/]=̙XB4q BIjOQ}(6UԌP=$u?Q5d- aÇDˢrq` DekN{ѽNjK Cyܻ%S 8C%ΒlIq}.Yglڤw.٤|G>G-@ϡx,S4ˈI((ɶRlMU~&Z2GiZXxFnW8fGsqa Egh| M߽qR8<@Q?v~PKA4̦R!e=org/codehaus/groovy/runtime/wrappers/GroovyObjectWrapper.javaTr0;2Ĥ9P3$M6ЉI%Fr%ɿweCH: [pC 'ǟR.\x0剖(4F e!}U7]EpCNR2%+@HF ΏHtUt#θ"óXJB6# A*`B3Ҋ7\]rnrD\gidHJ 8uAגLh0xtON`0 H{1U6MĆtt!󐬉8c1B,W9ՒkUM#K%7̔v|y.^EQ?X. e i/VR Oe%z`ih @JxvBÆ ӶwXefAϯUͨ O ͠4Z Ԣ9,iԁp:ko郆YL`c4)RtfI_;DU|KzjȪ^ hLI (PTFD ;EMऀŎ h7 -Gl"v辶1_JuSAZw*5.Y,ܫo.J>Uӎ.l8>W - T_s seɻj4ul;VGШs66g;_UmeQޑv->%0eILdw[1.^F6~8cFI@5#jPKA4cJ64org/codehaus/groovy/runtime/wrappers/IntWrapper.javaeRr0;>%<9\JqQD'3"ڷz<+ݞj=ZKlV {TS"e,𓌕Z&\fSiv})NQCg9E)=:H\F zzljC` -K DvE}߇bjSE}Z.=?4lphYT.,= qi/7IU-`uza:#{Y";pjBagH>Y-<>}<찏8% -V.%ww '}5˔>M*27J=J-岔9[SU'*B(vQZGFAQ\vjٰ2Z?B)'塹 Y0)FDx:RK^`C^R_al]\@vh Xxx8S5 PKA465org/codehaus/groovy/runtime/wrappers/LongWrapper.javaeRn@#+K㶴+5<`[Kwʿ-ƒpAo޼̰Ȫv],>⇮jY˜*Մ9d S͝8Gq%lS r}l)TN襫9#K9F}pZ>@7_\) 8Ԧ3FdJ=6=4lphYT.,= qi/7IUauza:#{E";pjBagH Y=>}<찏8% ->%O_Os's5˔>M*27J}d[e)sNTJ?Q-U- ,SN) Ksl\ͺ?7vHo}ctZJ%4|fuE^C5x PK@4]mךA 5org/codehaus/groovy/runtime/wrappers/PojoWrapper.javaUMsH+ 8X89aT Rĕ 5bliF;3BQmoχ,$1o{lgp)Zto^gZ 1xBcHP# [8TK ـa8g%!  k Xbg"Fٻ{Jd1 5%3})N#IN39IEZJHVmj* XΌ+ ܙ)0 Fmiz5Iy7\c5,Cs^'vy|Y\aubX-//ߋ{[ɭ8ֈ= ;)c1IiRTP Rk[UM fWOtE`@V[,2;e{V(URHJ4Je X&[y̎|D.3;n[G3RgoXidn[>;yEywP(i*U$a z;.X^xaFǢ'S-ydS8vttiܙ$YÜ{E)}@ݿ{#g7vi{mf+-R"}:1N[85mjq6G2W_B:Uێpi Ɖ׋'k7`l?.Y-Ny@U {ДJ7kS]O[kN#m#| ,T($;`$8,шNo'%IGwCִD:4v^ܷǔ7uLtoT]t=4ЊψTSi0p߀.r Kn]O 8H@/ϫlwd>?yltG5Me%UExwI%A\VI[SPKA4 <6org/codehaus/groovy/runtime/wrappers/ShortWrapper.javaeR0Q z^JiK"U6ڣpKljej@o޼XldU;ܮVM _Bdcb<Ȝ*Մ9?Xn0J;OqN :K!-J%A*6RKWs&s#N=I NKk)}T eDo$zd[e)sNTJ?Q-U- ,SN( Ksb\ͺ?7er ;RK_qR_a_ `v;rdx PKA4Eu#1org/codehaus/groovy/runtime/wrappers/Wrapper.javaZQo6~8/NYP$ܵ aDLdR#DY%9C $HQg=8 l$[49?>1_ #s)Wԃ{T^Q7{f_TLpxCS'#!*L7WR^q,c0Z 1 :m7-iZi(rHLr9S58ή^#iT)ILx )̑O"RR[3Mt|h8Pb;芄YJ!7 fkDŦzHTH 8#§v.0[}z%A|D+"A"Q'JMDfjƱǟH`TeHQ{6ŭ LF`~A9 9A\ AD¸tMV)4~62tILfQfO 8i5/$I8G$աۯ ;.U U6ٹ>Ła}lN1Lup̜,L^Ωca(vޫO #$ڎ}V6+d4NKr"Ј/+Ű2Eb;#zLw:ȅU@֯L{~6Uuf*]C@߈Ѽ;T3ݡA9&szHY+fı Ҧ JQq AdOԛe_{זG@sR{_EWSz 49bA7Zj @x60ob,)YӮ%NfLYŶsNS~7۠{&|.MAt5.~̍*y:w]#GCc͕36U(Xqĩ|.NIv I;ؤ `ós^~04hMҍ|rhϷbٯ CO-Ʃw hjde8c;]|\*U(d9}e%H pxx|tt|r%7`xͣQUEO*ZV>E1-Js's elem])](sj,X ՙ!Ye%(pIz0^U+꺂BeHVAmS9.?Ip ]^Kt+.n-cr@uqDdrtmFVBU"gI-DPT&K< PB"`کUw^"`ȭ*yĂz+kdwrOokRG2 kIB4I(h h4F ⻎j>h(Zh}xДLV # ̵1֕:B'hkێnN6Fk>*@BJʦgY,lͲWf-c23Q贓Ԥ#f#Ŷ 8ϖ׼-=&85Kl4\ <^S~aT#[tU8ȉK,MxM6+԰=# @ fY] ш]1?QׯAo:S0!xp}p?&ajizaJ(O̊zba'MCFֈy9o2_n¢+:ܚeg=WcFW bÐvp|^z}K:}L]VxzjѦv^{+>]'7y2-x ۔{w v-WH2τmuPbxl-{t{S/XW@ ^QDp̜O ox. DA I._ĺlg._y6ۖNuͩ/S2j7R :Piܛf%~NwVzȜ6<Ʌ ȭ_ ;0"N*Ud(ZSO?n=+jY?_N=(4glW+tl .>0kSmPK @4org/codehaus/groovy/sandbox/PK A4org/codehaus/groovy/sandbox/ui/PKA4ɡr-org/codehaus/groovy/sandbox/ui/Completer.java-10 @=/БLS;J ;EbOR\)3X-Fv4L!V9 ܽl'n{$m+om5ypZ_qU?wm= gROtBO52ǗwKcyV]2b+#͆"|`j%8ǫ1X[)@ܹ+"M* {o+/#D| STI6n&Ktȷ]Bo@U'Jϟc1J'?GO?ň·4tRUUƸ 1:JPi8P"]*Ul)uЩ L'N>Xf/4W&5GhYgPNFZv%J{po5jhozyCUYm t$`Yң_ b PK@4*org/codehaus/groovy/sandbox/ui/Prompt.java] 0y=@A|5Y66in*a/`K Z':mUdلe#7E3qBb7(fPqX8vI`C(9& ֆY#]?g=orJPgn198֠s5T-#m0;Ί8yt'!mYzKp8n~+(qm-EΜ@)^C gZ#Q+@׈z"#z.?~>n_:}({C]:1OA1;4,wxa(_Y᡼іja JU*ثPK A4org/codehaus/groovy/syntax/PKA4>x~ %)org/codehaus/groovy/syntax/ASTHelper.javaZmo8_1k,v╳}Iznbۢ(hYR!f(J^8ap83pfp!;%K /OOa,4QH+Kk$H>p KDвCNXd+HjHb_kr|[f#,9 NX%Kׯzv1#'բdqzxq5\ 1(g"nvF|6C1C-1-IZD.rLqbX+1KtI_xk5"hO`8iKL>|4^M`|p:->e8j kE;@1iFmK"e*R澘 -ఐ"Z, JhͧھTǽ#T=Be{ %PRnv^4{xRFk"dq(EY#8Hy#$I}i%Co"Ѕ -B\)FKcXa놑= Q` +tCc=F%z)K/G5J2EAķf*FZo'K$B#@*ƪ UJsL n0d/ =V %,FЯW)E gw[Ost0{&1D,$1s?駯pO00 _)T8 K5~HHb]<4g6Np$dZɍP"B GݚszHWK})D`h!~aWV@ܧT`d׉,CaKlnef8>leϲt|9FGI⌶1L͛,pB,$ RH7K!78!|%" ڝ.sZy{YG׻eɡuIL ;RFYMӏRG*'wI5f9|!D]ڥ;t܎ LduIqqeuf߲~ Ȅ9Aip*iVQoJ[atiJt_Jy续T=f8~:t{ըFXvS2gs,m"*'*0 xx7(C TjЃkf9aOܤ :=6'Ri%9U9(֓y"vtS2cm=g~ўo0zB=2'y7iiTQÏwPqcмcl;)k4eftiXa51*>f⸚N̋ſ)qrҴ]E&~Dal?ƧPhy?tr|xrCOll{6SVj C}gg;.suRʡ҄˫ﯧ_7Ğ(`S$ * !=2&(;HJSDPi?:~BKԞӧ% MұKuaSʔ$B* 475j\%5,Vڋ?$u5;%2ds,tZ]׮o$p;vd78-ٟDdedpez2K1NQ;OlFrF5M\3.ntpڅ9ĻHF95iՂY|"Nת<{;V/cs^xJg2cCXTL#^ XǽFaAm|fKO鑔Ui_6GGI,9&Pl*l}jw6MT[_ D"PK@4 +org/codehaus/groovy/syntax/ClassSource.javaV]sF}Wd&JtZVv,[ְIRv{vlnf::ܻ5:7mFV[]/+|w닟ط5qzזzҩFV;JQ툼xtN[U|nH6m:EzIcQW*k2W:Ԫ饉rDO\Z[_ozuQ.dU[In,T᠞hJ-)J٨Z׀|9f)zjU/?q+ݗF*M!N6 L'u*!^BCvJm}@HAfza1C Mc%,*,k՚F-2QcDB%>` =a8?7VtjN:Kʌ @iRM[3>Z~9PJbh @07OònK3:f6u0@|4QnLߦGX)٩y]ەnD\V:J P'qzek'ǧ$1@+tw}+ U˫8{?`p.{P* h6_Mx9:k 4F8/,=8`3/EDi'Y'¡O(+EԳZ$ܪƣ%IHy94 `B؞Ƒ d5:X]1EZD@6?=CEѤ݄E>3ؤpaǓS Tnp*9=` suTtߵOKUyK P}n͸X>7PKA4K5'org/codehaus/groovy/syntax/CSTNode.javaZmsHίP[HΉ]Avt ֭, F!Q#ayzĩ;>؂~Gg L:7qC8|M!9z$7w#.Fzr̓yJk?Kєni|<)0Ĕ%0pjd\%  $.gbM ܔj%"l 9\W),b?5-_) Z&0a5xqĕKPNIMHJR,uP`5? jHDXi౤B&1)!B(U*\FBk+MݫmT:rty$Poͻ gB7X0NW] ha73l{Ձ aAͺ)AeQȠR1ȏ9'8jJsJud$7K)C'lC#4$c܄Iz)2{5d\]k[=7 H fP "qKjW\@|PTF0NK?}p jA d5 BەsvpuQ3:|2x[}8F}9up2Oi<}*g~[ܣ1QNl1Ӿ=<74`8'H7b*>Wؓ4e3΄Ks<{Ӂ9rX@Fm70 eqN>Z 8Q8CBӁ%A;M0(z$6o`silz~s (Ա5E"ya[cJHo:.He™:{2Xp>I8ݳ09c8S t5{8 0> h>}1!*2 ֛pFDq3>=FG$X9ğLu*&/^1p&g`? E*Zn tZJ0ŽvYj$kL2_6b\;]][.R)3h/%FU?:AwOF9=xck4ϰy`r% ̍"نX%~9gތ0cJH50m1&w dnu8=dS2a^k&/QP nÚR*O@p#isĪRp{ pom;͎ 7*z8jb ]';e>gG}'9G/" bZV.Ux8!$6y6wP IIM bJiд ?Ϩ@LW/ s#*tHNLF2B2]S ")6lp:tp! .9f酜cbE}x+sm%-2e!l%ܸa4u6wpѠ!&4G"g1A,#Mow2TdVH*c0:<,ﷅ>pQ3<-%F?Z5/-JQi(񨝋oΒ$澪3܍:$X0h&wP1$h RB ˷>du:_?W A'5D(5W%b0x<33+{7'x`{,I*mo$HGʗԉQ=M3#:^1|~L4|i1�lưaZ r@G(Q{B`u3r]P_F'6TByoGH8xˉgpݣXc'1?Rh†vF$[M_F2ZRy?:m`d$FNCsXIt8_=$#CV֫o+,^jިb[G,325+ ΃uqj,Wx$2d)m`tnt04:$Cg9GڬWSBuKD^).Hz&4 #Pc!F]D/Xkކ MM% Clk1t[ "e{Y>Uvn&Њ]䳯[b!LLZN,P$zP YPˮLzcͮ ;2#:ar u#tF޹e*|,·h9]v6F 7~S?fḾC+JT`Z(uYF; fV{{ n 0D"D? $S*>Q.M E]H:CoʄsiRL_, L㓜]ppGMw.n/ ( 0$D:N>DQbQ^ )y?]ILTaS5%fكTY<\O0V0'g2ѩFb&qAǢ e)H4x7o/2EbeVҫ\+W+W{Vo7"bU+ʕk>OSL Q:Q awz8e0ō+bҕ!y]Zhs561K3c3;_j cRG<Lis}džw 73߅Hܖ6!wҋѸD)/D v$fk<%p˱>/a9q BgfA3"dLcIl-ŕ2Ur)[A5U1#n&kn-Oє͖\j+. #ֲ.Ȓjkhk>a&Y4o8g8~(xW"9XZ/s */f96xÁ'bźw^JC dYJK[=UDn[v/=.FǥYnNiлw6KbGik6I ~:\S_m[!],u0z&Dk~;,+Tbo^A򆗪CsrjNUN9lL->HyW҇Cxv6Ć[[Uav5dw3k;ƲnyR1VFXS5K;u+4LGdxRZt7U$pJ?\> .QMq*s_ m5sͭm1Cwte|y8x-U]j!.vgdOd~Ƴ78e,Hx+6{ao~uz~YWp~K7S.DΧ\PһՎe롈#O<<<~pD=N/+սgAҍfb{Y~!03Q]6YX&PKA4 mZm'org/codehaus/groovy/syntax/package.html5A0 gT9>a+Aum;/T 'g&)jMݱy+=_Kx]lĀn" )ԡ|PKA4͂/org/codehaus/groovy/syntax/ParserException.java 0 }'^`g" t]Ů)Iw1?I[4Y')[& >Rv8x]Ww-eBT;k8-͂Ȁ}D|RpWk&:ɏm'ofYr&zɣ+tӵC0ݼ>ِK6+W 7PKA4|P4D-org/codehaus/groovy/syntax/ReadException.javan!yWe1IǕv(M݋'Vk"7w΀Kƕ\nD ^:cb;cL8UnD'hW/iNLa*@HZ+ 0C(.ᣊ5Y "xCQQqYI1=PU1Q+g'Ex7nv%H2c8E2K t»#{4md^Q}C3:9~QQ6q\ڬ+3N> PKA4Fl h)org/codehaus/groovy/syntax/Reduction.javaXksHί뚚UAD5PS-as%lfJŒ>[/j/8UC<j''Z'o[^ӫw'oOr-3eA?jV翡z!2)҈ԈƏXR7IyQ3dԄ,AywGH^A^;xAJzޝb^owQ\}Wz=oYk/a?v ?î`KT ]ǻs;p/=B nn%-EF}gvz#kڀ۠`=~p?P,BCL u;mRv8EC߽c "^CnCQQc pa<_ ϰBkt^<c~Ϩ =Ke xόCH< 5tvyb>z <ótШV. cL|xE1xڷJ/ 1,ݦU`dj|tw΍sZ+}T+2rDVN]䀳ώbu`Z!MǑAbA-B ͐YQ$ldsw9e^XlֿϤ$;Tk;{X1Zl-A,5 i988H?J Ig~twyK\>zP~i)樑Î.3<:c+Aj\{f=e9J1"gY%([dnMg!XT>V_lBVg!<7޿s ]eR4S p$gBdv.8F+B#ڒ2R :%._5b)t$JrW |Zn13vd!tن̼o,hD*o^Y8td 9FÊhVmX%tlfolrxI`Q/ ҍD4[ Cڈ\rg>G3t5{n, 4/a΋Bms.F:}7Tm_KwJF v @SGspWxLV֞TOaA^x3$aN6(8A-#+dk/) w/8mc(%5Qe ;{1Y` (N#e7Hy2IX{^*UGR/U-U81YCU0O6'5㣷UQ$VpAm6/%;8(e*pc9SId$fd^$k-0tB/ȫiۤl]*˲~r=P*|:zQZc^Tdz.E}0^'|?*8sLLdN4rvoŁC RPɸ/Vg7A;Q-Fq}6镉DDQ}'LƜ{7| _LOI1"̶Rb`^ 6U6u>єODsecR1%UсDYed.bzt,>Ĥmx[Z'q 7=L6&iuK ;\5hTFM&<)wzy\q669ao[4g*}iECfVx,c~ht1rЫ ac4po߶E1?MX=T=_\+k$&Nm綉 n B7^߫\=FC +mqAKߩ}IJHҍCxtS\X?tyrlGɭ,f_φ&R27ؠF?f Er;lQf/PK@4q)gE -org/codehaus/groovy/syntax/SourceSummary.javaV]o6}ׯ 4 \;aKy+#ю:K4(٭7\Ne`8K z%sRvrVUݦUuoMS:;9y78ypvFox~}5WA@]n\9h%FGqP7q}  J٢4ƭMчcji]yjK[ Z5ڇonMAW[^QY̽m8Ҹl9uY"@>.[Y)uQW*ӞixRpմLOĆ7Qm27M^D! >{Tg y%WPqRP]'[L.9ݾ} .+8-D5@I,vw +]ݼ C2S l(^.ޕt^?r| @ 4Gup :]L_ܻ> W@ 㲥Sfw7>C..g_"f#H%m z&7r(tqMAQ2p(gfI%TpyϓT($%y=K,9 L #GPW=B$첤3䒮E7cqʀ.e#]"]H0d4)M$QPhk1D{9I܈8#5 9KƝgDBcx1]TDR%3l7HB| w=J66i^W2>&H4M5Cjz2M3AWI2d)H4NkD9ЧF hm/Jzd4N2G[A }MӅBIzQYnGSVԫzAd};dMX^8p[0Tl!ķ!N=mpu˽bpx 芭5@mxݢVt>Jǃ`\lI>ji]K|u1?1N+yS<9-acRjLGB[۹ny쮵U|X p,f}Ә2^a8/۹٦y׀Vvoݣ1^FX XeQy4Ϛ-VQo|1!ǟG1 Isv{!, PKA4A{ /org/codehaus/groovy/syntax/SyntaxException.javaWoHR$Ф锴U lsIߺhmHfGTyޛ{^Ey)ȥ/i@o޼k9lқ?8:8T&_R#$gjƓ3N{3UPTLdN2OGKn&)i7RIPf҆E UF &dS"}M$+4.ȢI&KRLA gfU:d儴zQLu:1\YV2e DGѵNM)yqZaf<L ($]%U,Ǎ2dSb2KTѠCN <,t h3!3䍲\[33O` TRqx])!N fpasYDo4V˝A6wCA1rFmia)ӤT%ø3]VTp*Th=9sJ) ?Jw.z#^eN,eRk}r;} Ù] NtX&HJzk`Bר$1LcIჍ U3is۵6l(eq%Z,VWBCюyF~u(v D I@^{ ,Rygv/K{Ѱ~<AI$1uȚ6DUb2[ȷXpA %Sx!:AJKAxŰB.lusDo&7R_u3o ^ ҏB?ߕPwhs]nLoS:@1_5}^Y=< sr9¾sl6kS>uf֯ 6G-޾6%9dRh`&D.z/ibHNnr>7V/ FRwgb4 U!! _Z=68c ҉;jI0;j%78U&P[OW[-{B. 'yQP`fkBlUbsagc[߭)` K$xbMymole׿Rg)6X[ [ːrRC߯܅)&}ZG*PՋ+uHs:Ox(ݍ6?M0ķIF4zɺ*P|ؓ}'IU߰道hs6j) }E5:q^^}oVݨ? ;j?PKA4$ &%org/codehaus/groovy/syntax/Token.javaZmFίRe%׉?oe-hwuIŽEHâXhHbͥ߯{fƋQ,bzz~f|gG/Y5.~gO>; '-4;tIK@KU1X-6jrM$rn &Af%[!Y !UTԆ} wAca(e(,user1pIL 2\;ȅ;t3x5'pZ߄k[oz7] ̝G>Ⱥ5ߵ:/S=cgy8{=m]m3vvn @-p>?5䊇`z yem-فkwp=LocӅܝM= ȩ Ǧ=F^kr|npeR렟#۵>&† fЦ/:c RJ=sAB{mP0 5!o~?-NGdr<}g-%kYriԁX0~{Dv|u3ߞ:G\LɘN."4u?VAo[ w Q)ߔE&8ؾESR,tm$l{WK)JhYCk0GP fl-cM~ ColEN'^oȏ?Wŝ%(麉fuY '&HK o3@ԏkqY=ٿ+݆eʠr%U+ Nrbo u >ú$7<1o#5.*-7Õ6ScZҳeB?ATE]2˔`Fh;Z*%vD;^C_aa&f(ݮO.\P6 Oԇ'wǦ*bӤ+7+%xGxl046vL;/>C(e99һ:K{,HTB9&6DglX қKD%(f@[.clqn%4?9*YV{`")C5O.ќ3!!@jVf!OuEա;\ ~p) tUV.۰PؐXɃN3u9atFdu!5$dN-zzhZ> 1#TƓ㋠:JQ:e]wkOBo%kDbۇU|h o؃84'cDիRTHԌ*g2/ɾu5XL$k>qq0f4F BԤf.m CY-_sZMda pq/ jAiVHi6J3v6 =]o)kQռt/ͭ4JiCosۨВsz(joF|PKA4jU16org/codehaus/groovy/syntax/TokenMismatchException.javauPK0s +HXt(eFmvJ ƻ (?gffާ;JIejvXvCpf-\Y'#^-GMBIP{~З6a' ˱O#B|Nc/?¾xyi8x21uMWNaҷ!জ,=>W~6Y%̏ *0f d 3r7=c>K|PKA4Tj<׀)%org/codehaus/groovy/syntax/Types.java\mwȒ_37cg;{^;X6@3" HBo[M4ޙsVV }}#÷!NsY76H'Z<}6$w 9F7~4w6J$ALv &!eFe薤aB6}^$~L$/g< f7nncޓ(eJf$ AEqN)m4F$ħ,H߂흂 Dx#q$R?2cm$ q'TychRB4P SV@CF܏@xƥ'KT(zVbf2.o ?20~8 bE35> M>:C!h(}4궿C<lQa(@"'Q#,JLe(-\d rβCtcΞFgI,t%܍-458FQ|쐾t3:Sہ2A E_,7ES%C(A1v@3?\z;!%H 7)I{:A@9Wާ.ɛkK%}}c_]KnN:vW.Ѭ.lَA/ͅG~^Ӭ_ui!Fo mꘃa]li e,?Gsӝ%W;3LûA rnxsH_s<305NvuJu cjFO{pJ<^j%k3dL];8ae_Q30g;~ѯuPFsnZ n ̸nME:G`wpz7tra]ysett1mk-4J `+ AfX8g?]@Lޥmj[T] *ځڿE>]w-JQ`^NMbq[puAs 0' XTml%}l6&1ΉֽnpȼڭsK?at[u$Odg(N ;@;~rW ~ŒKgu66v_B^`VFxƂ?|qz$y1ƾbB`H ) ( '|fio|`pI(hL>nO7g~8MhcÓ lxJ~PxqĿLN6?tc}v-a8AL#HX;/GpL`^e_ 4C, C x-ʖ,rSr$Pk{sJNʰ P `W0; ]'Sr"zҒ_27Zu.+p@4Phsҍba?8)m+1Z(N3[B G@-Ba1,*qE~ׄд`j8(N q8j8vB}! )FPsJN,D9(j\8:KgM9`><˃(EM$;:56zzRx) oߔ`p~a=q8V#G'Bz"ΰ[ lX0{z} @,֢Qx^]v< Eq= 4/ Ӈ XH(-ޑT udH#\\SÜF8ORvsav1}bŰ"`Сh`wsz(EC"zU8liJ80bzU3ihVl#AK#Sٚw0%bsK\2 7),JqC}ʓ,̘nfO4*+dމH2@a}Ddr ILU.wrRW ;D<6%zZ%ȾH2꽱cvŔQĈ^!gT!ϯ~.V+d(]?N􍾎K!֕X!aOTkخ=834e+e2!;8OQ]Қ xy:ܹt{xuH V2VI6$IXsG :_7E3h` ZRlXbx|(sl'!:f sYցG1L]1ʁx3!)W鴊Dq:P^Qy.t8XF*rdL,u%T{Euz0^BȍJ1mq؈tlj҆8zdsTn`=Ogcy rt]2Fڷ?b1FpN%j.tK.mJC NgmU8i5MybqokCJ&.K |HÒuCv0ANynښLqAs蠷w,'lHe$A粼<`/!${uiLMGp&^x>|e 1aޫ5VaȭYS~$ \YEn56$swՌ">vzsm8oZa/V)o+Wh&16A2]qa҂p`礤[0!fp$EiMiQgRs^zUPp~pYY_} fc*lϰآ9H;UI'8?ف51RdʈmktB&u5~H\D2'`B`=w`r21O,4 O5%`ln4Ug[jYQWj3'Iw_ L+lwK*nMZ'2)LQ0U %^4{C7E^lL',`H&#_*~P=YW-q?\4/H84\ Fȹ/Ă>/sƌ]7^.;sD}V5EmT_<*{7yʛp:Ve:QpnTT8t7qr3YǸŎb&"TC.>ȢU"*>J(Hy^磄6x4iJPiՇ!ynmC-=Qq؎hIOLp/Zih5Ov1w-~6AR8/7I ܐͭy"?ÿ b DNLJy psMnW-K^Zd1]E w)%+]"ˬ[xj8dhօ^!;E;`h;;-zFbfC])G2Zx\I 2qf074~th,g+5 =k?(ͷV6gx`U){Kuelz+X9ٰx(ʷ˾RpsXl+sozgvũ@0T.ۉW ǛmKZY= 9lZyVc5+%fYmaf0iK )A՚zz΀jg!MJxXnh 8i WMwT ^;تBs!ܴm\Xp0Zl5SAl^Jbeh4R@lvQ# 8`onB'zi:ʼnl>ހQy֧/k<XkUjSð(`|h^%T!S}sF6 M2ݱe ^^T*6(S8σG25EDtz怔՜YzW?rR|aZmr$1$y4@IJ°RKY4 )tV~؃KO.q}pmU=br퉙6f3z'fM(P!U *]߾*\ /xn&7u~1бZةaݢ9sMN[9M7YA@Zw- aUpg*]؛3s-rsu^ulIK7 dˏ(w;aå:PB$Rr5NThK+s.*ID+VܺfG^Yc5W/KB.+ # VF S$d[{0azp! $e(l4⻼k.1v>uCԚ-qT@O6WG]޵7mOsnҤ$:D˔*QӸ@$$aL* Rc=^;Sd?&&q%ujG)EG4Ɵ>I aMD:m)1J9azȆ2.jϣ[ [C=}\AlcJRl{NѤ1ѪYAvUy^{;Um87 K(5ъ/VfDm{3N" Nl:a|+V\ZWzm-ԫQ&o :ic&ada] c h!c4$`Nh8ٕ:yo{B 8e7=¾%y-m̔)c+>jv8IpMp@z6d:~xes⚈Sdx &HhfJ|FE F.[ҪFY<.- h7pi h$V/77X[ZL\i\:IJ֦ҩYU7^cVҮ\sx6xm }¡0¯YqGe 1>1߬ 3,45zpE|T]kU6D_0`eh|3*LhW?^mmeՍ4~:pN6 /[V%\F-)鵋Et&` @v09H}[7KZ@>}^IӳbI4=iŴ>ly1yϛD?'"$? #:&Jҷ% GzHtkW(Jxc"`}ȋnЙJyY3uUXN#mx'N|dOlg M]dfcEWȚ*]HtBreߩC*?w5Dz  ։4CڨQ}Hc=Ego1ai~ʘ+hX~H\c9}m2 (XK;;߸S:{~089Eۆmhn@s|nNfevyMxg#N-sIꬕ߫bɘIU]}=Gv`BIJ&lu(|Pɞ)<ފ51,}Jr5=q|> 1lE=:DŽy};_43@4{FgQӲ11#|Np="NyMH#Րt$ldwZS\ UoSZ ,IŻ3ᴟy]^t:3ZQU-vUgN%m>)1wZ+\ OzW3 u6'So"JKñ|Pa(0jb8..BةF M'm?9䈼0κ`8; sBgWGJխmg]> Usy[+eN wj 0T CF9 $̖c,+F;a!ԘiN`#eV\ɟګG^5q00}:W+rl &CYSL3-?9* yXڪGyFrv)ؼ +O:ɕJȚ:dQPa{('rTbyFO` ̗Zě' 5ҍ#5s-S9ȈsI֖Ck8rvTOQ)4(W*m#'ڑq^IcQt0׽l@F#Ųj;üƩv۫?90X A/*L]8&o*Ώf 2 |}OiCυCNg}Hܾ/wwPdAtfͫ s28P2APl ^FPQRRҹDTK]p@V&㋀ FS20cMsYΥ >t2/;!003nooy"s"Ӓ~&'{ PIdv[etwjz<лASGQfvSCa]ngMˉ8=2v Z^ϲ(G`]04<4_4{u6+'os atr*I,"YE:>ҳlG,iúIyJvĖ#lNbк=@+vBYNz)m:ybPpj"GnM:Bf0Yq#Ӹ+ N~Q0 $]txBEqa}$B c>4JKы[{t"t69YNphnb=˫w9G8*ÝŅՍKѣܺM,4JT3ΚbRQFH>Έ6n7h9nya'ׅ+"C}Fxqyr+n#ŌpX^em&7?j;p(n5_5qӝpyyVtIFԓY;+k˨yZJV%Y6ibe,qX.2 FK:.=qŬ.V%Tƕ r*o #H%i3 u^{NeDI*\k+qg9P|ZOr/..Uʮ<r*6/PK A4org/codehaus/groovy/tools/PK@4\J'org/codehaus/groovy/tools/Compiler.javaWmo_10D>ݥpvMl9FQ kr%mCq%%-̮,~ 6;/<3;kWQqNY,ulr-;kxF߿?}t~ݗ2rF%}jAuhlް7O/rjJ+HV]{6BAYRJ5%Vv.l%uc+jEfJ\Ti rMe *LZբI<9ЃndoV -L:wbkKeaCKkֺPE d?,̓fЬU;jCupkJUݐU6d]Dit.=LȲ6 ۱eu%#B-*D\:ެS{(a2[=UR/eLV)1رNu"F9Ճ08oaB~<,+.2X.V0}ༀKMͮXVsX.ks5G&H$6 vbd|L|jCsƯ@XsY^FY]N8I[OA v{ďD)ㄢ0#,'(Dڡh'ht!Xi(hD䲸<>ףx@7" \F(c-Dhw$0HhUVx84tɟ/QDV''3vވ\T\ q\s-LoH;ʪH͎ߐoإiQ"'{'51y«|bEȐ%Axހ/R˳| a!Nb_d(W3d7pQgCZS`]߳E/xAP֧V Vhݮgr-aYtB@u)ּNAboׅQqH ^nY%J(@źc]W񔖸zˤVΡu tb( AY; B&DDauZ\L#HXdaYv h)"$&Fಋ j_ރP8U CYX76KfQDA$Qp#P͉l-+e2]?m: %ze&̢S0[6AMQij۴h ~+c6eJZ_ה"y(x}hB-)/A9ԗNiEq]UOd& %=G>l0+0'vTTcGM08HҕCTڒM:7@ȁr v'j6ظT\jȼJr_; }bX(bofEJ)YJ#(_9r(Ns2J jޓؙ =Tdu*hxbݖ-Gl k]s`40oH v@kޥbq=\>es0*]ъW W"p͗$puyZ534\AD_*'3O [Ùr 2^3+vR~Ek*f(zhŨi T?y yGiM~5|MKޟB%!O뫦OeE#X DLb~_K/}ab,ԲĔ&:q(q ? ؈shr}"?BVb}}hAڇ7F`MP=C2a<,&m6b\zxٜ.E[2O;?j"- 4(#.?ǼЦa@ .~8 Vp |<2?/3>NQHǾaR٪E@l}ChC,Jlj/}9ax#F@uͧXx Jp]aP1cп$˨4ց_ѝh@#\tS$;Ҋ*sk[&_7͒ k[.y 77 8gh[ڡi{s;5ӕׅKH3ZTxjto˃'pYwk^87 lb 4{F%ܠ9As*w|bƒA{%Smm~ڌiii֕m1 XwpnagWezpvv0g$j/ͩs9Ǘ<`e#n9׶ B;E pd[Cy痐/) {)NwI`CfVb(Zjox;7]`s>s6|y4!TK ?>R=|;g<ﶨ)s?W] w+jJFى*j8P.xQKzlæ0>pXi//V:3֪s%VWs: .2O7y*\vVnĢg?XW/mhyLOi{=}cDQȓcj(\ḂdoOh8PKA4]K0S,org/codehaus/groovy/tools/ErrorReporter.javaXmsί8I'ऻNu/]J9 x~&yΫ~SW\R\֯V4om=;>}}Wܞ?y7%bLے^jQ{9],dFAE4)tBjL<66IY(#_fRI |9\",2IjJ<(SNhi,SQ,r9LsR5F|NJi&4&ԋ8gEKn㉜`O4UItFJ'1KeFj!ufБ,'-s$F2x, JUG2kFH2NE(`ukvV,0zq }Hz '<TQխܸYԴ(dsU&JvC,GRYq+D,FHh#:ul܌hcKB"h?p,% R$ӉҜ>.Tnݴ&x4C p7dYSGszV%`G:\LȤ `DQQ  n!WX#$8XJY#K)V.J@dp'r!rS<8 Cf F<ϗ'٪Ն (\7ut] 3 w(A~ ywa-4N?ܠI^ueFAH= q.4Ňr4k\s хa.`Ρ^gs| pAuskIgRpzmwls>:=ή绝I[F_Ix|ib( p\;.hoD3kvD Q`ekgQ6a#tiWxQּ~hz~FW751 \04Vߤ+̨a1V"X +0^Kqx  g 8:29JVriI9P(O#[$K W16TFY)RIvZ 3Pi,g7Ro}iEr-K!1<}J۞VI81SBh]k=kR"鬴iaR9Z`}yC/y^`96S{m$/:3 QmJOF (|.QqgƇւ$ OM͵~L*y` eKMi7![O6%QCX"uSM[iRdz@E4Ļr <,K^4YxI/;0x~$2;4&"so&il1]^mA+?%KJHx+XTaN2;o?>rp;r3/b(|B:k~xrT奁}hlCkַXV7IڷPKA4޴p$/org/codehaus/groovy/tools/FailsGenerator.groovyXKs6W\WL%UI&ɤOj&U^ Zvt 4lw7n#0&ՊmiiҍV%J s;]%O4*mJEߝ(J]0~މՌJcY|_rBI.1_ IUN&~+&E<'psG 'j"N4>lMa]gJ͖ [ iDvu SHh<8iRˠW`$+tǦwX) l ъ,gI6L0X~cos]*#,"_}fU2Yº'_љ 3!}~Fx_ n3\{ZhZ=>6VtZ9`Q>eE;ʃdj{?$Oس̖)Eua]:PC{ iZχRZc?>̡: 4[2Bmm h 5DIת|6}`y uD5t/ s!ɕwૠ >~G;X:mNह2X7%abz0 bdʥ.$2bm2u$>d N8p%^ [\]< J#XedBӑd]jv9C 3&&FS-Og?SRtB^ 7 k@U.+Cdp^&!`FhvBQ¦KlNxPr];pRܹ ƏH"5 Y+W8 nFD!bږHbA`V@J"g9|+Bl\4io7j?C i}FC &v g\X޴y^ͲZG ;,thn>dv7\(> >ink?}BG*)أ_dqtm^ub'*JvT܈FbAW0qЭNlwڛBޕ%5RK wу ;`d t/e/cW֊FSb0 p*rpHczH !v<DW(UNNץxh V'#q HF&[)aFU]*fA-c hAPGXL}ĠB0YGx !#t`dFe/86xj\_7}n4vle.Kȍ™F q^0fn⫩3'~0GѸS 'q~s#0BsxxzՃ#~ kT2u_pk9k* *q9;ǥpQkrBns4y':9]9Iq:1ua~:14xxz:j !?~Vt= lWؗv9<> ?BѨo&'/PKA4km7 1org/codehaus/groovy/tools/FileSystemCompiler.javaYmsHί裶cdswu:XW8I8ڪKh#$݌M]_CRG23 'xID TI\cQ`L2Ĕ2f`| ˜$*8X"R UYd#1u 2P .-X"$F(!Bp=zܔj) g<|cAs&q Xx2*dud9%&Lțu"֦d@&HyΖ4n7`G+FIϐiOPMČB{ot *bYP# YҔb(B(b@3.h3> a[%"F0Ba1WYΔyݮiEvxM;{o 7[sCϱ'q曆*''9/cr]9`ߍ6ޢezv=Ҁȃ}g{(:nrzӼ\6nН cd`:08kշ>=D`[C[s0hT$ܞ[ -h^,ێ0)a~K!mowll~0!hԵ=A!| }d!*);&uGwrz7,4 r\˹{{ V}xr6+|VCrسGvnGS^du'H_i6Hw*W R`bc`<஄.m((F1Wpӡ՞Rnys.]d蒓?-KRZ̠,$ 뎧6Lbj+ SS"Dpzme7yMݫ.+"Ϣ$vs]韾(8mȓ"ڠY˛3J&dnijQzW;;JZk FJ_uG:Nayyxv+.u!}1tt7 Yys@y%Y;af* ɳ^bW޳hɷxnj*gbXMƴZ[lm_]D` NyT"LTV:N[o(A͑zcm5֞0l*;e>h|0u8<ٟ~0S襱l4PKA4Ȑ|#org/codehaus/groovy/tools/Grok.java-L= 0+A;TtAM4&6' 7>ǽ'YG462&1wQjQ 5 $ 79"9dƎ5J8niH.[)EҎ¤&hF_f* nz+d(3oѓ샽\A|PKA4'b*org/codehaus/groovy/tools/GroovyClass.java} 0D=*H^OՓ %!YJLPIB\P !fRⰔ L3Y:eI Syip$H"7dfK…yC_b"3d|,h'Qzj񊋌`I7", c]-ܸ#f'ue[GEd4sw" ䷈@}4\Ϣd{MU?ر!0ɦ)9u؀P]lS1@V+.ڇU9suNgmPYk` t&:>*LJ=2' SGTp:"MQTPRX UG#8&l۴)aܒ#-g8 :% ˸CEȺ:Q/;ix>OYj֠oupوXȖov[qB~2E'e8q`YJ72V4[k9Kf;J^^6ğv!{/x .=׾DA&jC3a/!^ ]W Kz?n0/hd,QRmBo_,M<U6p6fYҽpZ:0 >|}s,ya('Eq/g:z<Mej>K _ԧLe)*`yۑzeIE.vjVU5nVӦ%AzϞ Z/Uq~mx@ MfaԠKf̧x˯*SFL9asyjDӊ5,vWE <4QH_pJH.67H?L!7E':vGv*Іȓ4 5zK)CFNMM1jJu5R}-}$35ƙ~k-\6.b#" ,H}iO /ROxe|-}MfE^#= PKA4} &2org/codehaus/groovy/tools/LoaderConfiguration.javaZmsV_qC2kaS۝: b"Ht.FXIqS}ιWo H3XޫOB "o!^.m~Z{^^[ī/kϿxbxػxahw+^Se"4+/^LV~ c"JX&2 0r'i϶ m)HW~"h>x/Ir!|af͖xӕbXG ykK~J|6qt/HW^ R, ṆpQDk^ƹ%*'kmI*bz~(C@[IJ'lM\&c H=1ˁUL%BMIYt/ B-??VJk$ȝ1 %+!6|a%&50}CŔ%`׷i8h*fEB(:JYGe-F6Ě2.hϡz$R֐caS^YyI/>ˡO)f:[64~΀a$NI5 q;4eo,2*£l?B' G' 1SOZ lXxKz"!3Ӭxڅ>}e`*ɶFsȃK$04x4NDG ?d +r3o3˥RĐJc2DJ8$5^a OEwrH󺆐S>W{Qh;g;IֺG$YY)*6Ru:b6x )zWw#Itط[HM1 >'IuLjeꂟ $jiq \' ڢ^AحZ"ڑIy:q0; <™ED<|e *﹧b-teW+cQDwxu@ʳ>!+BeY"N0&fҳ1!Igg=)ԏ,=ϼuX.K^Qǀ0ͩFphz'`}.('V3z8W`_~7F8x'Y^s,;)m]o4FOΚyZ__{T:Jڒꀢ8;K`Q/ LdK,i.& QiYGB.yD$ٽXa*N'Ƶj-|ܷ~{EV5{e5Fx$5?,.1fLeY1/աeMǚon,0VMǎρ[۟Ĝ\(gnАvG/}1ʑڝ AoKp8p q<}9)nJ^'/>W:9[¡I:% Zcm1IZyFױ3EjRF7w=ω+:+c;Tzcd CTsj=VEԑ )b#@:K2ԋ%xi;O@Xbܲ }xX(;u2yki/~~쾫\v| nEݢ~ \kq1|jd 1{;2bd1^A g=/H/泙PkvzTз$+Wy{^gPRFLQFO_3r*gzlQ _ViŔBPsڇ\1JmDBcMUS)kaqZɠ+M,ՀD^)gc-1 cHPe(Nj !0&3u'w-;VuG&VdL^jXPxR k7Қb%hY*uwdBRI. R$ MFWM %hg&ZYLEQhe@Tl8_;َ`_RT-ABOMU._t?@[&D9O,"k)dfs6GlH,qFW+Q~y8?hZf5Up!<=gsi]NOASlje|>&| .>Q|7W4"w<ėqxFo4=ӏ' ($fCw~ԧ`썦`O0'1 XqD FnpQS?㘢+w4r"dq$]@^|AGnԧ~]،N!4t~C> o׌$DӋ(iӇdȀ?hi߇Վa<1/Q Ʊӛ8-(Fpu2'c*ؙ(s핏!ryqW @`Li [ "q busCTj_gKracXa$> lhʼ+K7ɩTKncQGV*'[UYOA!4?u1,8ɉC'88ѝ'3[Lg)ʵZ[ܳݎ. ~-ZnyWhHICC-ZJ;3ukUѱ&X@hE55n Hl&Ƚ3+z@.NEL7҅`9gD3{UH*/cҜ93ANb%Fve @\ Tq ݱ>ɫ5-G&ʊՆ|74z,H̱jv6rSxmhzwa6G8;h O |1.(09h1Yj&{fIA*({7 eެNlVJ$׀[[Jyڂ#ԦΔ"}`΅>& 6㦦͙E6;(GEG@GYq8+M"+mEi89X!3gMz.NjQ/|Fy¿uϿ47l-9mA+Bzz2^뒸g;C׃EV{GޑyvU /PsVj-+G!5/ )H6%?2zǃ u*yɓ67=^G_/sް ŲNcW51`q .^R7I˞]BKs Qk_}C/zk =X/J[]c/Ɲ,1zhF+މPaǻb36@(7&5g{G3q t= tk@]pBEyD2R>@VIr Y gimppcFFhYoΖTw*nyg[`wVPK@4a(org/codehaus/groovy/tools/Utilities.javaKO0 VO+> dEq*BPǍLq25ZģIQ}wJmKKwC֧mc*w*O"uGŸm<*ҡCd2Cј᭧XK@/"&:ȉj@XWٔ)0 AUN-,leΏ bxg0Hn-]aC {rSU!apO&`AW1_H_3r7dny/g8IZ%t6(krVE_|~7EScnզet߄7ٍu$}ًa x5 mYW !pJ]7PK A4org/codehaus/groovy/tools/xml/PKA4 GB p,.org/codehaus/groovy/tools/xml/DomToGroovy.javaYmsH_Q(EV]Ine ɒPekE@Ȏ7~ MT 1tOwdMʉQt}t5<gO_g/4vK7w:0ַL9=h] =8.tq: ,bJb ,y>*/6eAt O .7f|Mh) S:umAO;ڤ<_p>5W~Jqt{>7? . n QĕpKzMM`!&I!fB$h1#Q%:4$rnDdr$@'G|ִ .Ѝoѥx[{]݋蚕f : ;-B͋W,&c%D5Dsa,nUr|{CL2^fp(eШXE1OLRWQ{.q1s0ϛ"YֱOSz7%K2 / $c܄e\e"g+rgn. @)D+]9tWXE\L+iwVnx#B\B7C?q4] N]k{v-̚58mNcXܙYv~}h#_N߃2lggQ5:a&9}ҁ́yj:H\cfpjX9<2'TvtQΆc擡gslf@NM{4˜N0SdҩzIv;vQ82c2F&9†M`#w:3I0 ͑a<<1F Jhnd2aϏltof1۰ޚ#>xm:!W2+\磹mr̩cX1g^Nf 8cٔͬ$p!r@lmtQt$7ajoȠ97mmZMf|Zmڕ=J9(BPcئDN[ɠv+*nW$ ?N_8E4J|!ܒ:G:_8r@g>q婻Vk2B>LR0Vkc0FZצXܼ)""[Y!օ 3"e v73~%ˣaQDgǫ';1 bt$ߝN$c&/HNb1taWݕit7v,DY}]^\5P)lkt8KE/us |f_coJCK?DCQ >ƴTiD;Twb^e Qȧٵ\`5`88t-6+; XFKIsfDM`hY7&6CI5M<}mr.b~:lZ vS,&ȹmx* FtgD4uz*;S}y7XFإiJ+Ėd=Q#uWn |XY d&TXaϨ4 G !*]j=x ьwջ:*3p',rz9K7fK%!g/k]^i=|Ejb"҉pUN#n5bW/Jۯ[)p&iDڸ#҈ȑqM]-jd`%j*SL¿?t 9% )FAsxC>{y_Pvfܴ)OMz)t?ă+팲hDJJ؏l/!S~z \^q\ 7}0MeK49z| `<ZU.HJE_eu Tw}٠qQ=ݹp񸩯}mXP:nZׇ켢69`{C5d[G$ {7Ւ/Ju\^"K+SC@4xn%0xf@Vr0d06B,-ӂ<{5Q\KO}A :2w|94B3uc41yxҊ&7x3 G-/6.ݭq-}ٍhn"RS\yH3uh\d>-R0?!!LGMOV'`k":;<a P }ӢHkbTeO1{ŸG?m?߶.T7~fl&g}O}NUݱD46nJ&hs퐋fyH <*7[T\w34|X0?*U,8\^b]d_fWz`ɡזUed܋?#3Cl4ٕ[EަJW*pשM&lXhP*UA3ߥhd矍U{ɥf[vJWPȪ[nm#BМW\MLL=!3$b~rOʿP#Wt;n861,*aJyQ+(U%B֯*);N1M>be6bgO1_f )_V꼓W*-} -_A jCQ\L3ZTV3vnQ>/<#ſ4{W{ޒo?Kw-Ut_rCG]6*w )Jhv_We$4:M{8g L,L!Lcp̸̘NHI,c1WyƅQ1l(1^BBxbsf!iՠQ z/<g01H˶LyF@ )y 3`"Dt HcNZJkYv.[[^+rW\F UbUe!OEAV R1#Ǖ(`QC 5)Y "?zJ< $WqF 3[Y2$sU&RwMZϱL,Ѹ"jcJH:G"$W)0yӪ0(,uEnAgQɠS:qӄcs,< U,$ґTѦbQ@&ȑ&y攷pEe[$0ʐ%*URh?[0[k& [c(L)_UQβlqnV6"w&x=~ ] pсΠ#~^?lUίC}x{."g[;Q߶QjsAK[Ճ ;^kd nܠ0zÑ7PP]lby} Wgz(Ѿ9u=`Q"Cп^ q`l[w1B!\}o:HccN0#ܓH?7]r}u; N m6.w5kn?pIVG:len+5W(|[ IpJm>yOVЁnqa5b jk| 7pWkbo^V3CuX { yB ''Kcs[^yfRw#=sгʑa%Lxx(w*)܍!Q\C F}<~'/x7/3$ f{rP4-Fv!$=eYI_ хK%ZԖœNs`#PdjPЧRBuZ,Oa ͓BV=%֨kI\tu0i[[FIopvP14Zgz@mH*iICZNf@ !O4Pgҙ5dc>!euYk~DWRg"U]hH&ES+i0`jQR6PqZt>9J8?|ᷳߛU/q,T9 JQe)lIagc K0B~2nBds;P/bѠFIj?ro7ߌXtz]L5N܊ SF+N.gEW}lK;{@}{gUǢ5<(C0ۚB_|;; n6l9S#ַUt.UqƵ hby}cLED%B2ţWO~m1J9R.(gxzYxqԏ'Jvw7zD_,+ j cl6EA #Y kVhʥePKA4rg i+)org/codehaus/groovy/wiki/Wiki2Markup.javaZsHCveyUq.m'E0x^ /)٪%A7O{O.^O>_WWx囓WO޼WO4K\oF`~^) VCxSP&:H20C),y`l XY ƒ%>uS6 t*HpS)y C䵛S.w .CL$0.WɊ\ŀn>zn"Q)B+ 2HEХR(b0;,%xm4й0b$2HQw +t3| 7.peӓPuזr~7M752Gp 0Luq;Nc ?g'0?ئ kr3+Jӹe::XvdMt@)=0&3kl&=Ɵ kl?\Z)KT7= 71Yp<&˚N0?98׃W;GDcSA?GmXT~%0lhXZh3NQc!aW҈ fdxk2^8sk~;7j6=pL543[Q|U >ţfMm̭׳; q0G<)w#4?Tw&޷)+xGX Dof$9NٜuPD#)-O5olmL"(\Q'2(&(.`4!dx%0 /:&C ~UɏP!LW*OY<:<}iGQ_/`G5'GQ.GY#> ^ CM s!ϱ2Y[%>W2ƢTŖA`9QSmeE10Z {Q5ʲ+$z4N ]2Eg}ZJɳ- 2S@u^6HEs:ԊZZ 9;xza{E)I,ļϵ*xE^_Kj†VMqzƂRkߺ;irB阭ծ+xnyqdS-x=8lsNRoKd%ꪍ4Z('x&AZ1]ͅO4へ5f'|V坋[C>A৘DC۾/y[:^K UKDӠ53ujHf,WldNAK.&Ҩa:jtՖq..QW匦+p^=_rݥ.aCַֻET[읢ƵW|tM 2O* i`bV)*XxY*mo3R};Z}U՗-5xlP?PKA4MK[ +org/codehaus/groovy/wiki/Wiki2TestCase.javaVOFߟb!]irUjAqSbJg%;Twu k̛7of <:o$2#_u[qN޿? NWS,_dxj|Q;{)[ C2 ; k%P,kQB"kjZRT/!L 7rբBRTuf+5ѹKԤE 6byǀč˨R̅DFY(sY Vȓt'L?!%ܲBEH!fwj-^hn8%m]%{""e&B۰VƽYJ0Bh K͹as;S:sӦt'lˀ"QJuf24/Glsm{TmclP PEغ]ZR`}kr>[W6}vik%:HXXgqJdRH33gP@sTGhd`boo/}5` cYA첰)̑fe@?;E]6fW+P]7~i]hĮYB~8K|8K8?˻wno},I'1ȱ%=a0xx#xF)K֏ 8«?cڐ]4D<@8~`6ci0Ix}>a#5 SJNDiYyx̂Mfoܣdn3C2~|۳M3aFĿd/MP` !0Iy:K]FR(a5XrN(qzCw0ppSdziʣУ&t`#W(tB(VnVQI [!"TLwҤ]% fg# s~k7>\ڶJwzI5@k4@7t 6ۥt4VY-m.6'JYuJE5f#\ЇNbv V,gCf.FX1kWǾY XABsWʜpR !񈽨|`CiVnN=;Vf'./ssk<574ߩS=tZd).g.ڋn1+wW4'l>>.n'gԡ*|kB=~mEno4erSw( [mUfl?YMv^8U65iPK @4Agroovy/PK A4A%groovy/inspect/PK @4h ;2Rgroovy/inspect/Inspector.javaPK A4A groovy/inspect/swingui/PK A4+ groovy/inspect/swingui/ObjectBrowser.groovyPK A4&ZQ$ groovy/inspect/swingui/TableMap.javaPK A4cvM1'groovy/inspect/swingui/TableSorter.javaPK A4 Au(groovy/lang/PK A4'7 %(groovy/lang/BenchmarkInterceptor.javaPK A4QA4+groovy/lang/Binding.javaPK A4e12groovy/lang/BitwiseNegateEvaluatingException.javaPK A4U7groovy/lang/Buildable.javaPK A4u﹖e 5;groovy/lang/Closure.javaPK A4 !sIgroovy/lang/ClosureException.javaPK @4渐)$Ngroovy/lang/DelegatingMetaClass.javaPK A4qq%Sgroovy/lang/DeprecationException.javaPK A4;c Ugroovy/lang/EmptyRange.javaPK @4VP!&"Xgroovy/lang/GroovyClassLoader.javaPK A4e?!+zgroovy/lang/GroovyCodeSource.javaPK @4?5$egroovy/lang/GroovyInterceptable.javaPK A417}4$1groovy/lang/GroovyLogTestCase.groovyPK @4YWg0 groovy/lang/GroovyObject.javaPK A4kXl $Igroovy/lang/GroovyObjectSupport.javaPK @4#lH]G%groovy/lang/GroovyResourceLoader.javaPK A46;g 'groovy/lang/GroovyRuntimeException.javaPK @4:Wgroovy/lang/GroovyShell.javaPK A4+J`i }groovy/lang/GString.javaPK @4wr /groovy/lang/IllegalPropertyAccessException.javaPK A4w?S 37groovy/lang/IncorrectClosureArgumentsException.javaPK A4,bgroovy/lang/Interceptor.javaPK A4n1 7rgroovy/lang/IntRange.javaPK A4; (groovy/lang/MetaArrayLengthProperty.javaPK A4ӝAD g8!groovy/lang/MetaBeanProperty.javaPK A462mcgroovy/lang/MetaClass.javaPK A4yK4groovy/lang/MetaClassImpl.javaPK @4"A 3)"ggroovy/lang/MetaClassRegistry.javaPK A48pn $6+groovy/lang/MetaExpandoProperty.javaPK A4 ^W"0groovy/lang/MetaFieldProperty.javaPK A4! 8groovy/lang/MetaMethod.javaPK A4` ,! 8Cgroovy/lang/MetaProperty.javaPK A4NR &Hgroovy/lang/MissingClassException.javaPK A4% &Ngroovy/lang/MissingFieldException.javaPK A4Ŝ) 'Ugroovy/lang/MissingMethodException.javaPK @4D_0` )[groovy/lang/MissingPropertyException.javaPK A4,a !agroovy/lang/NonEmptySequence.javaPK A4}; F-$ggroovy/lang/ObjectRange.javaPK A4׈tgroovy/lang/package.htmlPK A4yM tgroovy/lang/ParameterArray.javaPK @4ϫ: zgroovy/lang/PropertyValue.javaPK A4Yy*groovy/lang/ProxyMetaClass.javaPK A4Jn _groovy/lang/Range.javaPK A47A *groovy/lang/ReadOnlyPropertyException.javaPK @4$1t Dgroovy/lang/Reference.javaPK @42 &groovy/lang/Script.javaPK A4\I˶ fvgroovy/lang/Sequence.javaPK A4x9ccgroovy/lang/SpreadList.javaPK @4b.հgroovy/lang/SpreadListEvaluatingException.javaPK A4]}groovy/lang/SpreadMap.javaPK @4Փ`-8groovy/lang/SpreadMapEvaluatingException.javaPK @4o (groovy/lang/StringWriterIOException.javaPK A4Xx#groovy/lang/TracingInterceptor.javaPK A4y|groovy/lang/Tuple.javaPK @4aK% &groovy/lang/TypeMismatchException.javaPK A4=G groovy/lang/Writable.javaPK A4 ADgroovy/mock/PK A4S5^?P)ngroovy/mock/ClosureConstraintMatcher.javaPK @4uמDgroovy/mock/GroovyMock.javaPK A4Agroovy/mock/interceptor/PK A4TC%8groovy/mock/interceptor/Demand.groovyPK @4 8*/groovy/mock/interceptor/LooseExpectation.groovyPK @4RZ<&wgroovy/mock/interceptor/MockFor.groovyPK A4l6k.groovy/mock/interceptor/MockInterceptor.groovyPK A4O5/groovy/mock/interceptor/MockProxyMetaClass.javaPK @4Z1 $groovy/mock/interceptor/package.htmlPK @4\I! 0agroovy/mock/interceptor/StrictExpectation.groovyPK A4?&groovy/mock/interceptor/StubFor.groovyPK A4 Ar{groovy/mock/package.htmlPK A4 A#groovy/model/PK A4!}Ngroovy/model/ClosureModel.javaPK A4/$groovy/model/DefaultTableColumn.javaPK @4[m6F#groovy/model/DefaultTableModel.javaPK A4HߗD G groovy/model/FormModel.javaPK A480$K"groovy/model/NestedValueModel.javaPK A4 groovy/model/package.htmlPK A4= }׾N groovy/model/PropertyModel.javaPK A4eM}groovy/model/ValueHolder.javaPK A4-3 #groovy/model/ValueModel.javaPK @4A'groovy/security/PK @4h#1T/&(groovy/security/GroovyCodeSourcePermission.javaPK A4A)groovy/servlet/PK A4,'5s7')groovy/servlet/AbstractHttpServlet.javaPK @4 j!K;groovy/servlet/GroovyServlet.javaPK @4rLC%Fgroovy/servlet/package.htmlPK A4c}2 "Fgroovy/servlet/ServletBinding.javaPK A4{'T#Qgroovy/servlet/ServletCategory.javaPK A4dDmD#pVgroovy/servlet/TemplateServlet.javaPK A4 Awkgroovy/sql/PK A4*6tkgroovy/sql/CallResultSet.javaPK A44 Jmgroovy/sql/DataSet.javaPK @4  'wgroovy/sql/ExpandedVariable.javaPK A4uG&,xgroovy/sql/GroovyResultSet.javaPK @4u3bgroovy/sql/GroovyRowResult.javaPK A4Ggroovy/sql/InOutParameter.javaPK A4ďDgroovy/sql/InParameter.javaPK @4Xgroovy/sql/OutParameter.javaPK @4gw~groovy/sql/package.htmlPK A4-D4q%groovy/sql/ResultSetOutParameter.javaPK A42 !RGgroovy/sql/Sql.javaPK A4PDvgroovy/sql/SqlWhereVisitor.javaPK A4 A7groovy/swing/PK A4Abgroovy/swing/impl/PK @4n ׮&groovy/swing/impl/ComponentFacade.javaPK A4 &groovy/swing/impl/ContainerFacade.javaPK A4aǸL $groovy/swing/impl/DefaultAction.javaPK A45SY groovy/swing/impl/Factory.javaPK A49groovy/swing/impl/package.htmlPK @4bWF  groovy/swing/impl/Startable.javaPK A4>at "groovy/swing/impl/TableLayout.javaPK A4W0&:groovy/swing/impl/TableLayoutCell.javaPK A4$DŽ%Zgroovy/swing/impl/TableLayoutRow.javaPK A4iz}!groovy/swing/package.htmlPK @4[. groovy/swing/SwingBuilder.javaPK A4 A!groovy/text/PK A4 2j $&!groovy/text/GStringTemplateEngine.javaPK A4Uħ7,groovy/text/package.htmlPK @4G:E $%-groovy/text/SimpleTemplateEngine.javaPK A4 /8groovy/text/Template.javaPK A4xi =groovy/text/TemplateEngine.javaPK @4>X"Bgroovy/text/XmlTemplateEngine.javaPK A4 AIgroovy/ui/PK @4 CMJgroovy/ui/Console.groovyPK A48];`groovy/ui/ConsoleSupport.javaPK @4)<ggroovy/ui/GroovyMain.javaPK A49ء!xgroovy/ui/GroovySocketServer.javaPK A4eKԁgroovy/ui/InteractiveShell.javaPK A4n {groovy/ui/package.htmlPK A4*tɘgroovy/ui/ShellCompleter.javaPK A4"J&groovy/ui/SystemOutputInterceptor.javaPK A4 A9groovy/util/PK @4-jcgroovy/util/AllTestSuite.javaPK @4ZӺ #groovy/util/AntBuilder.javaPK A4TY groovy/util/BuilderSupport.javaPK @4Mv/?Կgroovy/util/CharsetToolkit.javaPK @4ʣ~ groovy/util/CliBuilder.groovyPK @4δv9R "groovy/util/ClosureComparator.javaPK A47 4 %groovy/util/Eval.javaPK @45udgroovy/util/Expando.javaPK A4Uu2"(Dgroovy/util/FileNameByRegexFinder.groovyPK A4j!Cgroovy/util/FileNameFinder.groovyPK @4 Vgroovy/util/GroovyLog.javaPK @48ȹ 8mgroovy/util/GroovyMBean.javaPK @49X<#groovy/util/GroovyScriptEngine.javaPK A4"FL!4 groovy/util/GroovyTestCase.javaPK A4[˝P Agroovy/util/GroovyTestSuite.javaPK A4s %groovy/util/IFileNameFinder.javaPK @4C %groovy/util/IndentPrinter.javaPK A4L" +groovy/util/MapEntry.javaPK A4 %32groovy/util/Node.javaPK @4oYm s=groovy/util/NodeBuilder.javaPK A4k62 Cgroovy/util/NodeList.javaPK A4@Ggroovy/util/NodePrinter.javaPK @4Kj KOgroovy/util/OrderBy.javaPK A4F‰vUgroovy/util/package.htmlPK A4 g RVgroovy/util/Proxy.javaPK A4*s "j\groovy/util/ResourceConnector.javaPK @4n } "agroovy/util/ResourceException.javaPK A4"FG fgroovy/util/ScriptException.javaPK A4Algroovy/util/slurpersupport/PK A4`M*Rlgroovy/util/slurpersupport/Attributes.javaPK A4R =t28qgroovy/util/slurpersupport/FilteredAttributes.javaPK A4.b4tgroovy/util/slurpersupport/FilteredNodeChildren.javaPK A4Y4K+Exgroovy/util/slurpersupport/GPathResult.javaPK A4ls\ *xgroovy/util/slurpersupport/NoChildren.javaPK @4_Ǥ!$groovy/util/slurpersupport/Node.javaPK A4G|b)groovy/util/slurpersupport/NodeChild.javaPK A4/ '%!,’groovy/util/slurpersupport/NodeChildren.javaPK A4_w{, groovy/util/slurpersupport/NodeIterator.javaPK @4}v vΜgroovy/util/XmlNodePrinter.javaPK A4B .groovy/util/XmlParser.javaPK @4 z/groovy/util/XmlSlurper.javaPK A4 Agroovy/xml/PK @4Agroovy/xml/dom/PK @4ǵ… @groovy/xml/dom/DOMCategory.javaPK @4s ` groovy/xml/DOMBuilder.javaPK A4@ *groovy/xml/MarkupBuilder.javaPK A4\Bgroovy/xml/Namespace.javaPK A4 + groovy/xml/NamespaceBuilder.javaPK A4]$jv '2groovy/xml/NamespaceBuilderSupport.javaPK @4y I=groovy/xml/package.htmlPK A4a (groovy/xml/QName.javaPK A4OYgroovy/xml/SAXBuilder.javaPK @4[i s,%groovy/xml/StreamingDOMBuilder.groovyPK A4gT +( groovy/xml/StreamingMarkupBuilder.groovyPK A4"Agroovy/xml/streamingmarkupsupport/PK A447Yb7A]groovy/xml/streamingmarkupsupport/AbstractStreamingBuilder.groovyPK A4$dﺴ8Ygroovy/xml/streamingmarkupsupport/BaseMarkupBuilder.javaPK A4ʈ0 .c"groovy/xml/streamingmarkupsupport/Builder.javaPK A47N7<(groovy/xml/streamingmarkupsupport/StreamingMarkupWriter.javaPK A4 .%30groovy/xml/StreamingSAXBuilder.groovyPK @4Au:org/PK @4 A:org/codehaus/PK A4A:org/codehaus/groovy/PK A4A:org/codehaus/groovy/ant/PK A4"8/Z9*;org/codehaus/groovy/ant/AntProjectPropertiesDelegate.javaPK @4[ b)MBorg/codehaus/groovy/ant/FileIterator.javaPK @4'k (Korg/codehaus/groovy/ant/FileScanner.javaPK A4eB/9#Rorg/codehaus/groovy/ant/Groovy.javaPK A408!->$eeorg/codehaus/groovy/ant/Groovyc.javaPK A4p$xworg/codehaus/groovy/ant/package.htmlPK A4wm*Rxorg/codehaus/groovy/ant/RootLoaderRef.javaPK A46o (corg/codehaus/groovy/ant/VerifyClass.javaPK @4a KP^org/codehaus/groovy/antlib.xmlPK A4Aorg/codehaus/groovy/antlr/PK @4 hnF0"org/codehaus/groovy/antlr/AntlrASTProcessor.javaPK A4SN 6ގorg/codehaus/groovy/antlr/AntlrASTProcessSnippets.javaPK @4P5a=0org/codehaus/groovy/antlr/AntlrParserPlugin.javaPK @4=R7Aorg/codehaus/groovy/antlr/AntlrParserPluginFactory.javaPK @4[ufK 1org/codehaus/groovy/antlr/AntlrSourceSummary.javaPK A4+Qi1 org/codehaus/groovy/antlr/ASTParserException.javaPK A4(v2org/codehaus/groovy/antlr/ASTRuntimeException.javaPK @4 z )"org/codehaus/groovy/antlr/groovy.gPK A4XBb .porg/codehaus/groovy/antlr/GroovySourceAST.javaPK @4)torg/codehaus/groovy/antlr/LexerFrame.javaPK @4q_") }org/codehaus/groovy/antlr/LineColumn.javaPK A4lA#Oorg/codehaus/groovy/antlr/Main.javaPK A4!Aчorg/codehaus/groovy/antlr/parser/PK A40fa-u1org/codehaus/groovy/antlr/parser/GroovyLexer.javaPK A4u$/6org/codehaus/groovy/antlr/parser/GroovyRecognizer.javaPK A4w=E6norg/codehaus/groovy/antlr/parser/GroovyTokenTypes.javaPK A4^A59vorg/codehaus/groovy/antlr/parser/GroovyTokenTypes.txtPK @4݇&N@+Eorg/codehaus/groovy/antlr/SourceBuffer.javaPK @4!A܄org/codehaus/groovy/antlr/syntax/PK @4ߌ 6org/codehaus/groovy/antlr/syntax/AntlrClassSource.javaPK A4%ABorg/codehaus/groovy/antlr/treewalker/PK @4b)_* :org/codehaus/groovy/antlr/treewalker/CompositeVisitor.javaPK A4;m H8org/codehaus/groovy/antlr/treewalker/MindMapPrinter.javaPK A4 b B;org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.javaPK A4v2{5Worg/codehaus/groovy/antlr/treewalker/NodePrinter.javaPK A4DU;ܰorg/codehaus/groovy/antlr/treewalker/PreOrderTraversal.javaPK A4^ ͮ*=ٳorg/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.javaPK A4RQ ?7org/codehaus/groovy/antlr/treewalker/SourcePrinter.javaPK A48%ӆ:org/codehaus/groovy/antlr/treewalker/SummaryCollector.javaPK @4(9Corg/codehaus/groovy/antlr/treewalker/TraversalHelper.javaPK A4$O31corg/codehaus/groovy/antlr/treewalker/Visitor.javaPK A4̈gfM8org/codehaus/groovy/antlr/treewalker/VisitorAdapter.javaPK A4 =4vorg/codehaus/groovy/antlr/UnicodeEscapingReader.javaPK A4Aorg/codehaus/groovy/ast/PK A4Wz* org/codehaus/groovy/ast/AnnotatedNode.javaPK A4S +org/codehaus/groovy/ast/AnnotationNode.javaPK @45-D!$_org/codehaus/groovy/ast/ASTNode.javaPK A448B4 org/codehaus/groovy/ast/ClassCodeVisitorSupport.javaPK @4w ,(Lorg/codehaus/groovy/ast/ClassHelper.javaPK A4o&org/codehaus/groovy/ast/ClassNode.javaPK A4eQr ,/:org/codehaus/groovy/ast/CodeVisitorSupport.javaPK A43]m (`Dorg/codehaus/groovy/ast/CompileUnit.javaPK @4Rk ,Oorg/codehaus/groovy/ast/ConstructorNode.javaPK A4oʀ,Uorg/codehaus/groovy/ast/DynamicVariable.javaPK A4AWorg/codehaus/groovy/ast/expr/PK A4c[D 8Worg/codehaus/groovy/ast/expr/ArgumentListExpression.javaPK A41]org/codehaus/groovy/ast/expr/ArrayExpression.javaPK @4j(5Cforg/codehaus/groovy/ast/expr/AttributeExpression.javaPK A4͝oJ82morg/codehaus/groovy/ast/expr/BinaryExpression.javaPK @4? 6!uorg/codehaus/groovy/ast/expr/BitwiseNegExpression.javaPK @4&Ɏ 3xzorg/codehaus/groovy/ast/expr/BooleanExpression.javaPK A4AZ0Worg/codehaus/groovy/ast/expr/CastExpression.javaPK A4H.}tM 1org/codehaus/groovy/ast/expr/ClassExpression.javaPK A4X/`/w3org/codehaus/groovy/ast/expr/ClosureExpression.javaPK A4>I4)org/codehaus/groovy/ast/expr/ConstantExpression.javaPK @4fR4;ęorg/codehaus/groovy/ast/expr/ConstructorCallExpression.javaPK A4DN5 7Qorg/codehaus/groovy/ast/expr/DeclarationExpression.javaPK A4: ,\org/codehaus/groovy/ast/expr/Expression.javaPK @4k7C 7org/codehaus/groovy/ast/expr/ExpressionTransformer.javaPK A4+! 1org/codehaus/groovy/ast/expr/FieldExpression.javaPK @4^`3org/codehaus/groovy/ast/expr/GStringExpression.javaPK A4 %0org/codehaus/groovy/ast/expr/ListExpression.javaPK A4ck 4org/codehaus/groovy/ast/expr/MapEntryExpression.javaPK @4 Ox/org/codehaus/groovy/ast/expr/MapExpression.javaPK @4>6org/codehaus/groovy/ast/expr/MethodCallExpression.javaPK @4'~S@9org/codehaus/groovy/ast/expr/MethodPointerExpression.javaPK A4$iA =Xorg/codehaus/groovy/ast/expr/NamedArgumentListExpression.javaPK A4o 4org/codehaus/groovy/ast/expr/NegationExpression.javaPK @4\ /org/codehaus/groovy/ast/expr/NotExpression.javaPK @4.s)org/codehaus/groovy/ast/expr/package.htmlPK A4jm 3korg/codehaus/groovy/ast/expr/PostfixExpression.javaPK A4:  2org/codehaus/groovy/ast/expr/PrefixExpression.javaPK A4k!4 org/codehaus/groovy/ast/expr/PropertyExpression.javaPK A4 OMjE 1% org/codehaus/groovy/ast/expr/RangeExpression.javaPK A4$ʄ 1 org/codehaus/groovy/ast/expr/RegexExpression.javaPK A4bN 2 org/codehaus/groovy/ast/expr/SpreadExpression.javaPK @4~ts 5 org/codehaus/groovy/ast/expr/SpreadMapExpression.javaPK A4v?4<I org/codehaus/groovy/ast/expr/StaticMethodCallExpression.javaPK @43% org/codehaus/groovy/ast/expr/TernaryExpression.javaPK A4?nk1?, org/codehaus/groovy/ast/expr/TupleExpression.javaPK A4۹Pr42 org/codehaus/groovy/ast/expr/VariableExpression.javaPK @4& y&: org/codehaus/groovy/ast/FieldNode.javaPK @4 /[B org/codehaus/groovy/ast/GroovyClassVisitor.javaPK @4SGI.G org/codehaus/groovy/ast/GroovyCodeVisitor.javaPK A4L 'N org/codehaus/groovy/ast/ImportNode.javaPK @4q9 +T org/codehaus/groovy/ast/InnerClassNode.javaPK A43g1 >'Z org/codehaus/groovy/ast/MethodNode.javaPK @4V &?d org/codehaus/groovy/ast/MixinNode.javaPK @4_k2 ,'j org/codehaus/groovy/ast/ModuleNode.javaPK A4m9,y$cx org/codehaus/groovy/ast/package.htmlPK @4&y org/codehaus/groovy/ast/Parameter.javaPK A4n)> org/codehaus/groovy/ast/PropertyNode.javaPK A4A org/codehaus/groovy/ast/stmt/PK A4-s 1O org/codehaus/groovy/ast/stmt/AssertStatement.javaPK A4[0* org/codehaus/groovy/ast/stmt/BlockStatement.javaPK @4I)s J 0ӓ org/codehaus/groovy/ast/stmt/BreakStatement.javaPK A4Z oc /. org/codehaus/groovy/ast/stmt/CaseStatement.javaPK A4RőMM 0ޞ org/codehaus/groovy/ast/stmt/CatchStatement.javaPK @4}Q R 3y org/codehaus/groovy/ast/stmt/ContinueStatement.javaPK @4q7OS 2ԩ org/codehaus/groovy/ast/stmt/DoWhileStatement.javaPK A4M3o 0w org/codehaus/groovy/ast/stmt/EmptyStatement.javaPK A4C 5 org/codehaus/groovy/ast/stmt/ExpressionStatement.javaPK A46r. org/codehaus/groovy/ast/stmt/ForStatement.javaPK A4fh_ - org/codehaus/groovy/ast/stmt/IfStatement.javaPK A4%#t)[ org/codehaus/groovy/ast/stmt/package.htmlPK A47tK 1 org/codehaus/groovy/ast/stmt/ReturnStatement.javaPK A4b + org/codehaus/groovy/ast/stmt/Statement.javaPK A4WB1 org/codehaus/groovy/ast/stmt/SwitchStatement.javaPK A4.ĸK4V 7 org/codehaus/groovy/ast/stmt/SynchronizedStatement.javaPK A4x3 01 org/codehaus/groovy/ast/stmt/ThrowStatement.javaPK @4ryd 3 org/codehaus/groovy/ast/stmt/TryCatchStatement.javaPK A4DyYW 0 org/codehaus/groovy/ast/stmt/WhileStatement.javaPK A4% %] org/codehaus/groovy/ast/Variable.javaPK A4s*; org/codehaus/groovy/ast/VariableScope.javaPK A4A3 org/codehaus/groovy/bsf/PK A4VF<+0i org/codehaus/groovy/bsf/CachingGroovyEngine.javaPK A4p>j ) org/codehaus/groovy/bsf/GroovyEngine.javaPK A4$$ org/codehaus/groovy/bsf/package.htmlPK A4A org/codehaus/groovy/classgen/PK A4GUN3 org/codehaus/groovy/classgen/AsmClassGenerator.javaPK A4LK 4f org/codehaus/groovy/classgen/BytecodeExpression.javaPK A4aJLY0Ul org/codehaus/groovy/classgen/BytecodeHelper.javaPK A4sIy ]#9 org/codehaus/groovy/classgen/ClassCompletionVerifier.javaPK @4_00c org/codehaus/groovy/classgen/ClassGenerator.javaPK A4Nܺ 9 org/codehaus/groovy/classgen/ClassGeneratorException.javaPK A4[*2P.Ė org/codehaus/groovy/classgen/CompileStack.javaPK @4v" 5. org/codehaus/groovy/classgen/DummyClassGenerator.javaPK @4}pj_2o org/codehaus/groovy/classgen/GeneratorContext.javaPK @4x.) org/codehaus/groovy/classgen/MethodCaller.javaPK @4H]~) org/codehaus/groovy/classgen/package.htmlPK A4 M(4 org/codehaus/groovy/classgen/ReflectorGenerator.javaPK @4@ "A org/codehaus/groovy/classgen/RuntimeIncompleteClassException.javaPK @4<?* org/codehaus/groovy/classgen/Variable.javaPK @4|h66C6S org/codehaus/groovy/classgen/VariableScopeVisitor.javaPK A4]+U4u* org/codehaus/groovy/classgen/Verifier.javaPK A4tD 5= org/codehaus/groovy/classgen/VerifierCodeVisitor.javaPK A4A org/codehaus/groovy/control/PK @4b ; org/codehaus/groovy/control/CompilationFailedException.javaPK A4Wh0G org/codehaus/groovy/control/CompilationUnit.javaPK A4%j961 org/codehaus/groovy/control/CompilerConfiguration.javaPK A4'q. 7VA org/codehaus/groovy/control/ConfigurationException.javaPK @41y ,/G org/codehaus/groovy/control/ErrorCollector.javaPK A4+rm +]S org/codehaus/groovy/control/HasCleanup.javaPK A4ATX org/codehaus/groovy/control/io/PK A4cXM 8X org/codehaus/groovy/control/io/AbstractReaderSource.javaPK A4UdSL 4` org/codehaus/groovy/control/io/FileReaderSource.javaPK @4 5 ;g org/codehaus/groovy/control/io/InputStreamReaderSource.javaPK A4(( .m org/codehaus/groovy/control/io/NullWriter.javaPK A4M.` 0r org/codehaus/groovy/control/io/ReaderSource.javaPK A4 6y org/codehaus/groovy/control/io/StringReaderSource.javaPK A4<: 3~ org/codehaus/groovy/control/io/URLReaderSource.javaPK @4!R ( org/codehaus/groovy/control/Janitor.javaPK A43. org/codehaus/groovy/control/LabelVerifier.javaPK A4%A org/codehaus/groovy/control/messages/PK A4ywXσ:8 org/codehaus/groovy/control/messages/ExceptionMessage.javaPK A4G8 org/codehaus/groovy/control/messages/LocatedMessage.javaPK @4G1 org/codehaus/groovy/control/messages/Message.javaPK @4p!X7F org/codehaus/groovy/control/messages/SimpleMessage.javaPK A4y+U< org/codehaus/groovy/control/messages/SyntaxErrorMessage.javaPK A4d| 8k org/codehaus/groovy/control/messages/WarningMessage.javaPK A4$ƻ$ C= org/codehaus/groovy/control/MultipleCompilationErrorsException.javaPK A4͙-9 org/codehaus/groovy/control/ParserPlugin.javaPK A4o4M4 org/codehaus/groovy/control/ParserPluginFactory.javaPK @4uŽ@' org/codehaus/groovy/control/Phases.javaPK A4/A org/codehaus/groovy/control/ProcessingUnit.javaPK A4yt/v org/codehaus/groovy/control/ResolveVisitor.javaPK A4J%ip0+< org/codehaus/groovy/control/SourceUnit.javaPK @4'z'B org/codehaus/groovy/GroovyBugError.javaPK A4D (\ org/codehaus/groovy/GroovyException.javaPK A4O|1j org/codehaus/groovy/GroovyExceptionInterface.javaPK A4j 5 org/codehaus/groovy/package.htmlPK A4A org/codehaus/groovy/runtime/PK A4$Ks/ org/codehaus/groovy/runtime/BigDecimalMath.javaPK A4f/ org/codehaus/groovy/runtime/BigIntegerMath.javaPK @4w U. org/codehaus/groovy/runtime/ClassExtender.javaPK @4z0 org/codehaus/groovy/runtime/ClosureListener.javaPK A4i/  org/codehaus/groovy/runtime/CurriedClosure.javaPK A4:8ƤFS5 org/codehaus/groovy/runtime/DefaultGroovyMethods.javaPK A4 ; org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.javaPK A4dI-( 1 org/codehaus/groovy/runtime/DefaultMethodKey.javaPK @4l|1c2n org/codehaus/groovy/runtime/FloatingPointMath.javaPK @4?m 5! org/codehaus/groovy/runtime/FlushingStreamWriter.javaPK A448K 6h org/codehaus/groovy/runtime/GroovyCategorySupport.javaPK @4! , org/codehaus/groovy/runtime/IntegerMath.javaPK @4=>%XI 3(B org/codehaus/groovy/runtime/Invoker.javaPK A40' . org/codehaus/groovy/runtime/InvokerHelper.javaPK @413p ;* org/codehaus/groovy/runtime/InvokerInvocationException.javaPK @4W7 org/codehaus/groovy/runtime/IteratorClosureAdapter.javaPK A4e ) org/codehaus/groovy/runtime/LongMath.javaPK A4sC0 org/codehaus/groovy/runtime/MetaClassHelper.javaPK A4t. org/codehaus/groovy/runtime/MethodClosure.javaPK @4Ғ -{ org/codehaus/groovy/runtime/MethodHelper.javaPK A4?*! org/codehaus/groovy/runtime/MethodKey.javaPK A4񔎾6) org/codehaus/groovy/runtime/NewInstanceMetaMethod.javaPK @4xv!40 org/codehaus/groovy/runtime/NewStaticMetaMethod.javaPK A4;Eo +7 org/codehaus/groovy/runtime/NullObject.javaPK @4+$+= org/codehaus/groovy/runtime/NumberMath.javaPK @45ȟ(F org/codehaus/groovy/runtime/package.htmlPK A4~߯ 5G org/codehaus/groovy/runtime/ReflectionMetaMethod.javaPK A46s 8M org/codehaus/groovy/runtime/ReflectionMethodInvoker.javaPK A4x~ %) org/codehaus/groovy/syntax/ASTHelper.javaPK @4 + org/codehaus/groovy/syntax/ClassSource.javaPK A4K5' org/codehaus/groovy/syntax/CSTNode.javaPK @4"r {#' org/codehaus/groovy/syntax/Numbers.javaPK A4 mZm' org/codehaus/groovy/syntax/package.htmlPK A4͂/h org/codehaus/groovy/syntax/ParserException.javaPK A4|P4D-l org/codehaus/groovy/syntax/ReadException.javaPK A4Fl h) org/codehaus/groovy/syntax/Reduction.javaPK A4HN 6 org/codehaus/groovy/syntax/RuntimeParserException.javaPK @4q)gE - org/codehaus/groovy/syntax/SourceSummary.javaPK A4A{ / org/codehaus/groovy/syntax/SyntaxException.javaPK A4$ &%Aorg/codehaus/groovy/syntax/Token.javaPK A4^z2a. org/codehaus/groovy/syntax/TokenException.javaPK A4jU163org/codehaus/groovy/syntax/TokenMismatchException.javaPK A4Tj<׀)%dorg/codehaus/groovy/syntax/Types.javaPK A4A'9org/codehaus/groovy/tools/PK @4\J'_9org/codehaus/groovy/tools/Compiler.javaPK A4W- - -?org/codehaus/groovy/tools/DocGenerator.groovyPK A4]K0S,fIorg/codehaus/groovy/tools/ErrorReporter.javaPK A4޴p$/?Rorg/codehaus/groovy/tools/FailsGenerator.groovyPK A4km7 1Zorg/codehaus/groovy/tools/FileSystemCompiler.javaPK A4Ȑ|#dorg/codehaus/groovy/tools/Grok.javaPK A4'b*eorg/codehaus/groovy/tools/GroovyClass.javaPK A4v x,forg/codehaus/groovy/tools/GroovyStarter.javaPK A4} &2xqorg/codehaus/groovy/tools/LoaderConfiguration.javaPK @4x&Korg/codehaus/groovy/tools/package.htmlPK @4;ZN !)org/codehaus/groovy/tools/RootLoader.javaPK @4a(org/codehaus/groovy/tools/Utilities.javaPK A4AJorg/codehaus/groovy/tools/xml/PK A4 GB p,.org/codehaus/groovy/tools/xml/DomToGroovy.javaPK A4\*_org/codehaus/groovy/tools/xml/package.htmlPK A4A-org/codehaus/groovy/wiki/PK @4?0%dorg/codehaus/groovy/wiki/package.htmlPK A4}Ro2Lorg/codehaus/groovy/wiki/TestCaseRenderEngine.javaPK A4rg i+) org/codehaus/groovy/wiki/Wiki2Markup.javaPK A4MK[ +org/codehaus/groovy/wiki/Wiki2TestCase.javaPKstapler-stapler-parent-1.231/core/lib/commons-jelly-1.0-src.zip0000664000175000017500000047624212414640747023606 0ustar ebourgebourgPK 2org/PK 2 org/apache/PK 2org/apache/commons/PK 2org/apache/commons/jelly/PK2ѐ@d+org/apache/commons/jelly/CompilableTag.javamSMo@Wh 6EɅPJ4 F9.uw81P냿f{of}jod; a#*#ҩkAѵJZTƕw2Fe1 ZE C8^]2^P=(HB* |r ĺ )TH}:f:A *J&pʝA4/Zƾ6YPrmphXwU@kZR݃U,ĵ h"3H1uc* dDZgvL;r$o67 zuрAͷfl 0_-MZ ̖=\^2ϕaDSE(@VT$Me2CHThJiy& SRv7쿺QyO"dK*(0X'8eNP9 Qص%՟ѺID@n0+,?D@D Qbzu;|Ɲ1|8 XZU;4=}4{/k_Љ8U c3 [7tK?1H2fVS\-h ikh6]jQ ]`s]4tQ6L: ۇ PK 2` |. 0org/apache/commons/jelly/DynaBeanTagSupport.javaVQo6~}O΂%q8N+!rW2SHʊ1NeqÌĻIN`وr0EL?^RPpR8QYLЀ'5+# 8 Naf?`.`#v"aH +!S ֛MvbRy"5%c,W2&i*-D-E Gj`0HW}7zw"T e^iED(Tdf۝7tw?&ʎ7WX'xі"'\U^U-ʵܨ>sjn)\SC؊XE#"Sa!1q<&wP;(kU&ikQ5l"`mpu9}H=D~uo'!*a4 cLJ:>|xv 9Bugw *>9Tz]084C:[(y ;&~5;QQԵ#ZMRSt|a@F𚼞\tQ5]%vpW<AajA=(%]_-Uiǃ%Q&s* KPEu?u>!+Apר}v0o8@|c/|hl6jgC3e%]ҿ 陎tCM.aF$(ao~ PK 2E%org/apache/commons/jelly/DynaTag.java}UMoFW C]#تaV%JWԐ\rihQðH̛7oގ6G+ń|M07\j'jJi Tw@h$ Q\L-CuVAi!aHlWƃTP4Ru 3 CopA @>?2˺xm5}wUxOSwՠs` -u=0Ī[ڈQY3ugK2N:o6W M(sXc| ?1|6EG[zEo` _ IFuє,'v9+ )9,eA* :aJF#y@ :M6j4΀fzV^؈j7@0|$(/*jYԜ^l^IPIPZqLoy`NdpA͐O5+01BcKt6%E ZYIz{crcʃA &tύE\'"iG{I8|1k[-Qj"24g77 g mT@oz>6Ez'XZwhNQI,Y\Fo}muiꓡnD m,ǭחO4?RJ="Z*Y&N7Ov  ޓ|["36J=^g_ŢՉt_i=PK2 t},org/apache/commons/jelly/DynaTagSupport.javaeTQO@~ﯘp#sU 3>n˴,{[jc7\C(|}vTF|ca8 {u Dnl4ĚY.E\#OQ\P*j#=P 8u 69rd i2H@ |KQYRY3"n|1C&Q:EOq"0ےZuu]gܗ:} l~Ih h[qM"V)KkjXbV:ֵ斋5'fځ#I?N ۘ$($yVO+x,*ŰXt1VbNOw0C4eߔv &wv{#~=%0OI+#rZ"PKnX \;0r _9}0&[RIE\A킃(k6XWJImG|"cXBVBˆxZ0c\SDmW%==7w$U{0 ո5F 6_˭oak]:{V B6vO%8uJhsx]+ ̢X8z)3ރ3﮽F[i`f2ͶՇXUXV¾H> Y?{+isCQ8%댐 ܻ?ί="]cW>|PK 2$org/apache/commons/jelly/expression/PK2+ǩx(<org/apache/commons/jelly/expression/CompositeExpression.javaZmo8_1'[q47M;INoQDleI'RqrPDr"]`P~Hl3|3Ct<$dఋ~)~7Lj2o<IY^ǒ<U.g-? LwL.fDA.9"*1,szㅐ'#)nl hݦJG|>F'٤cerp~q5x8RB #KUF5bsH2`cJ<Jē.HC T!Ĉ6`p0쒓_7x?|_ .pί nW->Wo2ߥE0Cݐs8) ɔb, -la,ƈ LHZVCrPZr5.4!?Ht9. -<}} $S2?W"Y/վ$xgo(1d ]dAƏBU׮QD3=Ob}3\$=; cN$!]TtA5$!<ԐWE0` AL Ef u0D$yr5E0f||͘Tr5AUll%y]'=v}ܚ zu/-t0  ҊkJ~RI+- $ 4s7C`1~ 1C%>l'.xb Ŋa}*^83,cvֈ}e={}ߞ3V*eXMu)[`DZb2q.U>kMC*ҷ0NGM&Rg#8.%FQ@FHa`uxWist%f ޳.(8޾{zp8Kfv8ĬҳNwJ)`UOAs)Ugû+ zs=ТzC68ZX*RS"Yšz ׵?\EU"&XҘ\&BPtXG)+S$/ HÜY_%|dQ׽fJ ;5 ԰c-#iA=AYaxiD c@c?: Ww ]&3(5D`jFMⶀ;WlJWvIݭn| n3E]im"CEY!׵B> dqj}iBy砻 Uît6V#VcM&3P[V&h d2VF5nZݶ u{sox}s)b>,ݚj+W_n""٦٪6քZԼv' O^ /Y@gic{mkƦ[hdmEw۲;\{]F68yR6wgho fiH-/Ys63Zlk;|jӣBisfX͟!|c=(O- attQp#Ú9~ϒgJpi>yʕP5}L}הtU MGl-d5׺2 +MD҅aHwtj>VE(Db-`wq\˗6h !)cZɯKp~)xv[]JlAiE2G RAWE.J6-:gNP@Γsim6PTCm(cm!g}T9Z Pdz-XbF\sm@diif1Izf.3rVz;d aqa'=O|pjJ0Q1[ tF\"/;ta%~t#d?i3 Q%48VBNPB]G3\ZHR?d7k\K~;^<9@3SHsAߗwWR;+-u{UK4{ѸFIn0uu⍰XkniS-rk=#qG5*| "Z@Uq0Fm_,n)*7y@7Q% [!<.<'x?)o>s_ >qƒvݫߊk-)z?wPK 2 3org/apache/commons/jelly/expression/Expression.javaVߏ8~}خhj_*ݲ:z=N2oXT!,KO}8<`{&jodvps}}3W\#+#+^*Nj[~*9pQh,YMt |/0^װ{PAm0,1ʁTMUJ2tk'00tdPѯA.smvHxƑ6E\6gmqz7%:X}R%Z =Xe"%؁6 4*` KLkD#~|d Iލi2`OK<^,Ƴt|wr:ѯ{Ͼ IF~2є,'^ n( 3ZޢQTh6rZ-|mqG2e՜!r#8x[NԡNn@N+WW0FL8 c@)TaR0{ParVo. y(3N0F[Ck!Ko(\]G-$akQ Mt[W7pH:R#V z\2AWSբTIlʱ 0S@[%Vp=҅"7[kF Ɛҝ#3O0sqL8}J&b-ɱm~!T:6}׬: ApqyD]YK RgkE3}KAz5 [LiC۬MWm F6m hӰ - Gfܦg>Cȿ&4ɲc/|sKee|QkJcxDf<1=gQ]C@e4Nb("tn-; #yC5|l,["ǨJ(G*ZW}Opٚ2٠ yga9R'[3`StM킓Q6{_PK 2H[B:org/apache/commons/jelly/expression/ExpressionFactory.javauS]O@|XE<@i/F!Hq(⬝nUs B?vffQ7.LYoǷsXnFHtFRkARa SThv?:F é/[+ObJTC:d) ե)P)B-iӜӲx%r . 0VtsmeuFqmZ=ē,~a-QX]IˎW;UbZ Q rGګ$6@O\U!7lc :Ib~͏ȡSr02|صhÙ l,f:n0?ѝ(An #1ړlۿd[.' LY!~rf?EA ){sEB=G{ڑ:,j=c.k"PK2:mYX:org/apache/commons/jelly/expression/ExpressionSupport.javaW[6~W2y0;lv!LIYt:aI0lv2,ܿ9jdR|:3pr||Ҧg0!tSӿHN̒)72Kpdf-/y1K& 8 ! M/jά`VHF5L@1x$FXr3sq |>0RgdҷIYI̘Y.!sRM;"՝AջD֠KU Q*wlpg5~Q=ҁ2jDԌ+֔{aW){y;}My[L ~5"Z7#K/c9M{,N;9Yl`Ĉ`DVx93H\1 ˄U@9,*E&4iLdNhfrNs/YF N.sƅw.K^3-SwX^˅OnqSxcxbd#'9؊BhF@;MmKi&Lп}иҽ s n8Иv;j4Hx~ƒ\+9CҜy 9 bWAK4u3\!嶶8Sƀm5ba.}0D--HdGs]6'Bbl2fp[M1DpԽR~Rh&Rߧ_v7X . Ʉ2|d*ɕB#=%;M.o<׾gzdkzlըƮԳDM:JgU,#)o.Ϋ俿9%*`*Z,!G/U ԦnShA[wIՖz֨+!!{L4 {` )&,+ԏpAO4QhjxBV?@ͳ`ቸ+7q*[XV\Ca߈ˡ fKk%=bVHkZEhâڳ5nZLp [krP+-ɇbAm\?4lCD- "]j4?O`dʣ~`{2nLZ[vtbw+ھ)ۓX˾~W~ϻPK 2)org/apache/commons/jelly/expression/jexl/PK2 6HU=<org/apache/commons/jelly/expression/jexl/JexlExpression.javaWsF~j p<ɋgB2%q!d:}8O:tӌJ:ioHtv)\lmln>^hDL_C=+a"+u{^'@7Ѐܝc&'8N d b HRmȑ0dS>̂L!IHc2Ca&ad.!o:16;vWU$JƑ6l=?#c0BxX+ ݳY2Cḓ6Dp}M0[o83#ܻ]!hpsMWw> d3Mrnؠ0: },!)ȳƘX&xݮ4S:ZrkpQ%4΋xmf?үJJǷq_ZֆuRiT9tdap) ~ v뮨K=1DJzT.ْ(N0)CnIn6P&w%kG{ =J{~"pá* zԷ K8 =saZ} u^|_>,ioG}+(twnADU'ZGs*No66 ߱X\iTdiB) ?*l{餭'9kg!~uOFtR{J#,nd%v &pqGMg<Uƭs{ PK 2S8iCorg/apache/commons/jelly/expression/jexl/JexlExpressionFactory.javaWmOH_1bhpj.=*ćI:^zk_u(cggfyeݝБNF'vw:ˉ^" ΅t8V؇k@Ʃ Ґʕ}&@\joh*kKY*aC4R$yĒ)$R"$͕V }-mPH6rIt~MM|͸it|68~ ԥ֧8iJF)  Pb6$FbjF=7ʪxܡ$̈́*F 3 ]&bjޠ?谑/˿?]җE< ::?{߿쟟zg_IP}mbTL sR6 t)MdF*k8cIc=&GH3U)5Djl_QHGdPod-"'؍Z- ޯG:E87xKEBg u\0NNSkr)ӳƵb)^-;G16X%'oU,WOmlb=U{/>WG $0^wfZJəNOsiS߻ԯN|,K>ϸxjxpqGNe.|pgLTP˅T|<"m7`uJmƉVӎ\]?e# ϩa=̤ /SG2 xzb,n֕>h#A@b h֨@G :!`ۻPK2vW<5org/apache/commons/jelly/expression/jexl/package.htmleo0WI$Dў(KS"SHј x"g%=Z !,|w `glTUWuďp+$/9S'­iu)H]|)c п=S%4WMd?quK1.fl]g~{ݠO-z(r52s"SvR*ON-mnĄyCKydtCvCod=n"@NW?C$! ٌ@ޢTg%ٗZQ!T f;`]dF] #7-lSӥ%”=W6vG?HӃoDӢ琹%LJ <Q[Y M~t6F*#(Ph_cõc $CRgPK 2u߽0org/apache/commons/jelly/expression/package.htmleo0 q:i;ĮW ⤃cRA%aZ!lç0hZn -B'ڍ org/apache/commons/jelly/expression/xpath/XPathExpression.javaW[o6~83A\9 ڗ).6s8iGZ>ʤFQq}PŲC1=ؔx.߹ãζF&+ ''y7+Q&bFj!*"6演1@h6L~g'1L[Eluk-9 RcfA*:KP1Fڕ0eD.!eݳ6;7M$Hdrr1O U)9,oAd*sš h"1H{V3ꍑVdw Y9/*dz&G3h6 X۫8Mo&\]fr570~ Cf)ٝp!@XRa,2&TR!hY99\TuŊ=rgC|N]GtiԴ(Tqq8g:Vq7ޛ$m.\lx<3pС0!2-S` Zb K0 T`J?=*M8ö hαM9l B5Ra|03D2Df, <rl3d43fdGAX,1J*V7AxG=N$5(sEK`ؘ&lRҙBqE i&\ǹVp$ hBm a&y菾ލ7UC\G=]Co YFu9SVN8B\QF|#&2T)׶NlܸЛlE6ysjlJ&ɲkiZtʼ1Z%\5Dю3N n)As,KIa> cu8/onM%9j@qr33vxbT1q^^K s=[Cs>~>؇FQg{k[-;A"XRmP#նuxM#Pv[D%[,hc)%(}2{x{4ۃ_,JҜڿ_Z3/u ȹrBTҹzZ|Ҙ[߈eLEm4] ղΒ7VݣdEƀ߭qlXU)k MʩBC0f%"mi lJD .$N1^?,1Z,2&0_|v/n =]<e\^:`I+]B#!W[IL"dbAP5iACƍհD- w_P/[3bLU9YAib+2&gp~5HYc߁:G1miS^$K:Gr'"QϷ ptiݺm[w9{ ٗϔY(ȺR ժ3o߃?PK 2QkL1org/apache/commons/jelly/impl/BreakException.javauSN0}W*un/[QhâVj"dk;jſؘKxfϜ3N"8 `0VT^؎i+يY.ELe( @`?BQa< Ale ۂZ lx9* \@.Us&rʟPrm3*P~U֪$.fq,uԯ&I/flX[Q1O5uS*gkZVju :;q?'lL@oA|Y߁ܥM|2X,b1LWbNW0ït~$|Vu@4 ]Ca#_)9ZeJR>( 7VC S[?k_$HGDJN6T?`]ockE?=W#&9.d'{8Nּd]YNJey8ڎH_ڑku߱48Q0g 7fPi5V>ǐ&׬AY6O-񉻯S~rr<^Я]ӼA^3qArע( |FP[vpHa˴AgG)wTE,aZ/KPK 2ԱXHj0org/apache/commons/jelly/impl/CollectionTag.javauSaO0_q5]_(CthaU+5eNrI;/ մsж|Y`fyA0~æ@V"%25"ܙZCyB&h^Aup'mO'bgj(!2tI/ VRCbJIFRўӱx%q T-A) hf(ZCc@k]ge4;ԃVXQK;JDZhXE#U7V\gI#+ޙvȭ-`ۄ40iFOn68]M8`jynՒ`|vȖ9RY˔NL["w2*Ld&nMrE#ЖX L=v6}9ؒgTj7&/{#y;|"c6)ȡ)dRx/txץogLq,5W MxlqNO*F汇*1TV&=܎QSv^ (,f3'} }:z{Qۺ u˱]Nj1!ߐQUr%{?{=??aFT[@X<52ؐa' U)3X8G>zPK2G0d;org/apache/commons/jelly/impl/CompositeTextScriptBlock.javaTMo8W $Q7MHK#D$e-wF'{̛7o N<8K]rgٔ`#,++ҩ E*NjSG^ȀYKp`4\0^P=(HB* |r ĺ )T.ot(wz /=t:ʝ΃`akEkj]%]7U`g- UكU,6ĵ;DflN3띑Nl ai=H:lBhA2 )܅nny{\ënnf9\7+w>OI2ʃ d91iQHuKVTTj!dzFQEP)Z"0L!Kٰuq#0 kN-)¿ǢL襍{~d_$QldŎ^pҴl^-NpqIt׺}*tc4fj*KQ96:iH0 vs,3f{9`0+8D45,I,*LS4HσjMGQԟ F4TPI-%Z:<c7u߿; fB( P%4{àp#J8>~g w, ac)֤b3I}Cl0\҈78EjtG,yZT ,=hp' zg*Z&M򻧼O!SBaoTî>?0n0Cx^-f'AۍIEIdz{H:O7&QZwP/m?}Ľ1'KW*y]cA$yޣ/PK2by6O24org/apache/commons/jelly/impl/DefaultTagFactory.javaUMo8W A{ |`Na-zc]IԒcCe$E$J3̣ ndW"8?, S%rcT.h,CEJ5c)pC`4M,^PJiBFRe@ʢ)A#( reݑ*~'֘2 1ʢnܽe>k֠Z(xU+cRffe(aDAZFUmNq6,a8K N,/zb6_w <,a~/9?l>1clLSv.!:-%]Q*6"ʬƌ ;R%WBh;V&0Ny]6Q46mq]yG?)5 &G{st/1;E},Pc83Ӛљ󴺚rMW:7|j?{V׺56RAe[b5[n!UJjXXk댐sԺ;QX-`U0,PF^dUpmX^:c%4a{KwDbᶉYǺt w0Rb 6íoNQ(w! 𡗹E}Ƣ46}կ.QR\p|+Qp*~pXLJt(;d9^Mhrp .hF8mZ6N l F/&s0,g v$p slɷ }~J3#+h/H!!*,/M%V;)v ??PK2r h<org/apache/commons/jelly/impl/DefaultTagLibraryResolver.javaYms۸_jn&R*Sָ3Uo,}(HB"Xv߻H|L$}y]x޳U\,;tȞW] ~L4OPЈ]O/`0>M!ԙpB[<"Yvg};vmw.;u }PِP^+s5Rm-3x:*3!.;_eKפYNmP4hLW{z蒦;j@nrrPUTogیc9`٘M%0k5פqD2aߎB‰ERT>'KmhtzzU7.ӽjthQl#ƈ#Īs@5;[]{_-oWC/Og6tn36(RVAAv(F &4ކѣcoOծ$~ 8 \8q9`7GyO3FtU]C;KLP܈A䍷}LuW|?^)q|{E(}`A#j?1;z/PK29a h1org/apache/commons/jelly/impl/DynamicBeanTag.java]sbfƠC'y,ղ,ORFT증>%y6x{vߠlϴ u~5Y& Zj!*&4|+T9.^[#7x&' x?«16bJ[(r$2Ls ћ,B%;i׎O’!dkaZ[=Nw],ı6ia1I~Q)9N|T%YSm@ ;YꝑV@&5-2ћ6l<&av/7fv1k8|5]]үpv+svjH*#>93|S:qt7Gl^+߃z)AEoj^d e7I}Dy>Vg687/۫fWHSEu{ZW+=~Z${7Xqrjx<X"cF!@KrO5()AbPP3[P*c=&'=b+k!gb= (A(Ѹê@:;DH=x #6 qzqZrg0Al(rt|;/MՁ4UoZ%W-8'2*4nO`Tu"o^weLy .=iw &AOZmA GbFMlWRڳkw9YPL/H·<Ů83#}_BhDpychQTq"OJ1'qG. ǤdE+]Mp3+% 5b Qu?TQRDB\pg+enN]57|l& kqa~pbbaǏi %ꑯf͏N'_wTVߺ9莋F7xuպo,,5/|ve C}7+M[RhM/FQx2X6>n} " MR$>_]H]hmT}l"4M{Ɇv9r'uhNGTSb`XL% puċFecOAyj#E5ᡀ 2ǃHê`!@]~6(FsDQ!' `Po |gJCy)~(oW)RcOJZĖ ;cH!ZVZ=v\ cXJK~u eu׊oyg;ǔ &lazRn%Vfo͈FS+8%0GPatlB[>KG=œ{0Xy{g3.\T3}& ¨O N>.i;մC+-u|#;bċ>(:9[Hxl7Za[qH~?צp"Nۚ՚]3ߓ8gRև6üɾ=Pp9pk I-N`;|!Gm zk"W]ZxM[:juRjeZ "$@(tEf4w VbSp|/zN~UX->OOϧvZ2o$„!jp*3< ^7|ZSXW1:l͐.)Zq_ZQ|C)?;juc9ٟƟpaힱ0v04}ўD`iJsQIQ=SZF/=Sehv"o;q$h4mn'PK 2j5org/apache/commons/jelly/impl/DynamicDynaBeanTag.javaX[s7~Wt%$/!I΄4$ͣ {RI a2#iKgչ|<:˕gώ9\8nXtavLqxf2fF2D5(".5S*!|J _dbff{Ls!4,DƀM"8YY? E߼tn3TEUAgehBf#S%NV>N.,5(W&f<`Tc A-5R;%!h_@2 mgV%C?FQrny-EB05ؒ2r%1#pڪ1$b-ņnEF=,-B5ƮQ#I)q2pö,̌HLf܌+3X6ouG s$ |/Y´#&ѷx͖lC|paAe{X\.O?PlGaBC~Q|Ś\x$Ήw?N!o(G@Y +.-$!^S"' 9D3;%txc|DՃ<_si1JPXefJĤ/op8hL󁭹_z5boVзϏn 9QN2W@+4SH?z=6l[GoQbE-debR8bmEAՆSaނ`ZXl*@ɔQmM*x;ݦUK ЁJwZ[f4tAmT0b%AʂLA+ռAYmO<+b`VL/YrEȼeڻaR6V^A̢NTCE^9ap*4CX z?OӄZ- { h^+t rVRэOh=p5hi0 xw уI[Ik M cU;2^W<(' AO#dn;$}[SV"@wD͙ugZb}c/t0"߳J ڟ*bǢi˓\2oN{,jmNyta}+_]OnKgx k&Aܨ"B`/[OkR w2pCAn2s+~7xV٢h-H^SPT5p )nI-aoGŅWtSM6mΉG%[U¾ʫf%ϝ/dla*wv!UDP'ϝ*H*w6|j:sP2_m?@3|qpx&w%GO{ Sp*ԍ?!-Dq)Y&lYn2mkU~qэy*k)CoPK2' -org/apache/commons/jelly/impl/DynamicTag.javaWs8~a`r2KH21ML룰Qb$$C+@f:lYo]A Rk-ҹ㣣.danT!f!歈4<\lWkpA@mZ`kBa8f"b[b3da%㭐'PSPBYSN16?VUȜǡi/+eMvxy=kUfBhxW1[Rq*z2DŴ[U>bMIh"Fm8Q'_'p?&wp9] 'g70}?.p OMApaqL.b&b MK9jɵĈ z! ՠ BX mk!̏d0.P#|Yɭ~-<% +3/,ﯼuhfV֫[^%4*rT3^*i[c2bs("鿾܎ ?Tb[Q8ڟgJ!1Fss ,K1,֜mgZ-HWH#,>⏷0[Rg$_S")|9f̬"'].3CJ+$818SG3b+rX-p!W}0 R40Xe)#1&L:ils7a!$ш-X$' DdT2*7)[1mq.rĮpE@tXgRY , >dg;Z jB|gd>l7#ɋ$r[}\"X{ReHÖJЎ k?ӰYhi\$"IvR9eC Fav}IrDG.ΏVZ>1,/srt񙬨Xꎮ~{1rxb J JTSjDzf1 #6BMQ?8݀MP78Pr$;l-T0OJl zڡn dGF {4Ia1+dcZx|=q 4J V*HQP?D/T[nY$ҢS/k`aܠE]`I*uVv9k{u 0l,JlWxtsiy9{iX4! DTG}oɸ惌Y&~pnh\sZQIOX\PT2Y9:eJ *O041`4Vtq3/:SΦX]$+C?~eMkb-A9SYᴦކHjs,>AwߺYw-m ^}gYQr9O7/.|\"ʑc\zgpmY;!6+F(a6Ƃ*/c״ؕo7*W+l~T*W>޾n^$otɨdM}#Qv ^?8;*6Aeߓ2uKP< ^$o5tEWgPen̈Ė-Ra 1ȌJڲh=j%v KOmJJJ=~n,ʥ֐g˻硢[pذ~jܹ+7RmM*țaG ^Z5[jUnOqwݑȕcDw*hE<+J]b/nUbJSsS;:,X<*=51E=`4N7\]+RS_PK 2W`H+org/apache/commons/jelly/impl/Embedded.javaY[sۺ~@D{*Slgc+Sұt2 Ip)@ɚ3Ņ(Iŷ<<9"'RT[KM޿{<,U4 |uSEr^󌕊$er++ 8I`g(b+j[R Mj@Wd FS*MxI2 Nˌ KHNi *xj|ZWfR8r1,,^O.Ƿ[@SHKx%Tւn.$5-Fr)Q΀(&JK>ud4T l$єLh:o}y FۇxJarw Ow00Þ*Ldݔ\XHb T+5]0k&KЈTLB*6vG`098v#+mΎKHM隦\l5IITKFWg]0;/'wcBjwG]_ B,tX3ʹ ~ZOt[IOKsJ/+ ->yI٧B >~Wr q/iy>]8>g"gǫs#X)¨ڒ"P!q 9!JÜ2,e|L"ƒ:+2"z[!>4>#)٦yE,UL SqTr@{rpj#Û4ʉH !8W3^.bNtdF3! p,MꢑȞXkQ>O8cI)dDG%Qvcs . ?#3FKZ۞(v1޾[} ƠYIp6]asܕkY2+Cy0L@ȉ431בVߕ+ăKIBQ&4:AЀ/& qD0@Q,!ٜH*V)w5E.|L5i5kMrv$(jSTK,MfڦT@f <Η-uP>ִaV*sSa͒-5K͌:`p=݃70eqN 5]u&O͖iIX7K-kTPzQP_svp`.Lmćg]jⷷn>!W.J  bkdvKmlS.ml2 %t-4N Jcy NE:~ N>kC$*~@Fd~VꅵK2]2*0E`Z9Q!4SƔk~J5 ߑ9KbW&tl(UN˽QNEJ?/^PYԘi8.3Z`l5Ћ&ӂ pp k n.ʠ1B7mwغsT2V%ƐOOgacY3{hN3/ h-N FA pl["ؚvW |6&I``J:vuZ-^92i]^6+R. Q`ً_=Ń~JչyzÝnԶ@a?u|%w*SNi o}rcO2m8ߗLy::d W!$ N'x=[@McRT\@ La;9LÄkPēƔ8U[6?@8pdi-'SREl8m. nKo)OzH:7l2 >gִaXۙmǝԞ -~7و:;+:M ПvS]ta<$ClM4p$rW).4 Ա3hMs -hZUIc;zeM}ygion:g锫+6O(p܍)r\OSMjwyx2}W`0m,Jw&7`ZƉ I_ SxFʏ3m<PK 2| 3org/apache/commons/jelly/impl/ExpressionScript.javaVMsH+zU9C$+L`RK U$a1^I!-`5ݯ{3Rpւ3b+ypq~~ѥ[D 2mǑ767 az~N®<14ût>0lz3OfSzWs2eT74 &7vbl (,EMI%HZ,AHeN@qeU<:e -CF<(ÿ4Vբay$r{^%cM)a$y /J]u曥3kd_\[m~1G"!kYZCe`4Jf^ь$.T{jBY B7bukn.w^ëzRFmF0'Yܪi(@AZabڑZ7n F|MY ^]͑|L!:fÞj\Q8iQߴXu)sP%-Do+^4*w﨔qځӏ)?p 5[ :r39%нRQԵǑ>OYk:v.Dl 4K2KyR={~swPJɖ`6[c*S}dٶڻ߮ /:}b?Or(T53_ت7Lv@tvsArNe(ʘ?K^W=pPK 2(x*org/apache/commons/jelly/impl/package.htmlen0){JVjW+FXi!ri`KvmSw DI9؇/a8)=v> BYE!WASJFEPZֳfR|5&5@&`$ |P;*kFyUs<tkZ5뀹x~:81b3nL琐G)Z0w-'`*V`#(5H9f$b#k4襴[Qie +Ko6UKT*x߹/]fO䟈c-'@㷫%9>~qޏU^TwB%1O &wprSވ.(} f&dj[JFZoU< 240~G{%Pnp)y^z ϘRR@ JLanc:eøzVB˥hDvYnMU"_esZUk7tj-/n^}g ?qR &L4+˥HKjP>*q22og9۰k7D?vjp}ȯ b#6ں߂tاڤ_2Rh!̈4cs/_nDl'7kx>'e a8}"NgYa0c.OX٧ghN?O]wҢVp/8}e<ُw Y=Wl[oK8 Z{{l:3Ɂ|Ucؿx)9c[x`J퇕0 >oPK 2q},org/apache/commons/jelly/impl/StaticTag.javaWYsH~Wq,WblWZvjkqFvK81^Ls-Gc uz1B+>}΄FTI+UW`$@ 6e:B5Uwlb9DBblHC"࣏&q(E#̤;?g6 RװfAјfp{JakWNbP7QƀƇDjx0STP FIfG=hTfiĖH[H6AՃv _ZvFn_7}m]_:Ep휷n~]B~mwDXsd:1pK! UїCSj(#(#QO 0`3HzìŎ!Sa'1 լTCi<}1%15_pDvMlr836[(1$ײY-M;ͭ8>=U=̧7W #K̂qRhCSce@Zn21"7f}Y$vL5>08|޹RWd@~( ó$-Fr Jgq{'buͱ0r*,r,܂2!!5, 㟁=l*_/Bgu+ .מR"k%g]OsBkKy/,׬G QYzē|IY$yg/w6+hI.Y3' \j}j2DUqd2.Ѥ)VA =|m/ҙjxXmlSEZKs=PO KKV|Pj1(ckIJVꕭfrܣoa*TC{{fҔL@DXzAѭ R~Z5.?g6,X4]̛J€R ϷH/;U49mZZ!R V`D. 9V, XɱMgiߩ։"{oCgy^hߴ-e%+*hiW.ty.QIڦ߸t{WM@r݃TdwnD*#9L31EG Y)4VC YL,Һ0vE;!G>Ή#|8^VVģ}Y]ZX}i)mWD ŴS{KLkgғ,VЫ~x{4{y> <X׊M֑+,RcpD 2g- - aE iG*ܸ] #;Stccb (f5#ƘraN2J+FԆtsMVLKt4#$gҬYʟ2}wvt .$8 !&0ńS^xz+2PÙy}.dlK$oK8_s2~ZxWǛ7Oe^و X["ʝk5TϵE4蜏~HEQ=~Yc2Br.w^I_=UΒ yj-mʽsvb%/g8SDK4^>A$l4Zs-qNs;jHe%ZH&Vשּׂ$e9$Y`PN5EK,ܠHHk1 ,0` " ,yb.@%\5;Ql .Z)"Brl? *lLeZ_c˃ f:vؖC򙯗`gީ2ķoCo&Ջ/(Ո浕(e̳L N@h-Vn!Р}A&0sǨ7dcAW@XYDZ`*&8?b2ehhx\+jfH 1SӖ?*yۏEAgϊn8(KpZIܣiaydtbqb$OfX+DqzA9F+KUK [qnGnL7FGwٌ8yaV OɉzǮCֽ4vV]/f@cc(y/iܧB8pB&2\׵ټt}zb~rNO+a}NK^A{C}\yr[>՞jPK 21 Wܼ-org/apache/commons/jelly/impl/TagFactory.javaTMO@W""BPMQ"šę8 ]ww'B:N7o$<1\rcDtpv%A\bƏT/\VWjNhp)Ksp6҃d,WiЇCmCݣKTCXXI@JBAR TA-ܲ9EL3\P}"kI7ҹ" ahrkz8J'̺zPC?+adVΘ qiϺ6 zΈY>ȭO`PA7N!I%NA$Ma \G74|KF7= ϡui|LSx9ih}[JL,Dƭœ +2;L!es#E!\ w_2xz9emܿ}ؘoBAZ-fQ92=WbDa HqƼ^P/ongӻhͦ3|w= KiETb'bWRJJT 3ljV%B9c+U|.iv_F<\l(wкtfZZ;Nxh993axtbi/yW6xH Фb8dGD0,Gb`lam)-P\mxqX C5i >\^~l]Ul|ʄ?lvc\03%}I5TՊ7DWy.jWV}'sЀnjaoXb|%-Rv'7\R$ևo!6EIͽdJ? ?:PK27T,org/apache/commons/jelly/impl/TagScript.javakss+Jt2}ؖE'Lm9#M:~8G1(i߻{/=R3>8<:bYrղ/a N8CǣgbWmٚXYl7lش,/YV7ELۼ]}4ĄEèf-lׂNdHϪm7O'۔KӪ^N 5_\?we!ۼvoׂ߲f|Y k+ۼ\Y `yl:D38 /^OWc+x9__؟/L`aS )vWB8(,*RY38Z`F%mDdkLVF 7# 90v +EQRDoxWCZ, 鴼25YS6} 8Z]mYU~x7Y(i+jVud D~/{(Gpx3K\r%o^J5=w+v7x% gpIy͗C;8;d|KaZ)j/Z40 v|sUÛof{ұ& xy<JQDF͙zLbakFۦ֬dBU+Of/inVն#<e[EMR۬*m]PCSm)Pׂcv9g089^h?]B¸&ח&oOZ) FݒFZCjJvg+2^ \ 5hh2pJ^H NR0+7p8\jND3lve4rKqˬOp ZJZH{*B/} jFMQhP?Q7$5PZ#)t\p%SMZDawŴ1Wg?U 2ihWr/X n V;TJZyJ2(* #p Xbp_zm~`IY#I^Q\ \/ q慚xɪb.ZPPnnA}sqNSXjɔzD^9Z}ZiM̗_2҆$*Fr0 {;P @ۺ0]7mQpճhmQx0OY+U]OlQA*Kދu0 f?c .1꿉Ƞ,`ٙ NqS HPA(Z_բ 3ިXȃY7@2]YiR0(^i3mN&g_F`a5 K`.fW3:'L4=b2HGooK i+%9-8)9;+@=9oDgOHߎ|@4F-5R1ثHmu0'GhFO,)O̷ԂX| w+6N@LPV*F:ND,'V I8) t6IIV54br|O+|XI ]ȗZ]N}\X*bmͱzSK HK_i/%β)13=Q3rٜ5΀]uG3Ry98G?ȕ&yv~r נ9)Mn=: |DHTM% ϭMM~[0f]Iw!PH楘m%J,'t8g3cM|SJl1Q<D Xz7n\-?9^iҴIڣAbuj4Fj, bt+訄.e>&`9i9.d#g5Y =՟/%'RS,ǟݟs.d"ua27\3aZ7"\@U=H /zHysL?< &[';AaEbyf㣻:Gj7G^!3(rflD?]Kg}&CGPC;(!MždT0ͳ/ц4kԠupb2r˸%HFigtś Y#&9R*D_Rs`\IF;9'3/UѮnXh*kXaHjdު0IFIN(Ghw7r_ARW1t >Uy}APkl](q/y^ 蹂û~4J4v7zׯEkičѻUxE/&-jT_N,Α%CWob1яn_Ӽ3.XD;ҁ{qL,2㑥v#UUQV@SɼBGjQ3EmV]vAPX‡-D'|w$mk`|5(cK@􏬺8Y0{7ch0@!@kn }JkI 8W䥊!(Yq՞7u=.kћ bPx"I&h (tEzE& 0W_mxf}%y)T bA^'? :ʸapم;C0B=؏zyڊo+6/?pɘU&o5\ƮiJ^]ĦM_@bҡ+2P_S-]\3, ji !T\O` H!Yv +#f33yUf:f 1qRPW=4&eJ1Tz"J,=H暔WA~%~駫ZMڜy]u#G”g|,QVk{x {@~ib5aY Y na%)cBV񀶎(;UH |;b:?#08x'M0J^I۽cv<x٤F"_[2 uq+;ۺfێPTڏ%H_Ig@ڤ,ٿ2~U@쨅ژLa%gC4< hSa$lH*倕}߆q\p99|o !lٵs̱gk}|Q*eX6݂[޵Q$}}g— ~gF $r!ʇ,o[ Q _uPQ֤cUv%jj }+;u (Xl5e} 5hڶZYX|+; MYY E/.cyhxF L0͛݅!3x&c[p~w?o_;PeEAW#ORҢQ.C%Vu5M W#Tjz_&X~=-Pm{C.<ܮZIU٭ˤ]nk'eu+~6J2# g'=~cqEiGO$17( HWJoT. 9I͑Y ؠE}WS|t ̶DTFE-[ }坙$\7K@Y#/.(& 6:\-?zC{?'^ budgyXѡJܚJ}iݮ'Oеw}Egly wNH_j׸Klda~'KC",:Z}he u]eVu,/9F\(rO9#sL) 1B☏^ #Ƶ{3L75$Ք}"֣l#;-yӅlZ}.11|7K3!I1{avSLDƺWnUqLJKXݦѓ}6QF*}c&V! HQ;`Fƌ+/l2w6p^e}9{KMz3x$)(JF!$+)`Б` bYgS]n+yB}_J=@vXw[D4d6m6]bцW5ߟ ;>[|H` r__FN5^^g2]mQ4)w:~ %~Ω=^Hڣ֤JZ=wtKoJ96|=8J1Y\ZEU2=ޜ.;"'n">QRIo@6{yPNCg):gw=_I=R}' fTF^¼=P?| PK2RB5 -org/apache/commons/jelly/impl/TextScript.javaVMo8WLđA{#źuݴX쁖i$$D4)l}pA \[%no`0,XH.̚)eϙ2p15Npn\i\A|2ܔV-@9b rD̊T<fi8b 3Kc0\0lux1>Mv>)V ϶ drM(sFFIK ̅6JJG nic9xƑq!ˏS^] '(+8OǗ|zgs hZEp 9].&R xMI\2xr\l>$)$\iɧn(DhF Od<"?nbBov|}W__!a2ֹD Md݄ 3aYR9 Z6/蜑x`2H+4D%7TW.$4=ADR`%DY>gBj>ЈA8 =ђel{>0^|6eLGi /Yrws6^/Hu49Skt"aǿ##KA$FYjޏ>!,2㦔xbsANã22L8 I4[M/g&V!sTSS $xticr: LX}J!hCD>+R$BS۫sr#@OŋZp*lv,)O LE:ǿ%Sdao__~Dt^L!:Z]g2Ny(6Mfk`ijw&8+:f1d6J<[t;)DEd^aREP"Y/ fW,$!Wه<2F;"eTM$X9R =[C6EI@z;|UŬHAC']pz 6]Zid)b .m0O0kl[&\<@,P9W]BV!Un+a,c .JY6& Zg3yT-#`8e:໋ :%Ӆ̚v1ű]з.m8ZJ(j?6lr=MCT4uj'q^5D<{_w1_-S+rMhYYLhxSb0$|`cww̆WљDCv Ui0HY薬Ouqx @"7A>W&lx9[]}a뇓GFdPX0`@@}ضnˈ_;K1N=9Agh&"I(xC#}pba#="-оO6,C/ ml\\a/m2fR8Mٜ@@ " J1_߁)3أkk6V9hZymN_qش*jR+lChѲ`CN}.ͪՏjUD:nݘqcbetSe7זn.dSnoW$Zn/"&iZ~]#`+dzV /LB61y\'!cquΦ"hRD'7s!'Dy['|EXibv3~ YTס\ZM#R>-y͂WOTfDr#S% ORpRpɈ/|5Wy-*GvmeHBN t.C`c#L9q髕MFUaJPv|9+obtCHD+ u3Ϊ9YlMsV=ZOW Vj[sSo5͉yl' 9_>:T UpsD7\k5(t(tX m-,귁+fsa LeRra$?xzO;PK 2܂ )org/apache/commons/jelly/jelly.propertiesMo8 x .|׵GJ4(R!!4t{k,=˙v0;Q'lr=7 ݩwB+F*D>po X

=:ort @iE*!Xb@((uJU L&>.'ү*总1;uq=!\M}!G^u~<Dks' e[ [ *y 3}ȽNzvuF;kv PŸyY~Kn*ys-?>vx3Hsd<^N ,[>R9H]'O,[:RC&mEnUlӚHq㾥Gȃޟ OYj|2x5@,˟SCڳ,CJ,&'m>rH>=ɻKA1Eʲ"AK1iL,{."c>IJ/'}g'&PK2VLu*org/apache/commons/jelly/JellyContext.java=ks7+p֊Jh*IUٖcE/u$'O[ gxѼu5 Iٲ+SF\f^?\%?u`/ʦ:+1tÞ/(1x *V̓QTz_!6Gb]6l׬(kH02ɮ\0f*5 6-^>:8XVc0AʃӋȅdj+5+VVT%b:+nFL"Y&*jjhG:md]ŀ}{t1!&ߝd?^NN.9;>;}>_/??&GL`fY )fvBx(\%:ԊvSފDJ@p`lJ6d>.\LOr=_v0* 4@ [&u1We çSt_ZuOK'RA",uXMRh$&l%>3Ԛ˦"tURjCʵa`D.)K0>E&Em聯z3ê ߘ;l6ɊFowDcπV|au+%SV2UK| $1xHDUʀ!6ΞXC`{aه$px86qv(&,Ejq;.l+Z';X 8 LY6i,;,WvHljh7`S[u.@gNU bЭ,׏[p޴L j3/9fEyk>Ur%䚥 F/F1v :EW,[0ZL>G;R~J@ ZKJ|o>`dPrN6 6)@-VÿMjPh zfrc6'|;abqfJ!xXryƔfx{lD$vI!YyBkH9nCʭWs{ [ĭ5w4kR+KEǵզN:+M~X)Ao8'#x3v +O&s*c꘽@ѸͪX`B7x(R^34Q@EEy&O)J>k4t%N[n\ލ+Apb{id 䙥Դ_$C%{QY2Εdʔ$x'``rߝB,h(%MZ#0wWIڍr bV+,%}C̢lāM?APG gԣu66Kl0&f 5r1G!`l#GD8"+[`P@(N[C-!1O`{vtmLnQ ac &O>I 6'4gJlpMzŚ-`ͯJx=7xvTs8Y%q;`xja~w> )oS!v &7% qim-?ʾ/$8l? #q%Q Sџ#~rZn ~z&] ̳>#f%4^}׀jbxnhcRR8:W cH$RwJy5aVg ) u X ?rExxalyyՐdIbT`g Zh/ 'VeLib &xQ2JoqyTbm s;\vT7ڥ2XL<+^.$ҷn/a24Me5V/EKTeWN`U\mYd2WjgؖڽvY@SD==&ha$+@,Ū){_~z|+.]y BFO!9"ք<Ϛ+?-Rga AÒ.bj+Cwk?eňv0c+͝O #6+8;sw ށtm'…xX`z~|jwwѱ-,݊$ػ޻yv {؎}y=#HrwEeFa]?`K-d<_}{;i|A#sr>3Nga+HHs(o ruMOE=A_2#u!>?W<๮2Lͼ籫7rZs^uQZ{P$(dzC? WMVG4WHetE8)]lptcUZd Z5V&%,RPj.(HEDKafàm첨&ΕH$Okd;?K^2B*+u݈@a%~Ჭc3?gډ%R:5n2m$ڵ8\Ĩq7.vTe/Y'3xP2 ^VK;&ѐl|TSukkG 8Q'NӦWOŠXs'`Lc*FajtwRJesԸ͕ԖO"$C"8ag Ww|0O 1v[+T @.Yż &J.1˪AXIK3KRC/g;I0!沖޲H6MԀRܷvG_T/W K _%(:EޑtW著 s㧃iDŬyB7U*}K !WvUʡSEE f& ioW?A4[@I <¼fKhLDVc?>bn`=vl<xu:7޽=>Wˆazʸrf`B1 Cמbt֔QwDKI!YmUGb2\s"\fB3hjq AIgT Z53,FBri|=*9"еƄVb%9q8oNl*Jc2n}r;>B;cRNq\Sj)M +A^@=喃T~ϼwnl ׭[bmWeWO#q%kgyNq0i!f]~I&wOHf/GS(G({)g"Yۗ;ﱵ-Kx6ղ1EGtx^?K~GEns?(1S{#x'1iԜrݘZ-Y(rJ0 R#io!)&KpMʆY̝۠a>;scn7]Xm2"pr֊`ݞ!Zh7WoW 6-tTuZ>-Q"zqGEŔK!'(.g?)skpJ53A诈v }`lO t)Bug՜)9@vK@Wg+N>$Bb캳ck4:c(bc/ PI;X*O 9&ֿPK 2ʂ;/org/apache/commons/jelly/JellyTagException.javaTn@+F(PMj$L帘lkﺻ8ʿw^ wf޼fA.dR<]u=n0]" O,b Jb Ce'(4΁l\ć4U@ӅCrљXr!  kX , p̋3 T,>2{!gQ:ۉ#]_Kc j krup^xX[֠G)*a3⚱ *u"A;-̜k4;9 h c|a[pi|;d2(.e8 =]002ꃏ &v.Fܡ %]`Nq Nu9-$cdoP]dsӳ[Z^zBr>ٿ.i+|R(Y/A~o&/{}pR&biθ0=\De>C՜d\` / vok 8 bookV5tV)CLX6,TkJ4U]*%B|x" Ow̽rA 5ۅ |:| $i۶/}c\׺rr64u%:4ʒ DMSI1YKт r OZ{ࢁ )筚7~Ǵ͌$}l&i>Ic nGףl2NήjJ Mdz$ˈj hLvbKwFXHFJ47"G&EPcu4`0pb!391N=Ip MK# $KAf"gMNZ[(YeAFa)0kl3/<8iQ_←q {tjBesF#[!?Ha G Jқ{Ņ~:H À7lNC؋7s)ih.ю"|ZKtS\bbi~ rT: |"kat;T>.埳KS6~gz`֋T37 oJ1 jRt^$iu1n+CB ꟥}FxݻQ'HۦHu~PK2*+org/apache/commons/jelly/MapTagSupport.javaTMo8W ke8F@@q,-%)+"}g(vCbrf߼7drڃS6ΪM|ò ֘Ԭ}4:GqT~RiG9p,CQ +Yp>:$cr);@;C1* )ڃҐ.ꌠUDa#Yyt䂚WD@IHmG$eOyzU_tI΁efVk- 1oukWz3\9oժ/Ds֏X6П0K4C6[/,a:_nSX?+>=qWm??|x~͊pP=d%riSɓ^\5D֕k抏+^$wdaEkH&LJٚXnܰ!,V-CNosT'񃮢K l̈́؈<inOfqfaÒL٣5s(Q7j @7ey/ #\zǯsaħpCa>Bʫڸ}/dxQ28xPK 2S2׳:7org/apache/commons/jelly/MissingAttributeException.javauS]o@|X9PjSB:MA¤Q{1wV;LȇݹqW\+- t;nn0[" KO,f ᛬D "1;yS*0҆_4M@7mҳkYA J#ap #S. Es&;ALsè@IO׍LC]Kc0:`q U^FWq ]{ѐyRb/PK2 ./org/apache/commons/jelly/NamespaceAwareTag.javaTMs0W09S&$ m3(b+%WqN{wGK}w{+\#Aߥ#ZdJʵ \F-Z+e(sQtK>'tB!6Jl@iEVD kRABet?'0 z *iz)Om۞{q͵ur~9N/?P5W%Z 5PNj XebA\Kт6 rsYF:. ,uF.JGje&tF)$i$2m2:v4Ƴ2'dLƴ'. IFcm)YN\zRWVzK֘ɕ̨57"GFSI˶Z"dRVٰo("މNVTһDzܜF1X^dٻ5}z8cQ%3b&Q9":]9 Re4~ð'p#я/"ӭv*_!9,K:$7x2 zZGJZ o 9&,`yzL4  :st䞦zt,HChX;7ŵ |:>>^pYM!>͊1ӡ"Sx;z)%GvIŽ9UtF삷 d;`_wb,'!η3OPK2(l%org/apache/commons/jelly/package.htmleQo0)nyQ-ĒTC>8=۔wBww Qunw|E5+dv3s\ɐ%J4r~p 7>`֟¨zR9-Ps/%j\B:-8%];YD<" (QS>uNaB64CmtivyN{nb d 62s#;. evRq /za^3H5|$ېC_q' .W8^S'N3IO@maD"Hn% .D88VƘ[L6Ѐ&!Rg0\0F Ai0T*\X89:+ynYQ |z J()ptFjqbX; /'og= 4T| VW%V AsYt2_ z&9/ݎh G*@¨Q s8ax2 #*z+N$pDSTE;R]S21/J@X'49ULZn% (IWyz$w!ͩePMPc\zOW3XΫb/mG/ו]р/wS ],GHЄVo_SQALM)~ LE"CKeGsV֞#+.$:.3]0?pbu(hDTQq*ʏtKjHTP/Xk=UM~2q0O,?z=:TØdH@^*V+xes;RS:q>5&#Bdʓ(]Ĥ5pTf|gӊյbi6眐v G[E{([>h;V ]%Y60 -Jژ#QhRcqiHrXgZt M ;)Xye= X':7$G6l5|aR 'ZxWvTt^24~̶^g;=T4r;myt,xw4O9Z!OCP  %7$m?hU%7VUӬN'X5/1g; gG߾ӤYmf멗\5IUt(╷٤S `'PK 2$,org/apache/commons/jelly/parser/package.htmlen0 \6 fu9@lӶY$y~ah IϏ8*=޴ޣg[XLj70pzY1Ǖ (֙(-V@hƬ7Dc)>Nj+) "Ip 5x+Q;Ji,9*2qpkoxZ0!`3nLՆxJOKГh-sC#0MH%+T;&pe]{G*w~@cqIoqdi<')z<9ep%yrIiwqߓnQi3$:Զ @ 5/.Ah4vzOKxq7`MԺNLYE&\m!HQ43 E(Mh>zZ+zP\.fPK2 w7!ڢ.org/apache/commons/jelly/parser/XMLParser.java=kwƱ+6:= А_"'Je%=D.I !YcXm9i~Ebwvvfvfvvv=867u\?+)6 ;uVKyUB7ydȹLe@u@$`O=ڛ??\pߞM89SΉvRz(,*FYg0reK)ՕKz7#"_-Fӟ5́k葾Eqn{n*K*}(ty[l1`{BfsmũcEzP)$xio[h껬Y=6''#~+|ƧPkͳlXx̪3b-Ӄ<څ={X|k7޺O:"[43$ŶzCPIU&Ǩ|[THb: vKlӌ3# /ho$iPy{Z+E4MXZ6ݲٴYپg3/ޯ"fNQ-`jT&fQPR2~>㺮zsdAw$YWcMـT]=3ПqM4 ;Os ,_Ǜg\>wA:! U%hAC dwoA~A]Q rɺvNLjx?d +5 w=Ϟ+%ᅼ?O_?`ߡWKpU 3eiZY[߽{rV"McJE6+LOo*k"(|<{G׫|Bk/,Pl .R^{͠83łטU^eE͌<-}]zLYWײlECY\ :FH"XCX $ՠk{YohM±^j3Ct3|#Ӯ"kDEu݈+ր鍏{kb@\v56OY״Df#7[G%C#z+Ȍuj}3}j؂_I5nBΧ$Z]Sv]>Yyb1 l*.M^mJU Z^M]肪t ~Bװq͐sJ YZj!; "_VH "+44˪*$l1 h8LtP YnW@5,㞲r`Y~ hG!vxO9 9k\9?_C`w†$/ mᒣvw mŃ͕uWfh(ۻC)G 4cSr"/EqR {Q^eHC 71+F PA7tG=X.,נ$rWn p(59C4,ʨPIgC\JXkXX̐5$Vd!q`XW 4T ճUj3܍`Yg@佡 ׀ڨ9̛dϳ'6{*N3zظG>5?.GL9Pl BU M\|qT%/%PrFqlPY۰uTv8+ZmaJx.F%Clx]uw:txVHyN>k<%+`C fDZ-!..hs̙9x% Zfb#:*;h 6#֏ :Fykr#"vaM~ 4dxL }`/NwoqrRy uhYԫHJ&oviʎ.9ՒKRY7r Y^uU2Wr{%0`+ {+46k+y ăi%}0qMc>В']p9唼/,3&j:t{tDzSAo\CÓ Ĝ DYwتF'v sB㮙\:,YXҷ "9.(Ăi`hn4H05BC/SqlW%)rnnpL&q:6!SC7T]*LgO "Z}&U/'pJSZ(Uem'~WyXyl %A) }f$ hC긙prȾ~յ1-B꨻~qJpB1&0AmdXm읶d̮.:S#eـ94Lh֪`l`3{ơŏs ޯ {50*#O9j{o)S{NF3*mvE2=qGȝ~B$+y~۸8*FϝIE.TDCdZKIIiwaO_ ~OBci6kٮyC6c=zܮ\cgl6Uq ]d0vE9nю.ɘkgzB7̱qO[p?t01v8lPg3nw|j} -E"I/`G\. ;X/JW4oAQA0ao)T7 tIaz#w|{ka`tYU'u)8kǀQr@E[ :vSGG(XO]J.[Lc1΋6*3bQX/>ԐwSw? 0u! MH&J/N}Bh`U@$@? 6oZJ,we?;$oX-YRzQ\y&ʆ.\#ݏ--EuNjSt;v#hR]*I} o M&$g#"gr|(ekv;~;ű풇ktǤ1E&emO0Kƃ5Fwo e=mdI/7}+ti\~rM5^ bdXQ`85R#\h:UVC^Ba>4YIi/E5#ezCHC6$gQVd4&F{&nH&uS,0 ]K{0>ߨ{tm bh.{V1٣:h jnYewF?5V8ch47lUWeoDy{k4ү?65LyMПP+5[0tIaKl6[IYX, 14ҟB MFgթbo*bsZXXl7BEU2|LTNSr"Y6s+yY4yKP 3Z>}R0UA8>EEfvapә4W vbaƍftG F|BP=ph :UQn  [:d.3Iv{c+ *<cFݤӡTrc$Fq= 7o:w>W21wښ{>GvGGmmca{_#ēHb-N:;]-$njvbEx؈>4{3# DFO6 8X/7QGTsۣ-J WΓ{1{,R/1UUrzLG<Sg/hg9V#4A>޿n߱>0_OÞNqKʱԻ]b0P?P/")\yHZqjEWR1qCҡl ٔ[˙̯0b󁩔P0 o1Py(Ho,H7-RH8i 361wS?;eS?m鰠3}>/D>V: (}[yױm[7o˶6f|z\WW2 ~E3 }:Y#&XmBe'-^-w%7%zdbfx yCIk7J6:P^UֈOJYaU]÷{ʌlC1%>3A'wZٮjzvpq=6vחe)@rtz)w&4v .EZh:y}岬{˥S:(Iv|$_8fLL3d(d4)nGPAV<0֎нcf6jʾz~,_fų2}TQ}XR+a lLF-n DL׻eĢU$O8p)908dN݋FvQ'4#ɼS ]bؼIIJPh{>#r&#f=wXL}a0'd V/{D{NeWQO.YP冸\:}gr,lA8\rr%^_2,`"K3"(\h%fzNf, 4 hT5]tYU_҈rsK]?wNJuyuf_;syݡTQ({M0aqq߆zv :}VR&H=1n]ntH@=9l)kiIo V"[ ܻXMWИrX 5pkya'[ 4.g4ȢpK bqk`K |dƹډ{1˶Tǭ7B+ 쇋j1?fJՔTTwwKutmzm_ ~tٵ}c6h wh86 *"agvĐI(u|Bn32D+,8WjkϩB\{٥ \vEsFTaKоv\so:/ksz䤜5bV\Q߾Ad9m2Is SryIn7?MsvZD#r&ozM&UoߏS=7*횋g&U:kUyK彈I~.dNׇΚ>qҼ]I,h]KtZ"l5^4K=yvQr8g_ކu4&v^;8tkFE_~.J5WN}2}Bo_ 9|q$4sy-SUy_91cHE(Rlteh$yiVQGRn=h-=y}IѢ:KoX-qSv+ԐTr uw|tVTM$D|4 ;AJqa0N8F ~BUoj(/,|Al&]t_@{ˁ?sp| ȋb-{=o-~y+u> kkzj+`rH$#ATώآRͫ]%Fr;C.92ˀx@l4 t(o+\ЯJ3&옸Uџ'd}vPy'hӶhER#wx~+aִi.ؕqW2q鈣gmNI*xQv]JJאϢdZFJYM3ʻ);ZIUb&̛Vw˕[ew_y `QOmeͨ) жׁod C | HF;'^p v1oќ4B$vⶲqPJLhbNŏWjQb|O]HqxcOvn ]ҹVÊw#?2` /L^.b:0nR \d5o〸xM"X}ԉYXNp)^u0C[AUv'j~ l^ρWC9P϶=z |޾0Zo&wMz ѧ0=3Aa DwJ+]~axLjh62PҺV; =PKչtf` `ʮpZa2o4Vƭ`w#5溅nhr<6E-?<|}ORMs5vѹryy+חr>w(^.,wk+b)U'ks-5e{0q!e 'LLD1β49X λ+BJnC^@ᑖK;zi2STOD8q&ҕOTiro,+oC~Iܑ-ع I"q1wRB5<]Lz;t(M+C;x\YF D'DK F&s|[ oRZcM=sp )n!rAR:[h&x3MsWWեnSw!2_?lMVGM%r.kz#/붪 |dSHțh`E.୭=2׫ȼd%έRiCgn.I3HOýxRhx?g- 5[MG ЖFj2OQdc9^݆dQ{j,gm;;hy'g{ NGadSH;\}kݼ]\37rXn$3'ݽwPK2ƥ$org/apache/commons/jelly/Script.javaeTr6+v49Et=V5QeԕfLi  5{BTl:HFtEKno&zC=ӢU9-C5 6SIι\QxJN&'; ^Ӆ@mG:Rcu=0cm PnhLXg@&uYPWHhV>$M*2ZW%rIWziّT Vը#U9Yºw:覚 Btօ9Bئ/RZcmӉ|Y>n?a٭W)mhݼ_ >b~_oOacDhj]BiO|˹.uiMթv Qˮ^AklBh >H~ccwQr͞Yn m%n'I!i#+S&*R.3E BF4*@XOgI;F3E(J`oaS5Va!K''DQXpR%w*Eu nWUtoiE *PB2ayi{R"P2XV7Y9fnO<>;oȓtN5B(՜Hr %ŸGω+g[Wg(HT>bh9'}gͽN30z72i=r]BqzKgUzyDICr?{i3&36r\P[ d@ s{RNP k-H[L=Obkv<ڨK )ؙN\Ri=X4 ͗G\ dz!szߩj.z.+ Z P/Lo[bٞ'zТ2?L@*! +~٢ 4VФ @T7{psOq[^qɡK>21l A2_|qα]irY s8^ ۻ(\; a pKΠP8k,+g4yy՗&VT{8tI9,bDRfH&dూ2΋Ov06*Q2 y6h?h /<~P Q/BjGZcSG~Ny%S^wͦmcL\eT&d$i=ڴ=srcjj/(ݱ:tV'C}v߁*QlA1'HNXIm {p2 ܯMT}/\kfc/ ^[B!5d K=EyvUO}b/~c &+\]ڿF,RMw%` {C[qCrif͛edUA}p˯$DJ[|c~U|9-t\χbTA37Fϒ2ۛaUb9 |ZIky(2yمfO7Y3h/(B;E6cض$TR>]: 7/G Ox.;/C)zu>zXVgt241=yDUZvW d[ޒXdm+Ho-S@TPK8زRzԼ*=#_ȁVW$԰L1,G__o) +#vaݝmC `)l0}'a_PK2i]B c9org/apache/commons/jelly/servlet/JellyServletContext.javaTMo@Wr(إP0TSǍ=w8NߙuqGyf웄 `bʍYNpq~~1 R$%"5NIN2A0F m6SA!6 A9TN$SJ ԒN;/-Y`O.M7ONT^a]ׁh:Bź6Lguu:UҲD]%b*Q 2#㻮$!v&\Tt0], q Q܇8s4ww?lD7C@uinSqb.F k([T3v$Y0K/ ~wh^:Ђ9*<~kNUT!PK2`w!org/apache/commons/jelly/Tag.javaUMsH+A+8,],uD#&f3#0}_;ZHt~uwms:_:=99LJexv1Y#M2/upGydi$uT;26PJL|qHlYZi:iQ }m1"(+$TH*gBu$"uyR4>XYMޓjx#UUZ-YG*w`M#(0KӋ:1mo6e;Jiv(=<18ϣt>4d>M_mTN;yKPXن8+Ak3v@UJSR8g]R(tl7.ݫN'9f KU>Hlj҅SV`K *RFp2D5"Huh T KD`9,1:gDMذoFC5hb l͇ƣGf⥳v=šU3m66;VP8 msжuBsJ }-b-:)qA`P"@7AR ~jD:(oR"سoDtIW;P% QÈio/_Г^`Y@![)l8O#.8u7U=pF%" NC >¥#dm|I6ۅ]aa=шBK=a1΁o⥺]lP-\mMo};[Чvb8Y`~&4ިCI0@rrڠM w,6ǁ{)M> ~`{ dhײ|cdDy}<PK 2)әV(org/apache/commons/jelly/TagLibrary.javaWKs6Wl<9r=%vCaJ.ژni`5hި?`ǻpM/>߯*6VoxWr/zFW]D N-\=tXZ7a)Gy茴VNs^n4ѣc OBt} @w+5 5, $aZuz J jB;r`r j zIQ߽̫_'Ykw;sG^V" ;dl.V߶ݶ|o;0`.DvނJsHYз F9jgq_=lL2h-EW?^D}7~)σ^(&edoo^+K#>iJΫt&o}ng$nܛ[Do+t#l7ZB޼}"cДŽOn6|lFۃP7h9J7PK 2org/apache/commons/jelly/tags/PK 2#org/apache/commons/jelly/tags/core/PK 2VU$'.org/apache/commons/jelly/tags/core/ArgTag.javaZs9~P[u3>vȥv_8qj!ˣ0 h .uK@~y0ԭn>}Ҹ{т : gso^~??xΡ3FrV,Qf"`*C5Ҽ }.RvTd{:ORԀ7kpHmnX l B*Rc)LÈXA(8 9B5v( |cȉb(P!ƧiUN\nwZyL{d֍lڽ\]G?V듈xB xW>[L}J׫$Tu a0UI8T-h8 hG0}4uhσow#xp7ħ~ :1dhR8yc7TҘ4qjb\D "LiYSt0ap*t{^d0?8<渰 (Z{RlJxBe+[2/Sa-{=5o13Aw%Zc NPT<9NSt1Zk_Y|!> xdo=^{4G Mlvoo2g QܽdǍ̲ȄFx!_öe ScbOGpi4 #I Mj>dj#/ !]bN&k+e >(Tw?eH~Oo^f#rA!{HC ,Wq#uj5wY0LR1Fk)EԺ)<`ʲ0\ WV>u 5"R W.6iʹWa\A]Ky֗71e:`Cvk-&+ss׺@/eP(hal1i $ ׏,x}a˧c+G&4*Kpk3٥fmN5[D>)8Kh`~CV ʘpѪ1Oi9)Ak-Y7r2 Wer}%a;(nC,f)oYLm0qBԢ}?}hp@[PI`ʬOI6z\c, a|\*Cne1h~rIC_lD=Wm &0FۂI(-HNI0Pr~ a>W޳20DLJV')_ƈ} 1oPb^Mvq' ;Xo$O)=A>$]e_&vbu.CP#X4lz 4jFDtZw۰Eu؎*gb k,d:Ԭh-ru. 8 r}z!&X6rC:HBo1f,2%V>eF_fM >/Ak}vVHđ*pPB߹t "#TV%V`,EQR:J9L"r*z}&4c?;y0iѨ? >qwd8O~ QFrS2ƈ;RS@r21g! C`a\H⍺-+!+Ω ZRȋW[-h?>w"f<997REwJ8`A{gG{tΠ?%Ea*X|f)N+V+6X8 [L߷B*o^Bܹз[}o>:C 225< Mc˲ތp) ~~ Dl>%R0|jЉ0G8ؒ[ D*c1.v^h/뺒?ל:c* ]NCl' ;;P -:$Cv]xF'/ Z cU^lw1neVr/W9t?SfZ޿+Er#(dp;Vs!Ef5FWE9]㪢{LEM a"lR趉 )KѮ՞Z cDQX8p몏&WIEԔHT&55 h_gliB>PERQ[O'A I%?b; X8Zqn4ޱf8"kz^Ia\ ajyXS=W٘ۧ345lv%RzՏ;9:E_[PK 2)&@ 0org/apache/commons/jelly/tags/core/BreakTag.javaUQoH~W̡*ڹ} ! I^m̮oƉ7^ ҇CQ7|wu`dpzrr:`B"HᣮT"*014`wAd_Д BuCx(m*0d >‚TuKbZڕQ |zi]Pзt"I, chys oדY4yK}gcY*iXbI\sQ6 2tf5Re( ZTM(#F]Gh _?u|{;-p=}.}7s:0$(+ i!>RY`,SSi*D EAf-KnkIZZ.NvH;![ͩkc?Vd%=28t6 EUwye2Aq7qz^\L9g T+sY9%,NǸ$YTr;NL(Qfܴ<HIuРi8ALV219,Α4YLAZ 6&WĒ eIӥPs*k7¥؞ XLGݵgTPq^|kBy(.7 ~ iT-i u@bZTI ;k;5-]xDq#Z0$_+w]#݆[Ni; .ܐxa[sX<]IAN-T -܈(yɺOɑXB $Ylg{SF׾]\Z)F4nIh"}p >˫%7{.E =!?>o>shfOV@Qߜy|4D¥/Gv)*OXU8V z@$;- 赻zUoJ0+PBjjH؂TyI\avNQǢYAbWAtvgrl q['A'cMvt5;cB]dW ~NeBV bBat"HfDZb\Ɠ&rڭjM(9u8#EF?'0{GdLn`0-@OqLD/9$+}Rk*HE&:4X L$f0}AР˙ӃSFFѪmE`h)~FubşS 3бo1d l1H4osw;Im~GhHXP-59(7,ChI+(p!TX4 V }NE$#l~(g7Ed8%eN8sHanH ad&u3żGMZ+ǔ1eAs#X!2%~I(̔Rs^4 8,EjCAD^lH“q! NNOp43vntgϺ'']21'U-eaM8JddQy6 /;P^6n)d#_X,WWBKJ46L̙S͹V~7iNr{ {I4W-q 7TEp~jU9j: .רg5^q=6 gʅ/7(@Rbfm*E)}/Нr#ov os: `Y\/^"rF@*:<^Ams`ۃk2iZuDۥ6ؙH#厤aH܄_]TJ5ʝBIZJ;wF^ew;A3)w )B?%YqiniMsXS"Hmϯ_r1/PK 2F6Z70org/apache/commons/jelly/tags/core/CatchTag.javaUMs6Wl59t=Ŏ3Qgԕ:4G\Ib4EA}xGp 9''SxaVV91"mMiyS43 t@3/˫ErYϦDߍv|TͬRfj:PC#+[I| >(09ч,20%0O~̓|~[~^l_%|5_.G-Ň) KuGLSu%(llOטNh&oT-:']3L`J]i៞K #VpX؊3XTш)ZGI>W*LeϟM褩%ؿ^6T7:;̀A[贀T`T8&k:yWbgUJiV%6gm(k9YJL|v` _(! YUpM&VOO:dI\U;Po7Jw6ˠ̻4~R2 [ob؆~q[-ׯ_͚R.E*á h$X;URHo;=brߎcQ#PYkakuƚ {oxx@W7t_.4ey4ؒ (rX}QN˵"rKuw6[{v:d%|{y琫G°úwlzzz@YYr"f޿wg-\[ˡT(aQǭ*%|#Sߗ`D-x+\2,w\{PcW^Ĉ $#E?JwPK 2i^1org/apache/commons/jelly/tags/core/ChooseTag.javaTR@+(`!a)Z"bmv]"IIFLvfB eHׯ;q8(W'A?)¨d!"57*"(zf2oy(&F 6 :CClP)$ >Xj"/3Ί:mX,4#8m 0mE7'պ⎄X%CZ+%X,#(Q\*\72\l~2cJ[94yŠJ.}:sŚdi_9.w _NN}80 h=!M} ,=XD 6v1D):&DxA&§/ZКݡtxY]0k1 ><_g[R"aT DӡV(V9 Ne ͇^,^Tۖwl)мqcgD]}_%lzlho7 |qPK2d x8&Z^xW4&Es]x >E! IFyGexDSzbG2R&2 mMr}FюBSJeD00,a/N$-!5–1E9[ ڸ+%pxL%"+("101˔iYqXh[^4vBXT@F^@`AnCy BN}&k+Q[zmȼXd ^y^0x mt١J-}opw^G/i - V!\Hߌ|::0|P>C׎"L< MK6؋bN_VEE, F/mEJ(~(NrΉ73DՋ|[4҇_{rSD]p.Z9=ɫN9oZkы/&4Lw-@*pDSr91(j!QMї)5e"B E$r%] {ԨO ]՜vE1I6m'"KKQ7/D4.DBa5!>̥Aky!Ac$0H+ I&ZR!(uT}r =`$,9xOo"7xas.bDT0A~ &ʬ#  p >DU!2G?⫈7CV"s1dxIHf]גpyuׅ38#}2WEWv_ݷe惗=. Xζɨ`> a(1s|v wi6;/[@VԧM(|,/~uDce=e:A\]m388МNG[8iX{f(U0k6.9عaCeI0mRt hv@cX¾`–~KM3V>1h4}lyDyj*͏ ^ACG}Oe:5.ψ"y$ql"wj&FT3t)nnmGXIPK 2YPaM/org/apache/commons/jelly/tags/core/ExprTag.javaUMS0Wl3l0 I(G8JrL]IL(CDݷOO\le<ߡNL-FRy +URGSjz Em1XbX&81 S4KHCBIYLΡFV\P@Fq֤16;(\Q2vw]b]Gݥ RSǣXbD\Q bg.2;`j9M$r-9RM&Rh|^$[?uŠ}]oe$:84w@4%ˉQ]XULːZK\N#POc5D04J[zü yK`>a,\+bCK(*m^P$TByƘ? ru[]|6&s76:@MC1p&\XdMa6 I|Pj"r;:08>mML:z"Im:SJ['8˹u3ɿl1,!L9#428*n_5{ \ȰLa0Ͻܮ۔ fQEG&DYG@_dp X!.;OIAGʒpZ.MU~/sq/<^lT\ )l#}J(,9t2fS,X֨ UD_R(ƭKg={ް腲͇{c6֔ԯqe9_Xc꽲A{~hoޒoV;]ޡJg/PK2]@!/org/apache/commons/jelly/tags/core/FileTag.javaXKs6WluT2:qFuZDʣG$$dMH)LxE<.-O \PVgϞOϰr, {Vpe3-d6y+")NtL/3hM$ KH2Tekp5 "`Ya/֜ɐ+p9 9mt߇ e&vίO>KRP/(PX"B ۃ,m sZ}!6P΀$&JbU*20_bK8{nv_/\߽/wvݫ p44@cc-ki!Gb-"T-۔la#wP#y Eת`Lb m|CghH9^l;SeN#<"U26.ـ[p"Oon__Zj W2<ӯ1ϟI7;7H^iPC='"g'&Fg.4" V"٬s46~C3Rjp!GAK3ߔ8tߊhK13F+y a@G:sU|Js~e-r2hb'2v^6h-Z`ٯS rya8cx ۇ(1Tm%eQX%Y0UV[=8N+1?+ N`FZGb1gi}x{B Z8ckG;9ujѫ,nz|;)b45X-&PGS}RȽ^{G5o5iLwV18n~ _<]p4e ~ x7[̓Ɠݸ9Yz N4 [1 392(. CRWy)>@(>p6H˨#/cƤj`0IG(Ĕ6 20&n1fư'LX_Џ?6*9(j3d]z*҈Yh@G{(yL !zAhI̔ LZ* [TN~=#:#xۆ47*Opu q2حV$谎P4 [p~/…6%5՞1x)nCF ~D@{Ġ˟{yĺR;N.F/ 3Q7}dЖ%>'.ud1tm Zu?e:iz !em-I3;,/kC)͊2h~bw5dqBb>y=ק}ej}bgA%r#ȧ =%geTNGUjiAkσFƦ'c;7i)MHsK'c6.dC6ۺNM!D/c;?R]B+ʠpna / 1v}ɍ.6VY]:MZ[f4_J b0[~wi7{T;~7fn3qzsxE]}1XΗE!ehej_7ȍw Ucl5تh>5@6bW8힪b=PK2~4 y-2org/apache/commons/jelly/tags/core/ForEachTag.javaZmoF_11* /勒:z}tXI+ ERq]L!KJ3˓ >sDT8=LwT,*dm'3"<+IHpAj\>ILRB'Uj\L zS|}J a^humn>dpΔSa($yq4'f@ Nxd>3YTlc}J&ѩIr,0Iel/CP\3Eט7ՐF&,c"WDXۊ TLPD˺eSTz3rз _~~~ Ó$cE(0uiP=JF HPeCsFS!o3`!0"0X3')D]Kp$Bf0ҍZ*h|[.3v" DF(AJhmAoo ӎfi*#iRRPlբ Xi*#"&0RriYHZ;RS7[г<4&jtwf+vt["y?E?ݼ]erkoLΖ%e0p-Z9ϳȟh:k4=:nMM\Du:o |3`xT3^sG1Mo4!ӻq"SOQ˦pJOw˷7"TEj=3zCZٌ.p3]Vko+oVދdcz2n|kgXMC1d)}蕮gY#;yB,k^ٝQ]t+ǠrU|fc{B5?OXϷ]bsCB$\%Pt G݂g'-u}4EҳO Kŕd+e&le&p<._ I]4s;ޓEk* -50`|gi@[p 意t @\ת~k>dP0?C^=Nj#* 8$ըaRʉT հt>@M,lj6|k⼂̇.$7vѫH̡iهJ.{{ɴ&fsQ|+A]YU{³\-i Vj5$Uk덂F,C!:J^RiC KLLT apm? GA}p hqt`u]>^4((܁0G8&H'&FzOD'JFu8 eO+BҺo$pз<LYf6+ {,}gCjPfVpAf~t4GǤY*P'R`DFƝ̶\GЮwkL*ɜ$|=zPK 2"3@4org/apache/commons/jelly/tags/core/GetStaticTag.javaW[s8~Wt:ʹ/2e)Ma&SGزQX$C=Gܺ~K:w; 2*, ̗9 o&caÅ,!HR<<\ ^\i4jip> xVb[ȤBsbr7! BSFݧD!&Đ PB.̔4&v:&`q UI\lF֥,Z? XB@)ۀTqHbQˆ,i.H0FEaVqD67xx"s:L W0NޏG0|Ɠ-2܇,@#b(震"!%K8$rUAJh Fb% }lmi&tts 5kDF)JeHC~czϓddS I> ̒) ѬIio.ɋgF0eZ_Jcjt^ :6K.!ļQ `)N!O#75*#hTLShlUt :$V箲Rqf ߄-, _pdcR8z` 1tP[ @л֠ )c5u bpxvqapT]Ue^wM94|bKÃw&9oם2{or:y9b4x.+օ߾}sz/l5bC[YaOA0S$iCϕX3gF.!|?UWnm4wڹ,z$Ò J ]0ڤsZd;n2dk)"|a{A |Ls$ Yr._ QuDޯV? ģ_ĽxL7yLӯ؁*B=br?=DwHDJn45J{WxcƦ,GzDیt <={%ent 2-еRh<N;d^vud|*f ֨m}͹$e9fSw?]\Д͙i'tu ƾP~òEE} nm \M2U ńKNtKof!% eB, Z]/#Z@gXZ~Pq -05OVk/r0ZX$5-"JV2݃-rQ"l8Ȑܛzfچ-td"ݭo/PK2[-org/apache/commons/jelly/tags/core/IfTag.javaUMoFWL$A!]#q`QPJWڄewb=3*cn|yfMµnvF''3y B܈R]NUpR8Ff,@4A2?X0St ؁ZCZ(d2lHJ !tm:> #>^;Az*A865gQu](zġ6eT 6ItPBk_4z!TXJt ٜfԝNriri#mZ?v ڄQB*NtI>%ߖW)d7*Y.-ċ{x3$ʨ~k w@0%Ӊy]xBHL2Tي[4:M--T׆}+!`k`UB'JK A=W"OgȪ_Rmi?,[״Տj㖚Sn# Y咑 ܊-HgabuX4KѺ bT Y9}F<,;QSԛ^EdW-n%ߝ/_8=g@n״UtΡ-7S@;[c䖞a~䆖CžxB/qUDVr(~t7M0f@;dA&u \jjrd;{b{uBI09S[H=c]+: {aFpT0Fө$eL,i]T~TwI1| iLK1WMC(soۻ\6ˆ쓕}L@V݊ڀ2యrc`.PK2( 1org/apache/commons/jelly/tags/core/ImportTag.javaVYsH~WR,vu%/qj2xyI L,iة@G___Oop򅖓Ã.jlB#|VE +Uk^31`WJKAmH@j*  Ȕ ِ2As 2Hy"E!̥:? #ކ qA 9= Q7JOzI)kzW˛;B )p"'T k"4Ffkie6 d34V˰kI0RuJȠ`؆`e#џ#xoF!ͧhp{CO|R># Ӊq XLˈB& L uFA:j`fJz4bGVȆ(Uҩ)0IC4ZQi[/t-BN_'?PI*99˼,maD[}8yάr3FN3q1Eخu醺XqS53([tY>̬Lhz9R'5dd@B;M!U150g;Tg2#Ҟ ]Pb9|. ;^;08>mB&V*!JE^fB`1 jZL }O9DE+& C%JHHrLcObе=k9C -調SaVuHԵ*C$JUjzewKvÕ [rBEy*&AL`#1M1a? =51\hd}dRYeU;{TD{\`Zf,"/krtH)Lš4m"U,FCۡ/RNIA ǔ6ZT XZ~Zi-3%c<=x hw߲R|QnSȊ$o{5Q3;uM =V/6LV~ѷk٣z{.J¬hnOQI&R7RxPX0خ>.%͠hZ.vz3a盘@3Õհu[;h ҍ#U$m~lwqo_s%lrF[h:zK׋wyP1cܒk]e_x=!)XHGϝxMR'Wc.'>PF%Lk4{i9=48I!Y|egjPKC܉q(*wJ`~M]m76PK 2ւķ? 2org/apache/commons/jelly/tags/core/IncludeTag.javaVmsFίj2pp=2=%upxH #wE vv}vo_sҀZY~x/XJSW3\Ԭ5OQh̀6P*6JŧдQ؊Z] %,4Pj$ asO0rQ䜉a ( | rb3R(h5 3{jcK5^Vw5Z"GA+xVMkV B3Ҳ^)nAZk4;A8u $OIۂ|×h ܌fq0 iuWm0/hrN\ S)S>)&f%! @&z/khPY tt:wذO q[2b('{t&?fg|Y߄cz*J쟟oJS$蜜@(:tN-2nM2\d5pa"5L LfN\-ύ<#.L|E[xu{ bKnoߜ +`OP@3JH2C Aij4l]/kfZxw)sbsYqB< -"-)C,=$Iƨ2T.[=AyāM_%!(4bs4P!#S3Qy{)34 _a`4&4k|g |a-sm^6V)̩/EMKP] S#*cMՙƻӱhTSbzf6MZ5J4m؛.U*z \7،]6y譐$Uh["sx兤ޛt;U Fi0{:UeL\Bh;SkjcU~:SHaPRO=p)ӭRógy%Qʅ0̓i!وZ3REfdzuV;wI̳  ϷR*`s5f X8iIVo"PdZywV؈ 0l,h i^逄|~y7d6-\L^g h~O^cP*NM91a!IYD98DrUAJd IL,VB~`cbWq52|(l|W|@d-hT\yR?Rm1{q|ѿEm;%HD VT4SyϷ7N 5_,ˮ%ubcvGa,IIÖr+$f`UH R4T0TN F;K_kqgE,;hB1E3kG"_Dc!RRF*"N*t[8cE~?9+:vvġ cgHޙsk1.Mk41}GJO6_o-@q-W\^[&rKhr%fbʌaPK2LU1org/apache/commons/jelly/tags/core/InvokeTag.javaWmoFίjI/"T]zbf̮*lj-g晷gƛINZӅ>t0YL_97k>B$p)"2dV[K ,4Ph$ a3|17rga)Ql$Đ3HANw"0S1E^#"Jhr.> \QƳ ٌb*$6↋4]$\g+6FJ@ec ']x7 'yN~0o&0p: F}H%#?+m91q 0>$c PSZs+)T~ܞx'MPz:zt';.)WZP>5ml^^j'/ft Ef⣲T>dX;CD>r:UCeom -ze#9)ⅇX  9aaʲAqp8cwW{C5.iM nu#u1uft"n?m9KЅXi^] E0.{ هw:BjƜ :6 qj:@`C6fiӍGd@FOōa)qޖvh |)C\5F$R S7PK25h 0org/apache/commons/jelly/tags/core/JellyTag.javaTr0+v2=%إC/ItS G^E27u@9T'GpaYOF'2E2NFƑ2F0:@ ~ԜZGpC{8SJl@C!R!]!6BIcJda&a^\P@A!oH+aUUfb]x=OsbDh΁若xQX, "Hg0J/ui鼕bZˑ?mBCw$›Q4vx;Yh>Mq9\̦d6_dz$˨MvbR{!B!5[JX2&i:+E5ZM@( ..von=]QD^d^Yv:DXw;~.D6 !tTyEO2YFv&Oؕ !V\9ܔz`-T)Ri0w#Z>:[L_uWB*o_{Яm='V jBqMn`k10\RCuN9G8; ?:Vi)تi X(hbe+`58rM*qŤU U'Xx{ =z;2}L!1 ItzyCk#H ص琦Újo鮍[#yzl@ %.l[VU0y!]d3.< m8n ߗk kDneݓա*?PK 2Y6/org/apache/commons/jelly/tags/core/MuteTag.javaUr6|W\5y=*zXZGJ/Vy8[n/֋l~_,SbH}ҮДNNNv j)c1J+ZLڱ.QU i\[ &&y]np9kr+R)ף(*m?7\ޛ^0Q]aU۪> }* `[Q4Y(TiԸoo+Eѷ5N;9%B'Kt”( j =;+u15<HONJn|ə_tVqӖ.4tNhwg}B\i C1Vo=lSo>r}9V1˒%X(\*Jqb|εՄfCu^_+"j<'tj(:HMrR[ФJ밗-DlLP_ږMB4d+"vПWeFWtek!oOsĒ6fI}+WB=<TXx5}ył6֣ݣ>OhɎӹ$=.v?T_h_z=w殱3c>Fz@3aϮ^ƞ Fb(= }PK 2(4org/apache/commons/jelly/tags/core/OtherwiseTag.javaTMs@ W!2%_BȔ4Llbv5W2N a:t[OӓVAÃt22;۝&=`2Gf"P\! U,ԪEny'#Tc p[҄h,y@ՆO9J+PAnbH 3"K ҋ,BEt2OcCO f@"]sIE%6In6ðH+{`w. U<]ȈU$5h"1H6ua*i0iމʑJlB ap a< &Fxda4hx= FCzM@Kf)YNKBwfzCfə4"AH Cj`aR _' <ЯScz4]H,}2xyDQo-?'"CBiO?u!tg(wYNP/h4YBFTG<_4is-U$FY9T>s>(+'F-l?סEddz vhf":hȭ)-6TVƴl3F wSߓ€W(:DB72Y3Ǖ PZf 'Kvp7"LjM "! |P;*kF :^W*lFV<`nQ@>&$l| I1^vK"=p=EzhI ?!iQ|'Ok?F-Ɗ7"_XЪh$֟%y5Q﹛T й^Tt⠏UnXZ:~bBLdCعPK2D0org/apache/commons/jelly/tags/core/ParseTag.javaXs8_1R(C!LGq夽ەd[Hۛw~v78S_k ȌhW)4ZV [ہRQN #d:;,EaXJG4=$@1 Lgd6HȧŇ9|\^Nӳ\\|zqw`rG9*d)ȝ|i}7㼥J9'b%4M%K9j˵D z# k .IL&6(vAt7| GgulXZ#͟Jʶ,*OdzJn6Y3]`穒+sf<6|vwyu^9K*eyG~$DN ʜhnEiOqGߪdjNQp.kLŬsnE2hL:1ÞЬ:Gse}kjyMņb%,U671#i(FVxX.m˴yRTNT/XiHZᆉ̨㯈.c&_4w ۠%3٘=2]o'={ $C\B0<tq`< #wke{#/yLg_Ŗ4& Yf /@q E.U MڇfL}b%G@ح prUÇtoV`d E#:4^h+i0[, źdܮ`qUrgt#IϿ{c 2:%?| $ ۇb.)};U"ǡ[%$Ԅ2==^fծ=^ 01y-_bCdeUˆ2U3\ >EޞQޛ&CTl1V>+|eH#]-rZ u)# LF^L#v dŸU PCS)~BknJ-\g\)* r UnS W5) =䪬"JԮ;;|[q z*EχAZQ\c J=ņP6 ,gI+ jѭoЭoG\1ua |?`{D9y jצrU="MsǭAwwmK m P@w%Ta&AT'sM/"mfNgS6o]֟G>pq]@]mhexBlJ_݆a?Ozbs*qv Ss(pNh|BDF< VI͋뷡l~'mz :5:H6/i7GV!+S-gkoAo'U˩v#[6 xMÓr5>CRpHJ& 3F]N`i/\hS5{ 6wkdA%@5K(3Ik,-$^ ~s:x dYO?/n?nO -(w!Bzthx V~: BS|TKHiIPK 2/8$ 1org/apache/commons/jelly/tags/core/RemoveTag.javaUMS0Wl3&) .iZH:q8GԖ\It]"0v޾} ؇KYOd,K,b Zb "4yg@lNQiʀà -Bd 9[J5yO DEƙH*nbǐS(QBAO@`ƓvkaLqUU1Jì?g݉ J XA6%@*`B3Ҳ7\^@ 3(>-͎h/ hF1 &|Aܱ ? h8cr4L!=]C4|U$sPɭ8sň;沦 L'THK"rJPEPʹmDpfa2s㼡_e $oCBhN)#x,[^)5DQ*v=_bY޻eacޏu{3*MQGNG}K?PyP-x 夥v-Bޮ)_rj{J0XMǗ!`YPN,Ϛ9㙑'd$o![!;wK?{c\r{wW7!Yhd*ba)m4/Ahafi)n_gL @Fj4mku۽YZ?PK2][0org/apache/commons/jelly/tags/core/ScopeTag.javaTMO0W*[/JVjʲdM4D+Ӕ{X~3~9ށ0ex =`#%L!J$p)\ P5P!?ЯtEH.*m"8gq ]>9za0~fu6~,$\Ea5B(RYlMv\*y^dn㥯q(ZHCIs DŽLF5)TLrs7Q9\ӨR;bCEli:zsptE5np! ~} hFTAUciGtH+ݾ9pN//-7C˷KCbRDYcK_h4]ww2 rAimp]ѲOjԤ{p7^zxЃ>'BwPK2>.org/apache/commons/jelly/tags/core/SetTag.javaXms_dDHa Փ|Բ-ORG<8p i/r=͇rlv}Z,=|6Ÿa%: zaHzl.Y 6|rNx ن)<i pг"&8 NήXģ.i-)ӖBB*hRIDTF^Y"iʝ0%3+@.עMH6~qnc,/RO[\|ԁ}ʢ #+ƳG9P%bؒ6$FՌzkUrDE0 5+mhF&DF'SLOt2߽׷)ӫד-~_#0Α5Lsg !LB%P-[b)i7dЈri֪`8g1Z+bՋ̿9GIclŲ-#@'1#\2$ R%y)Jw"oD9v&EƄEWG3}݃zZL4޽+m^~i(M}y-%/${##88?khRɊ i}\ ,^;HZN?oq@H+DُVd-TjO|ً&#O~YeA  u{Q|?oVΐA?N+yAC߃֎kt*CP"Ҵ@ISITˍtOP2:!15&y$ 9e; - 8a}#;#&K˅ pώ{DXި韐\ O sxPg*Hָ!W-ӕ.9m%!If:ЌP9˞iJ;&kjh!lpG4zf!n~l\3Tv_gPmA;%2 Xa9t59׏̲/(SؚG-(ئ)+g-5Ap\EaLnwaGtA3hX O:u P8gӮZPwB<>W2EW>UsU0Һ,bHUA7? P>@v#:Ff›v_ڷ Bd eP՜,jf = ,]jnֹ}ij}kx/Z6 U"`r(:k m˒7cy(B vYGxۣQO)Douj,캯Sb?\89➰aWa鎗@Q7E-@at>$E%Ƚ$pS#3l_nt`ѮSǽQgAVM|O]TUьzfnhM^ K+Rg]%i3M57иѺt 10퀢BRX:M=O|adu@E=c!N*h0JM( ձI`G|wCx&L4קPO/Em+ DL7R5IU@TgiX$B'+GrT=vhjl_ߓDwkS˳N?E-PW`]LOEF_+e,4h M-{N'mSپO7I00߷!%@1vjTHSu?P^`k/ %ȨzRmdVf¼{Bs}:ZU-J4iۍs"~ZQY_R5RqBU)w`2[ ];;P.RaPK 2ߔ}a6 1org/apache/commons/jelly/tags/core/SwitchTag.javaUmoFίEщ(RHBt T1w}\챽]C)I+]gfyf9n1\txu}|Y0LO_ ͊).E̬-Qh .Py1*nZ& 赻дh`]e ! d|L p\ gGXq8>032H_X3iƤNgZcܖ*$9VwnW7:!օg֠{e<_K5a+ XW.袀MQ|): ={p9^:y>M?ax?#p5\gpO[T2OMnˉA!9%CSj"X%*AAjm&u7Nz7/Ӡ2?Z?TYaۆE (ُ~X4r"wM,e MQ`J,N3fZԨI7:Ns'vc!1iP`Kڒ%M%k2+Vs`Ȳ| 3 ͜r\ha\"K8?ߪJ5poy[~^M_ROhK2X7 \o_[qJ+p?}2@s)W$$ozLW)ʱӘݞw%Oo^԰bM1oѣ1{+cԬwHh87/V21vZz'mjODzU]n^nqt˗4jUYkd* vl""4PK 2ht 1org/apache/commons/jelly/tags/core/ThreadTag.javaWMs"7+:wpm崬zqā*(fA!M$1OfO;Uj~%w/Zp&_[-&fW"ܙBKc;ea vSr _:+ؠ]-;=v6,P8$\*|N0 5$f+)t~Ω0Q03/\І~͛ |:nwZ" ͺu`4#ծG9w!-E<[ U"fU "Hk0ꕕ^\E IV CZBomBC? 䒝|N?N[??xe8Gp(s9L' )!9 BdyB)".:%mønh5%R؋є^ESP*(“ ĊRL*/ҥK,+S\XYD F~AZ(ʛORur-< cW|b$bF$ipOT=f6fOV>1BW5Bf "aN6 祪SQ{,LRXYʸB55|Ta˾GÔn)LP% v̐_cP3B'ߦ;ӯhm\)߬Fr <ڹH|&'#SH (d4+X!mץ 0S\3n<.c:k^8hd:'/^OɎε.}WDDLkm˗Bn,4{#ZclExTZv.IB]E;8yКXMB9zP5|6:c6{6kQ§ c23_N&sp~J 5XB&Ө#E oJt s!o8M \ءk2nxغ-|yGջZ5,-)7jn [3~JmG;z;{-ȵxQh.H]fܻ^? H 5{$5`եxvu4hCᙫ8 :QK_PK2Ũ7 %2org/apache/commons/jelly/tags/core/UseBeanTag.javaYs6_)TK!rVt^jg">$æJx /۽kn`vXo'G ;U!KÞ?{|^ť`ӌ/\͞tōTi dHA.EŊșȈ&r yE8acdqPKaCj`Rdɔ-6K$Oux a: Dƍ~d~s8Vfعzavl)H>К_a3j/@քƌB42݌v D6+M./ SSN s6|6!/ӧb~?w ~bӳ?fgFL`5q Dun.DM"L,Z.ak6j'v2oc $r+ نn (v HClFç\*7xĹX'biYSKZh0JFS?s}+zFťȹQyP7+b?wB'-<}ƧM+P9Kb ]M[!$! N{t/0LbfR!x$Q{M5Ĝ7Cb^,5~oc'7\^s ]O[.^]AsIAoH^ħWǗ/_<X\@.qn|JR[8f*Oa7GGCK Ix;Js+E\CfJLV7T5tak|tuçU&\l!u(gzA:c ũJAEABKo <[[tfx*reL7u;4r'o)H>7ttx^+%.Us= |9ѐӿ5>שڧBхR օtلy1G[2kFC0D6O?TqŠuC ǡHs/{gZp SUg i/2|ApuHSU n|;%WlZӬ7MW.9AGruaVd߆m dNME5:ZB;Dnsp d!ح; [bԝeZ@ IJ-tZ:7 Z E` #Tg.G(qZ[ `@5a)pB9j5^[&%T-&p #m a˙2TV)6Ḩ^#78STM  | ,94p]ܣZ,jefDq& ieh\KFq%*=[b+T=?hV8Qb@WR[1WBAJ9ӨAiZ@+wE1ߜiVt|=;xA[߆v/_@јUkET%.K-Ia곴i \ KD:҂Vq. ā}X&9q]O2@ ċ}1tdi1^+ߖd`cC:6hp/2ࡽ;@W7@4n\.ˀD*H@Uhjk7ߡVw9:TlXMu>%Eo8sўWBTbvJ=:Cpnmnʮ6Kv>oìogQ!W5Y$X{}We[؟ѿPK2AH 2org/apache/commons/jelly/tags/core/UseListTag.javaVKsH+zH^Wr1+Z/l4ڙJ߷{$Cj瀐)h t5rrpuyyե70[!sen# ]dpRg!僌1 Ѐ*IFcKX]ڝRL;(,ia!Ę;:͕YnT^ ||. ES@r.f 8fRFp<&ԕSZ0o! e<߂ U,U hbidN3ꍑNf.؊@vH댜=FJ@ )mxߟ]vy4c4x6Na~4Mt/i4e_rLtb⹛"AX1 SjٲK^(#ѤrY-L؍t7y^(j"z96%چN,-=2k6Z*#DN\6rhX):w}ߙX}'RnT, l Z)9$xх>1YxAXNSJ=PANV$ )+,-Ȅ.T߲Y$[_D|y1,l-{cX pȏn"䮚wp++v*r(ٻz2wEJyO+M$u^^=Zk7WlbN3ZayȨ]aGQ0u*_[-^k"꺖*qtzHi[kЁRAW tXq$KE'dF1V׿41Lh`2&CN!i$o3gj!aSZ荅Ao%rH_(}۝fv- GvVH__Qyſ&Nvvi=8NGh0́Òs@%;ɇnc ꆵ0]hdSY`޼o_->~CҐSq墱ɉ5P/V苃_F-=v Yi_lgWGZAi>_\w>"P„+aǤM/(̼"x۝Y{ Q(￵1_́۵vPK2 r{/org/apache/commons/jelly/tags/core/WhenTag.javaUMo8WLW%_Xwv푖ԒUcE{(DǛ7ohG0,wpr||2XQ%5 |еJZƞ2Ae1:@O&KpÈ h8>;]C)v"Ő6@o VDU!J6HN 6}C΃nW\uMEhEgktg  WKCw *B5a-Dڀ ҙӌ1IMz9L*3r]G=`DP0bCy< ՟+nnj>ay|5_.D/|~HQV`JӖ  ZdޢQTThJit68Q8 895$+.p"el0 ڸ~JdV$.d߿_0TTAxtPM2I*TVphA: k`-lsK<H˩;ra)dW Aˏ?:ed n%o߾99l@mפjH AbQo$*p xL,4 8"UFnf=3DowFc >EyiHo]ae f{ n$i ϴZ[d 7t4K:mni(Lt t. Rj9 W|{Y[kjJ *ʔD8Ol6짾 ^:ԩWF‹ J AҺ@AI䎤ENO(E$35p󨭾+oc'hМDۅi/IOTx=>Sg_qPK 2ΈY 0org/apache/commons/jelly/tags/core/WhileTag.javaV[S6~ϯ8dY2/ i٤C'"{ d!sw.rpiYM?`#t LBXkSTxitLjy#SJIDH#XY5[lbiJ%htH6T`AjH̬PRa!}V m$.H _+8tE,ج*Y׹_GB]k} Rē%P%bBXX 2t ^XjL*rR-V)MMhhvG5;l?u} w``x U{p$># 4p7B܂05$W`"2tV !3s"L:N#)Qr&} <.vi4{6DLHH%Z^d,6X_71kߡJFe2fX|hj¢Sdߘb".) P]"I٧"qAz!|J0JH`!%fǹ(}NE@nqz֜ 9A+s R7h /uJ'H x>·[K~:?t|B5儚%'uFwu 3%4^5j̽/zaZQ!Cu0>nBRZb<[(U"fU "Hk0ꕕ^ ˤy+g#3F:d 8\6~L?Ghxe4#]At_e$}̀`JJ l Ʉ9Bnh51B:n#)Qr!} o6HCB?kN]PFpJ/rG,5Xk~NE>LB}BqYpDZ? ǥ/ʿ*$G04?]&~pUwz ren%}.=:*GNf&]׮<Sǎ-f'ͅʛ=@}uwZ,A\/⴪A;ƕ39$J}n_ d*:u~5|_ukDL9R@"rtM18r)<ݔMP.V GO[D%-joBZO\2Df2-ޣ(kK#SH {K'ɚw̠]凜f˃RiAsR@zЄO@ӄ^Ҟy*F"~PK22+,org/apache/commons/jelly/tags/Resources.javaVmoH_1AĤ4F]&өZ`6w5wvm w4:Kų3<ҔmvA :B搲i H5)O.4K8BSUHSUC 26\T53&;iCKrn]λ{Hk֠K1/e*bcš+u"ne&\ǹmo. ٘ZB/Y¦-7mp=pGn!zޠO. {wM@LY[9q  Le Ig)s#rJ#P\۶j8er㼡e7jy|k Kѩ)7$ ߰XwZ ך7{%|FXY*A' d0t}Q()XR lO8zAHnHX L*B1K_\5b# 2X&fl@XA;ɛVvZBPxtpE,FsEIU7 _U7-*8}8*~|wkIU}fF3V8c sRi JA_ gUՂz":XUpǣs 4`ZѮ3CTrA K#zx|98ԺP9mF3ݝur b^j o^VSgQ} 'p&'zv Ωጂk!1VJ VO23% WRAw+\ RΊT֩:~s:(eb4Mo02 l_2|$>Fb\m}A3Խ)|Y} [`/su˂T d'pcQߛ'R\ټִwۻ/U)_(b?t'=w_~o~Bͦ\OY.tU b\L6k7Z 7_]V ߱4, ₭D0[-6y!wjB1˻a?; h ۈmNA2&M%-C`iBV,U\kٽSö"ٳ%PxKSMwZ"U<9~n !ylö_?J*4^ v7О_F,tOrLtqsIXVʹy ˂f]g k~WJx$3]ƕ6;~ew gcbQt/ɛuK˅wy&l'WReFgs#HsRE!/R[UESzr[P'd>!ݺTDcsiGЎ]1:9N)5Mjp˼Kljdo ='۫툞oKY'\dJ6.ge (AG94@I6877C|i5=F7?Leap<.M!"Mkm-d ,wks^u 8\A7ӽ +7tPn .G¬?QCF<謘i`}}7]Ö''s:\r]yVPR<4)/ Ew<-Z]J~0j]3h3_TЍqhGǍSij>X#1a/ۨ4_@؛uz}quW䣴yeJ;S?س `yW?5hly.9h ԍKXTAQG0mvzx~mխ _/?PK2&1|Bz(org/apache/commons/jelly/TagSupport.javaYms۸_ޤRG/q>c)t I(]$At_&^b_%\AW^apfrevLq lɌYly%bi$pfc+:zCZpIG x2ie +p1 b`Ya'Rː p9C…7ھ6on1kq$zz|5]~V{YµU/hUhkv H3)aD>HbB%i]`XG3Ύl:;&!|çr7pqs~:\p~ uz8 \hp݌ +L9JZ.ؚZn#ȹJj4pIb c~`˘cbSx+rp2?Pb mD"WEFLda`d bK)X .8?#f:aQ|uz2Ϊݰm棳Y5 vDmrJ,Mͬ OBT5v<څ;) ] -cfF~mЃw~h :(?:轣+ϞϻU#pRF 0xAkX]h4eiaԏ?+p$K2-Ƹ&LWX0D1tؕJoxWdqO0~R~WfJ&-[]OmyRO˨T"e=3$4[G0_A_ 86j _| Ң*n43{c뗞 t[ np;ɞg|تFG}UA6VFOi(+ث*.V:w.t:{ZMpGgM]!KDuZWK!>viGZQ[+4UQiӲwa;wUd{F6Ș m/A}Rm׉}rig+b7Ҁ>[momgD_"AG&/L(,tuc{, ! ǥc\wLqK=+jx3Sオ{sgmY0 HȎՓw}hdqBvݦ~A = re->GW\9]3 uY!&8e-蕆|WsݝݘwiL3fRu}yr}e/2kPAk&=[s~"?`-K|&ꐋe =6plV?Iq+ OHФTڴ'vg n vѽs(D@CeU][]2(tUMPKw"1[]/AO+B,':kq =nuD[g,Q2DqMkn>j0YD?LL“"fK!yBc TT0\@Ǝ -dBkHxs\@$[c`PJžTAZl8oIuz)j \QTElMZSVT6 iHPp郮 t41F5g5R NB]4 gaߑV,^V:Y.'1l5[ &l$e@2һLB"+I:Lj'<Ʋ FP rT׮Ǝ&7eo˼AGϩ!/ߠ6NIe 1__ϭU+2,3eOߤս/l*?^X['|p]v̚-4$)v4\-qݿpWm0A0 ~?]@ZZuփYFa(eTOdKoPߝ{ԂTgA.(G[Wŷ31h4/ף+Yhx,إƯri(|RڛQUv]v>KjP\S?RH>,;4޻ 4;%FNnԬ`UJ绋ߠbx=wZZ";'lJЏ{3ctҦqy&\ĕOtᦕj4'2';ch%v^Ҳ*\RNWJo#,}*kW C76!]|4fH]kں)-/77w-+0,8x5eKV)oWUV@Qy=t I3\WfUk2.yzw4XuNR/[|x*PK 2org/apache/commons/jelly/util/PK 2W)K3org/apache/commons/jelly/util/ClassLoaderUtils.javaWMo6WL}uW6MZN{]ZTI*SwHQ$ˉYCGfgR…LW GG} aB3s3p%$b$ 7yCL4F@/P87}&8g UBdKD40BL BLgIspx |rf3rHi^5f|Z~ <8*VGKj ̸g+`)E*XR;#mԹ'q/62S+Z#^5 &]e8Mh> oor7pq38ntg}4:*m91r B"$b<Ԓ8c1B,Q%\[Z5Y8mBNQˢKr  3\t:TL8kgvB#ՊP!Q#(&cQB2%,HL fD7WcEH ,M23if,IglK&ug;SXbDWK)ޢT%^d-h6NTX!$,K!dnaUFmD:^Fh^ |NZROnBF21`!S9u©%Ҿ(+<w62l]VBW<}, ̄y:;Yif)WE!//J@* j.@:H־[욮BZ_7W4{9ej>>VHtP=6֎j<*r  8׃ ʀpáNYg 9Xd.[ݤ+w1 l|~Ε6%'kGg i\{o'[&glMCj,t};ڙo ,Yh`:*Ӏ* f*T6SiJ=S]h %Vȗˢ܀V-Uޞ[QI yAL"@%HAo^7~[;l].}g6Wqûw[<<{,~a a;/UnjP{0|7s'f^19?>[SoPK2=Q3 4org/apache/commons/jelly/util/CommandLineParser.javaY[s۶~@9%/vFF=t$$dH9y8E"X.4|v@ m%_,599::?%#1s"OgTsF W^񘥊L0It{& ' pSA YlENVtKRIy{Y OI,VYi3ziq\P!9<}BBڌpl"j$\ KWWדWڭz&L)"ٟ9tKhRt &tC$t!iRo$<]rD63\׌V`6`4!I@~MƓ>2߽ywGG %7ח5<&ɿח}d{$jbr4'M0V$y .Y5)hD2&W\[8C6 _qmbC`,]<%'$(<9;8]ӈ5Y{00U%FRҭ5qf`͙*NxtFW(x~$_ ORm$ev>4t?5=qLJU;ͲCu[߂Vlv t5_\Av0#>;`sΓ%^2UxǦqD&$V|:5Ex2>ll.ymCmk8@R=MrV-% 1 ^ab*DDctN6rt ) 9Qow_wƉdy bѵ KUWf G-eJΙ\aK80v @UF7!"2ly'o_LϷ9Awl2,8 ~+;@@B0(0Ҭ|. gpW*kW2w2"aal~N&zGs%xf6ꌼXT/r<_ԋJǺ|:r=jHnON`sgc!fPY)bCd$2gD{mijDNv h?#dto(Tꚇ]{`th KY'%G;>JV,L ӊl%B'*ND#LҺP+ALOMFG;p<9a˪f|J"`?HPr:blZS5x뢲 Jɠ[Cc_jg栣X_k|neW5`XH25$k`bKϬu:LCO ZJ’=ǜ~A?XB'4[l/NS.k }`9W@cѮ:cZ w̝,rB;uў™:٦"ݮk?'$Sh{4O-ks5tNhD,(V :3S #7>z?,76~ʰ(蝕IE"|Be\'B5ֻz.L}u) ~戴Hu!,P%yyve\g|MHİB3q$JX3~xm>lz^l?A L+Z֏\2sF8!ǥyd!RJ^ zhō(T>UIǹdor챇y7{+Vcl0/yv]%S8h)$-] [-FXކuŏ(_߰<~Szփ3zmepq~~1g0[" k-3 4^Pg9jZ𻤸2?:ʀpNN/bm8$ `!~ɱ 5䦪:Gh_}" 3̽pA 5-t/ҴmDƉeXn&/:f} 5R5XbN\hXEZYVz( y+mÑJ@ ' fl w3Nl|FvBoo`8'$_jMrb(,LG՘˅̩4]6D( F[ImuD`%+7a]QΟވN(%JKu=c=|+HR[ѵ;-%gUCz F{YM0Qv)%ˬS Ux+rt؍Pʴ.0J@chGo$'#Z,%,CmY7(FIji<(xЍ +"25|z IvTr=5-0cwD&-Z4oBS[ VV?J xsxD]'&; E{(3xkT5- ܦU6[xfM3g3“.Ĥ^[~_A7وm{O xWiXF\<~;Ѱva U$} uؗ2 nkhtIG4쳭K6{v_[ }8Ti?wʮGmBg <6a(Ǜ݁RoGl7V}ȂO{v3v{o"~h~z) 7PK 2_@$5org/apache/commons/jelly/util/SafeContentHandler.javaVr6+:՞$V&j]c*u3 rE!-i:.@"%*l'flίùWljɠO~i0YH_Soe!"f-+/yBc4 fQ5ӇQiZz6[Mu,JiH\Ü 172SD&qT( |00 g y=HObLcOOX_G`=V)j ."ųXlF\S iHz" 0FYa9zt.4 A߂܌Ofx}=Lǣjr1&xr$h\* ډ.@lP˒1s4,F*A GqmӪ`daRqjC!מSb3Zb!vRRO74'm\ ¼#.)֐K2##WkĞ]GBd`.R*(AFi#@dXd3O˙.sTE"Nhbh TmfhbP۝GغʬY70 %%DU7c<5-ěMaw_2TS/}I10%96JAPoq:rdzLIڴZѧF1%]*cWM%˻&QrVIiIqQqAS_[#nۏ:kwRUŲ} FnT2Od][sXL'CC';CEMfٟ6Ӎ`ܞGksj%d V7O)gF{]d7]?Ʌ'[QWNihbXHe_lnN.#ܶsWcJD MFCo‡;zUUiYrp9>0ܬIMFC?< zPS/ӶfpzHZ N=/!NtOj PK2[U˵+org/apache/commons/jelly/util/TagUtils.javaSn@+F>ٖ QSJuAl)F9a ,,]LY JzX`;f`3Un4ӓ1?>B!LKFTUK)`@ v"c0N~'FU BekI|@*/%"Ff9]ji Oa;ʬ-?~]מh{Jls=]Ë̺C*ҬxQ2X,5( "1Z" te2VӲ=rd l(? !p6 p&t!,aQ%Lw-2>J0Mrvbx"PX)1,H+"j`EPɸ&2rlA~mwuGϹ9#(ƫ,I씶XSi'o9ތGGmgR;bwKGvn* O 9L% I+RHpRQq+$l=Y6mP|[[J^%qgѫv4wc,w了}_PK 24:'org/apache/commons/jelly/XMLOutput.java]{oG_!CQN6 ,و")9`ɛA4&9p(^~̐b'n $8Uu=Du/\?ZBo:*ɳ!4Ö/J5pAr*Jh!>}/u^\,D]*#)4IPwcDqXJjN^#Un` M4WjJxÔ-_^_^պ՛,Ue) N h-Кʕ !gkUTJ@$)"U4C#Lݿ&3;=;Won'_\\_W˳W׷'?ge0[8 3Av Zi$K5Nj9Sbߪ"*IZ&MIEQ6bGitX4t}E%~rËW$Q|U]-*\4.zy6'@uwO?BB_fe>;oʋup$_|/͠E:,P^>ͳJewX׮O~l¿{䤣kuW _;ts\.@6zNݼ<ǰ~P+~|H%+[N"- d `iV}2U AC9/WX&K&$HI)꠬s!KXy{v <{/N|!EW 쒺ZIZ~Ňd_rJq/aɭ{nL||S7խyT[rI4ẊT$*D ud$~E<ߝ\<` ~Ï=dH!P%`xS&`4[;fӏb Fd- gdVuӯ'77/ysZPH8AQVH%4E![ 7R@[YLUW߮V%ušD\cnssvɛ7_\zs 1QTA"1 deTrѠQqd#DQ4XZYC,7ZX;o{ߓtD1200V*-%VQɀIZ͓Gc%+%X~Dh 7~#mT|=sE9p \SP.2p`!M{ QHcux9nK/D\m29Bu*yJsc0sΜ2K$!dxoEue˦v̈́>ZlcZlihdaȌRXFZr8 #3VpʝT(%W P7Xdx,(nI+ӑ&eV5TNLXݳzX7 BdO>]U(@D܄0}-~)g-%&Zhf+8Єȍ]Cf `C{ls0E)ʹIrU 4ɠM$뒟4~:) c?GW<EG#NNnNvWnjL$U4 l [PK{>O|˼YpΫl(4qtoB˯rRUԩsnd\BӝV4A`d[_L>큟w !Cmx?l^ӮGt@阮s^}<Ҡ9O P F]|\;?^e^lLб 9ڇgsrT),{v T!:ƒʋg !,~'<7ZxZ|I"e)ô̮ڇ z%-٬8uѨwNc:1+* ȸ@ex-22$,ARuDǀm^r\B!5:7%&zABJ֗$pn7 N>J\6=XGǧ[i}e€2lQ]kNr sKgH []4c_r %U`nGR O7>&!)Õs/Gk2tUI#!x%nrTh>#D;BڂUj6#S/ `󎸳qZ ce-h%iߠ1,YBM7/ĥi^dܼf9uYb‰JaAm03"Ko|N([SW9IA@ Щ|Fqo Tũ',´tTyh|LO,^`qѬi5w@4Xy&IP11Z3j͜wˁi5:W$r[`G~VD(^KNt FNTH~Q)IpUSt` V` V \觭"%f^O04``dzޅ$bƓL \ PRQ*6lN>޴LVJ8 43T10lCY$vR5Wd"*yuŴ7`_ ].u.h~9&~)ti^w,9`*eMi)4Z%O%5pÈ2Yhɣ3y諁S${`U?G)r(o`Z\͸-[b?Ǡk'v{uKX؁P?b|%CRj.ӕ\}UڨF͵;tiA DS'W޼madw Iz3LV!fh=/כ,4jċj1i&^;PHgQ>Xu͎ n`ǻD8n (fqdtSgMyi2Mo[(+No]-S5Lk:٧&CG7c9ê_*RfF;{T<$dpn]G|#Wo׺5 B ^w(6+bJ3zk4Y r9Y:-U~!1Co,'54դ gbmiAMc:3SnFi uPfL Ė0YAg8,wlsI*#}jTMh >Y|T iQOׇENlK-(OV> v!)sQ<} XY0B%l t%^:㗼R `~I[]SJR,؅v_f+x9H}u#e tIZ: FCTl26L= q7}z,Pͦ-#E;KTdRvaS&BBLAp4:N&mDmCx'1X?R^"=@5vݛcYo_o4 .5(Ć>ǯMxgk0/vنw.MT;vn޿@lc?!FbO1ۥډC7OBX6'\!р[&6o5X /pBe5Mfu^{pC{?T@FU ( 0:BmD{8 A%cB%1po"*Xsg6T9JDDT&u6~4uqI!YW}  rV @;ð ]j ~- vf9-7[z2Gcd woT͖k%N\08)u] _&? &NԆ(&u1;;Gm*ES2ǃr[+O@a5&4rUa*>>Dҁtl1и%'r!EA-k+dYt2uOIf7gj!lߟE0^WX^'Z6w!=E׾^\82ާ \kHDGKnhy^@V&#0;O\z-IvLy R?ňtEC"Ŗu .<$XϿ`_#UxƊWvnn^vye6[2Y?ݥe挐9Q'Gf5ω5g;6~3m8dMHHthl+tVH3 .nnTIz s槫s#s"@rp-$i6s =$ktD3AEda 0!0. M.SN&D}h@̑˼u]^iiks. 9r"c }ۓ-nic\\\ ނyӤpu-zv"-ZRP ńo7Dd~q̦m5.i1iuYE<gX<aW_IܚĔ i*ѓ rOO#zc}*yl?6];&^t6»r~Kă-X1XWF04/:J0y9A]tٝE@"3,[ZNt͞;Vt-KUO5Y~lZ&l /)?tU/乄L}A/CBu +piq|M1@F٠93=I>1YZb1M}ϻyReB>PA+ev _MºܺI(fa0b2}بjc+mȭ›qxpkb%!j s)]ېr0y nWvnjfhuI?7쎧Z0KdOaLH];ηڃANNF!SXG"| m}6 ĝکA5(fxe1P.]`~qr]y>=諭M2.X*l򍁰C#&1uhh fScP`B$= l;軽-ԓ˛"oyGc%~s}.ؽ,~rC+H(#E6Mf57#ufp87ʽc_>3sx!yyc:@Z^1bF6=үlhsD{ŗ>ܜ!7epi\  ҖW>o74KzShuߋ hװ箯lV,Xc,XQZkûEIHOZgIv{mC^ &"x{f4}ީ~u}Ϧ}Rȷ02+W[Z^5/wB(ݬӅ LӰiv7C7Gv9hBmPK 2org/apache/commons/jelly/xpath/PK 2doPG3org/apache/commons/jelly/xpath/XPathComparator.javaWms8ίc:sC i?\NMHږO!̕~lǴ=>KڗgrQ tR7&;CvJhChXyf@$KC[aV֏BH!熡8C G 0@ʘl0n>}Ճtvuև4ZBa QlXc-5# V #e#DB%湩VbЫHK{1ɬ _&>4{w>]^L&W3˛fp1Lo23E LAtr7a! H:XCK9[rX W)FWдFd&067Ѡ4%;Ht9nlοϘY;'50?7"/qbFk$tԸr UH&k*#^^{ٮW|aU3<7~o )7,I甞`/ *SkK+݄ȳ52}ƥWi ٙʪo\->Dg`Q=~ 3S},cC3L)_*q,K[U\UKoz?ASLfCrԇ5h[{T=voAGHR(^j֍ڕ Q{Ll[:z}H)#nL5M3[(XZqJ] ?c5k&X^r}Nņॣt"M459jbmoQ훳\6v5T#8Q:}+F:C 30e$TZmd Hy/ # vwv3 a{ WՏ;fv[HhrĽ.W 8ILuJ׾ZmФXT.:y\ X/yݑ6[}]vip"زLy{֟6t£Fsh?8zGLBWIfv^m 6wMÐa3't~k}2L6ͻ Nmֶ:=ah8wMm䈠١z6 nsBޫ.)"TDca8Z&1LU_ C#QCFvݏAhhVX,‚?"košT/ރt!dowPK 2&;/org/apache/commons/jelly/xpath/XPathSource.javaeSN@|W"(J4"\[Tq(qsYGm{Ɖ{#8ݙ݄µVg9d< 9ATWbRnܚ"kSwZQh R +CN &1A_yi=Tq$A )tʔuR漻gJ0FiGrJ6r/{rzmێS<26 C "=*9VoR`,`fIjljU6iڱ՛ EX a(8('yןkxVh ,Wp\x-DG/n@Cz"S8ie#!5I&SZ5dl%&[jDߗ( $柞G~\[ bDEj|AxEcmUQY\kkRPm~M2iDz Oy":8.xù~6 RqP.Ld҉ .`Ite/ъ6g17Y &(&oe߳CFD//PK 2wx3org/apache/commons/jelly/xpath/XPathTagSupport.javaTMs0+'kBdJ;iD%awdL:}zi80vgl61lrb125 S 3\ l=QhL swc ᙥJ! kHy/1VXUnv*CFQCEwەSz^4.kRe^aw,nDZŸ5W8HU"Z)Vu"4 F6B{Hև !>aN-cz^Mpj :%݂|/z H>R)dr'&mv!; $ c򘬉fB&9 Uɵ=VMKSv6߾FC1<[t%uX;b&?s'7nò,d>Ql,6128u:DIӡDA(+V rŨd0%Ι򎕨!KHq)|<99(:~JH\a<ޛ)t'UJ,g Mu!!Cj epCzESHHC6K~Sd.@E Rhj%,}q,pKՕ_W7PK 2Aorg/PK 2 A"org/apache/PK 2AKorg/apache/commons/PK 2A|org/apache/commons/jelly/PK 2ѐ@d+org/apache/commons/jelly/CompilableTag.javaPK  2` |. 0org/apache/commons/jelly/DynaBeanTagSupport.javaPK  2E%org/apache/commons/jelly/DynaTag.javaPK 2 t}, org/apache/commons/jelly/DynaTagSupport.javaPK 2$Aorg/apache/commons/jelly/expression/PK 2+ǩx(<7org/apache/commons/jelly/expression/CompositeExpression.javaPK  2s!; org/apache/commons/jelly/expression/ConstantExpression.javaPK  2 3org/apache/commons/jelly/expression/Expression.javaPK  2H[B: org/apache/commons/jelly/expression/ExpressionFactory.javaPK 2:mYX:"org/apache/commons/jelly/expression/ExpressionSupport.javaPK 2)Av(org/apache/commons/jelly/expression/jexl/PK 2 6HU=<(org/apache/commons/jelly/expression/jexl/JexlExpression.javaPK  2S8iCT.org/apache/commons/jelly/expression/jexl/JexlExpressionFactory.javaPK 2vW<54org/apache/commons/jelly/expression/jexl/package.htmlPK  2u߽06org/apache/commons/jelly/expression/package.htmlPK 2*A9org/apache/commons/jelly/expression/xpath/PK  2ȵP>O9org/apache/commons/jelly/expression/xpath/XPathExpression.javaPK 2A`?org/apache/commons/jelly/impl/PK 2N_V) ,?org/apache/commons/jelly/impl/Attribute.javaPK 2{R^&-.org/apache/commons/jelly/tags/core/SetTag.javaPK  2ߔ}a6 1org/apache/commons/jelly/tags/core/SwitchTag.javaPK  2ht 1worg/apache/commons/jelly/tags/core/ThreadTag.javaPK 2Ũ7 %2org/apache/commons/jelly/tags/core/UseBeanTag.javaPK 2AH 2=org/apache/commons/jelly/tags/core/UseListTag.javaPK 2 r{/org/apache/commons/jelly/tags/core/WhenTag.javaPK  2ΈY 0org/apache/commons/jelly/tags/core/WhileTag.javaPK  2?O5Dorg/apache/commons/jelly/tags/core/WhitespaceTag.javaPK 22+,org/apache/commons/jelly/tags/Resources.javaPK 2* &2org/apache/commons/jelly/tags/Resources.propertiesPK 2&1|Bz(org/apache/commons/jelly/TagSupport.javaPK 2Aworg/apache/commons/jelly/test/PK  2B^0org/apache/commons/jelly/test/BaseJellyTest.javaPK 2A org/apache/commons/jelly/util/PK  2W)K3 org/apache/commons/jelly/util/ClassLoaderUtils.javaPK 2=Q3 4Norg/apache/commons/jelly/util/CommandLineParser.javaPK  24,? 9org/apache/commons/jelly/util/NestedRuntimeException.javaPK  2_@$5 org/apache/commons/jelly/util/SafeContentHandler.javaPK 2[U˵+%org/apache/commons/jelly/util/TagUtils.javaPK  24:'(org/apache/commons/jelly/XMLOutput.javaPK 2AGorg/apache/commons/jelly/xpath/PK  2doPG3[Gorg/apache/commons/jelly/xpath/XPathComparator.javaPK  2&;/Lorg/apache/commons/jelly/xpath/XPathSource.javaPK  2wx3Oorg/apache/commons/jelly/xpath/XPathTagSupport.javaPKuu*sRstapler-stapler-parent-1.231/core/lib/commons-beanutils-1.6-src.zip0000664000175000017500000061412212414640747024452 0ustar ebourgebourgPK 5.org/UT ->ť->UxPK 5. org/apache/UT ->ť->UxPK 5.org/apache/commons/UT ->ť->UxPK 5.org/apache/commons/beanutils/UT ->ť->UxPK 5.(org/apache/commons/beanutils/converters/UT ->ť->UxPK5.T% MCorg/apache/commons/beanutils/converters/AbstractArrayConverter.javaUT ->->UxYis_DTJR-4 YP R=L$"\$3{wwAI½WB^*OE/zRE5K3gQyz3Svx//x½SQ= Y z*%ʾ|=}b7oz߽y=s? -/b٥cֆ> K*\ _\ 6#)ePA {|k/W%Dŋg$A2yy c$a"2R(!ܱd}1axVqƳ9`0+ 23.lTus\X.ϼ*JEi]F"BqY9+dRx$IgKce{(/hΎtZ(pJhTrK,-k)"'Kb p[,0++g.,v^A8`jЉyUJ^IrH"e՘_ @[ZoN"!8M 궩tYyK;1˟DsU7n#{.Dbn)CϧuVeY\zώ1S'0W%km a5E!8@+).H]K)^h> U2UEdX ap)O|o+2BczPv'ETwJ X; LP#rv.=KQ_2F6(oknT$|f_)]uK"\Q p7js|[BdՋ`T1&>T/o;5l;WE-px,\}ex'~X89a3w؛̻yht7CoNC6lz!..ع5"2f?J7]eLG}MI2Mׇ^0[wV8dM4|w~lL~MЇhxaq{} oGa =f6 HVpY[[O`A:[nsv'D S g8?v!7B< ܮv6Yx5"g&n)sBh0'*z0U7!R4" V3b'}'*_iniQ7-%>swS۔З_Ama//# ;(4P%i˒u&H^PJ0Yњ}7?Ns_bI}UZgȀf$\)dg*Aמ3H\*aNNXh$N-CwE/5Q[Fp5b@,^*,".<i@JJ#\;vU$:h"K%z;ԓz;[Y.W ∳=Pa- bRV髞^%5l_x1iKIˣ$q`_12#,%OLP23m  ē HUF CV)[$C<1]#T%%3:Dc'D#ZqA)(s̨`XQO<(9VH3zQ& fl ydnA37~neoTLt|k*1ϘI!kߐz=v1B OZjTRıpNQhm :.u3Y^wTeEv]]U KUӡt@.uR̥n6?dծU4I:`Wf2Z"zBM4"jVW=C 02YC|fJTQ['1<ϝ6O)u5"hTn5AY&e_~Y_ܮ<>UeIE^KDSv.VbmYڪU"}g Ǜֳ{:@E택Z괥@4uT礫$-k%7,]41']vs; DU*$"rs/ι3:wv3e}ȖG]= 0!+i٢IZg"W ӺQnoیYFw<=`J HL|(uge{j7̜0߻I%_>;AAz@N\ O1' m SQQc>f3v?oQ7M㉨A;Rthz+QuYmwϪ[,ңGPK5.<@org/apache/commons/beanutils/converters/BigDecimalConverter.javaUT ->->UxWmo8_10XP/(h>INߖY(^c~3e/Z9gyO͸{!܎WyVNۿ vR=,- vhulmxrb*Xĭ?Zy{>/>~L/" ~z|%r! -S}볂_uox Thk!bys NTu;7]mx^ЍOӧOgQ[Y3V @IЂ9(sⳞ LӒKgP\*TLm`.2`-HeYR\H H( >LɕK`'IZπN ҺܒFޞv9yV,g `.\ђa@IeZC 4'k wCㄉ%ƕݡ.xfZvV~uPB;f2.<-X: `K~6\4mcj+t8tvAim$4bpn#g_RN3' #O'"V*9:Dx"3TbiCϟ'tE]zUG1NtY12ژJy2 k +fgֿpᠰ%5|+RD;KU@ao<.:tܪJ+chЩ\SNi&Rac KYVArxSPBPEPiym4d g9:ru㣚={Gcꐛy1ʷtɧS25@}Jܢ)wJYptn''{}W'? ΰ_8F Eg^h?t?fp#FՒ-1ƒŹ~U{GC<nHNd0QM}?tC<GoAx \g5v4 0 |T}pG ~ټH*=Щ=w$C;El!lsp΃s=d0ڄ;I=)HQ8 #?D܍FC/x]/$,<'rD|F^L)܏0ԙ{핡6_IC{ǂ{Ķf!:BdύZ4JQ^zwS:c'r#W#ڌ!&*b‰{o'vcȱa`%+` Mo^ JbvW%5D)_dǧ'*_KYSRZL#m9W{S0쓓ž?[fD̤*j5eMjj4+aюʾ"fu"n{DMx3NqXCSu{@G:bbpEޗcF^z zR[iIf|ʤKJ芅2Ȯ;87ԈEEqhYko_9af 5G螒H3Cģϐ f&p>K0^hLj88_{s%[Ž=4/=є hh.~QB0.ǀd& o=ӄCN' ;xlUMɓ|m (`$q䩔VR8F0Bc-*2BXU 6%dYVi4-GV!z!T^;bv>dMJv2lEy]%b  hWGzhC(dζWXVu;ct;CZ}Q$2KS XiB,p$<.D7F==mw n|D>TW_O PK5.p@org/apache/commons/beanutils/converters/BigIntegerConverter.javaUT ->->UxWmoH_QVZgD`2/&̅`rl۶q;fiԀ*`ۓ)cz׶ޜ鞳9`-Ŋ[:YGoɂEbin8K"Nr+fXD]H\\Mҩ?`޾}o=?»󋏟.>9K{?)=}XJ6`蔧uox4T`+k!b$a4<v;"yY@?:O>0L@NP9HssS|煌g%mΡ9 U(e՗Y2܀M\,AH+ʂPVb/Hiq!bXሓ$bπN$t#/.jv9EV$渹 `.XӒf@IE#!AXH tsPٶe =_EvaYƬ Iiy;AR,jk|negeNy04RPܠPU yWeX9\$kW|\ߣ_ )~Q3TU_Z^ @qJs 4AScy_HXh.W5%bR>?UmkfՀ,, CWιn|T$Rܤ͋T#K>6՟KMxYGSMj{/`|>پ >Ǐ~gG &6{ =w@(ۣs3ѝ7FރP868l\߹/7¯[/pG0sCۇԟPmx3w>{{8Th`xGc?onu9dɿPK5.$$ ?!Borg/apache/commons/beanutils/converters/BooleanArrayConverter.javaUT ->->UxYmsH_Em,;|,l ' RTFht3P߮NU6tO=֫x\`)|Z\(֟@dQg3ֈIElIA]+Hpr;B̙Ș cbI*s8iǿOZ'owoAy-J/R#TNJy%^1)K d@0F!K$k-zơm'fyKM3pݻ#2R%ϓq&Ǡ%L21gQq$3rZA2\2@$E(J 3ـEM 8DڲdB,26Ty4Ɨld8( 8"!eXvjL;inY'O B>ŹУ,@sIq0s2H|! \IQY<4 7 a^[^ڂ{p)lAo9175ZhŘ%YPp0LQ5*l8i)҉%#LAq^ք4 AlhDЖGA-ዘ1Rjq%,1&lbez~~>ͲZ,M]bTm5#oWKM %i rfeRIOFS4Q\`T2 HR-Â8.xC3tF%¬րZ[I|=k[8tH0acq6x1wXDEhFg弩(QEt}Tr=nԬgb)tF00:8pmFUCa2*[R[>ÛAҭf{%x׎^d6:ay8`: \ps3:vtk|a]5bCC׹q| .$Kb 7۾:gpO--Xﴇ]˅=l8^k97v`=kUZ+g/^~!A]M\huѵAqOnUGm, B z?'cXW]HG0 G{7 B /< W~#ݞ:m;n_g7pRۣWsNϷ]w8  CK!EWQ) ChruMovb^Ew:fYJ6?F- ZTާ I(cL1v }rnbq mwQ*r ^-cک eJ3C#IP2<ؑRloJ]Y+[_) 3:e:>[%)9]d4iP%~X !,Y~Ci/>$Ć:$xK|rRnˬDYQ * \'*_@I9#|Ǝz[XrQLwaX}9P|A<Z>۳Q8}g~T!k,fxZ+r`V6e_Q8J/B6pPy2-VcDm_p~Ϭ)'V@o \lX#Մ|=v0MT堮|=ԣg;2E LbTNʚ1K]y[u<~ *YA(J?m5%dv۹+7kc%CJqz?Gx92"Mȡ}->UxWkoF_q!Ȕ4b;Yms!KZr6JQ#5!Uh{p(Qة.G g{}NnE0&r*Z<8 [AǡNe"H 'Le*yr/TP' E&H(NvKΖi00<>{aeǤ3IE&ҹ(hXv  P" 2 ]XӬI(Lկ,rFQ4BudXHQR9Fx'ApX.QBJ7LvjliWjrEâ<  圗4S '9hmbGQ Rt#1Af ?_O:Z,FY] .4GFC˛1JYԎ|.)D.PƬTLFʁ 8!sr 8C8 +?H)o?IT*¼ѤUH-FkK44ޖ)Rާ2N# 4rx] qEH92L՟w ^m U<As.>xoJSݤ AXX%_6U7fωM*YxϦknimÇ$wmZ%q6c@5c{MrVgv7MqB~J& k]_+_Թ׎řt#MꛮXR{MPێguLn8]Lɻ5;u7- mwz]{GW67:vy<(h;ml]PRۖweNd`mޙ7Gl1F0;k{c9uz`wnTDbޯ(u>3pD 0W^*A_ 0;M|kl+L{_ۦP\5{ktkټcώg&:B؍P|nS9k2r3Bst8xV;'zVd:j˸@@ S !hD C1 V|MeYL;}Rd쪶eB _Athcڢ`c5!"t&yrHe+wqz|q16A:/(yն'j,G'bgWF$9ŀ>ef=KzH7}[({xY&{%;a"Gwg58(a}Y]FVF #pYyuF+ײV053h%BM 7.&QyG*E;Va]WP*YτmϾqQU$qZ҅"tQ8T gc|'pai2xjoX*?: 7|c Ժ=eNb5N6mQNdċ.FTϷԮ6*]rpKQ֩yPXK5?vHzA5Bᯑ]RG{݁?p^&/&b7ɪ.r<ocxPm_Oke,g:_NT1a=< PK5.ȴ x?org/apache/commons/beanutils/converters/ByteArrayConverter.javaUT ->->UxXko_10 TNeND,dI%)AP$KI-ݥR;3g<=zA\h$ 5'T4*f4D_"YFq>jE$UM%yw5syی(@nTgs!K!U]Zk|}NǍWq5<>yQ}I2r6D%yveZ;*Ny#~cUAv|\.")"SN7pc{w2T͛7lN5,E%44%-XJȹ5Z_Ud8e#)AJ3 2LH8SUERN(7eq+&BN#*d>OFx)'QI|dҶT'ִƆuqeVpxJxTF0G|[)V'KZljDQ }fyp,\Q2-/m+T oV l*2B;`LT-aæUL M'AqAlU]RdlG] b6yYD}znP' ^N烐:޵B(q[I]~ +ι /N?ZS{K0^8޵F+񺸘Rpt:^Eom;z`z܅y5续\ n;r3ZPpvK76Zc05kv AeXw7^ NR 1: }=H 4^7t}gRg:*]6CGN\Fa8 Wi->|^vKryNJ>x{xz\;-C80ϼM9O3E ZW6>)8jB(ф"9$B ZS$ hy|>\y0bBH2 0H{ 9dC LUk8Jҙ\yp&@I1&S4Gyt+'2_u{ThM-|aZN)AR7a~,[ڞE3tI-%7:nQM"J*7?E38lc>hi4%LJa#EƢnl`r{k6F`1RM5G4) >Vt`KU)yT {-F۸j6,Un4SQ6KږOTS}65n~3єQr=hCa-YP y]S,?JTn"| S(^L)7N:j@0Q\Lbb)~.K,O4b>}> E}k2ڕY&2 JSu˔TYj`f)<' jTdޠu1IgRӑ-eFJl4FrqSATT`WUXI8&vnK,JwomtMeg|o[HW%mX3n3UiL։Zޝ'zCU&jݼ]ŁM{˷n3pLAIh )[QjlQ~em׏YJ;-(f;)1wnl/JׂYn!BHz0jnmIU5d6%::[ZoA\\HN%fH>lz(1-NQ Q[&e zI`.}$y:LvP|SvQQfa&d*Չž)zpAZ-2;au[m8Y[C% .U"Mb-ٴ~gpYx:/PK5.Bj:org/apache/commons/beanutils/converters/ByteConverter.javaUT ->->UxWnH}WF*Lb'Yms!KZr6oӢZ'[hj6%HDNWvJ}EZNʗ$MЅxBeyg"EVIwrͫ+Q#"ChWԅyvSnâ]:oW^w^]v.zyկHOU9cI? JDeWF:)Xh.5vRfZhI$Y. tۻjV|Ao߾}ɊSe6"7M e.JN i:D62rUX/$zC3yI1'ͯ* FYi2KbsdXԋ(䔖Z)^(Nu=9MXr Y\Y.rRZXM XTbVdb<*@k;R1dcZ84NE@\Y]~9g6xuowLU\.dVuRXѴ@$D~6,Z1N2D,N&m)Ypm#V":ϒᯬYH p\T-d0'EtS̅snte,Xk>7$K)ƘJItֶH8p '@UMy3W\ms^4kWZ" ίJ']yλU}+y~hy M$9MF#vB?:AH3,Wl5 W)Uɟ[j9 sQMS:&k^ R喔miD[Ou>'n+ZZ)E#zon?L(kÀQzDt?o80GmՒ 1ѣtŽ~ɜ{GIw8ҥD~ww0jx}zh% " ~ߜ.~ ǃa ? ;DՇAHwo^u<(׍[tAIpu},v6H=ѽBjM8PoȏƑGa/d ^Sw16Ή\s"{vx1IMIM,s3F0TDiiX1vp/S[xvSZRh]CcɄ{4߁g=P uգv\W L{W`P ڳ@GLՀ'64I]~KD?#'œfxƎ~b3P9* lSa^6]P#?8yD)tNQ_3 x\S\EA&coUpmiF+תk0 7KP%B)P+f'ۘAVDlVTuT-h*;`NSqbs*lY=Z]Sv:8ުx_R 8\Fak/}!BwBՙ\u>Pu~|{;aTb•PZՁVߓ8r1+Hl j ڙau->UxXmo8_1XIФ-Jc$9(Dʒ@Jvs!X~I.z8hEpg^x\spy yxjdɎ|3՝rUHUWIZ]n.ﺬ`vvyRu{s&YW/8<>{|=y /ON_9}u 2ɳ/"kh[J٩1{i U9cYb@Y^"!ԬOn) 䕵-xf6о9xB;<<+Y:"qE,K~6\ ^h:,9BȭDUS1Yv1X-X%W)Js*GaANyFLt@k^iZSd7mʻ)•!f ̦=By4I$f:+ *AU1a%drT` RrҴV_ E!a(eLW:p kC$ L99-hS/+[ ,V :*L+U^@r(Gdpuj8^;Q̡0Yb?r|Ro?oUH ^v̧-JUQ]!x`t>_w8F7I07U.& G ?BhZ!FJFpk^?Ͻ! x c7d0QM}? \c+x0x0 Gg/Gaߍ!~Bo4M!\xh{1A^Dnz=Щ~jC_܇wo+/.Z 7 r! 'aGȃѨ n`H.I$:xNQ ;bRyA0m}@RwBFuTmo|$|{@hk\#DzQc/A=VGzmߜc'e3 vtkHзt2޵ 'fcPu0 +` ޼9:i] V1o|V|-rSLEF޴<{F)Am/*],g3"%к3@hTdfgcטdd@}Xbb2S}mZS$ hy|@ÈȰ51*8Fb}=* 3‰*ѵxDZIp(A<AgJKXͮ|oڻJix<_#2⠇Rbo±mxoi{*"z;{)؜Vr^[}yJɸܲ`h 8)*O\F(ph1nZ#J=ۅ,jz &fJEGd8r즮kzVIcIs9*M6wշzL?3:ㆾfO{'[?4Tnfܔ[ h~FSI7?f*2iO/Xbex=|?285bq_PY BQ94yR2Jѵ>sJt'M8n8Vd_lHd-SaUe鉵(46XyC0epN=[$[J4F6 -(Z>P~4#fO}|m]b ~-.l^Z0XeL_WŖq)-$63a{[,Zyw8=1:ujnk>XwؗG(e/1F8LqxJ߶_ny5Mb1jvГņ5J/1tf{V̧Oَ.+ ,F쮜ޕZRg-l~G%9RЙb١ݲu=IJZ];lYNSϚ<7>|; L܄+/ƌ~f)J\$s3*(%=7?.̱PϡRn;4;dgqo˷yH%[-cU7ײi֖SڵDV]~eyfPK5.O**3?org/apache/commons/beanutils/converters/CharacterConverter.javaUT ->->UxWnH}WFd!5M6%){6-eqBBT)QIvpİNWvHuAY6h/qGW qey東iYI.E'S r{,]JUHwP"«SXs==;{9;>^?#5үqJ IeYzeo]Qȋ[> glm,ٴX %G2ea&nf-^T<+ǏOYу0YNDN҂9(Kr煊%o'N%<+U$q BL6bFҿYY0<8GUXH5BNhe_H,R 1k"ɴmv N2bb59]5IR׮x_"s̯T*MFqH^ү>3.>yÞv=7hwz׿k(  m֒ 1҃;bx=/Ͻ>Τ[iCl#8\,g{n`r~Hsgm`ڡ7€A?=>q}sAA]'d37o=Zu<,v6H]sjMgl ( F7A腣Х0v-csB[x뇮 @4Gapf`>wtlkl#{NئQ| {;︼:`'/pOO/ ^ucGv#ԫ^&#ڌ <N1ȹ7I9YRrs9FPs4"F]Kn۱d'._*qʝj)Yum˥:܃>9::ׯ+sŌz 6c%D"Sŷ%! {$_Q|RsP5?8JmDn&=yᆞ1老0 )z+>o%"}#UGP6צL;fY&r*ʤHJʊ2ƶ[4vm4JEʭⳉkQ)(rɷ!r -vm n߻V5xn⠺/eB/<8{TC?0 :4[ 5"DAjkb84&̦5:aIgDģOIrPׄ'4 mMTf:\7" [WL^cnsڲGрΩ-EQIQp< \jƉ<l|rpklu_v %/;8`Mԣt?<2tQ_g6 Hx(dC]ENpUMF+ת0 _O♗QTo@]ꮔ˺YR 2kQYWCUH>FE2ϧC grt%gcr/pz2SpJ7lcwJlUS:DM븟.QId˺PQX`;,U+ȪQubEXI^.yM'`v)zoPK5.#b;org/apache/commons/beanutils/converters/ClassConverter.javaUT ->->UxWnH}WFd*!v5-6!)g6-esB&)T)Q$,SUyqD/[)RSQe'^r&qEBj>WYޙHE\Rt~舅qnoWԅy<;|35zuY-:;KS}I2.b IܜD!ux,T(5RfJhI$Y.tt;ۻj񤓇ǂZ {=sl* 8Dn93K9u,l I^dRvٔ\UciLL')=۴JGR`&$6"*,'E!jLR<IऩZ%ӄ\V3gGԬV+VSl.2%/YO Ǝ$x l,V BT$sĕվ.NKQB- ˬWANP,, ;km +ϪsS7-fMTsAWιvo)uHv5/rM:Tvj-SؔEptOnGy=w7ć_%wÿgxaa@ݨ{=Dt?i80G8 'dxMw^нg#ڏI ";hzx}׿zh%ɻno#Fp{ÏBQCaҕݫW=?y.(7wN7fzs/>[$ ME*hyt3Bz`jxkCN@؁qJAx = Wl7 >̇N>z0ۆ5^7jl3(l 4n7z:dO~~J'bǑv#ԫ^6&޽o"ڌ }N1{kR3Q+rt3 ,UZrs9Os4"FH]Knۉ|l'}OO\*IƝj)*um˥9ph F_;;ٌ8J?Q \\r D an#L =PSgc0aH2 AyS1JjM(oe9r&ʴHKƊGmnjm(x6j+ %*KvcV S4JtzxѸ_j3}Z$r\T*ɫy[ W45V-hRR"59' ֠;Ώ.8t R19onm4ØZm]0?.);:1\c<9}cTPiX30va;즎l3:aYظ7a2M/w=h$/*矴wRt!cM[W̭^brsڲSc;i5 MVo#qOF#Cyq/p@4ӱ vuMxډ+gOp95}C6}S=G:(yzVFM* $PFWI ^u,}ˢ5LF, Ǥ+f'`렮ALlQYWCՈXd6Kb->UxXmoF_10 TNe)ND,dIGRAbC.%W3Kz9T3ϼ{~Q"1'Tㅚo4n}dtZ}#|^j+ɻ]v4 NERT GSXCsAG/Goǯ_LkmFhC}HUZZƬuR}>'6%=-=~nVG z[A"tVȒxm~hN'ٙ-3Ga~Cn!(ф"ߧYcX z~}b.)8?f& OLf]285q73:hһQ2My/b}K嗓a44(.ɮ 3Q0ZLyEU+5+QVi|P"Ij>ye(%z&I6,8i3rSATT`WuG;7  ] v4:jkz+PrkG=I'6Mmay=|` jX˽c$PvȚ^c_T8yomf_^p >1su+J-J1 6_lx5ubE휡NJ5kP?hOtf{V4/fdK)6KQD~[NlKsj )5,.:Tͥ)j} ) u$r}ZG%*Ecb]'B'\HBtR `I;/,2:C.Lͪ.鉫_3f@.ąiRHɟ揎IֵWlӬd-G468Vs|6?t5cgA~{[L~PK5.I <org/apache/commons/beanutils/converters/DoubleConverter.javaUT ->->UxWmoH_A Sr~hJc$9~۱<5H7XȖ_b{{8U!Cr:Nt/T BvU,'iw~.X-*;)HҼk^]rb.;=H٭?8,^ѹ~ymy_Te?1$OTvado=Qȋ[> \)jVObMs/:yԊУ0̦C)ḁ^ɩca9MB'ȦT@UJKedBLEަuRIiʂQj̒بlzRU2K1ISNgB@ Xn! kڹg]NjV)6y sXLԊ,S 'ShmcGS KRxN#f"q##6r%S3|Pk^ˋNg^;UqqΜ9VMAW] R qfcRR2-R23\#0US^U}/{9A/Du(~B?VœFZ.MݪBu1`-pZ H8J#wB?:AH3,Wl5 WG>snamZR|Fdxmj:9Q0Yb*7n6ϻAM%[-NrY! <(>=GzD޿GX?c  M]n ?P4lCWK6dxK^н'֏IP ";hzYݾ?x==z{7zݑxs#8?G!u(a0ƃM߫ԃx݈ܾuAwO7fzc>w^HCIM8n8셌zK1ơ׆5"77 8# MTm7 >̇N=|mÚt`5Q_xw}t=^2ГzgB8ayk#q&ߒ{MV"oө"&wm}RjqԊ] +\Ay;tWt"DE:;ǧ'._ U$N_}GvSri`tNNNxJ\o3 | dTD5$s咍 PŚ:L,F)y&glB@Mvb05nj$ Q Ѓ]@x'ٳSWԄ[^޴27#MLiA+sm]w8bz5WJj3T:w:ˏ6EELCqv0bZ;] * 0Y/i荒%9RO"Dܝ:zbCHP#rDKxϪ :]Ðmko7u̯e]< 86M*|L{z6a> A^V_~a\@Jm¥qܱz5Ex Mv}ʆ(~&2G򑈂ƣE.C>3)6] /{ac|M(1e3{e(;t'JSdtLӨJ5=vK$[bʮ-yeZuAR~%yPE->UxXmoF_10 TNe)ND,dIGRAņ"]Jgv֫bwwfgynأ˥C9.&tvI/UR&dRy#E>+L7ݹh)"CnTRsJt<+D)%ZbtxM^y^y{%aMsMcg(Nص(Ny#TcIbT.IkYk `ۑ;*w*TK۷lN5, D^ԬFI-\Nm(.Uz3$!ʹ$@JYIshT"-T([J2)(M̕ubRMҲCbREHɲb淄S2DδƆuQeVR qxKxT ˊM1-+%`D)>Vxn.M2N+g˫m[p .-v8}sp'E2ȼUAT`GLV~6l:T^0t$PyV5U-uJGN'H";)<1bA|cPeVLa݊3<T\, [`\kNW̲;u T q2՝td@`"=KT w5&"*U(^Pb[@dRie$^ EKmH@@ Z.Rpiaۢ༫H"(N&֦/םns$CmpN1x`׌eɹTC)sZ^j;2\ U̦eQ;?zOx? J^w?{~'۬׍?Smu{QAL^L*!ί$WXIu,'sywq'J^A ?' juo]\Lߍ):sZyp7趽8uZn0FtxA;Vn.Z FwLjE}` ?- p ?6Zc05+vE(AE׎XwAˏNRs1:=s=H A7pgRo&*]6녟DN/}Ac8"׊W-!| _t yNJ>x=\;C80ϾnM9y0E Z.>)8jF1f\Ay;53n9h#}wOO\&-iΝ޶"FiiA\haJ|[qspan,iJ9TdggcDNl@ ѻ釨DjHfifr9HAbaĄhM 0H{ 9d#FH`pDIz*C9fەcU,pkCjl-ba{Nk8ILR9a~ל~p=3E-%[ t20䴲|[:)ߌÖ9FG3¨5F" ]lɻh#M:hTQid%&%+&2O* R<'L;4j6Y WS>˲ڎQL:mikgݤ:ńir=k7YֻAtMHSA[c^$t-MtD'eFujnfS5*8D97?e F._N~BvQJ we|Y9f +ج\YReAJ7h]S4lhqGᆒ!tܔyUU8;Vr# {i%Rn)lښoqmKTa,LXM^2_5{[XXV>̅]~\eڱ{(I;dmmef-UԼ|6//Q8̥?$p0ҸuW6ox5݄a5k?hOsfw֦/vdKƖ%5b7 Ud~[E!)5,.2YL)_jJ}y9'/?JNs(Q%j˄z> Vz"쥏$?O'~Yʐ>Cj1N,WE;IU Th@(-!=-6|{wqxOѥЁSnZ|Vls{x,ne<'PK5.;org/apache/commons/beanutils/converters/FloatConverter.javaUT ->->UxWmsH_ѥڪSCl'g͕,t˷jiU[= zIR۫:af_zso\^UYԳ4&+v,yi8*IKb/+XD]W\V\0rڿM5Vpi_޾}g._߂KG?)JDWJ6`:)OhhVB(՚I$y xBQ9RowD˲~|>| EO EY&Kr禆 <)+j,C]r@JQ˘/$gr !ҀuR-AH+P21OI4T(̒s(X%s|8⤩X' ? )H.ՕV<ЮhՊ7eU %`6+ZL>Vw$%G0jqʒ J˱.xfVv^~uPB;"3Wu&\a$˄~6\]cZ+ߙ*x> $y]$4b@, #Z":/௴>XiH ts(P٦c =_O/zm6Ť2sn"]9rnc5D>73r2fRR<])Y( D/ ,}Af,M[6YM턉stfю^ @qJs 4AScyD[K[&X,4v UI)7_ w5nՀ"嬤 C7ιIv)uJr6/FR6~wj"5':Rڕ{)U8zBal.$🼁;~C`3n8y0P4Ǒxcg4x{FޣPxJv£8žF^Y;1 C<҆D3L]@I|o#HkOlx`G?F{ËBpqxpmG ^:{s.TzR+HvgB" G at Cw8}$SpzF^4\AHء->UxXmo8_1XMФ-Jc$9(LʒAvs{$F!9ÙgyQ/r)PLz:d+29LɤuF$njŻYf2M1NE>J7ByJ%wj*s:jW/_|yeUAӭ-9qePlZ_E~ػ~ӋuC? )w: z8:Vgu: BqJrE[X΂N2qw9qtߋ|,V 6ZI_ݘK1z}Ξݶ.aAQ׍ˆ|u|{= hߊ[ pI,~z:aޕwGTFupŮhpA<}:h uz@w:_=gx?D4~]>0X 8Dk|x㥏6y GZ1%/a/uNpw[>X  kcM)8'}àH8:Y`A'G:f =+Ȳ7O0r.8ㆈ$mפTmK)gdjFV&\o#nncwZ,$>WLlMUxNә wi~:vBS;`I#p6|yO,NO`j;V2-N趥.wGΞbL&ϓl kڟrק0 DaAI:wM&vpE ֩) @Ux0rl/k|´ ^O.P\ Tq٠̧eSʕU +5KQvBdP;ڑJcΆfwn(?JMQQU]sc%3$w۹}/MoTh=Bjb㶳2W[-#m:lS6VSbͺޖ,`sW(jkYwv Y[[;w*v75-vˋes!)5L4nEiE$M*^?f*nn0Ś5l kS jvz%åC a42ߖ/r\j,,!?њ ~m,FW"@vj_j`Gtnq2MJT2Y.OջH{#`#_6p:໲πx0 ;'UQNZeq:U.H&EF f|O&b˽ c#jhQ;.: i90~p*䦵;k6<ƳPK5._5=org/apache/commons/beanutils/converters/IntegerConverter.javaUT ->->UxW]oF}0 T*nIִD,dIKR#jd8j{p(QIڴ ,G g{΋zA?I1:sx/Iĝg 2VD,4WWcG,EiH։H-mXMcj+_;&d6} {$YM$DiS2"{jWX=D9S)V iĬT$ns8FTdPb0/'EtSU ͙sjte,}|>X.`c6*%E.Y"%35U5e\%zr#Bi _XS~47m:V%|V-K44V) UȚt"Ͱ\1H$\4|V%snamZR#28rG5o{Gc갛y1HRN7ɧͦSm ?jցŶjU.k;?px}t> ~ѯ!>#>Q!ֆ;|/l?=pۦqDaD}ޏ  8Ϋ%b 2{/{9Ə8npK#74afvJ&D޹9]l=7~Rw8=(^xP۷.}ZxYtOmf 1az{:d1qݳ)(_#n^ء<]/L oczmxH8 `؂999+cfvC%DRՐ=KV/(>CX=?$LmTn'3YyᆮL_ =H;>"{tcpk2~Yf`2-h%4b ϦY[xBQ1FB+u+yy]EAuWF˔09_v4[8SC/a@th jDv=?h si57^'mN}]s:cFà izOφ{( ;-v.\w!;QW ^ab ڱ'pGLՀG?d7ilkt"vΈ9j A23I呈<$dPb3Հ[(Gx!&lzeuRog58(acY]E^&#pUymF+ת0 ⟖ K(7IuGkVNd;6a]6P)̄}ϱqU,2{]_b3ӱtQdhuM gc pz2}pJ7lcLlU3>FMtStdvĨ&2} jW{j[!Ҡ\LĶأZZ;eNyPa<]Հ9`hAƗ> \O PK5.9Dj x?org/apache/commons/beanutils/converters/LongArrayConverter.javaUT ->->UxXko_10 TNeND,dI%)AP$KI-ݥR;3g<=zA\h$ 5'T4*f4D_"YFq>jE$UM%yw5syی(@nTgs!K!Ug]Zk|}NǍWq5<>yQ}I2r6D%yveZ;*Ny#~cUAv|\.")"SN7pc{w2T͛7lN5,E%44%-XJȹ5Z_Ud8e#)AJ3 2LH8SUERN(7eq+&BN#*d>OFx)'QI|dҶT'ִƆuqeVpxJxTF0G|[)V'KZljDQ }fyp,\Q2-/m+T oV l*2B;`LT-aæUL M'AqAlU]RdlG] b6yYD}znP' ^N烐:޵B(q[I]~ +ι /N?ZS{K0^8޵F+񺸘Rpt:^Eom;z`z܅y5续\ n;r3ZPpvK76Zc05kv AeXw7^ NR 1: }=H 4^7t}gRg:*]6CGN\Fa8 Wi->|^vKryNJ>x{xz\;-C80ϼM9O3E ZW6>)8jB(ф"9$B ZS$ hy|>\y0bBH2 0H{ 9d)*ѵx%Lb<8v$U)HYZҚr7eFhJk( HM<~} Pg f% NL7Jk|N\ n5S (&WʁUF?%LK>̢ĵ@I, %Y)ֺeJ*Z׬\Y5MRe5*2oк$3GYN)H2 %6#W) * *pj$FeS;7 U ]vZjkx-Pqj67ߙe&lcDm-N׎ݓ@=!k*sxn^Ůn}Y~a& $Δƭ(5(€D_ @|ǬY%VĝzXF ;ahakA,}|`VOdtB!j|5Td$ת2H-`vQ jLN $V$oV'D-UX$0>< &enW; );Ό 0ZUaBh=y -S鰺-6|{wЪxOЦ΁SlZ{Fl[8,sna<PK5.i:org/apache/commons/beanutils/converters/LongConverter.javaUT ->->UxWnH}WF*Lb;Yms!KZ7oӢZ'[hj6%@"uԵ;Nt/T BvU,'iw~.X-*;)HҼk^]rb.;}=w?myGysw/~}CzIFKhU'*02շ(Qy^-BEsIB5+BK'r٦GX۹U< jgt׬Q[UfSQ!rӔ`0ZRԱ&yIIdS*sI*W2I2_h"o:)椴Ue( 5MfIllzRU2K1ISNg; Xn! ڹ]NjV)6y uXLԊ,S 'ShmcGS <ٞl,U ƩH+//.vZB:8Ԣ˅ QC +d4o܆E 4cIfw@iDM6%3 .vňڳHğ3Nd +4bV*79n#{*W2UK(1yiדZX^t:کJU9n 2pXj>_H,R 1"mqN2f=}D{z!Ҵ]kL,`)*4wm:V|V-K44V) UȚt"Ͱ\1H$\4|V%snamZR#28rG5{Gc갛y1HRN7ɧͦSm ?jցŶiU.k{?px=GxG~A>Q!ֆ;|/l?=pצqDaD}  8Ϋ%b 2/{9֏8nqK#74afvJ&D޻9]l=7~Rw8n<(xP۷.}ZxYtOmf 1az{:d1q=)(߄#^ء<]/L oczmxH8 `pk2fYf`2-h%tb픱_L CIyRUg(4uH)p!BK1FB\*wkay[@uKʔ09\s[O;SCa@ shjDv:?h [95^7n^'g{G.vSZRvhCcф4݁gP eգv\W L;W^cP ڱ@GLՀ'64I]~KD?#'ţf#xƖ~b3PU"GxD!ӽl~e~qRgUA Q򹊌M%ުҌ^WU׬aĿ,WBPTo@]ϓ^Ⱥ_lbYmR2QYםcXd;V2gcfƶAVeć*xo*?6 [;Y} I#U5ӁO}ȈDתt&CAH 6iZv_hi5iT>u`(PcQ [۸O->UxXko_10 TNeND,dI%)APKJ-ݥR;3g<=zA\h$ 5'T4㹚4D_"YDq>jEE;mF(@nTgs! !U3pZbtxE/~o7_oN^ٗ$#~vb$NYkG8)|Oxp"RE$uXdJ~8vlٝLn':~!SE^fB 9UQ K>NQ6R T*/e,0"yG\NUI1\߼,X4%$W։M 9MBh&y2K1 G@O$%u妢876S+|å*Q\V 9oYX ,/k'E)upiFܶwRoG%ߘK>1r*"B ;`LT-aæUL M'AqAi jS2ʣnBE,_V+g?dT  AHޭ8I@IQNb0栱ope,YxQ4Cy0))Hu).*I1c nC4JJ}W&Y4)ԗ?".2U|֢%&$ 9ssw4/D2A6<8ok$S>3ɯ?uf[Y*"9!&8gUpnkF2d݋xe!>T-5nmω[,Yepx.~kmo'¯mGrn`wxnu@wuΠu/t> ]{!^׹+]е뷮{/. \PC58>~Y]mɽq!WNuN ?^ݶz.a^P }]w\s= h{ [ pN<,~::Imڹtm:VC8Z߽fWQ08B/.]zu:= ջ`C OCuC}Fz,ua`n `VY !8KPSZvS;`߫9۰d\yGY'0>-ށ{F:mhkfݤg:)z6 ׆Z޷ Y$W)D-@(*<1D&b/QIRnsqDq 4 &Q2uia~̴ O.`\ ԕѮ2 Q0ZLaE+U +5KQJitP"Ib>v|/ӑ-iFJ4FqSATTU`WeXɍ8vnK,Jw8omtaeg|o[ oH%X3n3i\ǖZ杮'CVfjݼ]ŁM{˷n3pLAyh *[QhlQ~em׏YJ۽0@f;)0}nl/JYnɘ!BLF1nmYW56%;:[Zo"ܙ7Jךu"|}:xGDmbU']O$d0/rAv^MgHuv->UxWnH}WF*Lb;Yms!KZ7oӢZ'[hj6%@"uԵ;Nt/T BvU,'iw~.X-*;)HҼk^]rb.;\[l{E;͛7s_{S}N2XOF@߿fEܪ2ds2z% 4 LJN"RKU*u,͗I B3yI1'ͯ* FYi2KbsdXԋ(䔖Z)^(Nu=9MXr Y\XΝ=rRZXM XTbVdb<*@k;R1dcZ84NE@\Y]~9g6xuowLU\.dVuHRXѴ@$D~6,Z1oN2F,N&m)Yp+FОE"u*%_X)<RtSZBK~ԚYNU[.3gΩwSЕ:fWCBb]`٨Lgm̌pTՔ1s%Jpp 5|_+WdbOUV˸8mi*x3Omy8\4G)Hyx_B['(i劝@"አ9*ԟw ]m2"As>x;JSd͋AܐrI>m6՟whKQ-NrY+! <(>=Gz/ 6 } A{aA?6݌# #~hq^-c-=xA_G̹~4t#]Aw}78 C6wVp0y ͹gcp<蹑?𣐺AP}tAyUǃx݈ܾuA G^;`|j3[ s;/![$ ME&hyt7Bz%`jxk5Dboơo(3pF'M1{ ٠o|b6={0ۆ5^7jl3(l 47z:d'?O? ~ucǑv#ԫ^6&ޣo"ڌ }N1{oR3Q+rt3 TZrsO 4"FH]Knۉtǧ'._ U$N_}GvSri`tNNNxJ\o#| dmjH%+wqye|q6BO4>fj*7 %n_.36xpl$<@@Y;0l|ʁ0}NKc'"k̊bA; H]Ɔ&v`Kbo9|xLRy$bpKls_ $/98)&|^ %2:F4AxMet{ћdKU͵,_Y4Yʯ2/ހ'(X1;uu dBd3e6<ǪEWc>w |e/ǒFգ5՛mKʈU*5ް U~lvrgtGdj1jZZ'۷#F%6/_S*|hP.&RM1'Z-vrji5OjT?ۢ0PcQ [O<'PK5.w=org/apache/commons/beanutils/converters/SqlDateConverter.javaUT ->->UxWmsH_ѥڪS|ْ}#4 @ZՖu6Q0t?:֫x?s6Xr+^y5M}adgX.EVXSβL*$%r/P`W,%XɝI ws=9xk3}I2pdWIB<Ӗ[ k&9 g7DPsF&ϋ)= s+lJ04%X+>35lgIQdZv` RUJ\}& , X'T* e)f<Ց 9ˤ, r)V _+8i*I YBBJ7[Bvnv+@b1UQE%Cu MŊ4SO&JI)deZxhdquys UF;5fO[U({!md.8;C`7 q{=w@(أsC3 ѝ7F~CP( †'a`?wnCMÙ0IBs>2$t <'D|EnL)OHjjOȽHgRP1Xs6-AԲFлsGK>=y{B'?x$BnDV݂=xT֛1DBOSML8q|Rj8֊V"r` K@C,B`E v,wDk)bd"onk[I ~aT-z6C/Q$YB@ӯY4^6_STbEWCW ~N l|7G9PAyı@z$ƼO{]Y)uAR]uЪPUi +V G}xQ[F+ť*+YWVIG5IHp$K!0!vRSbk\8Ao븨oO0a3ןŎxD˲![/ "HtiU~W^'xP}&Kj^\Of*#dU^ahC#̱L`/i1J*'Ŝx;ad/*k!p?1u\k@۟WٴM;l~gD(;^o)?<F=o:#&9/:88ę1ٟߩDف=y* Qu@PK5.ĨLw=org/apache/commons/beanutils/converters/SqlTimeConverter.javaUT ->->UxWmsH_ѥڪS|ْ}#4 @ZՖu6Q0t?:֫x?s6Xr+^y5M}adgX.EVXSβL*$%r/P`W,%Fɒ;o{xs~Ż g"dJɀ"م X/:m<*Zpyf0yVpHTu;od(Hѣ0fDNSPH^p3S|Lm͠*8 Ud՗i1€uR.@H+Pb̓XisLʒ b\ሓbdπ%$t#%//jfGļQ+3\%ZT2TThI3E dDZ ܑ"NV) Mou3[4 ߨj1qYa Kdѯ܆mLc[Sfgs@iFBs($s βQ3:K&)EJMV@ȞOEJL7-c$, Zf]]L*4fO)ҕ!gF;f_Cs,9#(c*%eӹrJ(J,rҴo\vEƖh~^'eπSH|3{F;zK0a)1y[HLy})J_ 2b\5^H"HJNPv]V S  2tx띏:ޛdR!7ib$oImOM}&R~Ԭ)q]{/п|7pv~>q!xE{ynh7r73fȏ`=x EǹdK@[xp7Ћ>sohg-i"ϙ Ɠ`.$>Bgh{[7ƒ}tGpεǶ?[coh`G?B{ËBpQxpЭG ^:{s.TzR+HvgB"  a Cw8} SprF^4\AHء?L ;<ݻ= k6"{NڦP%ZȽzwqi''/tOџ^H'D:Bȍ^ \C9[z3Hp 'νvOJZQ`QJVTAvy(u%6"BHb!bNN|-E]L:}RD mm+:ރ>a/*sEv6wC%$\h5_SWqљʘ[sRtJy*؃i}@Ԕ5j3hܡ6/80B/‐dؙ\јiϺ+K}1.hPZj *-aJr!豯/}kh4Vq% ?騼f6 d3&->UxW[s~r*^nIBd},b`RT)t.M69U+X|wٔs"V(z& {fb2քJI f ds|eeiQbYᴟM0pf7_^Yg^9_$e"s%|볊u_x4T4`+{!j$A<v;Xi^A/>>anDOY&Kr 4)+Lj,B]r@JQ˘/$gr3!ҀeRAH+P21MfI4T(̒S(X$S|8⤩X&[ )H.չVѮ1kՊ7eU %`6 ZL>Vw$%G0jq0dKӛ}]/.hF?vLE\gҐ.:|SQUz< 7ܲ˥͉ٔyʑt!V 1kHL9pN@U%uL\%rzZ`\2ci·x׸"gX?6%FR؀cJg05pܸ&MĔA3Q  4冝DBARM򗥪?7fj@rVR`\m|$:I#|M:~vj"5Sڔ[)U8B\Q?x}?l3nw?xn0P4xCg0{[ ޽PxJvĿ{7p} :Ƌx&6 `4F~M}/twxC<wAxg\{d;6vC0(FA.*o_x7B*‘xdh|6- ݟƸo۷n}K=0q­Cs>28t <'D|FnG HjjȽPgRP1Xs6-AԱuK>=z{B5'?x8BnDN݀T61DBOSCL8v}R8֊"r` N!2lD`w.XSCļ9Kg;{xz򕉦&9u+Vr%|y}:::¯*SEOz67$Y!d4審/ڥ/532D-H re)19߯$@Ԕo 5 j[h^/2 T,+qJHrlO .io⥥@L ֥2kgN+XVMK=lk‹jZAZ!(.% Xq\ҼO:>XB#Y ͙{w]8 Y|DHs)HXp6!ܸ~GWQ,8qNSCH@^S$GvU\L:\e[7l@oԯ& !if0u\<y;p@3,xFRK==<([wn^\2زLp t8_%WKbQ %dy`x@lqnp,ډ2=xYG!)^ x7v S'Oƒ!*q~è {mz( $/pZn ."i-LU$i D QNf'%nAhîZuPm*fr̀ tyY0,VrNG֣稒Nb/^c&h:m*=: {[Y}8M5M]/rkCbG`3a5YcV;z'']Ho1۸߃%*PK5.GƩAorg/apache/commons/beanutils/converters/StringArrayConverter.javaUT ->->UxXko8_q 0NǑ>>4i(h^INZcMdIdAKRNV@u<;g˵SN3b9IqXYٙH-$-;ӕ# AVg+*NX$sza8//;O:'7NHM>\/Z@2ɳSMcz{ e%\ YJR?eV6P(Nn^7o{\l**0p4%MX2%KVrX&%,:lJR*󥊥ޙ$P4բl:+/+ȧ,6 T )\T4!ӄnLթUѮ|VS\^,eb"LeyX۸Hnq*.NZ.|c˅*Q)D9N-*i_ AӘʗ'MjG@ 6)Y"{hD,юE"u*$?T#FŀH\6r%Ӽ1}= 5Y׎0#һ)ʀY`!| QR 1*%U)YrJfځk8**1cqøD8HӚ}WXC^TPOWm:2%<2ĦEx&t0Pa\*;IRY#):T2h%ҥr\kVt /*N2צ$Y C1a͡X)4%o;{bDrGC7q7 Ckw {y畉Д0"%{5-ɝ@]ٝGl840N9:EIo{ǃV3 RV¬u=OKUbNza3azId3"wiIe] UNFz" ܻ7*,e9C~? {VVWWW6]D=ۓ(,th/a˘6ٰ{ʟ;ۺ$ZS_94:8|Y7/ˏ7^8ΤpйJcR H. ~V;%7 iIN{)];MgE*7a6V-%K- )ѧm:U-C (mIevWͱoJXXH:3䫞o2izP ZOA6=aU܅PK5.O<org/apache/commons/beanutils/converters/StringConverter.javaUT ->->UxWQo8~ϯ lR(RnEYIp,$'׷%:FR7X INVI73 gF޻#x?rVpyJתU{'&;v5}WVSvc-W(T.5K;Y6>{?F_F < 1R92fm:~~P׿Pي=T, &eG8md}㪃F?>#C\)X._UH\µ /J\.z:)W*%zs(&a)dؔ ԿE,s2.J. |V8T`Z$m#wִ:b9C:0[5mYFtH'JNY4XYc^Y[>u2؂=1Z:Qyӱ!tx{@3YR;up;3xě @RP6y#(K Κg0b^yFl* Js+ĭ .WE#{/=fR9u_!] rV=|ֶQ3[NjXr TW,Z}ϯYU C(~1hX믦xLy;p ֢&$t1E[H;{-:>nYbHK6l5%J|c.R\-nׁL$À\b4%_u u/GRа2ttq]o(4$|%}4o~ ? t!, $ DŽ?͢0u 88p5`g0 Au 'F 5܅Ip+U4ZuMQ'\Jf~E|'0'8 &q? J)*>f^ϢxF,8I*DIh#( ܽH=W+AHV~wB4&;&L-[O#'4yMSN> Lbd*&y:'zDA"_HSM0I3bn$ -a^GeF;@|8pzBlk|#ElFIЗ$$ AH1=DixR:>g6C(hyK\GkPsS$l:bypkZa`-+` \IFD%vW=5D b=<=Q)eC޴춶)/o`xGGG?G ng`w7An`%4yt,.oi݆ ~V|71L 5tQFO= thw+uv$'(kD <=ufiy3?زiUp軽Ushr.8'ZonV][W MOH: CJ]y;h˹R.z86X;NlraE'Ɖ_AdڅzɚSsB턑=9ݗ36яPK5.|4org/apache/commons/beanutils/converters/package.htmlUT ->->UxUAn0E9$piPMbTX̨'T }pr C/Ɩh~G=S14(n#VF/9KiBXvzH'hpo"K}#]z%\]k +Xy 4>tK+zKhJPJ>wyP>3nyboyPK5. </org/apache/commons/beanutils/BasicDynaBean.javaUT ->->Uxks~Ņ!e5EBZd Pә#y1xPfDJcejXq{{yzDtVuM$3;{kߋ:3F$nԉB\Ў.;4 @]Ј;G/ 9$={}iϾs{=b|ׂ ޙ#ij:^1#oiȀ;̋XܰNx!_b9'h-K?4:!]%bchBpB;as!%N7'I*aΌ{4ܒ69_pGld!`1 7|o$9n5kz-ǟpp .)I!x~ bm MNYu\,L./@ 8<> ;@TaA$k4U8 a%$kS7/ A0)ׅ91o~FVpq"&8nKBNm[JDm:=eK.lb9+˞ sm OmYs{{xch9[jqy 3wS%4Ed,8b0P-(X I8(+Ow !\SMѧTGp^MK2ڤՓA.f"Q.T  1ts04`; T;,,KdW1vp!'?D+4j.(\*uT?xSu젚*˄ʜ/@Ry^{q< $HLXKmwbOF7f蓟~Zp;bs<1, Fb^Guڦa9 }sM.6l20M6٣63ҝmdtII t/́it/M{4%qwb;!d< li]C*1@7&Uw0tn^~6GC80mFC{b룉E. `{10$yAߜ=_@\@56z&\ 8gw)"wo hBE:zӉqGY 6m7QBܖ11{ F %ZF]A /)Djmc2QjvaP7CPB;mʀZazvL`Y&vdhoa"zkZ1ӴvVjepBļ$),TX2')kڻR ?zTqdQ l|79#HPrbXC"B +d"팭o}k`=2ޞYl|^^9::#2Qe/? :uKdz EiѥR…|wÐnQ5+sm|ty*sFey{ګP? Kȸ 0qJI/s<č9P0R$1b!E[Y% ='"r"RV` 7R]NKED!AnѲTY gPW=Ά8"{h@}aO̒Xrb+$-.pAH ɨf?#T[fZD,tHUQHFqu@-i{ZUg5J6TYɘIC/!~ΪR;'FZ)O,m%RTVcU*UU$OY iml "o4lfQMП6Bb-GtOkx?}g(as9!31Jq>]1QYuTOwRїՑalk|;Bahw&8wAj+BcЂ+7||K(*%!Ɵ.:X,'/&V*nwxtGE2OX>- QBS(cD ~!0ӌ aAT^ő'A kg#. @0=*E^)EqJUNZP4𰸔OuQ?чW q-'a>+U}v}Mx Ⱦ6}BM,!)0O3gNE|hЩҬLc9'_0 !W+@U ٠Rކ"mNDXҸT^ZK`7Dm+ Ə!_-`PT_&)WBVz}I-H\9Iݐ2t DAXA(oqNO\)Z}bPK5.݄ f+0org/apache/commons/beanutils/BasicDynaClass.javaUT ->->UxZmoF_ Nh)n@c; K>r"W6.Ij~3B.)IP!e3>!O׷FL\*]^6]y{/.(M󄸿oג)Ʌ< i.Z:ny>Tb/#~wT02!K2&9\oUNNSrŋ3dMZ$́@~y0C2eLlYd,Y.&)2F,-D9OؓE*֙Cv<_Ti#uA6LylD|W4 qɒiq<$ysk_hλ 2. [a"AH-.i|4X3=$S,%1k& LwZ^@ڨ; ҰX$Fu1$A`ɂ8jEMH]WK30Ѹ'a\ؔ@\CBQC h>Iw1[2$O * pJז- 01[Uo.znU1f^+!'taU )YyⅣ)T !bEtxoĚƱ!oTA~ ^083PQ❝ R  3ts0 py}܂CД)1Np]>QΟe2T5j! } ґ.]cT/PY Jt>!7uro}tܼ oDZl rO]陸o/}x7?}XLww?!Ҁ8\!x0 \2dy &\皓1$2!wtp O {o` wOF)M'Km<>ݹCH%.&;~Lfa?&cixOq0'.0߿z`MAbV0=߻X.ٟs- >X$]듓C c0w( @Ϯ fKL&Ci%M Ҙ}y=P a|t:GN-ga^je,&w!㐷.<">z&LAi`K\\ >=7x}vh A5{eT6nHI UD|OƟ n_R}bEYG4. r@R5Ԝ!֐ Y~;g+/^=aZ*3J)iel˘<|՞^{ <}Of{e{ z`iחA1-4Yv[Đ/ xdlSUT,Y Y?toidTjj'1mʲ'd!.hE!5(b%%PYeXxIqlFr@H{ۼ"+!M0ZJW B{kL&ߊk_* .b&+6 5S7YQ)X;hea}G%Z!pIYi @r Ub5- 2/]2Ƥ?}yVF޾UZޓ'(UcT?O/Նǖ,J7,F  rI:d?kjc"5Eu!zGG"ֲO@Ƈ =2Ev[ rrkm P{uoФq)#ת'2RRT5 cLhFW/kW ]RrU?WeƖJ`|ؕW43 L[heݗ[Vx&?P$["Y#T&I20M1C -+ l vFChyPalE7 vViD2ּn'+9F&Qn3tPuGߠZ S9#O4.>5I7pD R(ddB 1[K8e#a5 i0\Α{R+e2@4~ŘJjy^XA@l8"4xaCkެ/͖cgrf%Jm*JS0jENR5["Pŧ16JwtIYzB†V "$iV TqLL;9/ȭR̊Χ٭x2(NT cUWH0"X0a˘пZk xX{Z)]I)4ڴ2Kˊ.HCCE804|=fB4VT񱦻wJClţ!\+ilIN"e$i7d)yje]ՔSdEb}HwZ'tMK;VuJNlOCX+WStê6cl렆&a!b4Op4>M[aK y!,fL&SiYXӌǻ_Ea|V*?F6dV C78KP5%"zbO )nX7GJ<$9&SN571~:)ۆӢ nPbVLǠʾR-ρVlsw{th/Mp5ZXz GF.FQiI#Qj>DźB_1WX➀s_¯+{:9xYӊ7En2?+pHm?PK5.[N)0org/apache/commons/beanutils/BeanComparator.javaUT ->->UxXQoH~ϯ SrnmUl%±\v,JaF7{?r$ْnCO@f!^ 鎳KldV2OdLee!=Њvl zrmP٩k\d3 l0W^^ 7p1|b}[.Ln ~yRPᆃc@S&"s(ƙI]P~o, ݄c'? t>|4o:,ւEY Q(Ym$[b2{ڛx' nPsb0_YMc/Mc+wBpL&F3wFkl1;7?f;R=a5B艹ZyF\?Y <0v[7sMc{r) A腋Ѕlv `2Cf7\ Q(H$" 4t}1'n΂"ܛLHD&:<޹' k {u̠{;nȥ=z{:UT 0yղ 6x70th$Kj=9HUhȘ1 Q7#+2^DRK28s{\%"w]}UhASn·x[DL/NZ ñ&ɻl6%tBi<=L"::+&"z nb2I,sXY2j8-%؏F&[|& (ZfP1ZEks}84S!^0_ ߗгTyT94~RRt]׉=PBIq#閙if+|wDjtrw"y~+FWJ\ӡx5p#)";zm^UMQD.U}\'%~ n{ϾrIAaf.f[ Kh%DϕlgXm, vi_ >fKl"Dk~cZE7q:EO}n˒1;N!{ \|02VYh5*Z_fx]:Af䗳PK5.X$Q+org/apache/commons/beanutils/BeanUtils.javaUT ->->Ux]{oG?X)"es!Q:7&Iv4ag$3Y\Ucz^S3UU{waw_ ͯ&r_$x#՛ e UO%d>_AJul~={݇|Ã%A]Ɉ ^o_J]I?jH H~ mmB02PVΏ8b Lձj2ݛPJ E[qহ}2<}>e<`b|bx<8fwa1b0`'GBp h&nΞ_4 ;:MC`| @yv:<Ij}w41ex[uգ7F 9 HʏY$n탇`k [Bre(x#]@RX>2gH5#,o;*aG6'HF@G䭜n!% C_)?S '4C4D ̒"Wɍg$#w*/x8ƮHH>{u,-F(/kgrњNu(D6<QmtܢFyw,!䑱*3RzA <2ҷsʇ잯5T>P, i<` ,Q|SlLjZ ?Ե!j+Kz,sGvD[:rh;sPQigOJCb2e]jq9$/mcدtAFv7>H ^+A,CCB#G'}yZ[FdZH[H Cn^H Lc]   ^:n7Uhgska!?K5c_HA|niY>i*hz 24R硃X&7f8)033Lal@^xٿ">FSJ@S$4SRYK ~ɃQ!K͔-Q~ WQm*yPMࡱ2=>mm-ErL“OOIZ]1)ڋ/ynIcȭm-8sҩDTnxvj{󩷫U|zWQJ>9zO(P?(2k:w[r<5R]،6OS%? h>T8xW;ʳ?kYxed~B &Š<j;G{ 6U°|~SmCnV#e_`kۣ͓ C]{t}Hs7qS_#=ݳ ryTlͻVvJSn(^lKעI-K.l xH+<´)YU QZ* 0y1oF\ >`/t+sM'ѹg5[y-'גVimhAtL'9K< M6CQZB΂%^){:S=3)&1Z ZW}ioXkyv-\x yUUWC>J b]Zַet}›Z]UCW<r(h5,+X&̮M~OT =2ݗ"-jF'&ؙQM@_\Ws()|(3w PV ̓K\ItҮm'>2ހ^He8 o,v@ KYT!]\tQpLmsSG,eO#^|5ۻ&b_qajE:^aH6!^tm>vc$h^qq4Gc$dA ;fKZ]KۅG# e,,&E{{^쮫ӫW(Vh gu(a O-*xe3,"mzy: G',(;:aa0\_OVHw?(1BUG_jT}AΫ1LXrzV$Ljr3p7 Rk :ßr)ԞTϖlK !m `EaLH!>NO8rݐo"*h'w,Er_rX-\WJ~pU;%7 k|+sYۼk̳^1u Adp1=5 & F6ř gZB֫ۏptܥg2:>?FR"l/xז8xPMLu$!.p9Խכ Bvm 5RwI4?m)TYx]sL`#p-tuQ/fKw[|Ǖʉ!E^Q8=rr\"6kD:_*=S֣5j5ڐW儲xPl<:cqY;sp]DoEUpAAɊw3TJrיp4TE9V (}Jllz]ԙ޳ه Co9V)npբ`OgbwX]5*w܉~P(#?eL<vChʶ0*ܞJe9[bԋ8P#,p6׸8M\0J\o۫DLeAF) ћYU 4̐H۳!^G4ayyLWLŻ7PK5.4 `)2org/apache/commons/beanutils/ConstructorUtils.javaUT ->->UxZmoF_15TJT9I/]ߕh,D*NPZI[\u+]R")uC[E3o\<=p!Vb!~rn0!O4 {rUbL_7rY2c)8Qf&k|9LTiFdH@Lܙ-̥u6"]TSf)qLEhDvTXq43X)3H,D܈dLf&h^\ݚvP+3$t %l*(HdvBhK6VBaDUC]Pf Bv~:(4B3f1ORV"񉂘\ =m0gP6 '̾ P5" -s逘YXDI5XxM؟pq7YȞ5 nKи? Lf2C֕jqJh;!ZqF.0TѼss :UUjՊt[c1T̢`_o c!7J=2xI2kq8.)4@m01vX_#J`9Egg|^p(Zs?*LS`ísU(դ)7/DP])CTܮ:UFԧMJlU(|G3voƣ7^?8>Kp}{ۛl4f}S0\ް7U.& G k/Ibfi1]µ;;΅7wF Q&\Hnq&g 7wզ} c+(703΍Ïɰh/7cU}pQybZA_.Tz`R˿q{^#X.u-d >s\>"eؽ&S"r^0 \>g0!RK1 # H3z'7@^n0ԙ{㕡1ߑNn_xLhGzAp-d/ ݫw{.=[wO'JuP$#܈Rv3j1D|/' ?실rcub`- +` 3l9!blDA`w.QCļ%m^=Q-"No[L~cin&܃#yTEh |wYEH+RY7bɢ<†!eDJuv?]L-x}}`εYqd{tԸu6}2kAW^{ OIY<q|q_,ڪX a%Kʏ,Z-ʴ`pYķzKŒH_vc MJ*XN9p)qܗɝvˢRwlp50!GG8NNOk~2|xu͔NѴ azD{;|q̜sH&١9e#$ a!~+ȟπEof2̽+ea/el;)0%GŊ2]*ѻ4˜NuǂENr/ dhC C)kd_>pwn—B$L??2z,g޲F"u1 f={ow^a \4\"'QSKY"hB]WL>lUit>fXAk7c)3rCԯ~(hz5 y+%{g=3'CЁOE\ s?=Б e^^*.MsFP>g)\5UZt%ѱsw& Z>&3 ޯǨKpûJ٬m. ې OtƘKڼM!@B7,DZQVWhE)`_jf<2&dHn8K&H/`)/tJX+7bC<Fx&UbmN%WmNS-b}4a/9'm0.{:GL(,Ѷ<#LRs{FK 159UT^5䐭U}|β([&+dSn->UxXaoF_10 h1nAhٓE˷Ć ~o$;j$Zpv̼ٝ}}D)R_PKfk3k!va%2*9V|E) 9ed}c.Z{ϼ3f[bsm*DT AY2 xJUV;rCfgF- /h[_`sD;mQxTeRRkC MKdim'YNp3y>Gq(|tFZgK6KhJCV ɞʵ, N<<ϟ_:YTu7M*=.0V+@W Ί61O=$V+)86Kyed1sZ|fA&SgUg+gA/EQt]*~jRQ%?/MդVˬ:voJ#lG;҃k8Jdǿ:Ghf7lok4r|\~cl޷0;CB w oiw=S4e UnI9^>m7u&5-}ծ^kU:ӛ0$^8 A~K+F}Lq$E1a7J q(I?];t5Ii4 oJi\i1H4 oƻ a6i8 Ћi0Sр1&INY@؁$ -( x2fN&aԛpȆ 3;|8t}l[<#{~͢Ĉ%NQp= 4b0 N0 acރIڞN#k{ױɦp@^.'ٌ#qjI&MދOJw a`=+Ȯ7/1xrX1B.XsCĽ} Q̞]ji^roZ*mFZ=c[0ܣ#"\ݖvm羶\>zt3lP &lqD(߭1d8<#ζou]rt-) HF:$/@BӵVsg&υVP/y޳^ύ q]_2mCEߺEOHدjϊ8Ps؜?Q~ze:cl;Ak =yoKZ {ʶ3rAQ2&e턓Z#fGt>PK5.-RN.org/apache/commons/beanutils/ConvertUtils.javaUT ->->Ux\iF_0Вl͌mX86YaaXՒS$c&JU]dı&Ǯxxt~U}2oo7o9m-7I]ĩ 0Hz ^9japt7],nް''OǏ=~{{Ͽ'a kľjMxapNBpcP g}a։9y.nww 485ˢ;~%fT;,XRˍfM:H)<clr9ߟZ w?x}`ֿl&Sf1@tmkf2{<-^-l<֞|bBudrZxeQ=C쳫tn]-W@mڳoЕcYG#Qo??x؟ۓ1؃||j錽@EՃ jG"fWkpvLά-dkkƌCw4`1ޢ)lnsL3ĞYw]<5D2y_T(H(ׯ3[ϭtq70дߋV }T!ZdX|^;f\+&P`t,|;A@{3,`SPb.ѥF\S46/Y @-D-odt}8z1 2Ay cN!!+v|J60}mCJ^==u)apD6m Ϛ2at ~;{Pw}孇i~i)Gqeq"OFCv1~q@= i aM ]O>QƉ7>ŕ9ĩN|0 $mC'=QDN p0X&} >QT~1dO@$ta}vK'I8s[;d{ߊdz.1y0sr,3ie&7U5N9@$^nD5S:!#RF#s-a(~{g PU\~)k5t) B@YUFU|$lf,*b&[a5K'3j$V ^)Uϓgḩg=xX@RkŔY+LO%+G2.tt2y߷G/a^Rt3{JVTT eȼR1L2 J!XF|TC7ix#.5a EB;)~abRFSZxs8I+r ≔\obPv8N)G\s,ƸW""2ƹZ<°m ;KW}G5  DfWܺ1wR})7xѪN8lH DBStBVebx#t&4MTu Btf-CS?-zl,,iTF]\jړ0r}ٶys@o[vaAѹ(@[*Zm&+si2R@ 뜥>ěNYٴ޺gG6G\61LbnR9rlC漴DeC,~л?]\7BĞS] 4&]%rlb- T/tmOu`hJ+}#]G3l~˃8Y-f+JwߗjnBoɒZvU .y jC(K ߦRiq,FkwAҚk8ƸPi{2 {ifjW Eu+ju2ULowJ37"iњ0^XթSj͟B7w!7LI:i9UT"j/xh`~ۚ2f^+PcRQOTSk|^XKPu*U;jM1 A|rV0VJT$VY PZcja5ќmj5fH@ZVlԚ`b&|/Huz"}tCM C0fHH?!vwV:YtQnNUf/ 皅xr ER L{>+4sk'WR#;cpM`*|KJ;;>ZB>m`S)uɽlНl 5B(XZ. ,52RGqM{b `8@)ܝPZTWb$TqjBE`o4sZ{ #mb&Xt:eqkΐ>RO!k {yCqHsH;!vw:YaFS7* ךx Ƣ0_N]+9kZxwoj;> ʭ&uPZ&Biw̩o}gQW7s_U⦔A^1VC%Wc[R q3“ No [35H}BƔb9jayC(TDhdA NK+= YT/jA?rlqJj%5$rZ}i->UxWo6bf7M{*p,$'JKt̮, d7(7d{9K@byaƯ5p+E!7z+TwUFv+;^IQ*^݉6cQ|vIH3ގ.G۷o/ǗOWAWUQGM?8J)tulhՋ[7|zl#wQ^I3Jarvotd㦡W]~ }f۪ FD~Y3 cf'QBƨUITV5t3+U Dkm֣j6m([]ʝKB-V5,6z hK,^UPl丱V6W=3vz[ F.RSzء,cgᷴ4/\\}>Ot ڢ8QxGv+F e!C[dDia8 f'Yop3 អx=NYD"Z})%_VgJ'".NI0ߗ^m%#.+/!Wʧ>12O$Z N @I5VkGRk=lVojglEYC*>t׮Veޜ{ttCyLQ.%8|q4g[\yՍ(iNC} `W՟q9zTRX#8dHx r|qߐz/ i6w6{ct[(4f~Ƌ$&~O1'BIX(0LEaQ4fI4zi >-$OhLqh$J݅hއ[6s~4^'~sQRϳ$8I:yzv!$J 0r]t+D~cZbi7aJW1NC:eq((]^Y-nx2v&Q?,R1iO;@؁2< d`.6~``/9ee†|q .;=܆OXmrP/N9$I4ofM8B^!J 3JyCy~v'zz.MɟGvqDҨ?N020_Jw¢N-*z0WcobF ]冈{Q]ߗ_O\+Nߵ]Y~fGďÖ;:->UxW]o8}ϯ t\M6Ul%±l߆iSIԐ]c璒8.eV@{k˝ /`21H6f;u$*TnOU)S30:^ x5n8y1+}:۰wۋw ^\p O(6H_;nmKqy>ӑ O m,Rr˵`c܈{PUr.Y79g>~? s|KҔً`0BoĢ_Æb!MSEhbL̨J'®<ɜ[*r͔UUJr)+HBLXB\\pTmeb.Y^&Zw# SFD-p2%,*9%`6U3E xrUNHR^Z\fB74]2xit ԁN,TRe"/y: S,C$kSߺ 516Dx Gd!=D1y9FKG[X oĊ#l:b#RU@݁1< Xw]`n;}/]98Kwck>wkL,HI.pTT q%Mj;64mWù"]d3~IDF{:%@$(h4R3UDv57$UM)7֟z "P p/{5t|ϔ:6/%&N&Y/ԧ-VhEӛ }Y8}Fa+MFB?7 Yp?0p5&qG=L(t}Dñ#`'1fZcoȋFGl8aէaĮ}(]}'dmئV4A;klgsd#޻#}aw Oh~A<}v;"Ž!'6 a#9gDޯQ`) &1p zs0^XA4J ;=xc=$-ka|p̢%evOSz " ":8ɏ:BȍPϽn:7=6BaH䈉û}R:q cJ+T` ޜa֤DwE!"oĚˣ===Qʔ+2NZn[یNua_Q!^5'꡷-+W }=W4}n⫁M^[k̔h\/P63i,1o0ށA5{Oa >Ɔ$ڕe\=N߰rWX'np*I*M=3?e ]9|jWpCs6<ҀQH$WNQ Fn%dQ3R(m`Eap/Fՠ\(qQHTmaq5ǿ{3刚4 TE;mwCݻ=-2 Cվ kZ_ էEkʄa0E spG6A?gHmC7?M#g$!I%#)DOQTmHa->UxXms۸_%E/Mq4DleI%)vK8 rN{@Jݹ4c"o.v {~8|.-U&zɪ,Y*/늿HTJeԴ==^d ;뜟WvVG˗z/{OGs_˜ (+YJ{o+qWi˟S/L\,RW ׂ e"Rtإ|;tXkXViy9Wͩ9˘FR蕘wPeYi9i;ե`TN39kvtVv؍Liꊴdj.dbLvPɪsVhs\TK^ៀ4U72_DsIB7Du\;xW2uո96e*wI1-9H >k;dR#5&nhr ]_`s D;ߗqF1WIMpVŠf*YKMڰlDkI(c@IZokBZ:L^9<_w,"Nh'"\& Aꏜ>1bAlK$U\D 81[oC{׻Vҥ{p,]x/ )&%Y"8M$IuBXI=Qӭw(4m7ME3@ME$Am?%`O X<Èp;< ߏ)Up9ZX>B j#S"xޙw"ۀ!i_P((DqOcǃtG~x-tL#;gC \L@b? B;`ԛRȄ Gr0>A#8"׏-!b x?g}"D!?x0;]Pួ*܎I6 N7 L((pdsoΔ8zEcJ5:f0ul6iBdDAbb 4qngbӫ㻟=Qʔm2IoGEm0g;0zO{{PT= 2é2t =x3єpo{0bT1b֨1^w䷅1!>0GEj|uBì!̥tO{6+P$tn{L4(nYl\k!=1/g(yc;3O1殱rCֆCh)Nw9=*ES7zqlS 64ʲMsN żk2imFWA ?c22 Nn{sJ?8wT 3ho#}/xtە&ϔz&q:DM*qGp٠kSuރy_Zk W g-gWP0P^U"+L1,d9u_PLwz 'r3TPK5.E} +org/apache/commons/beanutils/DynaClass.javaUT ->->UxXao_08;8iqm% V^(.o}\4_BQܝ73ofgfu^_}ktkjɴu/R٨U)37V !bpAƍ^o.{ٛׯ__/߱7W_3 9 'kR$H_Yݐ<Ӗc,Vrǵ`#= MK}usv 2(̭/c2f haފEFb!M弢 V@QN}39{Tzc<)mUUF-RVȄB,K`V[C%2*_HFWδ3 SƬT-2%<*9%`>W[ZrL>*AҰ xj>5 Jӌˍ Mo^^[}sԡЎJKބ)hA&k3oÆEumϦHLӬ".ҁ|Ռ8gkvX rR&JMA .b+2U }ٺ,~Zңr;u~rp]`Z>$Y-=$6;jfzqQ,kPE7pVJ67;΢:$H@6t̑h4lt<>ضDG IgEKtenA@9ƴ!5v 0¼ 6 o?| m֛"qҩ&& ]z=][UTA޼IbFD]s;k-̩-E?=6# ~+īfy{É_Yf>F Va73rSeegIٮ}MG{W=d҄Rz(7pz5rׂka26R2GW]Tf /M@v4k6TT^[q7*8[m .#eTǥKyą *Pr_FȅsaJiEeʋuR4h.W!9_ 51 S^eq ߺ%G7$I}qjo5(龬t#)Z3 6hҕ(<;ob|?5h8} c.OYuڄ#LUJ KLW@؀ jҮ#]lh@ۑr s~.c 1E鰾"5]4c@dU w.zɫ,sd46";|SGq|8Pp*W”4=U!ԇVNڊf&[%jLWm6ii0J ,2 (Χ\kǙCN PK5. '.org/apache/commons/beanutils/DynaProperty.javaUT ->->UxZs+v N z42ȶn0Ht:EZBIvywWBَwnXzxusLE_$ o'\ig"x( ]L;|P1LB$ٺM;h^|s:8|, d|`?(Fb3qX{ɻ'VL0K\9ny"X?E(R\z޾}es*q30h3fESSbT$+ ۑ4KɒLT\&PO&a̓5dm͘LÖ\4#ye"`D_(a||!Rѹj-R&Z @L3XqKDA @,?b,~ùHr^%\r]`m~u p!@˹3$$lHNB0( A% hYs\Z,<^4"ЖEܿm$?4ix8&R1.C5gY8tnooۺEk㘪sb!8@Sf-)* P5a'$x@[o1NɜGQ>wŏ1}EKF5&+ll!`4.A4GIL>OwXNSƛ!UR>ɟn6-O)Gdpv·r8޴Ruꐛy>@("E?:5L fOmY"\aq;N]x>"jW"S\FeeكMoq}qђ,{&BȍPO-nK99}tTjbpq@'rV:jXhʁLdӛ8CшC.[[?=QK]LØ:n)2~lQR`t_S%I.#ЅL2F#o;mghłmsO"r8F2\fef;Hn +dw*{< \9x@ 9}ñjjK&Fr#g qgDOX75مߍxg\+3do-^aƲ4eEȴ2?{{=:?41hQ LKZ B SyHS<[/ f`IsM=yr0zDnjf(0713s.̎9*W P[ PDQrb[ߪ1QSVXz=H+T 0E@ a(أb" & }I ֆqG+K^M'Dd%;5f<;}-Z(}mo8Fͩ|?~9O/кht9Ϛ2*`!xp|^T]ܧBGfPQ.Pi9P q4hHטruibib,Q%fH|JˌzB?OmY~XbA5ѵgdcѡ B`bݢUpJmUk++ީ[om(+xFPԄ]iTFﹶ 5.YJ!(2kIng"e@ S37]y@`IGӥtl*f_ #QPߗ\AeԆ4dwɻl9_QDY2O1t8w(Δ68kĆcC%ѓ%/4V֓f%7ffAv0_`A_DJ94+%"^ƪG) Q$_oE4b{y]p⒦uL3i"#Y~w%ka uI'F iaM6rs0Kpd9ҕᄲTV6^%I:^}h-OƦҼVtmqѕ'#rKTDjy#$v~O[ҭLnxB-]+zC1]֙\f07)+]hVtBe&lcˣJZmMJ})Sxj:6ߌjyvg23.֨Z=luK W-Hl7Y-WGՏ/q sY^-Ow&oZ୳mٳTyT6+ *Ljt Z۸ƭxE%r5Wek (XTtM㢞ʜ1(*ZJ?A>}YT.Eχut,SHaB ]I+CMKJ("VY2Sw u5MaͤWa&->Ux<o8o>XNǵp4Ÿz9i-L;jd+JI<)I(wShH|J{{sUFY޵S?^Htf܋4EG$ɲ= UF{5_$' ? iqjʞ?{}A:XnB(M 8:/NK^q%J$^^YH{S{z˫5}v?>ED`N,{)h3 CFI 1"MYÙY&8^8K|NOfA%h bqB?,E(x,l1D$ Ҕ:o9ܤW^ qm-G'n8oCA`Bs(J=@{_)N!8`D XL2Qhx iE3*(8bيGEbxhrx(Ob I6OA A䇙 5XPhӒQJyu߆|Wc\L' 9!? z#`ͫ4]v:m\g 5"YQ1~n:E@(ᢥ  -PM|U̟mJCPעE䭀M:O#F5zC-(q@aT!E f-Fi <}\_ג;9=B&Ii\)޶:@%KTH6m!BŤ¤Lct_ `:5),etл,`Y a/+vDly/Nͷ,eppRde[4 !# ȵ$ձ X ˧B (Ua :H0EF)IsC80D %Xָi i*pefhL?y+ eɫ,M!W:wbJ@Mh0J+~%irxe\,JLu/,2ٴ!GY Pn Ʋ°h^5q}, ql6fVC`Y@e I4QnxÛ &hc m0 cx\Y_ [Z<+grh _9#Z.7n3|- }b9f23* bW4ӑ{#Z֣/LB&ExY%M=pj@*qΔnGH=KdT$MgíӸ=ҘY+7`m 1bfۨSin3p[0g &9XE 2ʥ|ED@uo+}S&ygMeW*d|3x,"udUOA!>dgt*=]=' ,lWʗTVuj23 %,oBWe Ha!DU\yxgw]D$QBN0KT7e<_LUٺcr0Uox3_H}˄#b9iˠI`y3brly,+`4y:q7e,8wH3NV>LWHͱ?|!_,.prH.Js??qGw^7=;=ps7.{op85 `l8f X$^Vw^+W܏Rq?[eˋ)V~FGcyK^;̫)A:r|C~4 {!!b娝K,9 WaדnlԪZw .6mWUTMFzA ^dt c8 ToGovCj SR/FvMh݉]ã9]~ 92Dx@G r%[ZR~b,,L/A4І@h I]8W0Sa$A]PP1.U#,Cgh*lixwrWOw piKlI~b·jqx=òAfw_tߥS푹X|Fx@_KCKhȕ̖=[Jq͞G^ᓻ=DIF-)%46yR]/*DY]}cYt E:iά ʄ۟lz1d[⭜Ȼ(@->Ux=ksFObʡx(YԑTU;$$b!IޯfEɊc U~#OvAP`?hy,ع?a"썈? ٳ3ռ6?_19`~ᇧ`΢,k E"1m)146g<,YeDЛxfQLl oeM?! QXx駩US.x 'NDk?IN}DaH+ԞJ%,i&gI E|')O&<SLhKk6 iEN3AUP4dK\O!J_b䩈}$i`E$S4N̄P̟)<4%GTE|.ց \g\L;'0JF o bWXznqj֊Ak_oxl?7V19J~`TM&PYMW~<}q)N@% ^Or*BO2~t;r "?qF唀@5ApTdRc4ϒ;9@-B*JO?g{d@u &\NΏivW 鶐rӤțSEΔ\bj_ۓNJN*⦅}GJ#p0&3j -#zQw0Dk``ھӬl`_ "i]x?@nȎ!p322^չtk]{̧7 ^4z!Ml東$T6zJ$cWjZ):"CMd`9)|G|3tc 2Km[" z }hDZXh #h/WQ o:G5;w&%*}jxPL ~d z-E!@;Z'Y8\Trb3!`8/ۓSe6 Pz!XS1Y2ي 3a|R4HaDTdc nwx%kz! xsur.H!Z2xyDHL8f=.5>{1fh>tI`.M/#.b/5I<2Ln^J8ω&uCjq~)$W^R b+iB@ $D7+i! F"4p 䘌Ze"P(9͔Vʍ؂$ W1L$Q!иPDh"7*! F!^*kPXc g-fs6hI431!{zKtG6P*he<RBeq8j{HʄVjƒ#=!aOY 0D/Qa"Ňstڸ|>C_m@Q.R ,L 9=έ@tQt +i*@ 5p~{(?=Ư[je6vGza91 d)$Ge:ESͰpgg`K"\j˭ʥB:Fh7q*c T;բ6 |D:ɨrHHY (p@cW>97>JOV\-H ulv`c v}T$Yewhi)-Hm*=4RZf\.ȦQXEg׫cm*|Ǻʭu]=+w4y B9Z|Sڷ'[sͷx&9kPBK;&A5BM&CFݜa1٬b㡃YnlӦƙᾷQqrT8OOx[4D5|&iLLt#o LnTèbe[<$nЊUU1LYlR[K_D՝l#n;03LATzSM:]K0.'wc\~ã^ֺ\\l0 y@+gjlWor39)˜(EY+*쇫2&+1)S5<ƣB=f!$lo]ɻmɝ&T m]k<[ JB+}\'rŒdV}8c0 P8_kF%rMĎ JS #%UB ہ5utp\hHq&gb 2v z0 ]3;2ܥew\g ۀc~a$& j hG:8ipYAN>GX+N>2>L* <^nLj=% QP#<Ƈ]s;zʭ$<R<*miÌaq[so#ˆ A,Tl"aޒjGjbRrsdBDvT2l3r9ڱDk{n+R5.@Z-4x3q4RtIX³`5O.(djZ\-Q~(U;7x3/HKpӢO_ON~ޚ.}Rub>yFT^kmc#5580J.nD↠JW]+VuyۍۉHS)uXe etavJ;ki sB{g="45"py qn 7k^/e5W%^hr"zǸߑe,(Zƙ%S_/Pߨ!LqwpRRs  @vr-j2p^SGY n7ª,36#!4 kj]1\'ފx y¡^OTVƮ4!KAt0ٰs `JJĿ&9é{:K" -(h2ns*Ԯ_-r9k+g9RRt1vS]^RpBt|iH"Dy|bDž8ӉKIfAu6\CDd48J_Ȇ~ (.U}÷=C:g绂S֯M Fyr0 n}yi3 +zScʲ_o]cnR֭-5UEڱ_o/Im [{Cٍ򵚸S?\̵YڥO([$QnYv"zħo>0ok[K^~n;U6/? ˏ;t;ghLO%=U[҇݀~0Ӹ{@.Nj':˝L}cT^LrE.mI{T-p]ez N{%J%) :AZK<|sGx]rDJTi!RHXFI'd,kdSLkau>V78T(r* ?0sE |Ǹ5m0S.W#Ljxnp7G@VƲ J&p Rim#O@Ba[LeCMi"Vs+Fֵ(+Q=[Jr C6垨m h y};({ i|λaMu(FaPK5., _[H2org/apache/commons/beanutils/MutableDynaClass.javaUT ->->UxX]o}0R%f!K*I%ێȑ 8áDJهMs枹O^OR$JogiM|e%.bE]W7e_Eܳ]u%n 1Ȅ=q6t{C?z˫7o^D_҂khMSU\PTPm.Wt V(̭DTYFFP3L),72Y@&t^vEBX'̵Ci"U%WIHcsCZyZU2u6ij%*2KU,dtc\VWVށvԢU+V 6׺E ,jK)U :ؑjʀ0O¡q&\-M??gvxiuI ~upE\h]!rDrL7nâZgI<8 -".C‚b4XDP\JRN#f!q'tىL|1o'j}?>>r;n pmcj>$k)ƘJiep,R0|jIL.֨x`p(se-|_W"|dҴTɸ:utE X<6.A\r#{[HyxU%[5.S rx[ rE(9&6vWZgRh8G-ozln UH9%_i6:5--Gz>'n/w׭ѽR8>Gү!xAxcxaI@t{Cƀh# ǃlE4D4Bq^+c-=xOG͹~4ƙt#]Af#7,NB6p0roVq0yqD;sݩ;xFd {ÏBLQCIҍݛ ~ "6s7]PzdR+z ˃nazai>w^Hgb.ap`xl ( g7aGȣd2vLMnczΉ\sރۂ?99/bɕxnoo7;1Waz%1Z}O;&TkfbiQϪT 2"&K+.  w_nXG\}?]XѲ(*jgK+ѹl#ThO_h7evrE &b,#nJabXcҸhQf4inSǘF/iPtI1+Jݵ4^ Qv]:St'4Zy[^1 D$_u'Od/Й$$ZWoP*d]VP]K)&iVl#Anj~"7f1EWv&i/EK3xzUTYmӪ|"gnOz*B;.d {']nXkQi«g!p0Ჲђzr\B(mfG tāwjeX7A:cW+3Y?I$8ԜȌШfh f?8oS24SYWUֲm\wglDVȞ%K9b'`#0;m\WBׇF,zbIʟ~MXLȯ YR.{WW;g=9lp-V7{W)3-fjLuS옥s oWy*İ t^[|%m۹ /F^wh3v@ng~C,۠XUzӤvlH{ưUJ`ӻ7זnP5YUsԒ,mֿ7trg׵'f֞h$U'@/A/}ojeɗ}Ai;}PK5.nf&/org/apache/commons/beanutils/PropertyUtils.javaUT ->->Ux=ks8W`][)I&V&$;--67%);Wuݍ(YqD,Focٟ_`'l2U6Eh ̓d2Il,l;K׫`;I/i0~Vi2i>?ſؾsu/>~WѓY:Nazτ׀_YOD'^'N;6yG:ldžy~#gt9kя?uyq.c;QĨc`R􊏻쀏,Oó6gA}Zn>z0ϝlo`ސB&`9vO hxrx?9=鱟{OP8:0 P><Ó`pzhGo`)0ОV否 ; =hu:|?@jvCь `.c~n=B@o^ֳ?}1Dr.#'>ۡfWlgM8T4%; Ow_R28Ȋ WI4:%H'`t"B!hWЂ3ToezB5I0 cB$Ze:?sR`lw%j" ߮6|Bp2MҜK?dݗ>`[?| =p'q& LaħҢ <ݝ4 5DX'AzsfV2|l7@v_A0u+ `J?9&8kǺ̺,c}bnt`B &n$f4y.gσvk]L%;PV)Y?Ҁ m   !dX_Vo4іg2^϶.2`Q>ng'\c4 鐰g0b1 P p$6R8|,2qr0x@Tx x\Fc d]H a0V=>jDb"`|Tj) rK!N`$!$&Cm8I*ׄӐe\2_ `f#4t.. # F<ˤ+fK̕DIDHN :,9&`}ؽ0D<"/fQZ,~D3A† 9Sx'Q0Ghu;\V,`X9~Ay6gQ87I|b<%&$qٶl&3tQ<#f*G/ش5P{ lg 9h10.47GK6'ˁۂtl0rg>Ԛnnc*,vDq `sX(I4V[{Β@H$m;b%h"fg"eV9Uu?TGfƷeM_`DɕT"-Q!s7"z KB/Aa+"(t0h&yֹҔgS,Ly"40-+' '(bJIn% &(CUzy<~dQc[e#l\È0Q@(QwhD dm1!tO! M M핖^a._rJؑΚhp9b(ACnPZI, p* :*^J "o3ʨda UW?Q]#2gjE Bj 1a2.@QaCpQƒ1PW;uo&RHV:WWǂ➮)a-b2mT?>Y-C~pm2.4)=#V )`1 t1A wyV^ |EfvKi%>ȁBh?#w#_ߗ1Gf(xv8Ĉcih9Pfo1t.mK9uGt~&]TtmN:ʷ@X߹0;S_,=IJ X2i, $Ccfe 1}IAv?@\Űݘ-v6qrlL} SLrxi⎐Kth'l1v^lb ]Tx@x2}[̼Wf53ob%ͩ?SsSn#k 7pccSZ*V5 ʯ,܈)P*`#/NDQXX}Ѱ˻FFf&yQq? gP/=31<@b)(;׸d/z"5 0J8;]yEt+ Kƚ<&s[[1 7P8(k݋5%W0&l!+fkmi6 X#=fI]Lh b*dnJ/ &1M`xYyyQE~|sMbv9B.0Hf^Ҳ~{,?T[Rԣ6DnO*x%wbۛ4J=ZmckUUTZ`t)6X8*XuNZC{kQhc쳢96厔1Nl#K4F\Ӓk;2bl݇JTuFQ 5̈%JԼ%ߠ.Ğ}L32˕(Km*(KE]rmA9V6~`%gb)7a",Lvw"Ln~VT RqD&wE׭?ypqY"6Fϒ_BձD fKEo5\ڎf%ꍂn}thn+GzqyuQލ]]Ч3+Yꍊ2"9y&Yq,Ց: cOq+y /:ꏛڒ65$⨏f[|!WM"0)r[u[ _&Y}q!id}1|ͼ2B.A1}; \q|RqHZWf -Y`bvr9hsuC8*oꘃ:cw 2`҄'(Nuԧ.fRb1#P GQ'SH_ "+rCע^āG/r %՘)F,M.PhI<%Iw~gy:WKc>m 9Db?͂/,xֹPc,*4ɲ< S{q4@UsD mQJU suۿǹJ-q&0~q]vt^>,6N3m걿Y$P<+AvGWvi" Cjy0^kg;e+/!eH07Waܫޠ IB T)&˸"~7ũy)i]C*3I"!of`JKfHכ]G uLtuP1*s]k%Œ|Kx-9G<.W:WtsD,>qr_h<ѭ朽:: U ogKDvtѰ+guZƢ5,*tm=8Uj*G"p24M؄zwuk%ܶל/g+~9D-,-WrU~{۸p*\UI,k .,N@٬j69+"FFM-$Z㻪Qߪب;Rn#uJjԪRz9FV`ޢf,=iu_+͒4yue_4i2 _8`ѫ9=NI++B!gH"!0UjPͫjV7}]ɱfԻJ7efwQ{h 0\ hՋܢƜ@O(In?._؈u68PD0 KK#dj 4P5~;u "Rwa7Xɇ@ym3Cr Yz3 Spn?pB5Bn/m Nu{ȥ o⥇i߁ެfOTp:V^֫YW9m iM `lRqXcދ;nzk4{Ԓݸ%cո*}FujTW7ScP$Ko4B N:C7?ynj5A#PbxkF={b,-WYa&M5 /˖[jyE+.aȐ׼[|xJ0 ۺ}q3Cw¨JTY5~ZzC2X7g٘nV>CʬԥpƠƎgptgyu7`tW&b'(KFƕoP)ޚAš=ތZU<Ȼ]ܭ|C66rJvmjCլ_jZp3и[#rXon|ᭊ٘ۛs[v:]_JuĐٰݵ^hk bWzV+k j|?U{4{j Am|^[:ZɊê7!;؜q$7g\o_W^uWg{<ӧIEXuSSVlБt%vPK5.s+y74org/apache/commons/beanutils/ResultSetDynaClass.javaUT ->->Ux[moɑ_ڥKc $R!);`4ginόhz~Oۼp(%{>#骮zzZH3_ˍٶX$qU_ri_ydLޗj[Awj*"g"ܧ|,Qb?O^_~|y󫳟^1S-m*,陦1]\sZ|,Z֐2q%M4]A(ˇrWjNx^z Jis016H 3bD&ԃzTDqxQrӈ`0U&  "NڳTvqfR韲ȉFF2]F"ly."U!K9#'I.NW,i6"?5˘\:Baq(|GRT0k+%Glʝuix#3ӏ`ϊ],6* 8r Hs\S$(A$'Yi~6< 8-piAiUNPʥe}X54TRs2'#z N-X+!`uon3IGwb ̕f:.!g|\"y&erځ;8*!*Vы-r޾8C8 O޹⿌+R'_MdwJKI MfįIV'%@th-cx> d:c#?a`:I!oњݍ~Fs0KoXrp;x?ΡG`p~:%U`l#~2h!ffKMl>\`H@4GY]O>`tpOWZmo2 {htd7Wi.S2Weh< 1Fg0m!]l\@GY6afk7GJ3\h0 52HY7T!6(D!FuE, .Ě'mGO6$8JoJL-u{ zkFٳg_Q&^%<=Ǻx*gy{oInonFC%Oi@)[]l}˷-OSKE^|}l`P ǽ0u_MїP;3qU|CU*)wP.6˜-C <',t $'q}kQ)%S{zy֠`AbI*v}R:1%wēzVq"X<y r#6qjT~(TT—WCe0t0uca$ b! 2Z:%. ɞP*,64ԁ$4X+q#6=|'q?YYA_t nof/ ݳ%qd9OC=/T'҆ }]OvΏ.2+0.}RɨK! ]I&6,)ℤ#T'+UlN`J 2 =GbISG:^.+H$~;!ceA:0nDqu5M`8Dߥ+8NdksYd Þnᚧ+ғv:xi7De@eOz ZZ!l> buFc݆.'ɽR*@vٚƒoEȳ6^Tq୙ H+a-{E*,tC"S gN)x2t$5zYP 4Ut8t2jE5-Жq}92SNgs2n\foztrMJ|2wϥ<Ò8`睓h$=S*msLoRCK8w'c.^Y{OG3"k7.{<AEz dQņ+6&Oڔwv>5P3SL)v0'c嗿 ÆHʹBq$|E"valE/c-?8i䋳ik1#oYt;YspmKHj^g0֋il\$ɝǸ41%q"}a{9WRlLPK2M@,׺+W/#u\@#TLڞ劒׵pm܇&G0>/G0@?.YЌqӷһ^mBT=]@k׏E1E "c*[!N!H@wئ|g [I-}:6da<&kmtNM'EM*i=Qii !"E hʣg/jJZ~a:_k/FE7 ;f_/pl'﷣j`84.*ݍON4+ ҥ,#$YFEy#ˋ/0>O@*:@>M㱛k.PҭZ%LHjχ~\^X9w olĞ%G< RxLwQGY,kX$I%=ց3j=w\Dnk(eHCYPàf}sk8&rfml C+6BޏN!c\w /ʃWNJU3 ݂*5ta):ݶAȐV]JuCcy!~~="4SDBx4FS-אzT-5B&zGtU%h+ךfSy{2UĚaS E gSojvHKo~~_P~=_MM-ƶ+ee6hz .]$3"#AgsZM sg[߫nt@*C35lL?]}x'SP1*ˍAE|HqA1I&Cfm\q9MumKNsOlN͒fAVـZ@A{\.(U* |yʌLgͰdDwb'; ̾CܫBQT=~1| _2D=@JIE"ydf^䱉G3Gp{F.lY_LT)HTTӆ~G./W{/z_ŔY{W2nmZ^[ KU@#S}")m#T=_#9D̿^TD䡗 DigiÚG+gZ{VOkGNaV% vNOƧ32&+g PK5.7[ /3org/apache/commons/beanutils/ResultSetIterator.javaUT ->->UxZwFbiqK Nb J4:H4H=^7NǞ-[#QS2X Mgw[*Raȣd`4R?H pИke$ RVM#MoCNȳO<=HDx<#bR5mѩQhN[ql͈!HLT02]%Gn@@|;)OPV6<<>!FI &6lmI*E <%T τ' ?bG\IltMy"{wAb&B?MGb7o5M>A~".<nH4W.!|r$Et7#L`?!C6dyºZ 2az Ȭuzq9q7 YRm:aE}N,?r [#2gN]O!5NDۈob4Wg( {6,1(UA@4OvW9`!#4E*i‚e//`PU$s+_xObHyA44{m(SD4wT$ׂܴ#Jev8tIɂaq6;{SOnC9-aYS>@cF $!7FExMZ, .-8Ӌ6 7_5o1[brmkSXWc! 2&|dM^|F&[W f35e L/ȕi/[R5Lr" rm3k86S$6,g86+sĚ`bޘq.X5!){1OF̚N<Ú9d8l T97Ay|l*Ȳ Y\Xsm-x`pN~Cc<}HFƕtHw-Q 1 r̚g&y=5432R 1wșRmp8pV&p{V9/ks24quXy `)o ;fۊuAэ%=Tmqܝ0|xR5!W$Pud3Aj0f6vb!+T "킭ilo{+*VzURx'EnK$~^^ cpttfޒ=}~slyA;ŨQ}uܲ4.3ehʋj=dI^`_r_\f-Q|+?=[\s*[Rs0Ir2'dXo4cCa9\dgc,˔$Ш4 `R,1lb̽@qA+bɕ FtMey[gxg'{39lG`:_y^0DA%BsDtbܸM/0NM9 IbxF$& 7Ɏ0 %ՐxTu2Dʥ NgRc4^W?Ԧh>bYh `~]ɄdH0 k9`ƣ ]00acP?aqus \1z#sȰV0[B~gg339}{4͇gYP%ʂ]wM2; q̄A>m H3J&d#t=Cҩ*8SAƊPPh^l=бw'WB9PM2[ K `XVqS&q+$R" | @oT -GIc9g4в؏n$OFY"ôc縙Jc2!)XH.(ԁ?Ԩ5O @ tئpbEV,Zf--Eu.UVIYAuW: un* 7)[UQ\laN!w]&aYC^{9>%Ug{7c,Oꏚj2)Pa' G`SZ692AI!8,MѪ 0b"a5@x]s?v&`B>#Z ƢRv  (Ys˪ =`cɼ⏚͛@4F puKǍB, {D l=_^᥋UфnlTƴnqm2tkh[=[F4)+ Q>g?8ɍVp1$ꃢJY \O\ oF6/ jÍrZ lnG{H6w%q$cg.~ŀN) ck8f ^?fl,҃4sx%_rpb2|c|$yd?p?-Gջ/ebH4 sOƚb3NJFw4~xxjh!_\)|"~Ohj:KEy#jǨ? {ƂzR/=}1[n4Z %vSr;V Cħ@wjֵ&zmMS|E4Q_\ɿ'FhMXS?$at;B'rf^&Gz,FUƒv񫍰3ëft֫|&O>UDAsH.ƾ1^}oW-Ѵ7UmXճou8P,ݵPK5.<;1org/apache/commons/beanutils/RowSetDynaClass.javaUT ->->Ux[moG_+,`*8|dBQ5D*$eopapLT˼pH;>/p v#]]]OU=߉_(Pٱߧ+oNf< *MtVɤȣXuFod?͖}=m3m9=}z?~?>;OEHwQ"FT=D:Jcc~;:nOioXR{%=1KG)q*Ѫ+ިoad>P<{1J<-A' OD&SZejѳdjj`NR1B5n-{Tzv;||왈ңr;1ĕ@f*!rVT,EV]RXPẌ́.BU-xa sV2yU$r_MYo]q04ai̓,GJ`VRva;*͕Rk#y0#'s^nɔob+G`dPQ/8~ѾkLCj !Tr/AR u[[e}1<fb69LG7L_~xT gbh6ûTWחh`t0YWY0~7s1ep1i>bYFD&j4^ipuσks,9׃<\fz=ئglx9FgH% ћx.fK^wp=f|61C4L '4Lrd΂h8mdך]>CX#s0KKq6Dg[ZD*0cx3]V lo#z29h&f'rIMΉl:/*$F,`h:& [ nHÐ=keۆ&߉k+^R8fp^Tt^ٯ^_GN`6:> oXfn-NJvY"87[ ֜`f7 7GJUG: Ҹ@@R@'eQ] J[u/㻆' _(LoRJ|fmZ9 'OwrIxX:rAg裼I~Jq 2r!TkQ-qd\B-.7;&'O߱__+PןQNxɀ0S"BIO!Op&1$¦Zؼx_l;$m.DFK B 4,-L׳ӡxA>g܋mΰUޱ}KfxBD@C -)i2 V(Toh;0M#GNj. ;P4&b`MZ0,/4Lu{_ 1Ha1dk@41ީc;2o!JRz!}1qw7N/,U4guOh/xi)=AE~#wfKdOW19QWLIjҼV'f],}M;iP vN$) )3ƒ~bjG@E*qBZ l 䖛5J&_r4ä5=\ra(0DaT yQ9_ h{f`[[yS$A ,[/N7UWE_ïn$bɸ냅5}rnml7"O_ }Y)%EXl]b җtߌ!VPT.wVĐ~Z UN%y?ȸPl(8*!K/kpʮōQ@oN ;JU<$jO2􊕟g2dv\t`D).~E ;JZc M$꼆=@ٜ&W?F/82X'`y86^Js{s&([r5RL#B5kJjDf,5݃؁;1CL{LžJVQ+m qP]5!rTBPS7x , 3-Ŵ'BH""~fs-?2ӯ*i!]` {eJIAю"%zآ ]fM lhcFaދM}\ߎf 3hw("Sp~YL:B Qɨv_40%E_Y1,gm bF$xY^ED #9@!S|\{6RnOz6\bT te8F&n8hV( ~!WzXmZ2ÖkW$b llQQIWv`!M0 Z]?Gr:dLmoK iTf̨hhڠ+|Ɛ9ZWصa*ȱP͉7M \/AUp̤._MWܢ l,vX 4{.Ðx >Qy6qrcO+]BNhj/+HzcAR{>%`r@h>yG`Gh!,7ES݆.c5l q)9vإ"OfvZ&Qn 0f+ީ?d ྜྷHXEk2G,\C5nJG9hn@ɶKKTؕ\W6KLsv̝@~AehB͵!p[D*rnBmFnV 邼EvMC:gR qL mM]K1l4x9"dpgU̲WmhI:RեR,Tl] +]օxr{.jiu- 3egdA~մ`qF8FscUYzhՏj%st Vnރ? T3 q[zl3B|_UıZx-h F&lTSK{6S9Slkm{:&Seɒ/$I酆KW)"#'7&8We(G <+#QeQ%V^ yU {}h #[BsFR#>aGZ! ^$iY|5F(tw dyip'e۲u*6*DVJ]g,gB2cy[c9̷ .N-V@WiMfwrTO"߬!yF@v'XQӹG)-bCv!.Ԛ.$^geapP4;o\͗`w$i9mk.mC.BW~{i[G c@ H@[y6֑BVO+;wkwmP˅73}͋6ֱ A(z[<եba6m* H*EKjkgc9 s;bӭj *U̾OHzjc-}(/GM%Ľ1@94[(J͖37ȈZwvl?nD*dÀv,3G%aZP߄. @;c3m*͝^>kB/XIn;E 6 Σfp?/AES^i$D4b-l얒9[{euڧ7Y!j5Q>UW"'{*> t]DRm '5~TЖ`cQ{Y[S/ yz2:. YE$O7EĬJx]mTJN-[ Ij}zcFkO`9YXC+5f xAwvy8l,CISyӰ;c;FuD0K7vJ#TL`/kXιTǶ7vǂ!vj "t3Ȋ//V.4Se BoO`ZLgN9cJطm@eQE@WfucZ #Dh1ݺՔ8 S11ut%+`u 9|㨜r XRBiJ.L!!!!]s'vXpWqMXekt?ᕫŹ:tom!&E̺1՛́ fNg6{1 o篭l34 cӜгV͜ f*301Z: >CQ<{m_6 5e'*Мﳙ؜e,~kS-OߋӄjPK5.}%$ f-.org/apache/commons/beanutils/WrapDynaBean.javaUT ->->UxZ[SH~Wt*&cay![vdؼM[jd%N9ݭ/\Hq ;wth Ĝue,&:;*3z\ighxvRKrڡ fpnk׍Io3%9n$ˋ/ǝc<>y+"CeKr3^fdy\-oǐgXJ7lE%#}8e-r$ ]%2 WPНd"iڄXQDH2daېuYLd2Pb!LxL 9O[dųR EoyX09YBH!\d3/tHx<%Clxnβ#q{C\@yfQFA\$L'bK)$Xdk vD@ɔuiQ>g2mYg\6\|#05TpG(ŜMBH2OFi 2,Uer-_;8<' xD*%PJE!NuK#bmhDX"6eHĜOGT4n<;dK+g,˒NgZu:icf9l7y+b,Z%<ׄ& hL!Rݶ %~ #2 }wcHdxNl{ w3sOr,-2\KFcw4lbuse8`Lk{_kduOpH=|чGl:ۚ=@s\룚U*uAO}Bgk `+Hs-Q y3wo!mv&! 5z&Bn0)gD[~}'gO5b?32 Hi U+\¬d]= m?1?A _K+E6=&="Rpb<Œ4VBLFkM*H#WJI쥏O7'%gF?CUnrz@QѨ#Nid<7l5${rH+{Fd.nV"a ?yhw{oWJlFh3O)R!K'pLN|A`B{fmrcSfֹJI^Qn>tO|V齃g䶚qZEGQ?+'Ty)xh7V}i7x,CD:vZKwElݓ5Pa@CK<?\U}ڳA_Y扪+6(9<$.NutTL}t*0’~bk<=diylgQyxP}n;vtUO |2@1"~]>x,xO^_ EyX)f-+<eu1ai~N /~4*k}TG#gnmŮ/ r2DE`KG,|iPM}|*P\w3\/ ifcnox5oN\GH#SsUPK5.?{ )/org/apache/commons/beanutils/WrapDynaClass.javaUT ->->UxZsH5U # r- ^ɤj@BҴ$}K9&K%6{wp肉s] iCt#}ěM9Q0WU&4Xù]MClə ˟/Ϻg}u+"q#~LR ѹ< h:n/Mjf'#~vT02R!@@3'{W댴69{ MG ^y0E2Lld'lLy $O8O7Kd=#qk ;@ptM=om\Ϧd4wMtv9Y:D7ΝoIz7Or,{7zٰ7!w ;wcsGSCɷw/x6x ox4x xk]] x?E5w} ݾ,M>t- >X$]!ZH ?w @Ϯ7M]v<Hw'^_ vϴ'vIHԝLf@܎` ioUFRmo< :օD[C8|@?-mT&dZҗܷC;껸:FB=m==7xMA<ilݐ'=Tm=N ֿp{Tq)T l053HQ7rb@!B +T "휭ioskd#gܖ2y {rrO 3lmc 7I,2-\HȍI.$tIK\& U4%bm+~ٕ+"%TZv$fPX@Mu,u.km744,H_P"wDf;z#.V PZR#7ڥx_3K^| :xPR@ rk("zVJ"Ʌ`ʮ#atڬT< VDS| \ԕ5C!`{vj)Ea˷TV;D][gx' IP|}t\%FUd0$1j+V@W*U5R m4Sp WŶ j_Q&(t5_wm%vkm$X tձ SCZ< k -$YA0䊔#,C;g)Cپ4)(:>,;=ili(I2S젘b54QRXc\F?^\O>쾁ĦUL]9 /cr*e} >kBίTq)C}s >VsYCC~*y#9X);Yc,>>GZM*MQfFpU+gڲIdnwT6(^y/ix0l _. cXC.f74u)jtރ y>-Bم7Hg}PWZ;Z&"fZ5#k~VOMNWWZѐQ%[YK0d+J^vԉjCV&Tr/]BB[~4.+[x'𘬕:ŷӁӴb]HJ a AE)_:J ]q#:Y*JL`Xԥn('J 6 |eR[Ra#ȀvAH+fl3sz1*sIzظ=: O״+{f @eQW@Npm C*<|zbByx]Lz8j~ߌĹґRSt@Z=Hop4-[ҒcŤq [0AE!5T%W邫r=6 j;rŠWY؍䪹MloWL[sQ9]kvsZZS#_$/)j>U>8m]og}4={5)Cr^0 jjYg,z#ɓjz\<}f7HVyHM߁~4fcܨXtH4 4>cmԢ)ľ[FxKYv\G96ZUBГ&%P*e,{4\َ6AG>ύ\N .^"_v>~uz z4ZH0y᫮pnSh0}ILFՊcY8#x|}Hme_2uې:kGZdº j+NN$Txcuw2Jئ+<|+|'Mu'x4}:PK5.j=&])org/apache/commons/beanutils/package.htmlUT ->->Ux][u~ǯ@qdi\#+g#帶R $\40s eW@t|vݾ^L:Uۢ+&)Mo6o8,foj\;[\n{uţddU>mTMzv_#_wm5\M &඿wE[&#s6ኍi]^5ܛ*iS^VsEGtyQsǟ3`Z羨z(Kq_Cl BXgu~(δ5w:0N0Q%ɏ߽)wEmђO8vYT CR40x*nA.Ê-_]3_(V%{&| 5镽~Ul^~ܛޚꪸrU_ɇ;+mzv_]ݺ6SM]ݳ?UY`+ Lt,J )c3{L[-.'V6Iu5VAevș'}xl-dΰ\.[ WݭfG?@>[[\AaN'͑?l lExp gHgBZƁ-@}8 |(~7Ɵ+)47 㫖iʧMk}\oE;Z',fZc: CۗjPvmQz,,W+Γu;YPDY/M^Cg[H)ܴ>/2?]^^]nXFp_e[dw5!o.6D ڼ"E["`(T;WEp,s'K&|d3`iwM{lRGpky.A`loׄW 0{X,X!pOeA\5 0>1/a!`+GpGVAD(@bePGMZ; a(eA|ȴ+y'+]Dgײ!g]*lp4P-Ѧftەڢ=E,3//i)`irkj Xeqߺd2pOn_WH,-5=6`{,[vAB-c[آ` a["θEk%h3yIE n/ʾ!`N]>ʖO#}RPӗu-?I- P9Xj gK+KJfE0P l`%4H] hA`-k$Tv@Fe,`@Z뭹kqPku\.,!=)O%l^>\{YK?I}JG~E O!dJr v==~?]Dj=d_tpd=cLv)إD# ްҐ頮hR Jt8PA˱VL֖;ДJ`}QtpbUֈQ/Z#j 8(0ji2"ldS>}RAu(+#?M k p -M lp-\QՈ9,lYΒK˺%xI,.~O0%P>q&G,R/bjNgc y67[n/We68WW i\ ["Fs~XaKl̚&;4!}|ā܀4'c:m^Au кؒ#k:C@-$?oO;+9hZ,ޤZNX:G诠˫M{FL.wR&\'/Е0|cb2Fb)5(zY:q Q~zO;Sj ΎSE2m w⍆%= 󲬮;9}MM3lO$" ^2sh}'c)  /]PwU=}eٿͼk8Ls0>$x&3JGY ȎNΐd(Q.wAUYmkܡY(]˦^z[r)j gt^%7XmK|"s R/&j[g__@ VTZi̦=iqCc8 (5i4[ qOȭii7 8 g nizt-7`)PiM@k;ߑ 0m6Pf#:kmC (mMщUMȟRTO¹TːoY B& 0.zʼnYx~j] Pͦz fF3ח=ꊃn}4Ԗ}I}l,RX!}@(}"rbuUT'6j$Gb%D9T-NȌۜba@65| 55%Ri vOKHe\mA@"0Q2?|D"v5&RHqs18mlp”,CKSH#%()^U}\E )YEStdz9H($A5^# z$g@#ʴX yKb ;X6H#f +ɒ5'd;1r I[ 9@@ X%b|_P \kX+Dē妡8Rmb+笨6.DXy(pyknwa+ έ}9PEdAY@΁;&[B@,M ţUvE9[UOi"G7=,Gw k,Q" +5x1@no~߂U(i@ ִ6ۂX ][T9 h[їmhLg[ؗipњ(qV|:G>E⎈1" 4Y3z / )ʄzC3^tzL7W WE/5eU/[H1؁N=ٞ(;R;c-rĽ-,v9|rJX{f / DMFFMDe e[7mextĐ{-Cؤ޸eC~^< fHKqx'.^ w|wۯ@ws_X ?pEхǃ.U~: S.H훤|1R#ӸWwX m2EHݡ)w#b":u'E3t)NXأ ෼3#XӨG*.T2sȰT%?. ϡo[i\>K='+~N:SˣLtu%H 8qmjSyiUa(璼ǘeF j=9qA[Z#L%3Z (}!#놨=C)";ը.x,+W{4l8frfL]G?ks\z gNW (^ƒ¼9cy!wB1pfSt?pq>Gf4qb.p[žD 0\>ggZfd(|!P +vJ'[_Բaj/uRy/g8 `Oc՞K'';< H:f+ы ңrɼMb!gHDBs'65Ā eǜ&Fr 銊׎\C{X\豂 M!"+ LsT-C&϶+? IhŸl9s1ɧ#A#fZɘ6HkiӨOug$>UN">m[5Ӣ&AFțJFϏNx4pȼy_)@563xHR>Yg+']Ms+W=qVCbD5}S]!?<1L#L4T+0\HP#K`גt:M.P.kXC}{x# cK8DmT3H3Qe.G$s~ZrRcG  e>AG>xci4© V;as),[wEO]bXq,Kpj}16C ^*|Y,jB+ɒŝã;;9T~%/H"k2o71=$j7 VCz֗LH J*t~.$/YHiƁ8ߺ$ Ǯ ;E;7)XJ 5ket21 Fc3$d%RuFסZ?=BA/ /^F" q ׌d(I:]iv Ok~&|>(1_rbpާc zPha-y&>|TݍwqxŗAܧQ4)F6|$_s&+<7[2od#(9,oi1{,\q#=(hrQN!Ȣ003c9 x>F zbUg=QlIs㠵 %iKzheg-vtDvSOTǃОY9ŷNHm 4:5ؚ%͉6ZXYF&}BG+ 5dsbhl6b) 8`оNj-Eh|f,Ծ`M$R截}I)=\LK3uuY<ևKJqL` ,SH,AÃIr,0'Z^Az< 8:-RCq4ߣO/@d(1ۃ >9%6mC *?F8RF,~σ:;A,*ZZKnMC u&.{ &@75Op[l͒R%wl YKtZ?ᦨ 'I-rh &LVèu_U\R#uӅZ8Fxs]2wA&k<߂ȅzrܺ,LѮ~Ө?@'נJe[n+BI G+iZb):.ŏvk7R*(;ˑB C # -"|(.~ + "\"I_n86@~B佱޵f=,ٻ =X  g׆F)* 8o39l7 B59z45Oy1:UGAG['/a@b<=xO隐*$/" i7C>WFR3>)Jé;}Z!uBb"i#ĕB";:lt&8-bsF9ɴCԾOQ_L#cǫp_l;49vx&Qq4 3ITap0jp{g{ywD]LYl AChw1miDuSt|aK[k}M{ǽ:&EqcDoS#g$-|<uVyh)Lb !clbnǔ}Y͔wrމIR3ĸkb 輆Oro HU&3Ye3, ^R񂙱oSSe{72hSeb̦4C'VeTwoj7)!ڛ"׭EOc@t&Up(N*$Uc1 ȫVV<6`鬢/y vmC\Dv@ ?!pOYQeb4@~4"X&98[c8++u9/σ#87afy zt~u@ll9PJqԅ_Ik}1/ *Xnr>9@XL?<ܓ Qe m,u.j$|uVVVo!= ԕ4xvcxx.UMsa L;oywƟ=)aVZo%ud8H50|F֥D?!{Rp6g Op2a=xj| b$!6ҁFp8 cc?)* JhȐ0s-ԎGiԅkj`Ulu$ap_?͆fYAq(ZXe2:-0V*m,Y5/\rA/`vyc& kcgfģ[P"9@T]ж=o_pyQǵm AG<jtNƉT3Jŧ fFs^stL>? 5èTfPZ7+ym $: oFGvf}˪X}HQ a :iCrqWH/ Q0%G8=nI~E5ٹA8""O;9[@ӧ(;9h$MP %]-R(̷9ki@PuǯL_S~y8*]_8'`eA^f!NǦG/99d-)τ%U>$eX7GrU:Q@=y KcDl]K]A' gH^C:>5hBuVPtOg}>p9z٣؈c ~L9=MխYw$/ qUDƙ%~MKi-$rߣQ՞"׃zV=(j8tAOrbِI1EɲJ0QWJf":׿I7qs Ɇ]k*~&/I bڃ %O uHIX8e4;X>yuσ0HV ^2ޙ8X`rq!q"y8Ev\.cG.Ivn]@إ/v:Cg㟬σϏ0h%eオ|Y^iVux:N3D<'I9 sV7.d|&߇)4uۇ)BX.ФO\ s(ـ1XY-Vy Zԋc,fYTJjg peRʽ7YB2 5ɼ|whh"4C_@e e(-]c,,,#\pUJmXg.moJN#rOR'_NZ3'ŶWH#PT>[(={uIegQCxŷ؂ (xyy1LU Ke N\ClOIOx8;#hJs!02/D(iz V]4qq@3x̷$>St'Qp.yșc rYqX'0Ky qaRx#Dc.IcE4o8)EyߥvE7)Ǯ! ;[9!JW/) @^i5*~sɑ-9BȆp'C4Z-*)MaC^66ڇ|X!ol-拧`u^#2hI Avi۝-rIozn< J&.Y~am-}Ɠ ڇ_c\5Ui5xSGO=Nϑ^~}/H߫#M= k 8&[TM@CДSsU/Ҏ)ix90.:ChFmk^Oׂ~RhELtj'5uPK 5.$org/apache/commons/beanutils/locale/UT ->ť->UxPK 5./org/apache/commons/beanutils/locale/converters/UT ->ť->UxPK5.c%Morg/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.javaUT ->->UxX[SH~Wj %LBT-@SJ2,oӖ۸IjIvة=@faQUbE}.wn_N9suTfIfeQR8k*,y8JS*Z1G+,;RWWs$<K{z.$͚^|y쿁WoX"chC>>|벊l P,Ј͊3|> `gZUŁs66]{ۜwS+GC̺ (,LUӉe$&p$ :!X on .1R[CE2t^o) 'ն۝d+ܾhvC  89$”A3YV4 AAQM򗥮?FrՂ"嬤 Cr>,9jxckFm2h2a{HE)NPn1Z%58># =A] F_w%x^Z6^dǾY;aXp4Ł1ÙvN{R=>cT c3! <@x׏:=?J>*,=A!~A'ǡaGF=BC˷…FtjE;塟nxiZ(69}]="عX C\AQ0$Ɏx;TpL2gQ ;hR{a8p\ `h;${J_%@xhv,8{Hhk\#B:6-%D_x_{'=w|7 Ub&^ﶶDVHU6W}Ta`j }HE~ -OQбT:c /ԴeM6rJjqa(BCk֩rDN,HnuVXZVM0qʹ1Z'&6r㗮\)V}Mp~`5 upoB[Ygo/?b忶8}75l@zz8?G#L\C@h$~ =)56V =0_1o KLM C΅B'\Z7eXE"i9ѡ4h&jd~ka2Lܙ`O?I[YF:|| S-j|8N~#)+:ڜxm|ٵV_̥hL ,hjmenS$S<$ڽ;ͼ y?32V,#l[Jnj3-l6'$:&|Y(N(<]+^'aOvUA6VY^]o , @_TܭOT5S A9`3+do8->UxXkSHίEM@J!|aSM+ɰ|YndN﹭ $a6U%Vq}u/6r,‰P{ԞehG"Ʊ*Ý(K,-cU)](^L]K۴xwz8:`AglO n̆Q`"iyRZlr:B5T:dž֣OJ9ZQa`*z0WEoN0rHЈXDwE!"ob[~zdu1)wd=goj[!=) | /_4;Lܺ[LZ66dg$[UXi-"TC,)5c" BC57tj!| KY O̩=A=Q%ֿ&>[Lu3ϲ[ST,N{I;}&,qhD t}[biK.'qK:Zi][m-! K'YTPݢ7 ܧH,zH~5{c*f#eX-_Dٶ,~f\lO3HUM!N(<]+QV'a~*]jX1fk6{fXXn?06nX^}"ILޞ@ 'X!X]{D3n~ҹlf?}!1r%a}|<P<_ (PK5.Q$Gorg/apache/commons/beanutils/locale/converters/ByteLocaleConverter.javaUT ->->UxXkSFί8tRH!4a PX$Cֵ[$f%١Zn yF3<Ϲmg[ ~8l8Sq'E=JE^"L3,+NhuVdJeRZg\U\M{khkKxK ^z}KPc_ LBL*~<Ӗ1)W; Ts8D[p~qh۾ޑōW v]Q̱1P )%QjǶ(+%F5m.9 TUșTYi\TSJʺ")HJ ȄLTCL񥚲 ('M\WҶѹWƴ}u%IkV"Ǹ.+bh. f#9% 'jQBHRp,TLdWƖwmA+oAF ˤx^:L$ HV~M.δ^u8|An)y֫U)AKs9O'>1Ҁ8\"&|SYg$iU3TrvmsM1Ko 1"73@;0IT%O'$&9*(넰jW`%pPKV|KO 9mz0PTlwbsƢ% %0hؖ Scqd[K[ ,FtΛ'UE)7_/1U r oy䨅M~ɸ! Pɧ:B7u|JjY~Oԏ 7apw.?6(µ l.ۏ}/wzî?hC?1 yɕc$$83/{} Ǩ҅~gsC Ayfuzu}T ޹׏!:u{=Y8{ ]7>C28NЏCM<4=yz^'&7o Ԋ^wC?"Pl:}]="عX C\AQ0$ɎxTpL2gQ ;hR{a8p\ `h;${J_%@xhv,8{Hhk\#B:6-%D_x_{'=w|5 ULbi^NoDVHU6WgmTa`j KE~ -QбT:c /ԴeM6rJjqa(BCjS_4:#u9 MI֥LXV0ci[W5UfF>/*kGshJZS5a%\z8uZ^ æne n,cO _ǁOڐㄆ}{H!A)Ǚh@ mh.(u3 ďǣ&a+&6A{9_0\ }"o;u?*I L̉:~3F%_"`gHnW2qg?|^n!pfI'rDVH]2PFRbW%9c_xk&v??' YC jmntM5,xHN{wab:Mg#eUXro-%H6gSII^ʸOߊW2W> X(1f˕6{7,ѭ O_5ݏؗ- X_?Mԏ,?7>kH=S'/OWȟ0of/fD}ׁ͑}< 0ZχPK5.S; +Gorg/apache/commons/beanutils/locale/converters/DateLocaleConverter.javaUT ->->UxZ[S~>.V-ryɦ"l2$f5Ļ~gF|!6f6';~9cј#h])k3ǭ?HA,SֈEiDYeQ|f%"HgLLV'YW?m$1 xKxvxы ")2EW\GzyF6q#\VTxFC &m$tyRpvrۡ\}8|)Q̉(q&$*#brM+gcrGM(C TJ2fɈDȩj-ϯAHS9I1XoR!cr!bx_G9PN[^:HF,?6WS &ZBhQ$8 YH^ Gbjq)ٺ.g Rv\~:B3".,ͣ: $8"a,y ~MZucJ+7;t|N W6iuIhn]J y bX7M#Gv^!b@\,VH1Ddh^3<;jnoo&4)7wz'AR,[b5D<emB%+LVhoTU*bŠAip"X;i$4tɣ0O md V ]C : 9: ĐGAܧ"g% 4axp )SJsR=bd :nyWqTIv/)Iɚ!a Pv'2\Z7>n^S)T8<'{w~' N.w>x烮vH.^A^;xCCz^~s˕e$>'αKpO8-8~赇]LJPmZv{BΜnW 6X{:N{h^{zEkG:C2k#\tWV0p#X. B 8;n{h:`HG{d B ~' ف_xm7x >"?!m>G)$aiH^p@Y=:Cb׬_߿$Nޟ'5j z6MK? =띺K} } hgv~zшۚ64ӹ𴇚"g gwJ\f`&3` Umb+Jb$pX *#v%=Q LyJޔ޳vӋlAomhÛU9vE74p_i&dպchuPه9"b)01Q?}![B*5N뉦M6ȱEr KxzI+|Mm_.QEb'Bs7[M O:FZͷdԛ~bDXǢPJ^(`DE,J ]_ki6F, >ZK8.jieom켋 ,e.⚥s87Enu9}D. *@.?Po|^n/"lUG SVs8"}DmşV=67HڄLb`_?Lk-06&D-?&=П0ķsڏفO::}Wq:YBmbc.19Ss,R-E'DC BMi)s#qk)za|x>jNL\MOkqxhJ4<1}$i5R+Q]lϷo$д:fMc~d851U9ж|ƍyހ7> /DK5`*Fh"I~F#EU9-*gl>}(E_57U5'z-Y^HZ5c1pDdtX.P|VăYX>. _W od& oWW|cc9cU:ƒӅ/O=#q3_^]D?o6=|=.7kx+w8GhXiAkq4_s$:7S}A(,F J̿.M]}1I.aZ.u4kJ7耚/19LVZɘba(X\3ـmt?nn&)c{ r_k DJ[Ӭ7F52Q䵧 Sʭd쮓wX~W^̀e vucV qyj->UxZmsH_ڪ) qǛ - $˷`ZhT# H@b'ƹ\JP楧_l/gM:v4ba*gdǜ%E.⬝)TWmmebH\\e.Č==)[$9Kx+xqpo/AMdr#p?s =fr~u?ӒcEm7r2š'"d h**.ΡׯIѭbNdLXZNޘ3|Ҳb}>Yĸ tU& q=2 S J5˚p+kJ"')39S#@*\D Jk_ı AnoCAkM T+\\d9Z3TӔ O"stkW bGbV'k jQ yeuy YK Z;)PFuN Nރ |·= ;s&xNoM8ν7&;+H]s#α/pG:0tzÑ?.ڴ㝻],%^9>:Z{2N h:~{EkGt=dꩃB{:墝IBI:Ω@c[$03s2] G A7 ف_x7xzjpB2FsBGRБG]CGC .a3"67ߓN.\k#@u2-G[b/Ӟw;.HХ{Ϝ|ౣ2`DcM 6x't/;fUiQ[Sձ&RaMY0gqg~l4&Kw~6baҥ+E]*kӷ66ޱKMg7RJ,7'@<` 5oj^ _/u/gV3s: ,:Uk+kMf>Q׈?&h<5laj}wc?_? m|G_^_]#>+:?u{Pu%N ϧ夹&}2qL[9)GV[ȴK>/PK5.gW9$Iorg/apache/commons/beanutils/locale/converters/DoubleLocaleConverter.javaUT ->->UxXkSHίEM@JX!|aRM+ɰ6܆dIՒL=<0!+:q:-zF?h,WTȫQ"c:RegiHDiUʤ ūԥQ|sv%Y%΄**Nɢ-dh^<~o¬^8KeJ~b& L`y^->cDW6٤EZ)mf{;o*i'ޥׯ_ﱡkgU:Jh9IB`b(qˈXS*!TEVX/#F&2d)l,'2*-br,Řr/UT/9IX!mߺc]A٤1+\%<*#˂Q6%)'JYPy,fY{jI$+cˋ@R\[}9PjqWSQJ2("b~ eg/_t:t$Pw4NeIpwYErbGUGQ_M".?0l:@7=3d9.9\e~`777Ӵ춶y'AR,5ZxR"b3sdYdbIr0UQQ+{9AM$i7PRCFSͯ՝*CE]un߉h$ 9-c3G ӬM [I4 #i::sM Aqɧu?NjFbբ<Q5$585xbWZgdxH<(SzSyTL׺u|.r~OTVP?/%q;N?LN?wk}As;,G}zn`kwwb0^?w8-sKXH\}/ΑZҡ^{u| A?p fwv0J{B NnWuN?sg^ ~ / ~@G.wn!x[]]Zm{xG\-؇E8gΉhw(CNN?n}D2kAOh@bޏCB./0X a^n#|}=XtqQs8i)>|%tvyς.^Zdץĵ49t֛"gҩL0lZΔkd`%:f0wlb)X@DݎULzkT<둒BÇg[0-|._6; npí~%yJb ]ce~#x J̈HwL7rd$)[9L^xhgS y[+@jn@/S Žv'Qz٪?S69=YU $fQRU^)C.Y{ƭ vCPUWh[ sB-*)S߀ԭ(h̕1VE,.y6}C ى9orZ{=FơPzjBS&BМؤ]&sS!\`L+J'_b"kaȜMTZ/[LX; sCbȝ ڔ}?~؃݉9ӎ,q``a8Ps}EbiK.82ttI}H3KQvjwv%'kYS<}t}YڅEUw&VIm}m!Yl %lQ_*zQq/ ƕ(+e0sHd>&OY^}27&,sE_V߯'*ok75 _=Jǚ_ _Hׂ#_|~=OMCW :Dgrh?PK5.vmB$Horg/apache/commons/beanutils/locale/converters/FloatLocaleConverter.javaUT ->->UxXkSFί8tRH!4aˠ\IkyHZJ2Zn yF3<Ϲmg[ ~8l83q'E=NE^"L3,+Nhu.VdJeRZ\U\N/ϝM9//+xO/AMd~%r7sQ 3ͷ.N[~~Ljg\5DrZ]3š/܂3tC,nUׯЍbz'B6$F9Fl'״X>PV _"gReעTWIDLEUZ@&\e %b/ՌUG9i*E~ D!mxu`L۷oYWf%rB*`6sZ2H|rY!%(,5kBIDqelyqԹKk z;ѾTjЎLkL+ 2d%XZ.״LK['{'i* ]b,D̡[*)$g;&TK$Dy* 4b| =3qTsvmsM1Ko 1"73@;0IT%O$k$MUP a%d:xsKp2*rKSHa<-4_I-EKJ0a)1$-<ɊX,).7,75OR>o,u-1U r oy䨅M~ɸ! Pɧ:B7u|JjY~ď zz08^~ݍÏ?; ~^Z:^dľY:Q[p4aOŁ1 ;'=~|x:*]awF}7(h6Q^[?@yzݡ`4躱 tAhzFpQk#]?:1| \ht_V4:>#Xb#E躧]H*`HGgz B؏GAЍHvg~Nj@?@EzbWG)$QkHAhHIpF5+6dٱ!Qs +۴} acoh5 A~"~DFjGk^Wd{m6cD h91؏>)8֊2r` ΢!2lD$A`w.XSCļKwD+M19uVr}pszk %v8l7㰽lmme71l94ۨzAZn @c˩@Ou^i *R N+ )3`hSjs}µMl/]R4]%IJ)ޚ|j .X= :-T_ǷMﱵLJ0^ I8r԰}b7)280/JB#L) JD9M^b*n ?8hț[rk!OǰDBS+sÎ)Lz8¦%1lܙbo[;YF5||l ù$VT8E>Xuwmؗ6ZIݏf#Ey`Swi['h$ Uޝf؅NyHyn+mK⧲l>͆9=mZ~ou2DeU8OBvF6LYg^vMn , EovkfWcRO|escEcuύ7r|,I'G"35'L)!q5`sh<<|w2H|4aoPK5.AJt$Jorg/apache/commons/beanutils/locale/converters/IntegerLocaleConverter.javaUT ->->UxXkSHίEM@JX!!l*)c{$6F۸YR$v*}m$LfĊ>ιlO" u@4 ;y5Jdl]El6(Jvxuٙ<8wgWQ \RR\ {EYsoϟ7^gLOb_e!@uRl<_QT בԕH a9\qmlogӒv]QqV㨄$,FBX_eQ*9x;E阪B*JB4R74ԬZSʔ̲ͪXMȅɲcU6cӨ_r$%ױC6>71mu˺IcV*JxTF0GlK)'Jja,(<Ԭ=\7 J$3ĕ][sx;`?c)cLeP\ +fd%X¯iâL˖'I* JHN(jD̡[EU]'Hd`NHFnVϓveu.5-:msIW ̒C̺<SY$B$HM5H*f娄75P"fp_K) Tmu+ܾhvM F1ۙB#v,+ED0&XY8ojNHS>(t9^~7b剈 y䨁u^3j9Lq! Pɧ:R7u|NrY~OTVP?/%q;oN?LN?wk}As;,G}zn`kwwb0^?w8-s+XH\}/ΑZҡ^{u| A?p fwvJ{B NnWuN? g^ ~ / ~@G.wnt,R9sN܀v2V+(CNN?n} ?f'tzH؁aiH^piRg {JO 6Xtqhk#zpe?\zI;q{mW, ]5_8P; M00~] \KM19sOGh!x&j`azIi5Q+ t= ̳B@ 3L!fhD,A V#1ɭ<=qeu1)wd=g {k K.ė3q[ˁ֖*Gj1Vg]PGDjLOdz -OQT:c/ܴ<j1` @Lx":);˖m7:Yt =A L*)i%^TB?k׸cu|>tJhǕ*ZvDBP!"3yU%ŕ4;av+ |o!e\PGs?!7ۦpyH1{f&8eQ p-qt->UxX[S~WtQ[R!ME2$m"iT#Ʉ?ݣoxN†l6Jhf}}8϶t٘p2N2+z]3UDfKgY^W"-R9R]9`ٕʄϸ*̯zkhkKxK^~s̯E~|&J!}e?xi/Q񔃫HN8D[p~qh۾ޑŭW v]Q̱1P )%QjǶ(+%F5m.9 TUșTYi uER29h W*>BəK5eQN_:tHF2^5J֬Dqs]VQ\FrFK)O.+员fY4I0-/ڂ:pimAo5J1Ib-uH qEAK6\4i|ipx@)y˒e)[AZ%׹I'>1Ҁ8?\"&|SY%g$iUsssc7uƦkonpYzkYVڙI*y:$1 hN+{5%X[*^5T,CCSGao<-4_IƢ %0hؖ Scqd[K[ ,FtΛ'UE)7_/1U r oyਅM~ɸ!sPɧ*B7u|JjQ~Oԏ 7apw.ᇟ?wzQkA٠{]GC^d]b0~C?c<ړKHHp g^9/K؏Q 7ΰ0 ͦ]?\b+sCtzZ;p;3w8n}dq>yh{ANLn.:ө ~Eh"t3ċ`.Z$c03 3r!GQ؃ F$;sEo R1FzbWG)$akH~p@ipF5+}6dٱ!Qs K۴} %h5 A~"~DFjk^d nl|N 0Ѱsj}RZq%v= dZcLdћ3ECd؈H]y;SNwD+M19uVr}pszg v4l7Ӱnmme71l94ŻxAZֆOQбT:c /ԴeM6rJjqa(BCiS_4:#u9 MI֥LXV0ci[W5UfF>/*DŽkGshJZS3a%\z[8uZ^ æne n,?bO `}dڍ?xmqBþ=̃~YL4t mh.(u3 Ŀ$BGMA&(WLօmsgs0\ }"o;u*I L̉:~3F%_"`gHnW2qg?^8c$ iXr}9"iK.Fsqz|(}#)Kڜxmٵ|T?'YC jmntM,xHN{wab:Md#eUXpo-$I6~dSII^ʸOߊW2W> ;X(1f˕6{7ѭ˫O4ݏ- X_=Mԏ,ݿ4hH=S'˯O7ȟ1ofSBC x?8|?bx'6ԘO[PK5.n$Horg/apache/commons/beanutils/locale/converters/ShortLocaleConverter.javaUT ->->UxXkSHίEM@JX!!l*)c{%6F۸YR$f*}mo`&dQUbE}_>N~ES: {̈́ϋ%2"UF{q6eiaDVL P:L]QS+(t.T)TaL]|m kN}{5?x+R,)sE당,d3NTy#* rd:R2i!,:0,QrZNKo޼cC79Ϊt"r(Q5닱,J%Go(SUBR_F2 M25+,2d)l,'2*-brf,Řr/4*񗀜$ɮezI@u,Dy`LoݲlҘgcle( f%ja,(<Ԭ=\7 J$3䕱][s%.-v\(5Rx8H˨DV͐JFI F3/[:D:C[ d'ժ$*"91£ƪ#b(:SxCJHFnV?L2?VhZsv[漓 \)b`-Di1ÍK Xq֡3y>0&}HoL^UIq% C`nEA,$>b X^kkmޗ?7hF ?T(o.)ja:%J B-@h~TD0_QK$3Ern 7$KU/i}AW"LT2=d-LuIG%c_2`gؙEݷ㧟x݋׭{h5<́-#j `FY&h}u)Nήzl_:+8rfgAF9uE?n}Q\qdCٻS3]J$YWTWͶ| ٶ,~)ʆ !l6ѯiz{˼rȸOWJ2O$BvAxk&Ƭs}fߺp Ӣ/vkVwcB6O|g&f7?)3$0=2C) SS[CkxK|{~ }<"->UxZ[S~WtQ[vJ!6a Ж}$1"i3V|YH`CNN\X7m3Ec&u-R֊*/G [D7,XTkĢ,xZJ4j yՊ(}V%"ȦLLVg҉ z&(k KxkxW "rIK)W\dzO5F[<->*fh!bI]L1 QUe7"K~u]@#n7oHЭ0ǢQ6$7*L19eclU!ec(4,s* f!( BIŘOxDșLyQ1RL$ 1MZ6ڗooH@Ljb1ť*P"Bq 8)MK~2QY-\$G0˓bq,x]jYPq;VE\,+:%8#!EO O녮d&/`(3$V/IfǂS}CzpeFQ?\zI;q{mftnZU'_8x04B4xZl{C"gܩ2L0lGVcsªHJX),ks(U !pXK*#v%=QJELyF*)"c")7nALhMtE^ab{UCl/;;<ͅ,Z`[ƾ]-؇D1InW=5i+K$g7m5v)cK^(A-zbk@k+=0DBH-v Uw$2 /Dt 5Z5D{]jo=$붗lL0[=cw2atxyFLf^_m%(.vH,ʁ9WT 7mYa||>U6nS[YM'굍hBV&ɏzتKͲ%r=<0cG>u uUq.%+Ji~iyÓeʟt 0/H̛ DYVb*ʑ5ʳTU3$y0oǰLa$q˻,?3b|ݩ(P 8PN/joVo&}WmsLgl47hVeW-~24W yͅo}/PK5.< 'Jorg/apache/commons/beanutils/locale/converters/SqlTimeLocaleConverter.javaUT ->->UxZ[S~WtQ[vJH!6a Ж 1"k3=lN\X7m8vt\ sa&EDd8+ *GIƎWN5*ID6e`R9i''ZMP}g5?x+# 9%ؔ+.k;غi/1P5W X2eYpp(۾Y\I߼yGn9e6 4Qd)6`# ɇ%-8A(eȐgXȉ`ƋkR 1O9^lS>‡:./8i*f<uiMXq`D۷7S ƵXRQŔ?(Ь R#Zu$dme3WR˂ڎJ5(b$r²"X3&ɒǩZ_ӆ`UZ˗v' ΐU*3|X;I5|Mū,kJ/,)v-mU vح(A!0GGĶ;h(XmAte&NARgU+r,g-S+t2$"m{MmMF=,)[ew|R/I|Zħ-D2Nqts?m 8v/ q^0pkv# -ΠwO,8DE7E= +w g^:ѥ>؏x&. [@{(6moag^KŃ;nun ݶ.C~B׍E!y({m?Z|jP||Fcy\Zd- 'ힹ'^"U!A*hppF~4<8!a^p-tzh1a Bs"W(hH\G&>Y 4JafFKٱ񀬭9B^+ZYQ%VwOnˣ]D>.;(^⸖&cpj1Hw Z;\f`*3` ^ޙM|E^ab{UCl/;;| Y3?~6Zݏ1{| ܮzjti+K,Gg7m5v4DzнQZ*bpa "5 U [c Tul=q\L2GJ- K~a7 f,IJC'g|}\bip,)SuÍ [`lR%[]V6١8kdaG/"ɨ\~0xE\u; {J&hf#|)._a`CoůvpeP>Uw$2 t j)jj̱:V~{)o=$붗l1[=cw2atxy ͼT KQ\:?XosZXѮn4 %F$,}38mݦ /W5,OdkU_фLHU/˗eKzy6-a~f8}8KO<]KVx9eNuK~ܐ,=}[ÿVg(ixj=U? }o%|}6Dۈ/h귓ԝSXC}vxڻ>E|Ww{'Of gh1K| z{³,̫%Q+UX.y>#b} rԦgFD"m{1l+SHg? kn) )50_)) T1+ڙ盹F][ujXr8ʵŏR&uzsZwPK5.x'Oorg/apache/commons/beanutils/locale/converters/SqlTimestampLocaleConverter.javaUT ->->UxZ[S~WtQ[vJ!6a Ж 1"i=H6gUX3Ec&u-R֊E^n"XȊֈEYxR IӨ%U+ʣݚ8Jh 2,ZISV(ͻz]$Ϛ¾^<|^~sȱnx~jl .z։;غi/pQ5GY$ty̲Ypr۾\k o޼#E9e6 $ 1LN6b}6慒|Tt1~2Y$02-,qu BOQ*1Xoi3rr)|7:R$3];HFRjvIV,8,Z"TG#1! + ap/ Ay$fp]-4N"t5Y. ..hDupS#fE\,SQM'K%~MV;lN 76YU)esB,ڰ(o21K#f^!RX\ Ƴl1t}:qT~jf376k; •!f!9(YDhc*qUdbI| ! +.{9AQk*^UTd;BU>XZۮ&Ҟ8VˆQ b[H y=, W,79WpB>(t9^>7b t2$"6ٽ6u&c-@]ԓrij-)p2HQ@?/svߝ38\}] \;s ^;x !!t3/Eaz2?3oz {' ?î` 6-xAxgnKÍ=w{!NuN?zC20v8rQyV#w!k#\tWV0p#X.b!A8gΉ@6Z$c0=32! GAЅ~ϽnaZOQ 3hxR?M8_ `3${JOKRXpqs֨9GÕiZኽsOމk4'A^6O/ ^C!D#Wݮ8ι=.xƝ*`a`?x+ :́52Ȳ6ؒRH`IvĮdۻ'J_)ϨW%Edw]䶂Ňk;0Z;;&D|U0]+]۝B*.LEvmHD1I ]5(L H nF4)bl(tCh,H?al _lx5+Cj6@H(T]cBwXB&Q(FI+3ъ6 8?j#0V",KY؇QEFeT^lgLnA|I ^]6١j_xȰڋ}HAK$ÝosJ&R3QI,ŪtL16ab/u# &w\*L-p:27KHQIPU˜hcuT2-i3nhu+L6&X~_myxzā!/ ILaZ$m%.v_JHʮWLu*MkuIx;V$1ґo6Gs UjBV&W8ƙW%fRr=1\3d~/D`~ge2n9UTT)ͷ9#2kGŨuOcZFo&Z*X|->UxZmsH_ڪq^>vRAsB Fkэ$.~3#$ĉs*A߆do̟0qvH|A/i{8(mf~붟 6VE<#LdLm7a|ݓb NӧOۇ/WG/^&oR`-4Qc]?cG[i~Gf L6|A/ X\(vwx,FЄW^[ٜ<20(IR&lbh)Ztr )4Us092c_,aQoD@X'!Iوnβ#-ڡ&] |Z . 5|c)m)bO34k W)Dȏؔ;K bAs+-˳MYpϊ] YPI}qpSͅVLxYtJqF=Y~旰fPU!݉œtAQ^V j~l)h5&fHSUW)={, 1^V ,˒vPƠ45bY%D{.ORHahҜ©A@Qy@ D\c;E ؟ʤ0/d-tD$0fhC}>+쟢EBsⴲJy" (ci*Y9ٔ-H"#dmQa]j8VCVF_:ߪֆY~ϓB`vyL|:+ku?M~~Cr]8`_{%H}϶NoԵ-8yxг/mA 1t.p<{^{f{}pKٝQt`8rȻRbqc}͡gQkzs3{N- d1Z>և*>)aTq cN}#Pkesi#I:DŽ~3r'׷~S{?x M7=u.lhaƦ$- pb[G3$OZ_t`n@q, iT2&MyJ.G1tI1Ģwp %\|ay,cQLP'YJcÅm`+f:ic5_ ؚ-=9qj(d8->Ux1n0 EwtPhJ@5zNҵO}|ڠ9M hzG++-SQ`Y Vt㜹43Mcj&t 74;y̫rCTtNţx&3m h `{NtfAG>T[=jyDz2;)n4f2vG#/PK5.S4[ '<org/apache/commons/beanutils/locale/BaseLocaleConverter.javaUT ->->UxY[sH~8뚪S!v - $41 J-A)=$,8d2CU;΋=x?]r6 tb;R&$ 얥; b!bٙpYɎLuDza ުH,3&y_]vEi6mn- ^˫/ǝ__B:m9._2ڣXOsZ>F?`)OlR0-)]fApo޼9"CŜ< (QK.mĺ|, '9-O!*)4$YH0Hշ3pJe Ȅ0T,)^dsDX "IF<;1 fY\fQ\&bI R$?%D(ĔuPipyelyyYh߷1)b*|ORX`&!d >4^jt RAW%U)-gF8-ٴ nc ''f~}BE,1&|#u.8gYrVn.m3}ߊ1&0u 5$B٘fGTW45UN}-!](*U"f t.'R;wuKҹa_&MPE%/D %,>l7=wR*Xi c3\CmfT9&o@_A Sx[̧{<) /rm;vzv~?5O`gڞφ.8WcHnu^ A?9} };Wa 62<+^;'Q#o0gM{[ΕQ P1^kdukpDa| [NM5 T[o8Teь2Vѐ{ '4ZqE\(ORdΉ n)Bfw.4cyE<5p!&w*8#liJl.rm'yoq6s*#yR-dHh4J6 NNLY$!D\/LxMFBh=z4Z95|q#M+e$]+A Σ QTWV{ʐ tg`݄]Oؘ +@efcjB;}3ci3 ˈ>Br]R5؍jtH{񃀾K#4:Qf1ܸtQ_+S$h257SNvv%NV!6;Uݏ`y,̰ħASd}&4郛Yg V$Sq0*rkY!\VJ.-j(LmmaU5Njl0iotE vQ=WZ PVv>C<+ll\m5L9lbс׆ڂ'q}ssxQc;#ɁO9x4ҩ]wS΢$_ٕ% 3fAUP"՟WT嚻ZQlPh\\m *v^+1mp^{0N8oyVr+G]c4)):2Њ<ڔŋs?PK5.Qk8org/apache/commons/beanutils/locale/LocaleBeanUtils.javaUT ->->Ux]}sH?b-d1?6SANtT* Hv|S8, Q͉MH(S1? Ɣ_9FpN,3uƼA4X8aH'dބs;(q]fd{lH+)A='#T5'8b!h .2G%ޒB&Z#.C6I\ìXص ^e>SvQqS[Lq^h!> <9pl%7%2J_ܝ7'r8؍Ҝ@4qj"(=+(%7@# ]z^R_UJ|pѸ `#T{邹<"rImL,2Nk3xEcL{c,lUPM g/@=|w,?qW#{-Y@JaO 8 Q sp4G w ? 8n K !D3$.$wkdRa=#e_wF(88LR=H._AuipZ1p~~Tޙz';AYwn6\'boXyz16~;0 Fn3lݷ5r<no@:9A2ELz'1x' }IΚv}r6,H6VimH%f:&ƹ]6Ϛ-+{v́>X&[Ct&h}5@5w-0e-ރ гPCk[Mn6<h )& y-mseXKN2jϠɻ.`HhMjvF?`Vs>#^Ef>ps6%1܁ r=ea:g؀𩒟r]q/ C=aBv䆂Rޗ {bl)*U4*@a"l=(B!IS}}Vm/ܥL.ۅY8mFNjIYnB(rhP8 JH-6A81!R` %[u#(f-',ӌ}SS {*{gq̱*ȹ PT`k}1 hKۍJlI IHeRzE=&j" WUL{`F,H.|?4许IZ)DL\H|F4䶂KDGddEөLx)(8p_f3m3>s 3 MXGuw2 +fp9o HJJJ GnOJiܘ-tMcኘ0>T(ǔ:8}FQ (}ds+#wG]e:^bp\5t} f"*2}]3L{q\a ŅN\"s5X7•+SAS5|I%#T+b-Eo|ID%tye(/bMpbDIʖN:EVo|-lX0  IY U亻A;IZqG!QAKL9qF`hySy+떀j,q,nOm_MLՓ?IU2p+SR9^(WW5ŽY;YO;|¼%`i0uD’ᾮS|˲WỌ kǂON^㐗5Iy+[$ODJC։x4f9䂮6ˋ|ֿpYfEoD9@Wp<#g4b Sva٣^=J\!Ǜ|=v@CɎ$]q$s&6gVAFS7Rt)yQĔNfw ދޤ[:U>dF.e!~*&CR@&Ee<*R}GH 0`R6v#Q3v)5wQQަt]I4'JҜ_=\#OcWv/kAݥ,åI!oȋ9j:)RJO"mO5nPyY-o5/F"HhZi}MS%TCY8qע!kXC9*R*SmsMIOA^e r, s(7XD0I,xnsqү  f&+%9UNU%,̕jyT5)3㰢rX3l(_JęE91Z쀨YcF-]btW&ՠh=춍uGd|%9C]Z}G^Hg4C&`>;)p!jb37#\븥@#GC~ސͳ|Jl|jT0Faoz_`wiZ'=Rr ]J=,~2SQ&mT.?,48$dP>ΘkSe>1Sq[#*=Nرě6?;r:Wr܆pG(8\&ԗ:N<_KsRg%1zɗ?!ȇROI&~8ɹCH+GT^4n~R/[6dE<%N6OIKcƼgtj8iPK5.7l[@;org/apache/commons/beanutils/locale/LocaleConvertUtils.javaUT ->->UxZsbә@b'cu0"pn&әbBj%\~هqe&1GyDƧbk6zB޽n&~<ލeFqyn@C tpl{Cu'ϟ>Y^~s!~7 g#nBOkc?5]Q %[$wnLhi\ޞ)>\%坐g/^xœ4 t9ĔxC;s'"9q9I9% *أxK,^6aQl/|OL&BD㵟$tNm9|IVnQ vKp Slyl)O`E "{6إ$ YbmIx,Vhzi YV;OLPbμtMժ! zbK}7ڠSW]G O~i [DipۖQJ+rېtIT" tesma1ivZ%Itudl`9̂R!sK(.@,&cO8 m/@ jLxꡬx$з-s0xת^"tװc*fP/9n <.I@qX Pts04f1<}AܱB!-[J'[0Ljˇ9  r AX7FicktI;!(0PG6.q) "g֙"ぃ؎5sFc1fՆy=1= 9=Z %pB.A`io IJA|d!&/,hz(ן2KFֻ-#{۱N@}M=`mlb*D[3_(txTq(6,H!r@5!֐ Y0ń~{CWn(o}kd0C2YlT ~Y^=:[wx)T*ώudb2Gg;z!;.O.\t]C\BB rOs,+ʽű=3A[9鲾H :XW[PQշ]Gf 3>2z:ԭ+6X %o,tp꡼j+v͐v6nB,n0se#X‡\utMqKH/YKao?%ƞƟ@L!L8sѿ4\B4"`$b6o8HG:`Cfa@-K q˚q&8܍}p%/ ePV"TO_vBi 7Fd[2e$Ul#0ށy,r[3]"x4*BXm zV5)7b UBaԝqjq}#ܑS7)nѠU?3X,$)b-$v"a"MӃ]r]`Ď2qUy&7n Q4&tE-oӀ"?#$)~R="ay'!g.+G2<ȱp 1B= Eq)N j,i2=l> Y11^\r\:OL4M38qɁL`-%WHvg/iO7@)(,>b[£Ѽ!K ޳ nr0D' l+T9d0gi婔o/ Sd" uS/85T/[^ uFb+T.ժ9lX%m -VG۵e*?"%t^(/h.\PCȕ@x੊{S沊`&?B#]ս2U&DltlͩN\[%IOժ |ƫisjeD ,+"Q"qZj0(UDn%&iyyͣY CYYE(\ 4Xdj?&oApX@4o-xST|)j#HXG$uiDd[C׃Kq4H^5hS^SqRuNfmT I*;!Q AyZ,[x$I1bw>^jFo(>m]5!pb,ln]w+_po2 7_ҔiZ2mB)v/3)`h ؾf3|=kiT%WIJIVB.N )ZD=&wЂ2h6GpΑ#$Ԇ/aeE9.@&SߏTJU?)JSV4]TPcBfPs#(WXtuT4Jн F3"*>X AS?W? 1u|#4\&+LN?ݟ!Y3A~MJ\_!NHQ Yl+ h g} 4i ,&-1oRhɩR; Ơ3QgPz)OغFPOpî90XuR=ˆpר<o[ln^bd ›i" O7'qvc1+RASYR.x4fPD;-xJ_xCzkNRZJ ٍR*:˜B4A,Ðj-\e,oW[ft3U;]Fb5q/}7*!c&/FBt3ũ! \8Zs3cybM=BD)`OuٴKzj`%`gYWPeQIžZF}%_O*LHB׮|(R[DC.v?@)I)@M<3橞ĘK*/ab̌O5mʳ V UT+ 3F\ [D?A\j!yXR$i>C$P>',(|Zo`P~4bN?\Yـ)9-psn ۀ+& r+QsfڀZca69_nva}(3ga xQp(5gM-;k/bӗOkEA(me@FPK5.cB8org/apache/commons/beanutils/locale/LocaleConverter.javaUT ->->UxWn8}WPN_:=;hE +mh9E6{l粳/)$)2|B)2i.ik9L7U,rO<.BU^ +ó1q(J`jUSľ<]l'çᇋxqd2]<%dEr*KkӎD-/ߴy^頒$zI^[a$MT*J:t' n˝Qޥgts&&X7E&j <'kX14 :HfZ4DQSITnL*Bhͺrhicߺe3T!PJVu-3*ި J%zGJu)6n-ˎ G] N)S:X*ʁ0ia4jsq <ҥo?ti+26kYԢniZ$% &;cgz/? qEvC`^l4o1Cjفb紊tF/<S| Y9MXVĽqw';$#gޭ꺼M,1g!W] DYJ!)p IY+eyoq0k=|m( [8if2O:OmHpi!i68;}k_An,:%[uw93+_l;ìCe.Ew o^/p:Prt]?2o>_~nʞprލ|, ?wc 3~,saDl#ƀiN d> ] M Q:-$ӭy7qI<}A2Ş4Ɩ.( čh6fah(#`ɿ 7dbugq8$1$&/&Qaӕo <|y 'j3 |F0I#ֽczZ-8 ˮ@x~'A2O|QرI1cc>k |_JL?3Vn{# mTmFLqxj[\#z^r̢D%J= l@A!A v{ΓpA<: 6crGw=b8S+L 8`]FeMnRYUR78.aˤ":MhٷPK5.iu0org/apache/commons/beanutils/locale/package.htmlUT ->->Ux=1n0 Ew)EC\(- "]7j?'[x|"mlL'/$ eC%C*H \en$̫ͬ% i'|q Ro-F.↕~By%5k*{)̲)"HrlP|\ј enPK 5. Aorg/UT->UxPK 5. A7org/apache/UT->UxPK 5. Auorg/apache/commons/UT->UxPK 5. Aorg/apache/commons/beanutils/UT->UxPK 5.( A org/apache/commons/beanutils/converters/UT->UxPK5.T% MC forg/apache/commons/beanutils/converters/AbstractArrayConverter.javaUT->UxPK5.<@ { org/apache/commons/beanutils/converters/BigDecimalConverter.javaUT->UxPK5.p@ org/apache/commons/beanutils/converters/BigIntegerConverter.javaUT->UxPK5.$$ ?!B Norg/apache/commons/beanutils/converters/BooleanArrayConverter.javaUT->UxPK5.S= (org/apache/commons/beanutils/converters/BooleanConverter.javaUT->UxPK5.ȴ x? L1org/apache/commons/beanutils/converters/ByteArrayConverter.javaUT->UxPK5.Bj: :org/apache/commons/beanutils/converters/ByteConverter.javaUT->UxPK5..V' D PCorg/apache/commons/beanutils/converters/CharacterArrayConverter.javaUT->UxPK5.O**3? Lorg/apache/commons/beanutils/converters/CharacterConverter.javaUT->UxPK5.#b; VUorg/apache/commons/beanutils/converters/ClassConverter.javaUT->UxPK5.xGq" A &^org/apache/commons/beanutils/converters/DoubleArrayConverter.javaUT->UxPK5.I < gorg/apache/commons/beanutils/converters/DoubleConverter.javaUT->UxPK5.Q" @ 6porg/apache/commons/beanutils/converters/FloatArrayConverter.javaUT->UxPK5.; yorg/apache/commons/beanutils/converters/FloatConverter.javaUT->UxPK5.dwg B ?org/apache/commons/beanutils/converters/IntegerArrayConverter.javaUT->UxPK5._5= Ӌorg/apache/commons/beanutils/converters/IntegerConverter.javaUT->UxPK5.9Dj x? Jorg/apache/commons/beanutils/converters/LongArrayConverter.javaUT->UxPK5.i: ܝorg/apache/commons/beanutils/converters/LongConverter.javaUT->UxPK5. Y! @ Oorg/apache/commons/beanutils/converters/ShortArrayConverter.javaUT->UxPK5.q; org/apache/commons/beanutils/converters/ShortConverter.javaUT->UxPK5.w= Vorg/apache/commons/beanutils/converters/SqlDateConverter.javaUT->UxPK5.ĨLw= org/apache/commons/beanutils/converters/SqlTimeConverter.javaUT->UxPK5.:xB org/apache/commons/beanutils/converters/SqlTimestampConverter.javaUT->UxPK5.GƩA org/apache/commons/beanutils/converters/StringArrayConverter.javaUT->UxPK5.O< org/apache/commons/beanutils/converters/StringConverter.javaUT->UxPK5.|4 org/apache/commons/beanutils/converters/package.htmlUT->UxPK5. </ "org/apache/commons/beanutils/BasicDynaBean.javaUT->UxPK5.݄ f+0 9org/apache/commons/beanutils/BasicDynaClass.javaUT->UxPK5.[N)0 org/apache/commons/beanutils/BeanComparator.javaUT->UxPK5.X$Q+ 'org/apache/commons/beanutils/BeanUtils.javaUT->UxPK5.4 `)2 c$org/apache/commons/beanutils/ConstructorUtils.javaUT->UxPK5.Fi:dm5 /org/apache/commons/beanutils/ConversionException.javaUT->UxPK5.-RN. :7org/apache/commons/beanutils/ConvertUtils.javaUT->UxPK5.Z2+ pIorg/apache/commons/beanutils/Converter.javaUT->UxPK5.3 8 (Porg/apache/commons/beanutils/ConvertingWrapDynaBean.javaUT->UxPK5.1.1* Xorg/apache/commons/beanutils/DynaBean.javaUT->UxPK5.E} + aorg/apache/commons/beanutils/DynaClass.javaUT->UxPK5. '. jorg/apache/commons/beanutils/DynaProperty.javaUT->UxPK5.i^T: vorg/apache/commons/beanutils/MappedPropertyDescriptor.javaUT->UxPK5.ƲvQl- $org/apache/commons/beanutils/MethodUtils.javaUT->UxPK5., _[H2 org/apache/commons/beanutils/MutableDynaClass.javaUT->UxPK5.nf&/ org/apache/commons/beanutils/PropertyUtils.javaUT->UxPK5.s+y74 ;org/apache/commons/beanutils/ResultSetDynaClass.javaUT->UxPK5.7[ /3 Forg/apache/commons/beanutils/ResultSetIterator.javaUT->UxPK5.<;1 uorg/apache/commons/beanutils/RowSetDynaClass.javaUT->UxPK5.}%$ f-. org/apache/commons/beanutils/WrapDynaBean.javaUT->UxPK5.?{ )/  org/apache/commons/beanutils/WrapDynaClass.javaUT->UxPK5.j=&]) +org/apache/commons/beanutils/package.htmlUT->UxPK 5.$ AAorg/apache/commons/beanutils/locale/UT->UxPK 5./ ABorg/apache/commons/beanutils/locale/converters/UT->UxPK5.c%M }Borg/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.javaUT->UxPK5.v#%M Jorg/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.javaUT->UxPK5.Q$G }Sorg/apache/commons/beanutils/locale/converters/ByteLocaleConverter.javaUT->UxPK5.S; +G [org/apache/commons/beanutils/locale/converters/DateLocaleConverter.javaUT->UxPK5.&  )J forg/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.javaUT->UxPK5.gW9$I oorg/apache/commons/beanutils/locale/converters/DoubleLocaleConverter.javaUT->UxPK5.vmB$H  xorg/apache/commons/beanutils/locale/converters/FloatLocaleConverter.javaUT->UxPK5.AJt$J org/apache/commons/beanutils/locale/converters/IntegerLocaleConverter.javaUT->UxPK5.zm$G org/apache/commons/beanutils/locale/converters/LongLocaleConverter.javaUT->UxPK5.n$H |org/apache/commons/beanutils/locale/converters/ShortLocaleConverter.javaUT->UxPK5.*1QE'J org/apache/commons/beanutils/locale/converters/SqlDateLocaleConverter.javaUT->UxPK5.< 'J *org/apache/commons/beanutils/locale/converters/SqlTimeLocaleConverter.javaUT->UxPK5.x'O `org/apache/commons/beanutils/locale/converters/SqlTimestampLocaleConverter.javaUT->UxPK5.&e -.I org/apache/commons/beanutils/locale/converters/StringLocaleConverter.javaUT->UxPK5."K; org/apache/commons/beanutils/locale/converters/package.htmlUT->UxPK5.S4[ '< Jorg/apache/commons/beanutils/locale/BaseLocaleConverter.javaUT->UxPK5.Qk8 zorg/apache/commons/beanutils/locale/LocaleBeanUtils.javaUT->UxPK5.7l[@; org/apache/commons/beanutils/locale/LocaleConvertUtils.javaUT->UxPK5.cB8 Porg/apache/commons/beanutils/locale/LocaleConverter.javaUT->UxPK5.iu0 Oorg/apache/commons/beanutils/locale/package.htmlUT->UxPKKK!sstapler-stapler-parent-1.231/core/LICENSE.txt0000664000175000017500000000245212414640747020252 0ustar ebourgebourgCopyright (c) 2004-2010, Kohsuke Kawaguchi All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. 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.stapler-stapler-parent-1.231/core/pom.xml0000664000175000017500000001063412414640747017745 0ustar ebourgebourg 4.0.0 org.kohsuke.stapler stapler-parent 1.231 stapler Stapler Stapler HTTP request handling engine maven-jar-plugin test-jar javax.annotation javax.annotation-api 1.2 javax.servlet servlet-api 2.3 provided commons-discovery commons-discovery 0.4 commons-beanutils commons-beanutils 1.7.0 commons-io commons-io 1.3.1 org.jvnet.localizer localizer 1.7 org.kohsuke.stapler json-lib 2.4-jenkins-2 org.jvnet tiger-types 1.3 org.codehaus.groovy groovy-all 1.8.3 true com.google.guava guava 14.0 org.kohsuke asm5 5.0.1 org.jenkins-ci annotation-indexer 1.9 true commons-fileupload commons-fileupload 1.2.1 com.sun.xml.txw2 txw2 20070624 true junit junit org.mockito mockito-all org.kohsuke.metainf-services metainf-services true org.mortbay.jetty jetty org.jvnet.hudson htmlunit com.jolira hickory 1.0.0 test com.google.code.findbugs jsr305 2.0.1 com.jcraft jzlib 1.1.3 stapler-stapler-parent-1.231/core/release.sh0000664000175000017500000000046512414640747020405 0ustar ebourgebourg#!/bin/sh -ex mvn -B release:prepare release:perform ver=$(show-pom-version target/checkout/pom.xml) javanettasks uploadFile stapler /stapler-$ver.zip "$ver release" stable target/checkout/target/stapler-$ver-bin.zip cp -R target/checkout/target/site/* ../www cd ../www rcvsadd . "pushing javadoc for $ver" stapler-stapler-parent-1.231/LICENSE.txt0000664000175000017500000000246012414640747017321 0ustar ebourgebourgCopyright (c) 2009-, Kohsuke Kawaguchi and other contributors 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. 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. stapler-stapler-parent-1.231/pom.xml0000664000175000017500000001626612414640747017024 0ustar ebourgebourg 4.0.0 org.kohsuke pom 10 org.kohsuke.stapler stapler-parent pom 1.231 Stapler Stapler HTTP request handling engine core jsp jelly jruby groovy jrebel http://stapler.kohsuke.org/ 2-clause BSD license repo http://opensource.org/licenses/bsd-license.php scm:git:git://github.com/stapler/stapler.git scm:git:ssh://git@github.com/stapler/stapler.git https://github.com/stapler/stapler stapler-parent-1.231 3.0.4 maven.jenkins-ci.org http://maven.jenkins-ci.org:8081/content/repositories/snapshots/ github-pages gitsite:git@github.com/stapler/stapler.git Kohsuke Kawaguchi kohsuke kk@kohsuke.org repo.jenkins-ci.org http://repo.jenkins-ci.org/public/ repo.jenkins-ci.org http://repo.jenkins-ci.org/public/ UTF-8 6 maven-compiler-plugin 3.1 1.${java.level} 1.${java.level} org.codehaus.mojo animal-sniffer-maven-plugin 1.9 check org.codehaus.mojo.signature java1${java.level} 1.0 org.apache.maven.plugins maven-enforcer-plugin 1.3.1 enforce [1.${java.level},) 1.${java.level} com.headius.invokebinder.* org.codehaus.mojo extra-enforcer-rules 1.0-beta-2 maven-release-plugin 2.5 clean install -P release true org.apache.maven.plugins maven-site-plugin org.kohsuke doxia-module-markdown 1.0 org.jvnet.maven-jellydoc-plugin maven-jellydoc-plugin 1.2 maven-project-info-reports-plugin 2.7 license maven-javadoc-plugin 2.9.1 true org.kohsuke.doklet.Doklet true org.kohsuke doklet 1.0 org.kohsuke.metainf-services metainf-services 1.5 org.mortbay.jetty jetty 6.1.11 test org.mockito mockito-all 1.8.5 test org.jvnet.hudson htmlunit 2.6-hudson-2 test xml-apis xml-apis junit junit 4.11 test stapler-stapler-parent-1.231/jelly/0000775000175000017500000000000012414640747016613 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/0000775000175000017500000000000012414640747017402 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/0000775000175000017500000000000012414640747020361 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/java/0000775000175000017500000000000012414640747021302 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/java/org/0000775000175000017500000000000012414640747022071 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/java/org/kohsuke/0000775000175000017500000000000012414640747023542 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/java/org/kohsuke/stapler/0000775000175000017500000000000012414640747025214 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/java/org/kohsuke/stapler/jelly/0000775000175000017500000000000012414640747026333 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/java/org/kohsuke/stapler/jelly/BindTagJQueryTest.java0000664000175000017500000000244412414640747032512 0ustar ebourgebourgpackage org.kohsuke.stapler.jelly; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.kohsuke.stapler.framework.adjunct.AdjunctManager; import org.kohsuke.stapler.test.JettyTestCase; import java.net.URL; /** * Description * * @author Robert Sandell <sandell.robert@gmail.com> */ public class BindTagJQueryTest extends JettyTestCase { private String value; public AdjunctManager am; private int number; @Override protected void setUp() throws Exception { super.setUp(); this.am = new AdjunctManager(servletContext,getClass().getClassLoader(),"am"); } public void test1() throws Exception { WebClient wc = new WebClient(); HtmlPage page = wc.getPage(new URL(url, "/")); String content = page.getWebResponse().getContentAsString(); System.out.println(content); //Check that prototype is included in the page assertFalse(content.contains("/am/org/kohsuke/stapler/framework/prototype/prototype.js")); page.executeJavaScript("v.foo('hello world', 2);"); assertEquals("hello world",value); assertEquals(2, number); } public void jsFoo(String arg, int arg2) { this.value = arg; this.number = arg2; } } stapler-stapler-parent-1.231/jelly/src/test/java/org/kohsuke/stapler/jelly/BindTagTest.java0000664000175000017500000000221312414640747031344 0ustar ebourgebourgpackage org.kohsuke.stapler.jelly; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.kohsuke.stapler.framework.adjunct.AdjunctManager; import org.kohsuke.stapler.test.JettyTestCase; import java.net.URL; /** * @author Kohsuke Kawaguchi */ public class BindTagTest extends JettyTestCase { private String value; public AdjunctManager am; @Override protected void setUp() throws Exception { super.setUp(); this.am = new AdjunctManager(servletContext,getClass().getClassLoader(),"am"); } public void test1() throws Exception { WebClient wc = new WebClient(); HtmlPage page = wc.getPage(new URL(url, "/")); String content = page.getWebResponse().getContentAsString(); System.out.println(content); //Check that prototype is included in the page assertTrue(content.contains("/am/org/kohsuke/stapler/framework/prototype/prototype.js")); page.executeJavaScript("v.foo('hello world');"); assertEquals("hello world",value); } public void jsFoo(String arg) { this.value = arg; } } ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/java/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest.javastapler-stapler-parent-1.231/jelly/src/test/java/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest0000664000175000017500000000126712414640747033305 0ustar ebourgebourgpackage org.kohsuke.stapler.jelly; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.kohsuke.stapler.test.JettyTestCase; import java.net.URL; /** * @author Kohsuke Kawaguchi */ public class TagLibNamespaceExportTest extends JettyTestCase { public void test1() throws Exception { WebClient wc = new WebClient(); HtmlPage page = wc.getPage(new URL(url, "/")); String content = page.getWebResponse().getContentAsString(); System.out.println(content); assertTrue(content.contains("foo")); assertTrue(!content.contains("bar")); assertTrue(!content.contains("zot")); } } stapler-stapler-parent-1.231/jelly/src/test/resources/0000775000175000017500000000000012414640747022373 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/resources/org/0000775000175000017500000000000012414640747023162 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/0000775000175000017500000000000012414640747024633 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/0000775000175000017500000000000012414640747026305 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/0000775000175000017500000000000012414640747027424 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/BindTagTest/0000775000175000017500000000000012414640747031574 5ustar ebourgebourg././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/BindTagTest/index.jellystapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/BindTagTest/index.je0000664000175000017500000000022312414640747033220 0ustar ebourgebourg ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/stapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExpor0000775000175000017500000000000012414640747033342 5ustar ebourgebourg././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/index.jellystapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExpor0000664000175000017500000000100512414640747033340 0ustar ebourgebourg foo ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/sub.jellystapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExpor0000664000175000017500000000024212414640747033342 0ustar ebourgebourg bar ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/taglib/stapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExpor0000775000175000017500000000000012414640747033342 5ustar ebourgebourg././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/taglib/tagfile.jellystapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExpor0000664000175000017500000000024212414640747033342 0ustar ebourgebourg zot ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/taglib/taglibstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExpor0000664000175000017500000000000012414640747033332 0ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/BindTagJQueryTest/0000775000175000017500000000000012414640747032734 5ustar ebourgebourg././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/BindTagJQueryTest/index.jellystapler-stapler-parent-1.231/jelly/src/test/resources/org/kohsuke/stapler/jelly/BindTagJQueryTest/in0000664000175000017500000000034412414640747033266 0ustar ebourgebourg stapler-stapler-parent-1.231/jelly/src/main/0000775000175000017500000000000012414640747020326 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/main/java/0000775000175000017500000000000012414640747021247 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/main/java/org/0000775000175000017500000000000012414640747022036 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/0000775000175000017500000000000012414640747023507 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/0000775000175000017500000000000012414640747025161 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/0000775000175000017500000000000012414640747027156 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/0000775000175000017500000000000012414640747030606 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/Adjunct.java0000664000175000017500000001767412414640747033060 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.adjunct; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.Script; import org.kohsuke.stapler.MetaClassLoader; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.jelly.JellyClassLoaderTearOff; import org.kohsuke.stapler.jelly.JellyFacet; import org.xml.sax.SAXException; import org.kohsuke.stapler.StaplerRequest; import org.apache.commons.jelly.XMLOutput; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * In-memory cache of fully inlined "adjunct" which is a pair of CSS and JavaScript. * * @author Kohsuke Kawaguchi */ public class Adjunct { public final AdjunctManager manager; /** * Fully qualified name of this adjunct that follows the dot notation. */ public final String name; /** * The same as {@link #name} but uses '/' separator. */ public final String slashedName; /** * Just the package name portion of {@link #slashedName}. No trailing '/'. */ public final String packageName; /** * List of fully qualified adjunct names that are required before this adjunct. */ public final List required = new ArrayList(); private final boolean hasCss; private final boolean hasJavaScript; /** * If the HTML that includes CSS/JavaScripts are provided * by this adjunct, non-null. This allows external JavaScript/CSS * resources to be handled in the adjunct mechanism. */ private final String inclusionFragment; /** * If the adjunct includes a Jelly script, set to that script. * This allows a Jelly script to generate the inclusion fragment. * Think of this as a programmable version of the {@link #inclusionFragment}. */ private final Script script; /** * Builds an adjunct. * * @param name * Fully qualified name of the adjunct. * @param classLoader * This is where adjuncts are loaded from. */ public Adjunct(AdjunctManager manager, String name, final ClassLoader classLoader) throws IOException { this.manager = manager; this.name = name; this.slashedName = name.replace('.','/'); this.packageName = slashedName.substring(0, Math.max(0,slashedName.lastIndexOf('/'))); this.hasCss = parseOne(classLoader, slashedName+".css"); this.hasJavaScript = parseOne(classLoader,slashedName+".js"); this.inclusionFragment = parseHtml(classLoader,slashedName+".html"); URL jelly = classLoader.getResource(slashedName + ".jelly"); if (jelly!=null) { try { script = MetaClassLoader.get(classLoader).loadTearOff(JellyClassLoaderTearOff.class).createContext().compileScript(jelly); } catch (JellyException e) { throw new IOException("Failed to load "+jelly,e); } } else { script = null; } if(!hasCss && !hasJavaScript && inclusionFragment==null && script==null) throw new NoSuchAdjunctException("Neither "+ name +".css, .js, .html, nor .jelly were found"); } /** * Obtains the absolute URL that points to the package of this adjunct. * Useful as a basis to refer to other resources. */ public String getPackageUrl() { return getPackageUrl(Stapler.getCurrentRequest()); } private String getPackageUrl(StaplerRequest req) { return req.getContextPath() + '/' + manager.rootURL + '/' + packageName; } private String getBaseName(StaplerRequest req) { return req.getContextPath() + '/' + manager.rootURL + '/' + slashedName; } /** * Parses CSS or JavaScript files and extract dependencies. */ private boolean parseOne(ClassLoader classLoader, String resName) throws IOException { InputStream is = classLoader.getResourceAsStream(resName); if (is == null) return false; BufferedReader in = new BufferedReader(new InputStreamReader(is,UTF8)); String line; while((line=in.readLine())!=null) { Matcher m = INCLUDE.matcher(line); if(m.lookingAt()) required.add(m.group(1)); } in.close(); return true; } /** * Parses HTML files and extract dependencies. */ private String parseHtml(ClassLoader classLoader, String resName) throws IOException { InputStream is = classLoader.getResourceAsStream(resName); if (is == null) return null; BufferedReader in = new BufferedReader(new InputStreamReader(is,UTF8)); String line; StringBuilder buf = new StringBuilder(); while((line=in.readLine())!=null) { Matcher m = HTML_INCLUDE.matcher(line); if(m.lookingAt()) required.add(m.group(1)); else buf.append(line).append('\n'); } in.close(); return buf.toString(); } public boolean has(Kind k) { switch (k) { case CSS: return hasCss; case JS: return hasJavaScript; } throw new AssertionError(k); } public void write(StaplerRequest req, XMLOutput out) throws SAXException, IOException { if(inclusionFragment!=null) { out.write(inclusionFragment); return; } if (script!=null) try { WebApp.getCurrent().getFacet(JellyFacet.class).scriptInvoker.invokeScript(req, Stapler.getCurrentResponse(), script, this, out); } catch (JellyTagException e) { throw new IOException("Failed to execute Jelly script for adjunct "+name,e); } if(hasCss) out.write(""); if(hasJavaScript) out.write(""); } public enum Kind { CSS, JS } /** * "@include fully.qualified.name" in a block or line comment. */ private static final Pattern INCLUDE = Pattern.compile("/[/*]\\s*@include (\\S+)"); /** * <@include fully.qualified.name> */ private static final Pattern HTML_INCLUDE = Pattern.compile("<@include (\\S+)>"); private static final Charset UTF8 = Charset.forName("UTF-8"); } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctManager.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctManage0000664000175000017500000002007712414640747033240 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.adjunct; import org.kohsuke.stapler.*; import javax.servlet.ServletException; import javax.servlet.ServletContext; import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import java.io.IOException; import java.net.URL; import java.util.concurrent.ConcurrentHashMap; /** * This application-scoped object that exposes djuncts to URL. * *

* Adjuncts are packaging of JavaScript, CSS, and other static assets in jar files with dependency * information between them. This allows JavaScript libraries and other static assets to be reused * across different projects through Maven/Ivy. * *

* To use {@link AdjunctManager} in your application, create one instance, and bind it to URL * (like you do any other objects.) The most typical way of doing this is to define it as a * field in your top-level object. * *

 * public class MyApplication {
 *     public final AdjunctManager adjuncts = new AdjunctManager(context,getClass().getClassLoader(),"/adjuncts");
 * }
 * 
* *

* How you include an adjunct will depend on your template language, but for example in Jelly you do: *

 * <st:adjunct includes="org.kohsuke.stapler.bootstrap"/>
 * 
* * Or from Groovy you do: *
 * adjunct "org.kohsuke.stapler.bootstrap"
 * 
* *

* ... and this produces a series of style and script tags that include all the * necessary JavaScript, CSS, and their dependencies. * *

* Internally, this class provides caching for {@link Adjunct}s. * * @author Kohsuke Kawaguchi * @see Adjunct */ public class AdjunctManager { private final ConcurrentHashMap adjuncts = new ConcurrentHashMap(); /** * Map used as a set to remember which resources can be served. */ private final ConcurrentHashMap allowedResources = new ConcurrentHashMap(); private final ClassLoader classLoader; /** * Absolute URL of the {@link AdjunctManager} in the calling application where it is bound to. * *

* The path is treated relative from the context path of the application, and it * needs to end without '/'. So it needs to be something like "foo/adjuncts" or * just "adjuncts". Can be e.g. {@code adjuncts/uNiQuEhAsH} to improve caching behavior. */ public final String rootURL; /** * Hint instructing adjuncts to load a debuggable non-minified version of the script, * as opposed to the production version. * * This is only a hint, and so the semantics of it isn't very well defined. The intention * is to assist JavaScript debugging. */ public boolean debug = Boolean.getBoolean(AdjunctManager.class.getName()+".debug"); public final WebApp webApp; private final long expiration; @Deprecated public AdjunctManager(ServletContext context,ClassLoader classLoader, String rootURL) { this(context, classLoader, rootURL, /* one day */24L * 60 * 60 * 1000); } /** * @param classLoader * ClassLoader to load adjuncts from. * @param rootURL * See {@link #rootURL} for the meaning of this parameter. * @param expiration milliseconds from service time until expiration, for {@link #doDynamic} * (as in {@link StaplerResponse#serveFile(StaplerRequest, URL, long)}); * if {@link #rootURL} is unique per session then this can be very long; * otherwise a day might be reasonable */ public AdjunctManager(ServletContext context, ClassLoader classLoader, String rootURL, long expiration) { this.classLoader = classLoader; this.rootURL = rootURL; this.webApp = WebApp.get(context); this.expiration = expiration; // register this globally context.setAttribute(KEY,this); } public static AdjunctManager get(ServletContext context) { return (AdjunctManager) context.getAttribute(KEY); } /** * Obtains the adjunct. * * @return * always non-null. * @throws IOException * if failed to locate {@link Adjunct}. */ public Adjunct get(String name) throws IOException { Adjunct a = adjuncts.get(name); if(a!=null) return a; // found it synchronized (this) { a = adjuncts.get(name); if(a!=null) return a; // one more check before we start loading a = new Adjunct(this,name,classLoader); adjuncts.put(name,a); return a; } } /** * Serves resources in the class loader. */ public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { String path = req.getRestOfPath(); if (path.charAt(0)=='/') path = path.substring(1); if(!allowedResources.containsKey(path)) { if(!allowResourceToBeServed(path)) { rsp.sendError(SC_FORBIDDEN); return; } // remember URLs that we can serve. but don't remember error ones, as it might be unbounded allowedResources.put(path,path); } URL res = classLoader.getResource(path); if(res==null) { throw HttpResponses.error(SC_NOT_FOUND,new IllegalArgumentException("No such adjunct found: "+path)); } else { long expires = MetaClass.NO_CACHE ? 0 : expiration; rsp.serveFile(req,res,expires); } } /** * Controls whether the given resource can be served to browsers. * *

* This method can be overridden by the sub classes to change the access control behavior. * *

* {@link AdjunctManager} is capable of serving all the resources visible * in the classloader by default. If the resource files need to be kept private, * return false, which causes the request to fail with 401. * * Otherwise return true, in which case the resource will be served. */ protected boolean allowResourceToBeServed(String absolutePath) { // does it have an adjunct directory marker? int idx = absolutePath.lastIndexOf('/'); if (idx>0 && classLoader.getResource(absolutePath.substring(0,idx)+"/.adjunct")!=null) return true; // backward compatible behaviour return absolutePath.endsWith(".gif") || absolutePath.endsWith(".png") || absolutePath.endsWith(".css") || absolutePath.endsWith(".js"); } /** * Key in {@link ServletContext} to look up {@link AdjunctManager}. */ private static final String KEY = AdjunctManager.class.getName(); } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctsInPage.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctsInPag0000664000175000017500000001436512414640747033234 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.adjunct; import org.apache.commons.jelly.XMLOutput; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; import org.xml.sax.SAXException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * This request-scope object keeps track of which {@link Adjunct}s are already included. * * @author Kohsuke Kawaguchi */ public class AdjunctsInPage { private final AdjunctManager manager; /** * All adjuncts that are already included in the page. */ private final Set included = new HashSet(); /** * {@link Adjunct}s that haven't written to HTML yet because <head> * tag hasn't been written yet. */ private final List pending = new ArrayList(); private final StaplerRequest request; /** * Obtains the instance associated with the current request of the given {@link StaplerRequest}. */ public static AdjunctsInPage get() { return get(Stapler.getCurrentRequest()); } /** * Obtains the instance associated with the current request of the given {@link StaplerRequest}. * *

* This method is handy when the caller already have the request object around, * so that we can save {@link Stapler#getCurrentRequest()} call. */ public static AdjunctsInPage get(StaplerRequest request) { AdjunctsInPage aip = (AdjunctsInPage) request.getAttribute(KEY); if(aip==null) request.setAttribute(KEY,aip=new AdjunctsInPage(AdjunctManager.get(request.getServletContext()),request)); return aip; } private AdjunctsInPage(AdjunctManager manager,StaplerRequest request) { this.manager = manager; this.request = request; } /** * Gets what has been already included/assumed. * * This method returns a live unmodifiable view of what's included. * So if at some later point more adjuncts are loaded, the view * obtained earlier will reflect that. */ public Set getIncluded() { return Collections.unmodifiableSet(included); } /** * Checks if something has already been included/assumed. */ public boolean isIncluded(String include) { return included.contains(include); } /** * Generates the script tag and CSS link tag to include necessary adjuncts, * and records the fact that those adjuncts are already included in the page, * so that it won't be loaded again. */ public void generate(XMLOutput out, String... includes) throws IOException, SAXException { List needed = new ArrayList(); for (String include : includes) findNeeded(include,needed); for (Adjunct adj : needed) adj.write(request,out); } /** * When you include your version of the adjunct externally, you can use * this method to inform {@link AdjunctsInPage} that those adjuncts are * already included in the page. */ public void assumeIncluded(String... includes) throws IOException, SAXException { assumeIncluded(Arrays.asList(includes)); } public void assumeIncluded(Collection includes) throws IOException, SAXException { List needed = new ArrayList(); for (String include : includes) findNeeded(include,needed); } /** * Works like the {@link #generate(XMLOutput, String...)} method * but just put the adjuncts to {@link #pending} without writing it. */ public void spool(String... includes) throws IOException, SAXException { for (String include : includes) findNeeded(include,pending); } /** * Writes out what's spooled by {@link #spool(String...)} method. */ public void writeSpooled(XMLOutput out) throws SAXException, IOException { for (Adjunct adj : pending) adj.write(request,out); pending.clear(); } /** * Builds up the needed adjuncts into the 'needed' list. */ private void findNeeded(String include, List needed) throws IOException { if(!included.add(include)) return; // already sent // list dependencies first try { Adjunct a = manager.get(include); for (String req : a.required) findNeeded(req,needed); needed.add(a); } catch (NoSuchAdjunctException e) { LOGGER.log(Level.WARNING, "No such adjunct found: "+include,e); } } private static final String KEY = AdjunctsInPage.class.getName(); private static final Logger LOGGER = Logger.getLogger(AdjunctsInPage.class.getName()); } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/package-info.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/package-info.0000664000175000017500000001145212414640747033136 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ /** * JavaScript/CSS packaging mechanism. * *

* A part of writing a web application involves reusing JavaScript libraries that are developed by 3rd parties. * Such JavaScript libraries often come in a package of js files, CSS, images, and so on. To integrate those * libraries to your application, you often need to do: * *

    *
  • Copy files into the webapp resource directories. *
  • If the JavaScript library depends on other JavaScript libraries, copy those, too. *
  • For each page where you use them, write script and link tags to load images and CSS, as well as their dependencies. *
* *

* This tediousness hurts the small-scale reusability of JavaScript libraries. * The adjunct framework in Stapler attempts to solve this by allowing libraries/components to express * dependencies among themselves, and grouping CSS and JavaScript together, so that a single "inclusion" * would include everything that a JavaScript library needs. * *

What packagers do

*
    *
  1. * Package JavaScript libraries as a jar file, including CSS and asset files, typically through Maven. * CSS (*.css), JavaScript (*.js), and HTML (*.html) that are only different by their extensions are grouped * into "adjunct", which becomes the unit of dependency management. All three aspects of an adjunct is optional. * More about what these files do later. * *
  2. * If this library depends on other libraries, use Maven's dependency management to have the resulting jars * express dependencies. * *
  3. * Express dependencies among adjuncts. * *
* * *

What webapp developers do

*
    *
  1. * Include adjunct jar files into WEB-INF/libs either directly or indirectly, typically via Maven. * *
  2. * Bind {@link AdjunctManager} to URL by using Stapler. This object serves adjunct JavaScript, CSS, images, and so on. * *
  3. * Use <st:adjunct> tag to load adjunct into the page. This tag expands to the <script> and <link> tags * for the adjunct itself and all the dependencies. It also remembers what adjuncts are already loaded into the page, * so when multiple <st:adjunt> tags are used to load different libraries, it won't repeatedly load the same script. * *
* * *

Adjunct

*

Name

*

* Adjuncts are identified by their fully qualified names, which is the package name + base name of the file name * (this is just like how a Java class gets its FQCN.) * *

Expressing dependencies

*

* Lines of the following form in JavaScript and CSS are interpreted by the adjunct framework to express * dependencies to other adjuncts. They have to start at the beginning of the line, without a leading whitespace. *

 * // @include fully.qualified.adjunct.name
 * /* @include fully.qualified.adjunct.name
 * 
*

* HTML file can have the following line to indicate a dependency. *

 * <@include fully.qualified.adjunct.name>
 * 
* *

Page injection

*

* Stapler loads an adjunct into a page by generating a link tag and a script tag to load the JS and CSS files, * respectively. The URLs these tags point to are served by {@link AdjunctManager}. If an HTML file is a part of an adjunct, * its content is just included inline along with script and link tags. This is useful to write a glue to load a large * 3rd party JavaScript libraries without modifying them or changing their names. */ package org.kohsuke.stapler.framework.adjunct; ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/NoSuchAdjunctException.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/NoSuchAdjunct0000664000175000017500000000357612414640747033254 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.framework.adjunct; import java.io.IOException; /** * @author Kohsuke Kawaguchi */ public class NoSuchAdjunctException extends IOException { public NoSuchAdjunctException() { } public NoSuchAdjunctException(String message) { super(message); } public NoSuchAdjunctException(String message, Throwable cause) { super(message); initCause(cause); } public NoSuchAdjunctException(Throwable cause) { super(); initCause(cause); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/0000775000175000017500000000000012414640747026300 5ustar ebourgebourgstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/JellyTagFileLoader.java0000664000175000017500000000423512414640747032611 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.kohsuke.stapler.Facet; import org.apache.commons.jelly.Script; import org.apache.commons.jelly.JellyException; import java.util.List; /** * Extension point that lets Jelly scripts written in other languages. * * @author Kohsuke Kawaguchi */ public abstract class JellyTagFileLoader { /** * Loads a tag file for the given tag library. * * @return null * if this loader didn't find the script. */ public abstract Script load(CustomTagLibrary taglib, String name, ClassLoader classLoader) throws JellyException; /** * Discovers all the facets in the classloader. */ public static List discover(ClassLoader cl) { return Facet.discoverExtensions(JellyTagFileLoader.class,cl); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/RedirectTag.java0000664000175000017500000000455612414640747031352 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerResponse; import org.jvnet.maven.jellydoc.annotation.NoContent; import org.jvnet.maven.jellydoc.annotation.Required; import java.io.IOException; /** * Sends HTTP redirect. * * @author Kohsuke Kawaguchi */ @NoContent public class RedirectTag extends TagSupport { private String url; /** * Sets the target URL to redirect to. This just gets passed * to {@link StaplerResponse#sendRedirect2(String)}. */ @Required public void setUrl(String url) { this.url = url; } public void doTag(XMLOutput output) throws JellyTagException { try { Stapler.getCurrentResponse().sendRedirect2(url); } catch (IOException e) { throw new JellyTagException("Failed to redirect to "+url,e); } } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/CustomTagLibrary.java0000664000175000017500000001311412414640747032376 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyContext; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.Script; import org.apache.commons.jelly.Tag; import org.apache.commons.jelly.TagLibrary; import org.apache.commons.jelly.impl.TagScript; import org.kohsuke.stapler.MetaClass; import org.kohsuke.stapler.MetaClassLoader; import org.xml.sax.Attributes; import java.net.URL; import java.util.Hashtable; import java.util.List; import java.util.Map; /** * {@link TagLibrary} that loads tags from tag files in a directory. * * @author Kohsuke Kawaguchi */ public final class CustomTagLibrary extends TagLibrary { /** * Inherits values from this context. * This context would be shared by multiple threads, * but as long as we all just read it, it should be OK. */ private final JellyContext master; private final ClassLoader classLoader; public final MetaClassLoader metaClassLoader; public final String nsUri; public final String basePath; /** * Compiled tag files. */ private final Map scripts = new Hashtable(); private final List loaders; public CustomTagLibrary(JellyContext master, ClassLoader classLoader, String nsUri, String basePath) { this.master = master; this.classLoader = classLoader; this.nsUri = nsUri; this.basePath = basePath; this.metaClassLoader = MetaClassLoader.get(classLoader); this.loaders = JellyTagFileLoader.discover(classLoader); } public TagScript createTagScript(String name, Attributes attributes) throws JellyException { final Script def = load(name); if(def==null) return null; return new CallTagLibScript() { protected Script resolveDefinition(JellyContext context) { return def; } }; } public Tag createTag(String name, Attributes attributes) throws JellyException { // IIUC, this method is only used by static tag to discover the correct tag at runtime, // and since stapler taglibs are always resolved statically, we shouldn't have to implement this method // at all. // by not implementing this method, we can put all the login in the TagScript-subtype, which eliminates // the need of stateful Tag instances and their overheads. return null; } /** * Obtains the script for the given tag name. Loads if necessary. * *

* Synchronizing this method would have a potential race condition * if two threads try to load two tags that are referencing each other. * *

* So we synchronize {@link #scripts}, even though this means * we may end up compiling the same script twice. */ private Script load(String name) throws JellyException { Script script = scripts.get(name); if(script!=null && !MetaClass.NO_CACHE) return script; script=null; if(MetaClassLoader.debugLoader!=null) script = load(name, MetaClassLoader.debugLoader.loader); if(script==null) script = load(name, classLoader); return script; } private Script load(String name, ClassLoader classLoader) throws JellyException { Script script; // prefer 'foo.jellytag' but for backward compatibility, support the plain .jelly extention as well. URL res = classLoader.getResource(basePath + '/' + name + ".jellytag"); if (res==null) res = classLoader.getResource(basePath + '/' + name + ".jelly"); if(res!=null) { script = loadJellyScript(res); scripts.put(name,script); return script; } for (JellyTagFileLoader loader : loaders) { Script s = loader.load(this, name, classLoader); if(s!=null) { scripts.put(name,s); return s; } } return null; } private Script loadJellyScript(URL res) throws JellyException { // compile script JellyContext context = new CustomJellyContext(master); context.setClassLoader(classLoader); return context.compileScript(res); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/OutTag.java0000664000175000017500000000565012414640747030354 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; import org.apache.commons.jelly.expression.Expression; import org.xml.sax.SAXException; import org.jvnet.maven.jellydoc.annotation.NoContent; import org.jvnet.maven.jellydoc.annotation.Required; /** * Tag that outputs the specified value but with escaping, * so that you can escape a portion even if the * {@link XMLOutput} is not escaping. * * @author Kohsuke Kawaguchi */ @NoContent public class OutTag extends TagSupport { private Expression value; @Required public void setValue(Expression value) { this.value = value; } public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException { final String text = value.evaluateAsString(context); if (text != null) { StringBuilder buf = new StringBuilder(text.length()); for (int i=0; i> taglibs; public static ExpressionFactory EXPRESSION_FACTORY = new JexlExpressionFactory(); public JellyClassLoaderTearOff(MetaClassLoader owner) { this.owner = owner; } public TagLibrary getTagLibrary(String nsUri) { LoadingCache m=null; if(taglibs!=null) m = taglibs.get(); if(m==null) { m = CacheBuilder.newBuilder().build(new CacheLoader() { public TagLibrary load(String nsUri) { if(owner.parent!=null) { // parent first TagLibrary tl = owner.parent.loadTearOff(JellyClassLoaderTearOff.class).getTagLibrary(nsUri); if(tl!=null) return tl; } String taglibBasePath = trimHeadSlash(nsUri); try { URL res = owner.loader.getResource(taglibBasePath +"/taglib"); if(res!=null) return new CustomTagLibrary(createContext(),owner.loader,nsUri,taglibBasePath); } catch (IllegalArgumentException e) { // if taglibBasePath doesn't even look like an URL, getResource throws IllegalArgumentException. // see http://old.nabble.com/bug-1.331-to26145963.html } // support URIs like "this:it" or "this:instance". Note that "this" URI itself is registered elsewhere if (nsUri.startsWith("this:")) try { return new ThisTagLibrary(EXPRESSION_FACTORY.createExpression(nsUri.substring(5))); } catch (JellyException e) { throw new IllegalArgumentException("Illegal expression in the URI: "+nsUri,e); } if (nsUri.equals("jelly:stapler")) return new StaplerTagLibrary(); return NO_SUCH_TAGLIBRARY; // "not found" is also cached. } }); taglibs = new WeakReference>(m); } TagLibrary tl = m.getUnchecked(nsUri); if (tl==NO_SUCH_TAGLIBRARY) return null; return tl; } private String trimHeadSlash(String nsUri) { if(nsUri.startsWith("/")) return nsUri.substring(1); else return nsUri; } /** * Creates {@link JellyContext} for compiling view scripts * for classes in this classloader. */ public JellyContext createContext() { JellyContext context = new CustomJellyContext(ROOT_CONTEXT); context.setClassLoader(owner.loader); context.setExportLibraries(false); return context; } /** * Used as the root context for compiling scripts. */ private static final JellyContext ROOT_CONTEXT = new CustomJellyContext(); /** * Place holder in the cache to indicate "no such taglib" */ private static final TagLibrary NO_SUCH_TAGLIBRARY = new TagLibrary() {}; } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/DoctypeTag.java0000664000175000017500000000445412414640747031215 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.XMLOutput; import org.apache.commons.jelly.JellyTagException; import org.jvnet.maven.jellydoc.annotation.NoContent; import org.jvnet.maven.jellydoc.annotation.Required; import java.io.IOException; /** * Writes out DOCTYPE declaration. * * @author Kohsuke Kawaguchi */ @NoContent public class DoctypeTag extends AbstractStaplerTag { private String publicId; private String systemId; @Required public void setPublicId(String publicId) { this.publicId = publicId; } @Required public void setSystemId(String systemId) { this.systemId = systemId; } public void doTag(XMLOutput output) throws JellyTagException { try { getResponse().getOutputStream().println(""); } catch (IOException e) { throw new JellyTagException(e); } } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/JellyViewScript.java0000664000175000017500000000755212414640747032253 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyContext; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.Script; import org.apache.commons.jelly.XMLOutput; import org.kohsuke.stapler.lang.Klass; import java.net.URL; import java.util.logging.Logger; /** * Represents a loaded Jelly view script that remembers where it came from. * * @author Kohsuke Kawaguchi */ public final class JellyViewScript implements Script { private static final Logger LOGGER = Logger.getLogger(JellyViewScript.class.getName()); /** * Which class is this view loaded from? * @deprecated as of 1.177 * Use {@link #fromKlass} */ public final Class from; public final Klass fromKlass; /** * Full URL that points to the source of the script. */ public final URL source; private Script base; /** * @deprecated as of 1.177 * use {@link #JellyViewScript(Klass, URL, Script)} */ public JellyViewScript(Class from, URL source, Script base) { this.from = from; this.fromKlass = Klass.java(from); this.source = source; this.base = base; } public JellyViewScript(Klass from, URL source, Script base) { this.from = from.toJavaClass(); this.fromKlass = from; this.source = source; this.base = base; } public Script compile() throws JellyException { base = base.compile(); return this; } public void run(JellyContext context, XMLOutput output) throws JellyTagException { Thread t = Thread.currentThread(); String n = t.getName(); // JellyViewScript.getName() is a bit too verbose for this purpose (we do not really need the package prefix): String url = source.toExternalForm(); String c = from.getName(); c = c.substring(c.lastIndexOf('.') + 1); String n2 = n + " " + c.replace('$', '/') + "/" + url.substring(url.lastIndexOf('/') + 1); t.setName(n2); LOGGER.fine(n2); try { base.run(context,output); } finally { t.setName(n); } } public String getName() { // get to the file name portion String url = source.toExternalForm(); url = url.substring(url.lastIndexOf('/') +1); url = url.substring(url.lastIndexOf('\\') +1); return from.getName().replace('.','/').replace('$','/')+'/'+url; } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/IncludeTag.java0000664000175000017500000001316112414640747031164 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyContext; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.Script; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; import org.apache.commons.jelly.impl.TagScript; import org.kohsuke.stapler.MetaClass; import org.kohsuke.stapler.WebApp; import org.xml.sax.SAXException; import org.jvnet.maven.jellydoc.annotation.Required; /** * Tag that includes views of the object. * * @author Kohsuke Kawaguchi */ public class IncludeTag extends TagSupport { private Object it; private String page; private Object from; private boolean optional; private Class clazz; /** * Specifies the name of the JSP to be included. */ @Required public void setPage(String page) { this.page = page; } /** * Specifies the object for which JSP will be included. * Defaults to the "it" object in the current context. */ public void setIt(Object it) { this.it = it; } /** * When loading the script, use the classloader from this object * to locate the script. Otherwise defaults to "it" object. */ public void setFrom(Object from) { this.from = from; } /** * When loading script, load from this class. * * By default this is "from.getClass()". This takes * precedence over the {@link #setFrom(Object)} method. */ public void setClass(Class clazz) { this.clazz = clazz; } /** * If true, not finding the page is not an error. * (And in such a case, the body of the include tag is evaluated instead.) */ public void setOptional(boolean optional) { this.optional = optional; } public void doTag(XMLOutput output) throws JellyTagException { if(page==null) { // this makes it convenient when the caller wants to gracefully the expression for @page // otherwise this results in http://pastie.org/601828 if (optional) { invokeBody(output); return; } throw new JellyTagException("The page attribute is not specified"); } Object it = this.it; if(it==null) it = getContext().getVariable("it"); MetaClass c = WebApp.getCurrent().getMetaClass(getScriptClass(it)); Script script; try { script = c.loadTearOff(JellyClassTearOff.class).findScript(page); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new JellyTagException("Error loading '"+page+"' for "+c.klass,e); } if(script==null) { if(optional) { invokeBody(output); return; } throw new JellyTagException("No page found '"+page+"' for "+c.klass); } context = new JellyContext(getContext()); context.setExportLibraries(false); if(this.it!=null) context.setVariable("it",this.it); context.setVariable("from", from!=null?from:it); ClassLoader old = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(c.classLoader.loader); try { String source = null; if(JellyFacet.TRACE) { if (script instanceof TagScript) { TagScript ts = (TagScript) script; source = ts.getFileName(); } else source = page+" (exact source location unknown)"; String msg = "\nBegin " + source+'\n'; output.comment(msg.toCharArray(),0,msg.length()); } script.run(context,output); if(source!=null) { String msg = "\nEnd " + source+'\n'; output.comment(msg.toCharArray(),0,msg.length()); } } catch (SAXException e) { throw new JellyTagException(e); } finally { Thread.currentThread().setContextClassLoader(old); } } private Class getScriptClass(Object it) { if (clazz != null) return clazz; if (from != null) return from.getClass(); else return it.getClass(); } } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/InternationalizedStringExpression.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/InternationalizedStringEx0000664000175000017500000002024012414640747033370 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.expression.Expression; import org.apache.commons.jelly.expression.ExpressionSupport; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.JellyContext; import org.jvnet.localizer.LocaleProvider; import org.kohsuke.stapler.Stapler; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.Arrays; /** * Expression of the form "%messageName(arg1,arg2,...)" that represents * internationalized text. * *

* The "(arg1,...)" portion is optional and can be ommitted. Each argument * is assumed to be a parenthesis-balanced expression and passed to * {@link JellyClassLoaderTearOff#EXPRESSION_FACTORY} to be parsed. * *

* The message resource is loaded from files like "xyz.properties" and * "xyz_ja.properties" when the expression is placed in "xyz.jelly". * * * @author Kohsuke Kawaguchi */ public class InternationalizedStringExpression extends ExpressionSupport { public final ResourceBundle resourceBundle; private final Expression[] arguments; public final String key; public final String expressionText; public InternationalizedStringExpression(ResourceBundle resourceBundle, String text) throws JellyException { this.resourceBundle = resourceBundle; this.expressionText = text; if(!text.startsWith("%")) throw new JellyException(text+" doesn't start with %"); text = text.substring(1); int idx = text.indexOf('('); if(idx<0) { // no arguments key = text; arguments = EMPTY_ARGUMENTS; return; } List args = new ArrayList(); key = text.substring(0,idx); text = text.substring(idx+1); // at this point text="arg,arg)" while(text.length()>0) { String token = tokenize(text); args.add(JellyClassLoaderTearOff.EXPRESSION_FACTORY.createExpression(token)); text = text.substring(token.length()+1); } this.arguments = args.toArray(new Expression[args.size()]); } public List getArguments() { return Collections.unmodifiableList(Arrays.asList(arguments)); } /** * Takes a string like "arg)" or "arg,arg,...)", then * find "arg" and returns it. * * Note: this code is also copied into idea-stapler-plugin, * so don't forget to update that when this code changes. */ private String tokenize(String text) throws JellyException { int parenthesis=0; for(int idx=0;idx * This tag should be placed right inside {@link DocumentationTag} * to describe attributes of a tag. The body would describe * the meaning of an attribute in a natural language. * The description text can also use * Textile markup * * @author Kohsuke Kawaguchi */ public class AttributeTag extends TagSupport { public void doTag(XMLOutput output) { // noop } /** * Name of the attribute. */ @Required public void setName(String v) {} /** * If the attribute is required, specify use="required". * (This is modeled after XML Schema attribute declaration.) * *

* By default, use="optional" is assumed. */ public void setUse(String v) {} /** * If it makes sense, describe the Java type that the attribute * expects as values. */ public void setType(String v) {} /** * If the attribute is deprecated, set to true. * Use of the deprecated attribute will cause a warning. */ public void setDeprecated(boolean v) {} } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/AdjunctTag.java0000664000175000017500000000662512414640747031200 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.XMLOutput; import org.kohsuke.stapler.framework.adjunct.AdjunctManager; import org.kohsuke.stapler.framework.adjunct.AdjunctsInPage; import org.xml.sax.SAXException; import org.jvnet.maven.jellydoc.annotation.NoContent; import org.jvnet.maven.jellydoc.annotation.Required; import java.io.IOException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Writes out links to adjunct CSS and JavaScript, if not done so already. * * @author Kohsuke Kawaguchi */ @NoContent public class AdjunctTag extends AbstractStaplerTag { private String[] includes; private String[] assumes; /** * Comma-separated adjunct names. */ public void setIncludes(String _includes) { includes = parse(_includes); } /** * Comma-separated adjunct names that are externally included in the page * and should be suppressed. */ public void setAssumes(String _assumes) { assumes = parse(_assumes); } private String[] parse(String s) { String[] r = s.split(","); for (int i = 0; i < r.length; i++) r[i] = r[i].trim(); return r; } public void doTag(XMLOutput out) throws JellyTagException { AdjunctManager m = AdjunctManager.get(getServletContext()); if(m==null) { LOGGER.log(Level.WARNING,"AdjunctManager is not installed for this application. Skipping tags", new Exception()); return; } try { AdjunctsInPage a = AdjunctsInPage.get(); if (assumes!=null) a.assumeIncluded(assumes); if (includes!=null) a.generate(out, includes); } catch (IOException e) { throw new JellyTagException(e); } catch (SAXException e) { throw new JellyTagException(e); } } private static final Logger LOGGER = Logger.getLogger(AdjunctTag.class.getName()); } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/StatusCodeTag.java0000664000175000017500000000410512414640747031655 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.XMLOutput; import org.apache.commons.jelly.JellyTagException; import org.jvnet.maven.jellydoc.annotation.NoContent; import org.jvnet.maven.jellydoc.annotation.Required; /** * Sets HTTP status code. * *

* This is generally useful for programatically creating the error page. * * @author Kohsuke Kawaguchi */ @NoContent public class StatusCodeTag extends AbstractStaplerTag { private int code; /** * HTTP status code to send back. */ @Required public void setValue(int code) { this.code = code; } public void doTag(XMLOutput output) throws JellyTagException { getResponse().setStatus(code); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/IsUserInRoleTag.java0000664000175000017500000000436712414640747032134 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.XMLOutput; import org.jvnet.maven.jellydoc.annotation.Required; import javax.servlet.http.HttpServletRequest; /** * @author Kohsuke Kawaguchi */ public class IsUserInRoleTag extends AbstractStaplerTag { private String role; /** * The name of the role against which the user is checked. */ @Required public void setRole(String role) { this.role = role; } public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException { HttpServletRequest req = getRequest(); // work around http://jira.codehaus.org/browse/JETTY-234 req.getUserPrincipal(); if(req.isUserInRole(role)) getBody().run(getContext(),output); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/AbstractStaplerTag.java0000664000175000017500000000404512414640747032700 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.TagSupport; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author Kohsuke Kawaguchi */ abstract class AbstractStaplerTag extends TagSupport { protected HttpServletRequest getRequest() { return (HttpServletRequest)getContext().getVariable("request"); } protected HttpServletResponse getResponse() { return (HttpServletResponse)getContext().getVariable("response"); } protected ServletContext getServletContext() { return (ServletContext)getContext().getVariable("servletContext"); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/ContentTypeTag.java0000664000175000017500000000462312414640747032060 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.XMLOutput; import org.jvnet.maven.jellydoc.annotation.Required; import org.jvnet.maven.jellydoc.annotation.NoContent; import javax.servlet.http.HttpServletResponse; /** * Set the HTTP Content-Type header of the page. * * @author Kohsuke Kawaguchi */ @NoContent public class ContentTypeTag extends AbstractStaplerTag { private String contentType; /** * The content-type value, such as "text/html". */ @Required public void setValue(String contentType) { this.contentType = contentType; } public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException { HttpServletResponse rsp = getResponse(); if (rsp!=null) rsp.setContentType(contentType); if (output instanceof HTMLWriterOutput) ((HTMLWriterOutput)output).useHTML(contentType.startsWith("text/html")); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/RequiresView.java0000664000175000017500000000442612414640747031603 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Indicates that concrete subtypes must have the views of the specified names. * For example, if your abstract class defines a mandatory view "foo.jelly", write * {@code @RequiresView("foo.jelly")}. * *

* TODO: write a checker that makes sure all the subtypes have required views. * I initially tried to do this in {@link AnnotationProcessorImpl}, but they don't see * resources, so the check needs to be done much later, probably by inspecting the jar file. * * @author Kohsuke Kawaguchi */ @Documented @Retention(RUNTIME) @Target(TYPE) public @interface RequiresView { /** * Names of the view that's required. */ String[] value(); } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/StaplerTagLibrary.java0000664000175000017500000001170012414640747032535 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyContext; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.Script; import org.apache.commons.jelly.TagLibrary; import org.apache.commons.jelly.XMLOutput; import org.apache.commons.jelly.impl.TagScript; import org.xml.sax.Attributes; import javax.servlet.http.HttpServletRequest; import java.util.HashSet; import java.util.Set; /** * @author Kohsuke Kawaguchi */ public class StaplerTagLibrary extends TagLibrary { public StaplerTagLibrary() { registerTag("adjunct",AdjunctTag.class); registerTag("bind",BindTag.class); registerTag("compress",CompressTag.class); registerTag("contentType",ContentTypeTag.class); registerTag("copyStream",CopyStreamTag.class); registerTag("doctype",DoctypeTag.class); registerTag("findAncestor",FindAncestorTag.class); registerTag("header",HeaderTag.class); // deprecated. for compatibility registerTag("addHeader",HeaderTag.class); registerTag("setHeader",SetHeaderTag.class); registerTag("include",IncludeTag.class); registerTag("isUserInRole",IsUserInRoleTag.class); registerTag("nbsp",NbspTag.class); registerTag("out",OutTag.class); registerTag("parentScope",ParentScopeTag.class); registerTag("redirect",RedirectTag.class); registerTag("statusCode",StatusCodeTag.class); registerTag("structuredMessageArgument",StructuredMessageArgumentTag.class); registerTag("structuredMessageFormat",StructuredMessageFormatTag.class); } @Override public TagScript createTagScript(String name, Attributes attributes) throws JellyException { // performance optimization if (name.equals("documentation")) return new TagScript() { public void run(JellyContext context, XMLOutput output) throws JellyTagException { // noop } @Override public void setTagBody(Script tagBody) { // noop, we don't evaluate the body, so don't even keep it in memory. } }; if (name.equals("getOutput")) return new TagScript() { /** * Adds {@link XMLOutput} to the context. */ public void run(JellyContext context, XMLOutput output) throws JellyTagException { context.setVariable(getAttribute("var").evaluateAsString(context),output); } }; if (name.equals("once")) return new TagScript() { /** * Adds {@link XMLOutput} to the context. */ public void run(JellyContext context, XMLOutput output) throws JellyTagException { HttpServletRequest request = (HttpServletRequest)context.getVariable("request"); Set executedScripts = (Set) request.getAttribute(ONCE_TAG_KEY); if(executedScripts==null) request.setAttribute(ONCE_TAG_KEY,executedScripts=new HashSet()); String key = getFileName()+':'+getLineNumber()+':'+getColumnNumber(); if(executedScripts.add(key)) // run it just for the first time getTagBody().run(context,output); } }; return super.createTagScript(name, attributes); } private static final String ONCE_TAG_KEY = "stapler.once"; } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/HTMLWriterOutput.java0000664000175000017500000000632412414640747032332 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.XMLOutput; import org.dom4j.io.HTMLWriter; import org.dom4j.io.OutputFormat; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.io.Writer; /** * Wrapper for XMLOutput using HTMLWriter that can turn off its HTML handling * (if the Content-Type gets set to something other than text/html). * * @author Alan.Harder@Sun.Com */ public class HTMLWriterOutput extends XMLOutput { private HTMLWriter htmlWriter; private OutputFormat format; public static HTMLWriterOutput create(OutputStream out) throws UnsupportedEncodingException { OutputFormat format = createFormat(); return new HTMLWriterOutput(new HTMLWriter(out, format), format, false); } public static HTMLWriterOutput create(Writer out, boolean escapeText) { OutputFormat format = createFormat(); return new HTMLWriterOutput(new HTMLWriter(out, format), format, escapeText); } private static OutputFormat createFormat() { OutputFormat format = new OutputFormat(); format.setXHTML(true); // Only use short close for tags identified by HTMLWriter: format.setExpandEmptyElements(true); return format; } private HTMLWriterOutput(HTMLWriter hw, OutputFormat fmt, boolean escapeText) { super(hw); hw.setEscapeText(escapeText); this.htmlWriter = hw; this.format = fmt; } @Override public void close() throws IOException { htmlWriter.close(); } /** * False to turn off HTML handling and reenable "/>" for any empty XML element. * True to switch back to default mode with HTML handling. */ public void useHTML(boolean enabled) { htmlWriter.setEnabled(enabled); format.setExpandEmptyElements(enabled); } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/ReallyStaticTagLibrary.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/ReallyStaticTagLibrary.ja0000664000175000017500000001477412414640747033212 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyContext; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.Tag; import org.apache.commons.jelly.TagLibrary; import org.apache.commons.jelly.XMLOutput; import org.apache.commons.jelly.expression.ConstantExpression; import org.apache.commons.jelly.expression.Expression; import org.apache.commons.jelly.impl.ExpressionAttribute; import org.apache.commons.jelly.impl.StaticTag; import org.apache.commons.jelly.impl.StaticTagScript; import org.apache.commons.jelly.impl.TagScript; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; /** * Jelly tag library for static tags. * *

* Unlike {@link StaticTagScript}, this doesn't even try to see if the tag name is available as a dynamic tag. * By not doing so, this implementation achieves a better performance both in speed and memory usage. * *

* Jelly by default uses {@link StaticTagScript} instance to represent a tag that's parsed as a static tag, * and for each invocation, this code checks if the tag it represents is now defined as a dynamic tag. * Plus it got the code to cache {@link StaticTag} instances per thread, which consumes more space and time. * * @author Kohsuke Kawaguchi * @since 1.342 */ public class ReallyStaticTagLibrary extends TagLibrary { /** * IIUC, this method will never be invoked. */ @Override public Tag createTag(final String name, Attributes attributes) throws JellyException { return null; } @Override public TagScript createTagScript(String tagName, Attributes atts) throws JellyException { return createTagScript(); } /** * Creates a new instance of {@link TagScript} that generates a literal element. */ public static TagScript createTagScript() { return new TagScript() { /** * If all the attributes are constant, as is often the case with literal tags, * then we can skip the attribute expression evaluation altogether. */ private boolean allAttributesAreConstant = true; @Override public void addAttribute(String name, Expression expression) { allAttributesAreConstant &= expression instanceof ConstantExpression; super.addAttribute(name, expression); } @Override public void addAttribute(String name, String prefix, String nsURI, Expression expression) { allAttributesAreConstant &= expression instanceof ConstantExpression; super.addAttribute(name, prefix, nsURI, expression); } public void run(JellyContext context, XMLOutput output) throws JellyTagException { Attributes actual = (allAttributesAreConstant && !EMIT_LOCATION) ? getSaxAttributes() : buildAttributes(context); try { output.startElement(getNsUri(),getLocalName(),getElementName(),actual); getTagBody().run(context,output); output.endElement(getNsUri(),getLocalName(),getElementName()); } catch (SAXException x) { throw new JellyTagException(x); } } private AttributesImpl buildAttributes(JellyContext context) { AttributesImpl actual = new AttributesImpl(); for (ExpressionAttribute att : attributes.values()) { Expression expression = att.exp; String v = expression.evaluateAsString(context); if (v==null) continue; // treat null as no attribute actual.addAttribute(att.nsURI, att.name, att.qname(),"CDATA", v); } if (EMIT_LOCATION) { actual.addAttribute("","file","file","CDATA",String.valueOf(getFileName())); actual.addAttribute("","line","line","CDATA",String.valueOf(getLineNumber())); // try to obtain the meaningful part of the script and put it in CSS with a // class name like "jelly-foo-bar-xyz" given "file://path/to/src/tree/src/main/resources/foo/bar/xyz.jelly" String form = getFileName().replace('\\','/'); for (String suffix : SUFFIX) { int idx = form.lastIndexOf(suffix); if (idx>0) form=form.substring(idx+suffix.length()); } int c = actual.getIndex("class"); if (c>=0) actual.setValue(c, actual.getValue(c)+" "+form); else actual.addAttribute("","class","class","CDATA",form); } return actual; } }; } /** * Reusable instance. */ public static final TagLibrary INSTANCE = new ReallyStaticTagLibrary(); /** * If true, emit the location information. */ public static boolean EMIT_LOCATION = false; private static final String[] SUFFIX = {"src/main/resources/","src/test/resources/"}; } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/NbspTag.java0000664000175000017500000000403712414640747030505 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; import org.xml.sax.SAXException; import org.jvnet.maven.jellydoc.annotation.NoContent; /** * Writes out '&nbsp;'. * * @author Kohsuke Kawaguchi */ @NoContent public class NbspTag extends TagSupport { public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException { try { output.write("\u00A0"); // nbsp } catch (SAXException e) { throw new JellyTagException(e); } } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/HeaderTag.java0000664000175000017500000000441612414640747030774 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.XMLOutput; import org.jvnet.maven.jellydoc.annotation.NoContent; import org.jvnet.maven.jellydoc.annotation.Required; /** * Adds an HTTP header to the response. * * @author Kohsuke Kawaguchi * @see SetHeaderTag */ @NoContent public class HeaderTag extends AbstractStaplerTag { private String name; private String value; /** * Header name. */ @Required public void setName(String name) { this.name = name; } /** * Header value. */ @Required public void setValue(String value) { this.value = value; } public void doTag(XMLOutput output) throws JellyTagException { if (name==null || value==null) return; getResponse().addHeader(name,value); } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/AnnotationProcessorImpl.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/AnnotationProcessorImpl.j0000664000175000017500000000743012414640747033313 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.kohsuke.MetaInfServices; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementFilter; import javax.tools.Diagnostic.Kind; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * @author Kohsuke Kawaguchi */ @SuppressWarnings({"Since15"}) //@MetaInfServices(Processor.class) public class AnnotationProcessorImpl extends AbstractProcessor { private final Map missingViews = new HashMap(); private static class MissingViews extends HashSet {} @Override public Set getSupportedAnnotationTypes() { return Collections.singleton("*"); } @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) return false; missingViews.clear(); for (TypeElement t : ElementFilter.typesIn(roundEnv.getRootElements())) { check(t); } missingViews.clear(); return false; } private MissingViews check(TypeElement t) { MissingViews r = missingViews.get(t); if (r==null) { r = new MissingViews(); missingViews.put(t,r); r.addAll(check(t.getSuperclass())); for (TypeMirror i : t.getInterfaces()) r.addAll(check(i)); RequiresView a = t.getAnnotation(RequiresView.class); if (a!=null) r.addAll(Arrays.asList(a.value())); if (!r.isEmpty() && !t.getModifiers().contains(Modifier.ABSTRACT)) { processingEnv.getMessager().printMessage(Kind.ERROR, t.getQualifiedName()+" is missing views: "+r,t); } } return r; } private MissingViews check(TypeMirror t) { if (t.getKind()== TypeKind.DECLARED) return check((TypeElement)((DeclaredType)t).asElement()); return EMPTY; } private static final MissingViews EMPTY = new MissingViews(); } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/FindAncestorTag.java0000664000175000017500000000621012414640747032155 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.NamespaceAwareTag; import org.apache.commons.jelly.Tag; import org.apache.commons.jelly.XMLOutput; import org.jvnet.maven.jellydoc.annotation.NoContent; import java.util.Map; /** * Finds the nearest tag (in the call stack) that has the given tag name, * and sets that as a variable. * * @author Kohsuke Kawaguchi */ @NoContent public class FindAncestorTag extends AbstractStaplerTag implements NamespaceAwareTag { private String tag; private String var; private Map nsMap; /** * Variable name to set the discovered {@link Tag} object. */ public void setVar(String var) { this.var = var; } /** * QName of the tag to look for. */ public void setTag(String tag) { this.tag = tag; } public void doTag(XMLOutput output) throws JellyTagException { // I don't think anyone is using this, but if we need to resurrect this, // we need to tweak CustomTagLibrary class and build up the stack of elements being processed. throw new UnsupportedOperationException(); // int idx = tag.indexOf(':'); // String prefix = tag.substring(0,idx); // String localName = tag.substring(idx+1); // // String uri = (String) nsMap.get(prefix); // // Tag tag = this; // while((tag=findAncestorWithClass(tag,StaplerDynamicTag.class))!=null) { // StaplerDynamicTag t = (StaplerDynamicTag)tag; // if(t.getLocalName().equals(localName) && t.getNsUri().equals(uri)) // break; // } // getContext().setVariable(var,tag); } public void setNamespaceContext(Map prefixToUriMap) { this.nsMap = prefixToUriMap; } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/JellyRequestDispatcher.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/JellyRequestDispatcher.ja0000664000175000017500000000544312414640747033261 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.Script; import org.kohsuke.stapler.MetaClass; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.WebApp; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.IOException; /** * @author Kohsuke Kawaguchi */ public final class JellyRequestDispatcher implements RequestDispatcher { private final Object it; private final Script script; private final JellyFacet facet; public JellyRequestDispatcher(Object it, Script script) { this.it = it; this.script = script; facet = WebApp.getCurrent().getFacet(JellyFacet.class); } public void forward(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { try { facet.scriptInvoker.invokeScript( (StaplerRequest)servletRequest, (StaplerResponse)servletResponse, script, it); } catch (JellyTagException e) { throw new ServletException(e); } } public void include(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { forward(servletRequest,servletResponse); } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/StructuredMessageArgumentTag.javastapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/StructuredMessageArgument0000664000175000017500000000431612414640747033403 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.XMLOutput; import java.io.StringWriter; /** * Body is evaluated and is used as an argument for the surrounding <structuredMessageFormat> element. * * @author Kohsuke Kawaguchi */ public class StructuredMessageArgumentTag extends AbstractStaplerTag { public void doTag(XMLOutput output) throws JellyTagException { StructuredMessageFormatTag tag = (StructuredMessageFormatTag)findAncestorWithClass(StructuredMessageFormatTag.class); if(tag == null) throw new JellyTagException("This tag must be enclosed inside a tag" ); StringWriter sw = new StringWriter(); XMLOutput o = XMLOutput.createXMLOutput(sw); invokeBody(o); tag.addArgument(sw); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/CopyStreamTag.java0000664000175000017500000000767312414640747031702 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.XMLOutput; import org.xml.sax.SAXException; import org.jvnet.maven.jellydoc.annotation.NoContent; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; /** * Copies a stream as text. * @author Kohsuke Kawaguchi */ @NoContent public class CopyStreamTag extends AbstractStaplerTag { private Reader in; public void setReader(Reader in) { this.in = in; } public void setInputStream(InputStream in) { this.in = new InputStreamReader(in); } public void setFile(File f) throws FileNotFoundException { this.in = new FileReader(f); } public void setUrl(URL url) throws IOException { setInputStream(url.openStream()); } public void doTag(XMLOutput xmlOutput) throws JellyTagException { if(in==null) // In JEXL, failures evaluate to null, so if the input is meant to be // set from expression, we don't want that evaluation failure to cause // the entire page rendering to fail. return; char[] buf = new char[8192]; int len; try { try { while((len=in.read(buf,0,buf.length))>=0) { int last = 0; for (int i=0; i * For non-trivial web applications, where the performance matters, it is normally a good trade-off to spend * a bit of CPU cycles to compress data. This is because: * *

    *
  • CPU is already 1 or 2 order of magnitude faster than RAM and network. *
  • CPU is getting faster than any other components, such as RAM and network. *
  • Because of the TCP window slow start, on a large latency network, compression makes difference in * the order of 100ms to 1sec to the completion of a request by saving multiple roundtrips. *
* * Stuff rendered by Jelly is predominantly text, so the compression would work well. * * @see http://www.slideshare.net/guest22d4179/latency-trumps-all */ public static boolean COMPRESS_BY_DEFAULT = Boolean.parseBoolean(System.getProperty(DefaultScriptInvoker.class.getName()+".compress","true")); } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/CallTagLibScript.java0000664000175000017500000001327412414640747032275 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyContext; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.Script; import org.apache.commons.jelly.XMLOutput; import org.apache.commons.jelly.expression.Expression; import org.apache.commons.jelly.impl.DynamicTag; import org.apache.commons.jelly.impl.ExpressionAttribute; import org.apache.commons.jelly.impl.TagScript; import org.xml.sax.SAXException; import java.util.HashMap; import java.util.Map; /** * {@link TagScript} that invokes a {@link Script} as a tag. * * @author Kohsuke Kawaguchi */ public abstract class CallTagLibScript extends TagScript { /** * Resolves to the definition of the script to call to. */ protected abstract Script resolveDefinition(JellyContext context) throws JellyTagException; @Override public void run(final JellyContext context, XMLOutput output) throws JellyTagException { // evaluated values of the attributes Map args = new HashMap(attributes.size()); for (Map.Entry e : attributes.entrySet()) { Expression expression = e.getValue().exp; args.put(e.getKey(),expression.evaluate(context)); } // create new context based on current attributes JellyContext newJellyContext = context.newJellyContext(args); newJellyContext.setExportLibraries(false); newJellyContext.setVariable( "attrs", args ); // uses this to discover what to invoke newJellyContext.setVariable("org.apache.commons.jelly.body", new Script() { public Script compile() throws JellyException { return this; } /** * When <d:invokeBody/> is used to call back into the calling script, * the Jelly name resolution rule is in such that the body is evaluated with * the variable scope of the <d:invokeBody/> caller. This is very different * from a typical closure name resolution mechanism, where the body is evaluated * with the variable scope of where the body was created. * *

* More concretely, in Jelly, this often shows up as a problem as inability to * access the "attrs" variable from inside a body, because every {@link DynamicTag} * invocation sets this variable in a new scope. * *

* To counter this effect, this class temporarily restores the original "attrs" * when the body is evaluated. This makes the name resolution of 'attrs' work * like what programmers normally expect. * *

* The same problem also shows up as a lack of local variables — when a tag * calls into the body via <d:invokeBody/>, the invoked body will see all the * variables that are defined in the caller, which is again not what a normal programming language * does. But unfortunately, changing this is too pervasive. */ public void run(JellyContext nestedContext, XMLOutput output) throws JellyTagException { Map m = nestedContext.getVariables(); Object oldAttrs = m.put("attrs",context.getVariable("attrs")); try { getTagBody().run(nestedContext,output); } finally { m.put("attrs",oldAttrs); } } }); newJellyContext.setVariable("org.apache.commons.jelly.body.scope", context); final Script def = resolveDefinition(newJellyContext); if(JellyFacet.TRACE) { try { String source = getSource(); String msg = "<" + source+">"; output.comment(msg.toCharArray(),0,msg.length()); def.run(newJellyContext, output); msg = ""; output.comment(msg.toCharArray(),0,msg.length()); } catch (SAXException e) { throw new JellyTagException(e); } } else { def.run(newJellyContext, output); } } protected String getSource() { return "{jelly:"+getNsUri()+"}:"+getLocalName(); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/package-info.java0000664000175000017500000000303512414640747031470 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ /** * Optional Jelly support, to write views in Jelly. */ @TagLibUri("jelly:stapler") package org.kohsuke.stapler.jelly; import org.jvnet.maven.jellydoc.annotation.TagLibUri;stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/JellyFacet.java0000664000175000017500000001454412414640747031175 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.Script; import org.apache.commons.jelly.expression.ExpressionFactory; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.Dispatcher; import org.kohsuke.stapler.Facet; import org.kohsuke.stapler.MetaClass; import org.kohsuke.stapler.RequestImpl; import org.kohsuke.stapler.ResponseImpl; import org.kohsuke.stapler.TearOffSupport; import org.kohsuke.stapler.lang.Klass; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; /** * {@link Facet} that adds Jelly as the view. * * @author Kohsuke Kawaguchi */ @MetaInfServices(Facet.class) public class JellyFacet extends Facet implements JellyCompatibleFacet { /** * Used to invoke Jelly script. Can be replaced to the custom object. */ public volatile ScriptInvoker scriptInvoker = new DefaultScriptInvoker(); /** * Used to load {@link ResourceBundle}s. */ public volatile ResourceBundleFactory resourceBundleFactory = ResourceBundleFactory.INSTANCE; public void buildViewDispatchers(final MetaClass owner, List dispatchers) { dispatchers.add(new Dispatcher() { final JellyClassTearOff tearOff = owner.loadTearOff(JellyClassTearOff.class); public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException { // check Jelly view String next = req.tokens.peek(); if(next==null) return false; // only match the end of the URL if (req.tokens.countRemainingTokens()>1) return false; // and avoid serving both "foo" and "foo/" as relative URL semantics are drastically different if (req.tokens.endsWithSlash) return false; try { Script script = tearOff.findScript(next+".jelly"); if(script==null) return false; // no Jelly script found req.tokens.next(); if (traceable()) { // Null not expected here String src = next+".jelly"; if (script instanceof JellyViewScript) { JellyViewScript jvs = (JellyViewScript) script; src = jvs.getName(); } trace(req,rsp,"-> %s on <%s>", src, node); } scriptInvoker.invokeScript(req, rsp, script, node); return true; } catch (RuntimeException e) { throw e; } catch (IOException e) { throw e; } catch (Exception e) { throw new ServletException(e); } } public String toString() { return "VIEW.jelly for url=/VIEW"; } }); } public Collection> getClassTearOffTypes() { return TEAROFF_TYPES; } public Collection getScriptExtensions() { return EXTENSION; } public RequestDispatcher createRequestDispatcher(RequestImpl request, Klass type, Object it, String viewName) throws IOException { TearOffSupport mc = request.stapler.getWebApp().getMetaClass(type); return mc.loadTearOff(JellyClassTearOff.class).createDispatcher(it,viewName); } public boolean handleIndexRequest(RequestImpl req, ResponseImpl rsp, Object node, MetaClass nodeMetaClass) throws IOException, ServletException { return nodeMetaClass.loadTearOff(JellyClassTearOff.class).serveIndexJelly(req,rsp,node); } /** * Sets the Jelly {@link ExpressionFactory} to be used to parse views. * *

* This method should be invoked from your implementation of * {@link ServletContextListener#contextInitialized(ServletContextEvent)}. * *

* Once views are parsed, they won't be re-parsed just because you called * this method to override the expression factory. * *

* The primary use case of this feature is to customize the behavior * of JEXL evaluation. */ public static void setExpressionFactory( ServletContextEvent event, ExpressionFactory factory ) { JellyClassLoaderTearOff.EXPRESSION_FACTORY = factory; } /** * This flag will activate the Jelly evaluation trace. * It generates extra comments into HTML, indicating where the fragment was rendered. */ public static boolean TRACE = Boolean.getBoolean("stapler.jelly.trace"); private static final Set> TEAROFF_TYPES = Collections.singleton(JellyClassTearOff.class); private static final Set EXTENSION = Collections.singleton(".jelly"); } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/ParentScopeTag.java0000664000175000017500000000351512414640747032026 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; /** * Executes the body in the parent scope. * This is useful for creating a 'local' scope. * * @author Kohsuke Kawaguchi */ public class ParentScopeTag extends TagSupport { public void doTag(XMLOutput output) throws JellyTagException { getBody().run(context.getParent(), output); } } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/CustomJellyContext.java0000664000175000017500000001715712414640747032775 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.parser.XMLParser; import org.apache.commons.jelly.expression.ExpressionFactory; import org.apache.commons.jelly.expression.Expression; import org.apache.commons.jelly.expression.ExpressionSupport; import org.apache.commons.jelly.JellyContext; import org.apache.commons.jelly.JellyException; import org.apache.commons.jelly.TagLibrary; import org.kohsuke.stapler.MetaClassLoader; import java.net.URL; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.Map; import java.util.HashMap; /** * {@link XMLParser} that uses {@link JellyClassLoaderTearOff#EXPRESSION_FACTORY} * for expression parsing. * * @author Kohsuke Kawaguchi */ class CustomJellyContext extends JellyContext { private JellyClassLoaderTearOff jclt; CustomJellyContext() { init(); } CustomJellyContext(URL url) { super(url); init(); } CustomJellyContext(URL url, URL url1) { super(url, url1); init(); } CustomJellyContext(JellyContext jellyContext) { super(jellyContext); init(); } CustomJellyContext(JellyContext jellyContext, URL url) { super(jellyContext, url); init(); } CustomJellyContext(JellyContext jellyContext, URL url, URL url1) { super(jellyContext, url, url1); init(); } private void init() { // by not allowing the empty namespace URI "" to be handled as dynamic tags, // we achieve substantial performance improvement. registerTagLibrary("",ReallyStaticTagLibrary.INSTANCE); registerTagLibrary("this",ThisTagLibrary.INSTANCE); } @Override protected XMLParser createXMLParser() { return new CustomXMLParser(); } @Override public void setClassLoader(ClassLoader classLoader) { super.setClassLoader(classLoader); jclt = MetaClassLoader.get(classLoader).loadTearOff(JellyClassLoaderTearOff.class); } @Override public TagLibrary getTagLibrary(String namespaceURI) { TagLibrary tl = super.getTagLibrary(namespaceURI); // delegate to JellyClassLoaderTearOff for taglib handling if(tl==null && jclt!=null) { tl = jclt.getTagLibrary(namespaceURI); if (tl!=null) registerTagLibrary(namespaceURI,tl); } return tl; } private static class CustomXMLParser extends XMLParser implements ExpressionFactory { private ResourceBundle resourceBundle; @Override protected ExpressionFactory createExpressionFactory() { return this; } public Expression createExpression(final String text) throws JellyException { if(text.startsWith("%")) { // this is a message resource reference return createI18nExp(text); } else { Matcher m = RESOURCE_LITERAL_STRING.matcher(text); if(m.find()) { // contains the resource literal, so pre-process them. final StringBuilder buf = new StringBuilder(); final Map resourceLiterals = new HashMap(); int e=0; do { // copy the text preceding the match buf.append(text.substring(e,m.start())); String varName = "__resourceLiteral__"+resourceLiterals.size()+"__"; InternationalizedStringExpression exp = createI18nExp(unquote(m.group())); resourceLiterals.put(varName,exp); // replace the literal by the evaluation buf.append(varName).append(".evaluate(context)"); e = m.end(); } while(m.find()); buf.append(text.substring(e)); return new I18nExpWithArgsExpression(text, resourceLiterals, buf.toString()); } return JellyClassLoaderTearOff.EXPRESSION_FACTORY.createExpression(text); } } private InternationalizedStringExpression createI18nExp(String text) throws JellyException { return new InternationalizedStringExpression(getResourceBundle(),text); } @Override protected Expression createEscapingExpression(Expression exp) { if ( exp instanceof InternationalizedStringExpression) { InternationalizedStringExpression i18nexp = (InternationalizedStringExpression) exp; return i18nexp.makeEscapingExpression(); } return super.createEscapingExpression(exp); } private String unquote(String s) { return s.substring(1,s.length()-1); } private ResourceBundle getResourceBundle() { if(resourceBundle==null) resourceBundle = ResourceBundle.load(locator.getSystemId()); return resourceBundle; } /** * {@link Expression} that handles things like "%foo(a,b,c)" */ private static class I18nExpWithArgsExpression extends ExpressionSupport { final Expression innerExpression; private final String text; private final Map resourceLiterals; public I18nExpWithArgsExpression(String text, Map resourceLiterals, String exp) throws JellyException { this.text = text; this.resourceLiterals = resourceLiterals; innerExpression = JellyClassLoaderTearOff.EXPRESSION_FACTORY.createExpression(exp); } public String getExpressionText() { return text; } public Object evaluate(JellyContext context) { context = new CustomJellyContext(context); context.setVariables(resourceLiterals); return innerExpression.evaluate(context); } } } // "%...." string literal that starts with '%' private static final Pattern RESOURCE_LITERAL_STRING = Pattern.compile("(\"%[^\"]+\")|('%[^']+')"); }stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/JellyCompatibleFacet.java0000664000175000017500000000116612414640747033171 0ustar ebourgebourgpackage org.kohsuke.stapler.jelly; import org.apache.commons.jelly.Script; import org.kohsuke.stapler.AbstractTearOff; import org.kohsuke.stapler.Facet; import java.util.Collection; /** * {@link Facet} subtype (although not captured in a type hierarchy) that loads Jelly-compatible scripts. * * @author Kohsuke Kawaguchi */ public interface JellyCompatibleFacet { /** * */ Collection>> getClassTearOffTypes(); /** * Gets the list of view script extensions, such as ".jelly". */ Collection getScriptExtensions(); } stapler-stapler-parent-1.231/jelly/src/main/java/org/kohsuke/stapler/jelly/BindTag.java0000664000175000017500000001215012414640747030452 0ustar ebourgebourg/* * Copyright (c) 2004-2010, Kohsuke Kawaguchi * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 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. * * 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. */ package org.kohsuke.stapler.jelly; import org.apache.commons.jelly.JellyTagException; import org.apache.commons.jelly.XMLOutput; import org.jvnet.maven.jellydoc.annotation.NoContent; import org.jvnet.maven.jellydoc.annotation.Required; import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.bind.Bound; import org.kohsuke.stapler.framework.adjunct.AdjunctsInPage; import org.xml.sax.SAXException; /** * Binds a server-side object to client side so that JavaScript can call into server. * This tag evaluates to a <script> tag. * * @author Kohsuke Kawaguchi */ @NoContent public class BindTag extends AbstractStaplerTag { private String varName; private Object javaObject; /** * JavaScript variable name to set the proxy to. *

* This name can be arbitrary left hand side expression, * such as "a[0]" or "a.b.c". * * If this value is unspecified, the tag generates a JavaScript expression to create a proxy. */ public void setVar(String varName) { this.varName = varName; } @Required public void setValue(Object o) { this.javaObject = o; } public void doTag(XMLOutput out) throws JellyTagException { // make sure we get the supporting script in place ensureDependencies(out); AdjunctTag a = new AdjunctTag(); a.setContext(getContext()); a.setIncludes("org.kohsuke.stapler.bind"); a.doTag(out); try { String expr; if (javaObject==null) { expr = "null"; } else { Bound h = WebApp.getCurrent().boundObjectTable.bind(javaObject); expr = h.getProxyScript(); } if (varName==null) { // this mode (of writing just the expression) needs to be used with caution because // the adjunct tag above might produce HTML end def test_erb_in_style assert_equal(< foo { bar: <%= "baz" %>; } HTML end def test_erb_in_line assert_equal 'foo bar #{baz}', render_erb('foo bar <%= baz %>') assert_equal 'foo bar #{baz}! Bang.', render_erb('foo bar <%= baz %>! Bang.') end def test_erb_multi_in_line assert_equal('foo bar #{baz}! Bang #{bop}.', render_erb('foo bar <%= baz %>! Bang <%= bop %>.')) assert_equal('foo bar #{baz}#{bop}!', render_erb('foo bar <%= baz %><%= bop %>!')) end def test_erb_with_html_special_chars assert_equal '= 3 < 5 ? "OK" : "Your computer is b0rken"', render_erb('<%= 3 < 5 ? "OK" : "Your computer is b0rken" %>') end def test_erb_in_class_attribute assert_equal "%div{:class => dyna_class} I have a dynamic attribute", render_erb('

I have a dynamic attribute
') end def test_erb_in_id_attribute assert_equal "%div{:id => dyna_id} I have a dynamic attribute", render_erb('
I have a dynamic attribute
') end def test_erb_in_attribute_results_in_string_interpolation assert_equal('%div{:id => "item_#{i}"} Ruby string interpolation FTW', render_erb('
Ruby string interpolation FTW
')) end def test_erb_in_attribute_with_trailing_content assert_equal('%div{:class => "#{12}!"} Bang!', render_erb('
Bang!
')) end def test_erb_in_html_escaped_attribute assert_equal '%div{:class => "foo"} Bang!', render_erb('
">Bang!
') end def test_erb_in_attribute_to_multiple_interpolations assert_equal('%div{:class => "#{12} + #{13}"} Math is super', render_erb('
Math is super
')) end def test_whitespace_eating_erb_tags assert_equal '- form_for', render_erb('<%- form_for -%>') end def test_interpolation_in_erb assert_equal('= "Foo #{bar} baz"', render_erb('<%= "Foo #{bar} baz" %>')) end def test_interpolation_in_erb_attrs assert_equal('%p{:foo => "#{bar} baz"}', render_erb('

">

')) end def test_multiline_erb_silent_script assert_equal(< <% foo bar baz %>

foo

ERB end def test_multiline_erb_loud_script assert_equal(< <%= foo + bar.baz.bang + baz %>

foo

ERB end def test_weirdly_indented_multiline_erb_loud_script assert_equal(< <%= foo + bar.baz.bang + baz %>

foo

ERB end def test_two_multiline_erb_loud_scripts assert_equal(< <%= foo + bar.baz.bang + baz %> <%= foo.bar do bang end %>

foo

ERB end def test_multiline_then_single_line_erb_loud_scripts assert_equal(< <%= foo + bar.baz.bang + baz %> <%= foo.bar %>

foo

ERB end def test_multiline_erb_but_really_single_line assert_equal(< <%= foo %>

foo

ERB end ### Block Parsing def test_block_parsing assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_args assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_equals assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_modified_end assert_equal(< blah <% end.bip %> ERB end def test_block_parsing_with_modified_end_with_block assert_equal(< blah <% end.bip do %> brang <% end %> ERB end def test_multiline_block_opener assert_equal(< foo <% end %> ERB end def test_if_elsif_else_parsing assert_equal(<

bar

<% elsif bar.foo("zip") %>
baz
<% else %> bibble <% end %> ERB end def test_case_when_parsing assert_equal(< <% when "bip" %>

bip

<% when "bop" %>

BOP

<% when bizzle.bang.boop.blip %> BIZZLE BANG BOOP BLIP <% end %> ERB assert_equal(<

bip

<% when "bop" %>

BOP

<% when bizzle.bang.boop.blip %> BIZZLE BANG BOOP BLIP <% end %> ERB end def test_begin_rescue_ensure assert_equal(< e %p b - ensure %p c HAML <% begin %>

a

<% rescue FooException => e %>

b

<% ensure %>

c

<% end %> ERB end # Regression def test_tag_inside_block assert_equal(< <% foo.each do %> <% end %> ERB end def test_silent_inside_block_inside_tag assert_equal(< <% foo.each do %> <% haml_puts "foo" %> <% end %> ERB end end ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/html2haml_test.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/html2haml_test.r0000775000175000017500000001676412414640747032471 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/html2haml/erb_tests' require 'haml/html' class Html2HamlTest < Test::Unit::TestCase def test_empty_render_should_remain_empty assert_equal '', render('') end def test_doctype assert_equal '!!!', render("") assert_equal '!!! 1.1', render('') assert_equal '!!! Strict', render('') assert_equal '!!! Frameset', render('') assert_equal '!!! Mobile 1.2', render('') assert_equal '!!! Basic 1.1', render('') assert_equal '!!!', render('') assert_equal '!!! Strict', render('') assert_equal '!!! Frameset', render('') assert_equal '!!!', render('') end def test_id_and_class_should_be_removed_from_hash assert_equal '%span#foo.bar', render(' ') end def test_no_tag_name_for_div_if_class_or_id_is_present assert_equal '#foo', render('
') assert_equal '.foo', render('
') end def test_multiple_class_names assert_equal '.foo.bar.baz', render('
') end def test_should_have_pretty_attributes assert_equal('%input{:name => "login", :type => "text"}/', render('')) assert_equal('%meta{:content => "text/html", "http-equiv" => "Content-Type"}/', render('')) end def test_class_with_dot_and_hash assert_equal('%div{:class => "foo.bar"}', render("
")) assert_equal('%div{:class => "foo#bar"}', render("
")) assert_equal('.foo.bar{:class => "foo#bar foo.bar"}', render("
")) end def test_id_with_dot_and_hash assert_equal('%div{:id => "foo.bar"}', render("
")) assert_equal('%div{:id => "foo#bar"}', render("
")) end def test_interpolation assert_equal('Foo \#{bar} baz', render('Foo #{bar} baz')) end def test_interpolation_in_attrs assert_equal('%p{:foo => "\#{bar} baz"}', render('

')) end def test_cdata assert_equal(<
flop
HAML

flop
]]>

HTML end def test_self_closing_tag assert_equal("%foo/", render("")) end def test_inline_text assert_equal("%p foo", render("

foo

")) end def test_inline_comment assert_equal("/ foo", render("")) assert_equal(<

bar

HTML end def test_non_inline_comment assert_equal(< HTML end def test_non_inline_text assert_equal(< foo

HTML assert_equal(< foo

HTML assert_equal(<foo

HTML end def test_script_tag assert_equal(< function foo() { return "12" & "13"; } HTML end def test_script_tag_with_cdata assert_equal(< HTML end def test_pre assert_equal(<foo bar baz HTML end def test_pre_code assert_equal(<foo bar baz HTML end def test_code_without_pre assert_equal(<foo bar baz HTML end def test_conditional_comment assert_equal(< bar baz HTML end def test_style_to_css_filter assert_equal(< foo { bar: baz; } HTML end def test_inline_conditional_comment assert_equal(< bar baz HTML end def test_minus_in_tag assert_equal("%p - foo bar -", render("

- foo bar -

")) end def test_equals_in_tag assert_equal("%p = foo bar =", render("

= foo bar =

")) end def test_hash_in_tag assert_equal("%p # foo bar #", render("

# foo bar #

")) end def test_comma_post_tag assert_equal(< Foo , %span bar Foo %span> bar , %span baz HAML
Foo, bar Foobar, baz
HTML end def test_comma_post_tag_with_text_before assert_equal(< Batch Foo, Bar HTML end begin require 'haml/html/erb' include ErbTests rescue LoadError => e puts "\n** Couldn't require #{e.message[/-- (.*)$/, 1]}, skipping some tests" end # Encodings unless Haml::Util.ruby1_8? def test_encoding_error render("foo\nbar\nb\xFEaz".force_encoding("utf-8")) assert(false, "Expected exception") rescue Haml::Error => e assert_equal(3, e.line) assert_equal('Invalid UTF-8 character "\xFE"', e.message) end def test_ascii_incompatible_encoding_error template = "foo\nbar\nb_z".encode("utf-16le") template[9] = "\xFE".force_encoding("utf-16le") render(template) assert(false, "Expected exception") rescue Haml::Error => e assert_equal(3, e.line) assert_equal('Invalid UTF-16LE character "\xFE"', e.message) end end # Regression Tests def test_xhtml_strict_doctype assert_equal('!!! Strict', render(< HTML end protected def render(text, options = {}) Haml::HTML.new(text, options).render.rstrip end def render_erb(text) render(text, :erb => true) end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/helper_test.rb0000775000175000017500000003201712414640747032207 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' class ActionView::Base def nested_tag content_tag(:span) {content_tag(:div) {"something"}} end def wacky_form form_tag("/foo") {"bar"} end end module Haml::Helpers def something_that_uses_haml_concat haml_concat('foo').to_s end end class HelperTest < Test::Unit::TestCase Post = Struct.new('Post', :body, :error_field, :errors) class PostErrors def on(name) return unless name == 'error_field' ["Really bad error"] end alias_method :full_messages, :on def [](name) on(name) || [] end end def setup @base = ActionView::Base.new @base.controller = ActionController::Base.new if defined?(ActionController::Response) # This is needed for >=3.0.0 @base.controller.response = ActionController::Response.new end @base.instance_variable_set('@post', Post.new("Foo bar\nbaz", nil, PostErrors.new)) end def render(text, options = {}) if options == :action_view @base.render :inline => text, :type => :haml else scope = options.delete :scope_object Haml::Engine.new(text, options).to_html(scope ? scope : Object.new) end end def test_flatten assert_equal("FooBar", Haml::Helpers.flatten("FooBar")) assert_equal("FooBar", Haml::Helpers.flatten("Foo\rBar")) assert_equal("Foo Bar", Haml::Helpers.flatten("Foo\nBar")) assert_equal("Hello World! YOU ARE FLAT? OMGZ!", Haml::Helpers.flatten("Hello\nWorld!\nYOU ARE \rFLAT?\n\rOMGZ!")) end def test_list_of_should_render_correctly assert_equal("
  • 1
  • \n
  • 2
  • \n", render("= list_of([1, 2]) do |i|\n = i")) assert_equal("
  • [1]
  • \n", render("= list_of([[1]]) do |i|\n = i.inspect")) assert_equal("
  • \n

    Fee

    \n

    A word!

    \n
  • \n
  • \n

    Fi

    \n

    A word!

    \n
  • \n
  • \n

    Fo

    \n

    A word!

    \n
  • \n
  • \n

    Fum

    \n

    A word!

    \n
  • \n", render("= list_of(['Fee', 'Fi', 'Fo', 'Fum']) do |title|\n %h1= title\n %p A word!")) end def test_buffer_access assert(render("= buffer") =~ /#/) assert_equal(render("= (buffer == _hamlout)"), "true\n") end def test_tabs assert_equal("foo\n bar\nbaz\n", render("foo\n- tab_up\nbar\n- tab_down\nbaz")) assert_equal("

    tabbed

    \n", render("- buffer.tabulation=5\n%p tabbed")) end def test_with_tabs assert_equal(< "<%= flatten('Foo\\nBar') %>") rescue NoMethodError, Haml::Util.av_template_class(:Error) proper_behavior = true end assert(proper_behavior) begin ActionView::Base.new.render(:inline => "<%= concat('foo') %>") rescue ArgumentError, NameError proper_behavior = true end assert(proper_behavior) end def test_action_view_included assert(Haml::Helpers.action_view?) end def test_form_tag # This is usually provided by ActionController::Base. def @base.protect_against_forgery?; false; end assert_equal(<#{rails_form_opener}

    bar

    baz HTML #{rails_block_helper_char} form_tag 'foo' do %p bar %strong baz HAML end def test_text_area assert_equal(%(\n), render('= text_area_tag "body", "Foo\nBar\n Baz\n Boom"', :action_view)) assert_equal(%(\n), render('= text_area :post, :body', :action_view)) assert_equal(%(
    Foo bar
       baz
    \n), render('= content_tag "pre", "Foo bar\n baz"', :action_view)) end def test_capture_haml assert_equal(<13

    \\n" HTML - (foo = capture_haml(13) do |a| %p= a - end; nil) = foo.dump HAML end def test_content_tag_block assert_equal(<

    bar

    bar HTML #{rails_block_helper_char} content_tag :div do %p bar %strong bar HAML end def test_content_tag_error_wrapping def @base.protect_against_forgery?; false; end error_class = Haml::Util.ap_geq_3? ? "field_with_errors" : "fieldWithErrors" assert_equal(<#{rails_form_opener}
    HTML #{rails_block_helper_char} form_for #{form_for_calling_convention('post')}, :url => '' do |f| = f.label 'error_field' HAML end def test_form_tag_in_helper_with_string_block def @base.protect_against_forgery?; false; end assert_equal(<#{rails_form_opener}bar HTML #{rails_block_helper_char} wacky_form HAML end def test_haml_tag_name_attribute_with_id assert_equal("

    \n", render("- haml_tag 'p#some_id'")) end def test_haml_tag_name_attribute_with_colon_id assert_equal("

    \n", render("- haml_tag 'p#some:id'")) end def test_haml_tag_without_name_but_with_id assert_equal("
    \n", render("- haml_tag '#some_id'")) end def test_haml_tag_without_name_but_with_class assert_equal("
    \n", render("- haml_tag '.foo'")) end def test_haml_tag_without_name_but_with_colon_class assert_equal("
    \n", render("- haml_tag '.foo:bar'")) end def test_haml_tag_name_with_id_and_class assert_equal("

    \n", render("- haml_tag 'p#some_id.foo'")) end def test_haml_tag_name_with_class assert_equal("

    \n", render("- haml_tag 'p.foo'")) end def test_haml_tag_name_with_class_and_id assert_equal("

    \n", render("- haml_tag 'p.foo#some_id'")) end def test_haml_tag_name_with_id_and_multiple_classes assert_equal("

    \n", render("- haml_tag 'p#some_id.foo.bar'")) end def test_haml_tag_name_with_multiple_classes_and_id assert_equal("

    \n", render("- haml_tag 'p.foo.bar#some_id'")) end def test_haml_tag_name_and_attribute_classes_merging assert_equal("

    \n", render("- haml_tag 'p#some_id.foo', :class => 'bar'")) end def test_haml_tag_name_and_attribute_classes_merging assert_equal("

    \n", render("- haml_tag 'p.foo', :class => 'bar'")) end def test_haml_tag_name_merges_id_and_attribute_id assert_equal("

    \n", render("- haml_tag 'p#foo', :id => 'bar'")) end def test_haml_tag_attribute_html_escaping assert_equal("

    baz

    \n", render("%p{:id => 'foo&bar'} baz", :escape_html => true)) end def test_haml_tag_autoclosed_tags_are_closed assert_equal("
    \n", render("- haml_tag :br, :class => 'foo'")) end def test_haml_tag_with_class_array assert_equal("

    foo

    \n", render("- haml_tag :p, 'foo', :class => %w[a b]")) assert_equal("

    foo

    \n", render("- haml_tag 'p.c.d', 'foo', :class => %w[a b]")) end def test_haml_tag_with_id_array assert_equal("

    foo

    \n", render("- haml_tag :p, 'foo', :id => %w[a b]")) assert_equal("

    foo

    \n", render("- haml_tag 'p#c', 'foo', :id => %w[a b]")) end def test_haml_tag_with_data_hash assert_equal("

    foo

    \n", render("- haml_tag :p, 'foo', :data => {:foo => 'bar', :baz => true}")) end def test_haml_tag_non_autoclosed_tags_arent_closed assert_equal("

    \n", render("- haml_tag :p")) end def test_haml_tag_renders_text_on_a_single_line assert_equal("

    #{'a' * 100}

    \n", render("- haml_tag :p, 'a' * 100")) end def test_haml_tag_raises_error_for_multiple_content assert_raise(Haml::Error) { render("- haml_tag :p, 'foo' do\n bar") } end def test_haml_tag_flags assert_equal("

    \n", render("- haml_tag :p, :/")) assert_equal("

    kumquat

    \n", render("- haml_tag :p, :< do\n kumquat")) assert_raise(Haml::Error) { render("- haml_tag :p, 'foo', :/") } assert_raise(Haml::Error) { render("- haml_tag :p, :/ do\n foo") } end def test_haml_tag_error_return assert_raise(Haml::Error) { render("= haml_tag :p") } end def test_haml_tag_with_multiline_string assert_equal(< foo bar baz

    HTML - haml_tag :p, "foo\\nbar\\nbaz" HAML end def test_haml_concat_with_multiline_string assert_equal(< foo bar baz

    HTML %p - haml_concat "foo\\nbar\\nbaz" HAML end def test_haml_tag_with_ugly assert_equal(< true))

    Hi!

    HTML - haml_tag :p do - haml_tag :strong, "Hi!" HAML end def test_is_haml assert(!ActionView::Base.new.is_haml?) assert_equal("true\n", render("= is_haml?")) assert_equal("true\n", render("= is_haml?", :action_view)) assert_equal("false", @base.render(:inline => '<%= is_haml? %>')) assert_equal("false\n", render("= render :inline => '<%= is_haml? %>'", :action_view)) end def test_page_class controller = Struct.new(:controller_name, :action_name).new('troller', 'tion') scope = Struct.new(:controller).new(controller) result = render("%div{:class => page_class} MyDiv", :scope_object => scope) expected = "
    MyDiv
    \n" assert_equal expected, result end def test_indented_capture prior = Haml::Util.ap_geq_3? ? "" : " \n" assert_equal("#{prior} Foo\n ", @base.render(:inline => " <% res = capture do %>\n Foo\n <% end %><%= res %>")) end def test_capture_deals_properly_with_collections Haml::Helpers.module_eval do def trc(collection, &block) collection.each do |record| haml_concat capture_haml(record, &block) end end end assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect")) end def test_find_and_preserve_with_block assert_equal("
    Foo
    Bar
    \nFoo\nBar\n", render("= find_and_preserve do\n %pre\n Foo\n Bar\n Foo\n Bar")) end def test_find_and_preserve_with_block_and_tags assert_equal("
    Foo\nBar
    \nFoo\nBar\n", render("= find_and_preserve([]) do\n %pre\n Foo\n Bar\n Foo\n Bar")) end def test_preserve_with_block assert_equal("
    Foo
    Bar
    Foo Bar\n", render("= preserve do\n %pre\n Foo\n Bar\n Foo\n Bar")) end def test_init_haml_helpers context = Object.new class << context include Haml::Helpers end context.init_haml_helpers result = context.capture_haml do context.haml_tag :p, :attr => "val" do context.haml_concat "Blah" end end assert_equal("

    \n Blah\n

    \n", result) end def test_non_haml assert_equal("false\n", render("= non_haml { is_haml? }")) end def test_content_tag_nested assert_equal "
    something
    ", render("= nested_tag", :action_view).strip end def test_error_return assert_raise(Haml::Error, < e assert_equal 2, e.backtrace[1].scan(/:(\d+)/).first.first.to_i end def test_error_return_line_in_helper render("- something_that_uses_haml_concat") assert false, "Expected Haml::Error" rescue Haml::Error => e assert_equal 16, e.backtrace[0].scan(/:(\d+)/).first.first.to_i end class ActsLikeTag # We want to be able to have people include monkeypatched ActionView helpers # without redefining is_haml?. # This is accomplished via Object#is_haml?, and this is a test for it. include ActionView::Helpers::TagHelper def to_s content_tag :p, 'some tag content' end end def test_random_class_includes_tag_helper assert_equal "

    some tag content

    ", ActsLikeTag.new.to_s end def test_capture_with_nuke_outer assert_equal "
    \n*
    hi there!
    \n", render(< hi there! HAML assert_equal "
    \n*
    hi there!
    \n", render(< hi there! HAML end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/util_test.rb0000775000175000017500000002137212414640747031707 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' require 'pathname' class UtilTest < Test::Unit::TestCase include Haml::Util class Dumpable attr_reader :arr def initialize; @arr = []; end def _before_dump; @arr << :before; end def _after_dump; @arr << :after; end def _around_dump @arr << :around_before yield @arr << :around_after end def _after_load; @arr << :loaded; end end def test_scope assert(File.exist?(scope("Rakefile"))) end def test_to_hash assert_equal({ :foo => 1, :bar => 2, :baz => 3 }, to_hash([[:foo, 1], [:bar, 2], [:baz, 3]])) end def test_map_keys assert_equal({ "foo" => 1, "bar" => 2, "baz" => 3 }, map_keys({:foo => 1, :bar => 2, :baz => 3}) {|k| k.to_s}) end def test_map_vals assert_equal({ :foo => "1", :bar => "2", :baz => "3" }, map_vals({:foo => 1, :bar => 2, :baz => 3}) {|k| k.to_s}) end def test_map_hash assert_equal({ "foo" => "1", "bar" => "2", "baz" => "3" }, map_hash({:foo => 1, :bar => 2, :baz => 3}) {|k, v| [k.to_s, v.to_s]}) end def test_powerset return unless Set[Set[]] == Set[Set[]] # There's a bug in Ruby 1.8.6 that breaks nested set equality assert_equal([[].to_set].to_set, powerset([])) assert_equal([[].to_set, [1].to_set].to_set, powerset([1])) assert_equal([[].to_set, [1].to_set, [2].to_set, [1, 2].to_set].to_set, powerset([1, 2])) assert_equal([[].to_set, [1].to_set, [2].to_set, [3].to_set, [1, 2].to_set, [2, 3].to_set, [1, 3].to_set, [1, 2, 3].to_set].to_set, powerset([1, 2, 3])) end def test_restrict assert_equal(0.5, restrict(0.5, 0..1)) assert_equal(1, restrict(2, 0..1)) assert_equal(1.3, restrict(2, 0..1.3)) assert_equal(0, restrict(-1, 0..1)) end def test_merge_adjacent_strings assert_equal(["foo bar baz", :bang, "biz bop", 12], merge_adjacent_strings(["foo ", "bar ", "baz", :bang, "biz", " bop", 12])) str = "foo" assert_equal(["foo foo foo", :bang, "foo foo", 12], merge_adjacent_strings([str, " ", str, " ", str, :bang, str, " ", str, 12])) end def test_intersperse assert_equal(["foo", " ", "bar", " ", "baz"], intersperse(%w[foo bar baz], " ")) assert_equal([], intersperse([], " ")) end def test_substitute assert_equal(["foo", "bar", "baz", 3, 4], substitute([1, 2, 3, 4], [1, 2], ["foo", "bar", "baz"])) assert_equal([1, "foo", "bar", "baz", 4], substitute([1, 2, 3, 4], [2, 3], ["foo", "bar", "baz"])) assert_equal([1, 2, "foo", "bar", "baz"], substitute([1, 2, 3, 4], [3, 4], ["foo", "bar", "baz"])) assert_equal([1, "foo", "bar", "baz", 2, 3, 4], substitute([1, 2, 2, 2, 3, 4], [2, 2], ["foo", "bar", "baz"])) end def test_strip_string_array assert_equal(["foo ", " bar ", " baz"], strip_string_array([" foo ", " bar ", " baz "])) assert_equal([:foo, " bar ", " baz"], strip_string_array([:foo, " bar ", " baz "])) assert_equal(["foo ", " bar ", :baz], strip_string_array([" foo ", " bar ", :baz])) end def test_paths assert_equal([[1, 3, 5], [2, 3, 5], [1, 4, 5], [2, 4, 5]], paths([[1, 2], [3, 4], [5]])) assert_equal([[]], paths([])) assert_equal([[1, 2, 3]], paths([[1], [2], [3]])) end def test_lcs assert_equal([1, 2, 3], lcs([1, 2, 3], [1, 2, 3])) assert_equal([], lcs([], [1, 2, 3])) assert_equal([], lcs([1, 2, 3], [])) assert_equal([1, 2, 3], lcs([5, 1, 4, 2, 3, 17], [0, 0, 1, 2, 6, 3])) assert_equal([1], lcs([1, 2, 3, 4], [4, 3, 2, 1])) assert_equal([1, 2], lcs([1, 2, 3, 4], [3, 4, 1, 2])) end def test_lcs_with_block assert_equal(["1", "2", "3"], lcs([1, 4, 2, 5, 3], [1, 2, 3]) {|a, b| a == b && a.to_s}) assert_equal([-4, 2, 8], lcs([-5, 3, 2, 8], [-4, 1, 8]) {|a, b| (a - b).abs <= 1 && [a, b].max}) end def test_silence_warnings old_stderr, $stderr = $stderr, StringIO.new warn "Out" assert_equal("Out\n", $stderr.string) silence_warnings {warn "In"} assert_equal("Out\n", $stderr.string) ensure $stderr = old_stderr end def test_haml_warn assert_warning("Foo!") {haml_warn "Foo!"} end def test_silence_haml_warnings old_stderr, $stderr = $stderr, StringIO.new silence_haml_warnings {warn "Out"} assert_equal("Out\n", $stderr.string) silence_haml_warnings {haml_warn "In"} assert_equal("Out\n", $stderr.string) ensure $stderr = old_stderr end def test_has assert(has?(:instance_method, String, :chomp!)) assert(has?(:private_instance_method, Haml::Engine, :set_locals)) end def test_enum_with_index assert_equal(%w[foo0 bar1 baz2], enum_with_index(%w[foo bar baz]).map {|s, i| "#{s}#{i}"}) end def test_enum_cons assert_equal(%w[foobar barbaz], enum_cons(%w[foo bar baz], 2).map {|s1, s2| "#{s1}#{s2}"}) end def test_ord assert_equal(102, ord("f")) assert_equal(98, ord("bar")) end def test_flatten assert_equal([1, 2, 3], flatten([1, 2, 3], 0)) assert_equal([1, 2, 3], flatten([1, 2, 3], 1)) assert_equal([1, 2, 3], flatten([1, 2, 3], 2)) assert_equal([[1, 2], 3], flatten([[1, 2], 3], 0)) assert_equal([1, 2, 3], flatten([[1, 2], 3], 1)) assert_equal([1, 2, 3], flatten([[1, 2], 3], 2)) assert_equal([[[1], 2], [3], 4], flatten([[[1], 2], [3], 4], 0)) assert_equal([[1], 2, 3, 4], flatten([[[1], 2], [3], 4], 1)) assert_equal([1, 2, 3, 4], flatten([[[1], 2], [3], 4], 2)) end def test_set_hash assert(set_hash(Set[1, 2, 3]) == set_hash(Set[3, 2, 1])) assert(set_hash(Set[1, 2, 3]) == set_hash(Set[1, 2, 3])) s1 = Set[] s1 << 1 s1 << 2 s1 << 3 s2 = Set[] s2 << 3 s2 << 2 s2 << 1 assert(set_hash(s1) == set_hash(s2)) end def test_set_eql assert(set_eql?(Set[1, 2, 3], Set[3, 2, 1])) assert(set_eql?(Set[1, 2, 3], Set[1, 2, 3])) s1 = Set[] s1 << 1 s1 << 2 s1 << 3 s2 = Set[] s2 << 3 s2 << 2 s2 << 1 assert(set_eql?(s1, s2)) end def test_caller_info assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle'")) assert_equal(["/tmp/foo.rb", 12, nil], caller_info("/tmp/foo.rb:12")) assert_equal(["(haml)", 12, "blah"], caller_info("(haml):12: in `blah'")) assert_equal(["", 12, "boop"], caller_info(":12: in `boop'")) assert_equal(["/tmp/foo.rb", -12, "fizzle"], caller_info("/tmp/foo.rb:-12: in `fizzle'")) assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle {}'")) end def test_version_gt assert_version_gt("2.0.0", "1.0.0") assert_version_gt("1.1.0", "1.0.0") assert_version_gt("1.0.1", "1.0.0") assert_version_gt("1.0.0", "1.0.0.rc") assert_version_gt("1.0.0.1", "1.0.0.rc") assert_version_gt("1.0.0.rc", "0.9.9") assert_version_gt("1.0.0.beta", "1.0.0.alpha") assert_version_eq("1.0.0", "1.0.0") assert_version_eq("1.0.0", "1.0.0.0") end def assert_version_gt(v1, v2) #assert(version_gt(v1, v2), "Expected #{v1} > #{v2}") assert(!version_gt(v2, v1), "Expected #{v2} < #{v1}") end def assert_version_eq(v1, v2) assert(!version_gt(v1, v2), "Expected #{v1} = #{v2}") assert(!version_gt(v2, v1), "Expected #{v2} = #{v1}") end def test_dump_and_load obj = Dumpable.new data = dump(obj) assert_equal([:before, :around_before, :around_after, :after], obj.arr) obj2 = load(data) assert_equal([:before, :around_before, :loaded], obj2.arr) end class FooBar def foo Haml::Util.abstract(self) end end def test_abstract assert_raise_message(NotImplementedError, "UtilTest::FooBar must implement #foo") {FooBar.new.foo} end def test_def_static_method klass = Class.new def_static_method(klass, :static_method, [:arg1, :arg2], :sarg1, :sarg2, <and<% else %>but never<% end %> " << arg2 <% if sarg2 %> s << "." <% end %> RUBY c = klass.new assert_equal("Always brush your teeth and comb your hair.", c.send(static_method_name(:static_method, true, true), "brush your teeth", "comb your hair")) assert_equal("Always brush your teeth and comb your hair", c.send(static_method_name(:static_method, true, false), "brush your teeth", "comb your hair")) assert_equal("Always brush your teeth but never play with fire.", c.send(static_method_name(:static_method, false, true), "brush your teeth", "play with fire")) assert_equal("Always brush your teeth but never play with fire", c.send(static_method_name(:static_method, false, false), "brush your teeth", "play with fire")) end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/0000775000175000017500000000000012414640747031334 5ustar ebourgebourg././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_layout.erbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_layou0000664000175000017500000000003312414640747032543 0ustar ebourgebourgBefore <%= yield -%> After ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/partials.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/partia0000664000175000017500000000020512414640747032534 0ustar ebourgebourg- @foo = 'value one' %p @foo = = @foo - @foo = 'value two' %p @foo = = @foo = test_partial "partial" %p @foo = = @foo ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/action_view.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/action0000664000175000017500000000337212414640747032541 0ustar ebourgebourg!!! %html{html_attrs} %head %title Hampton Catlin Is Totally Awesome %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"} %body %h1 This is very much like the standard template, except that it has some ActionView-specific stuff. It's only used for benchmarking. .crazy_partials= render :partial => 'haml/templates/av_partial_1' / You're In my house now! .header Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! = 1 + 9 + 8 + 2 #numbers should work and this should be ignored #body= " Quotes should be loved! Just like people!" - 120.times do |number| - number Wow.| %p = "Holy cow " + | "multiline " + | "tags! " + | "A pipe (|) even!" | = [1, 2, 3].collect { |n| "PipesIgnored|" } = [1, 2, 3].collect { |n| | n.to_s | }.join("|") | %div.silent - foo = String.new - foo << "this" - foo << " shouldn't" - foo << " evaluate" = foo + " but now it should!" -# Woah crap a comment! -# That was a line that shouldn't close everything. %ul.really.cool - ('a'..'f').each do |a| %li= a #combo.of_divs_with_underscore= @should_eval = "with this text" = [ 104, 101, 108, 108, 111 ].map do |byte| - byte.chr .footer %strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works" ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/partial_layout.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/partia0000664000175000017500000000036712414640747032545 0ustar ebourgebourg%h1 Partial layout used with for block: - if Haml::Util.ap_geq_3? = render :layout => 'layout_for_partial.haml' do %p Some content within a layout - else - render :layout => 'layout_for_partial.haml' do %p Some content within a layout ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/tag_parsing.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/tag_pa0000664000175000017500000000041512414640747032512 0ustar ebourgebourg%div.tags %foo 1 %FOO 2 %fooBAR 3 %fooBar 4 %foo_bar 5 %foo-bar 6 %foo:bar 7 %foo.bar 8 %fooBAr_baz:boom_bar 9 %foo13 10 %foo2u 11 %div.classes %p.foo.bar#baz#boom .fooBar a .foo-bar b .foo_bar c .FOOBAR d .foo16 e .123 f .foo2u g ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/just_stuff.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/just_s0000664000175000017500000000322712414640747032572 0ustar ebourgebourg!!! XML !!! XML ISO-8859-1 !!! XML UtF-8 Foo bar !!! !!! 1.1 !!! 1.1 Strict !!! Strict foo bar !!! FRAMESET %strong{:apos => "Foo's bar!"} Boo! == Embedded? false! == Embedded? #{true}! - embedded = true == Embedded? #{embedded}! == Embedded? #{"twice! #{true}"}! == Embedded? #{"one"} af"t"er #{"another"}! %p== Embedded? false! %p== Embedded? #{true}! - embedded = true %p== Embedded? #{embedded}! %p== Embedded? #{"twice! #{true}"}! %p== Embedded? #{"one"} af"t"er #{"another"}! = "stuff followed by whitespace" - if true %strong block with whitespace %p \Escape \- character \%p foo \yee\ha / Short comment / This is a block comment cool, huh? %strong there can even be sub-tags! = "Or script!" -# Haml comment -# Nested Haml comment - raise 'dead' %p{ :class => "" } class attribute should appear! %p{ :gorbachev => nil } this attribute shouldn't appear /[if lte IE6] conditional comment! /[if gte IE7] %p Block conditional comment %div %h1 Cool, eh? /[if gte IE5.2] Woah a period. = "test" | "test" | -# Hard tabs shouldn't throw errors. - case :foo - when :bar %br Blah - when :foo %br - case :foo - when :bar %meta{ :foo => 'blah'} - when :foo %meta{ :foo => 'bar'} %img %hr %link %script Inline content %br Nested content %p.foo{:class => true ? 'bar' : 'baz'}[@article] Blah %p.foo{:class => false ? 'bar' : ''}[@article] Blah %p.foo{:class => %w[bar baz]}[@article] Blah %p.qux{:class => 'quux'}[@article] Blump %p#foo{:id => %w[bar baz]}[@article] Whee == #{"Woah inner quotes"} %p.dynamic_quote{:quotes => "single '", :dyn => 1 + 2} %p.dynamic_self_closing{:dyn => 1 + 2}/ %body :plain hello %div %img ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/original_engine.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/origin0000664000175000017500000000071412414640747032550 0ustar ebourgebourg!!! %html %head %title Stop. haml time #content %h1 This is a title! %p Lorem ipsum dolor sit amet, consectetur adipisicing elit %p{:class => 'foo'} Cigarettes! %h2 Man alive! %ul.things %li Slippers %li Shoes %li Bathrobe %li Coffee %pre This is some text that's in a pre block! Let's see what happens when it's rendered! What about now, since we're on a new line? ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/standard.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/standa0000664000175000017500000000317412414640747032536 0ustar ebourgebourg!!! %html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en-US", "lang" => "en-US"} %head %title Hampton Catlin Is Totally Awesome %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"} %body / You're In my house now! .header Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! = 1 + 9 + 8 + 2 #numbers should work and this should be ignored #body= " Quotes should be loved! Just like people!" - 120.times do |number| = number Wow.| %p{:code => 1 + 2} = "Holy cow " + | "multiline " + | "tags! " + | "A pipe (|) even!" | = [1, 2, 3].collect { |n| "PipesIgnored|" }.join = [1, 2, 3].collect { |n| | n.to_s | }.join("|") | - bar = 17 %div.silent{:foo => bar} - foo = String.new - foo << "this" - foo << " shouldn't" - foo << " evaluate" = foo + " but now it should!" -# Woah crap a comment! -# That was a line that shouldn't close everything. %ul.really.cool - ('a'..'f').each do |a| %li= a #combo.of_divs_with_underscore= @should_eval = "with this text" = "foo".each_line do |line| - nil .footer %strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works" ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/breakage.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/breaka0000664000175000017500000000017512414640747032507 0ustar ebourgebourg%p %h1 Hello! = "lots of lines" - raise "Oh no!" %p this is after the exception %strong yes it is! ho ho ho. ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/silent_script.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/silent0000664000175000017500000000111712414640747032555 0ustar ebourgebourg%div %h1 I can count! - (1..20).each do |i| = i %h1 I know my ABCs! %ul - ('a'..'z').each do |i| %li= i %h1 I can catch errors! - begin - String.silly - rescue NameError => e = "Oh no! \"#{e}\" happened!" %p "false" is: - if false = "true" - else = "false" - if true - 5.times do |i| - if i % 2 == 1 Odd! - else Even! - else = "This can't happen!" - 13 | .foo %strong foobar - 5.times | do | |a| | %strong= a .test - "foo | bar | baz" | %p boom ././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_layout_for_partial.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_layou0000664000175000017500000000007712414640747032553 0ustar ebourgebourg.partial-layout %h2 This is inside a partial layout = yield././@LongLink0000644000000000000000000000017100000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/nuke_outer_whitespace.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/nuke_o0000664000175000017500000000262012414640747032537 0ustar ebourgebourg%p %p %q> Foo %p %p %q{:a => 1 + 1}> Foo %p %p %q> Foo %p %p %q{:a => 1 + 1}> Foo %p %p %q> = "Foo" %p %p %q{:a => 1 + 1}> = "Foo" %p %p %q>= "Foo" %p %p %q{:a => 1 + 1}>= "Foo" %p %p %q> = "Foo\nBar" %p %p %q{:a => 1 + 1}> = "Foo\nBar" %p %p %q>= "Foo\nBar" %p %p %q{:a => 1 + 1}>= "Foo\nBar" %p %p - tab_up foo %q> Foo bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}> Foo bar - tab_down %p %p - tab_up foo %q> Foo bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}> Foo bar - tab_down %p %p - tab_up foo %q> = "Foo" bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}> = "Foo" bar - tab_down %p %p - tab_up foo %q>= "Foo" bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}>= "Foo" bar - tab_down %p %p - tab_up foo %q> = "Foo\nBar" bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}> = "Foo\nBar" bar - tab_down %p %p - tab_up foo %q>= "Foo\nBar" bar - tab_down %p %p - tab_up foo %q{:a => 1 + 1}>= "Foo\nBar" bar - tab_down %p %p %q> %p %p %q>/ %p %p %q{:a => 1 + 1}> %p %p %q{:a => 1 + 1}>/ ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/content_for_layout.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/conten0000664000175000017500000000012512414640747032543 0ustar ebourgebourg!!! %html %head %body #yieldy = yield :layout #nosym = yield ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/very_basic.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/very_b0000664000175000017500000000003212414640747032540 0ustar ebourgebourg!!! %html %head %body ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/list.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/list.h0000664000175000017500000000013512414640747032457 0ustar ebourgebourg!Not a Doctype! %ul %li a %li b %li c %li d %li e %li f %li g %li h %li i ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_text_area.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_text_0000664000175000017500000000013612414640747032541 0ustar ebourgebourg.text_area_test_area ~ "" = "" ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/helpful.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/helpfu0000664000175000017500000000046512414640747032547 0ustar ebourgebourg%div[@article] %h1= @article.title %div= @article.body #id[@article] id .class[@article] class #id.class[@article] id class %div{:class => "article full"}[@article]= "boo" %div{'class' => "article full"}[@article]= "moo" %div.articleFull[@article]= "foo" %span[@not_a_real_variable_and_will_be_nil] Boo ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/eval_suppressed.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/eval_s0000664000175000017500000000021312414640747032524 0ustar ebourgebourg= "not me!" = "nor me!" - haml_concat "not even me!" %p= "NO!" %p~ "UH-UH!" %h1 Me! #foo %p#bar All %br/ %p.baz This Should render ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/helpers.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/helper0000664000175000017500000000226112414640747032537 0ustar ebourgebourg= h("&&&&&&&&&&&") # This is an ActionView Helper... should load - foo = capture do # This ActionView Helper is designed for ERB, but should work with haml %div %p.title Title %p.text Woah this is really crazy I mean wow, man. - 3.times do = foo %p foo - tab_up %p reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally loooooooooooooooooong - tab_down .woah #funky = capture_haml do %div %h1 Big! %p Small / Invisible = capture do .dilly %p foo %h1 bar = surround '(', ')' do %strong parentheses! = precede '*' do %span.small Not really click = succeed '.' do %a{:href=>"thing"} here %p baz - haml_buffer.tabulation = 10 %p boom - concat "foo\n" - haml_buffer.tabulation = 0 = list_of({:google => 'http://www.google.com'}) do |name, link| %a{ :href => link }= name %p - haml_concat "foo" %div - haml_concat "bar" - haml_concat "boom" baz - haml_concat "boom, again" - haml_tag :table do - haml_tag :tr do - haml_tag :td, {:class => 'cell'} do - haml_tag :strong, "strong!" - haml_concat "data" - haml_tag :td do - haml_concat "more_data" - haml_tag :hr - haml_tag :div, '' ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/render_layout.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/render0000664000175000017500000000005112414640747032532 0ustar ebourgebourg= render :layout => 'layout' do During ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_av_partial_1_ugly.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_av_pa0000664000175000017500000000034712414640747032510 0ustar ebourgebourg%h2 This is a pretty complicated partial .partial %p It has several nested partials, %ul - 5.times do %li %strong Partial: - @nesting = 5 = render :partial => 'haml/templates/av_partial_2_ugly'././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/partialize.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/partia0000664000175000017500000000004112414640747032532 0ustar ebourgebourg= render :file => "#{name}.haml" ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_partial.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_parti0000664000175000017500000000015112414640747032532 0ustar ebourgebourg%p @foo = = @foo - @foo = 'value three' == Toplevel? #{haml_buffer.toplevel?} %p @foo = = @foo ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_av_partial_1.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_av_pa0000664000175000017500000000034212414640747032503 0ustar ebourgebourg%h2 This is a pretty complicated partial .partial %p It has several nested partials, %ul - 5.times do %li %strong Partial: - @nesting = 5 = render :partial => 'haml/templates/av_partial_2'././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_av_partial_2.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_av_pa0000664000175000017500000000027512414640747032510 0ustar ebourgebourg- @nesting -= 1 .partial{:level => @nesting} %h3 This is a crazy deep-nested partial. %p== Nesting level #{@nesting} = render :partial => 'haml/templates/av_partial_2' if @nesting > 0././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/standard_ugly.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/standa0000664000175000017500000000317412414640747032536 0ustar ebourgebourg!!! %html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en-US", "lang" => "en-US"} %head %title Hampton Catlin Is Totally Awesome %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"} %body / You're In my house now! .header Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! = 1 + 9 + 8 + 2 #numbers should work and this should be ignored #body= " Quotes should be loved! Just like people!" - 120.times do |number| = number Wow.| %p{:code => 1 + 2} = "Holy cow " + | "multiline " + | "tags! " + | "A pipe (|) even!" | = [1, 2, 3].collect { |n| "PipesIgnored|" }.join = [1, 2, 3].collect { |n| | n.to_s | }.join("|") | - bar = 17 %div.silent{:foo => bar} - foo = String.new - foo << "this" - foo << " shouldn't" - foo << " evaluate" = foo + " but now it should!" -# Woah crap a comment! -# That was a line that shouldn't close everything. %ul.really.cool - ('a'..'f').each do |a| %li= a #combo.of_divs_with_underscore= @should_eval = "with this text" = "foo".each_line do |line| - nil .footer %strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works" ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/filters.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/filter0000664000175000017500000000162312414640747032546 0ustar ebourgebourg%style - width = 5 + 17 :sass p :border :style dotted :width #{width}px :color #ff00ff h1 :font-weight normal :test This Should Not Print %p :javascript function newline(str) { return "\n" + str; } :plain This Is Plain Text %strong right? \#{not interpolated} \\#{1 + 2} \\\#{also not} \\ - last = "noitalo" %p %pre :preserve This pre is pretty deeply nested. Does #{"interp" + last.reverse} work? :preserve This one is, too. Nested, that is. - num = 10 %ul :erb <% num.times do |c| %>
  • <%= (c+97).chr %>
  • <% end %> <% res = 178 %> .res= res = "Text!" - var = "Hello" :ruby printf "%s, World!\n", var print "How are you doing today?\n" :escaped

    I think — or do I?

    ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_av_partial_2_ugly.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/_av_pa0000664000175000017500000000030212414640747032477 0ustar ebourgebourg- @nesting -= 1 .partial{:level => @nesting} %h3 This is a crazy deep-nested partial. %p== Nesting level #{@nesting} = render :partial => 'haml/templates/av_partial_2_ugly' if @nesting > 0././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/action_view_ugly.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/action0000664000175000017500000000337712414640747032546 0ustar ebourgebourg!!! %html{html_attrs} %head %title Hampton Catlin Is Totally Awesome %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"} %body %h1 This is very much like the standard template, except that it has some ActionView-specific stuff. It's only used for benchmarking. .crazy_partials= render :partial => 'haml/templates/av_partial_1_ugly' / You're In my house now! .header Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! = 1 + 9 + 8 + 2 #numbers should work and this should be ignored #body= " Quotes should be loved! Just like people!" - 120.times do |number| - number Wow.| %p = "Holy cow " + | "multiline " + | "tags! " + | "A pipe (|) even!" | = [1, 2, 3].collect { |n| "PipesIgnored|" } = [1, 2, 3].collect { |n| | n.to_s | }.join("|") | %div.silent - foo = String.new - foo << "this" - foo << " shouldn't" - foo << " evaluate" = foo + " but now it should!" -# Woah crap a comment! -# That was a line that shouldn't close everything. %ul.really.cool - ('a'..'f').each do |a| %li= a #combo.of_divs_with_underscore= @should_eval = "with this text" = [ 104, 101, 108, 108, 111 ].map do |byte| - byte.chr .footer %strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works" ././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/whitespace_handling.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/whites0000664000175000017500000000645712414640747032576 0ustar ebourgebourg#whitespace_test = test_partial "text_area", :value => "Oneline" = test_partial "text_area", :value => "Two\nlines" ~ test_partial "text_area", :value => "Oneline" ~ test_partial "text_area", :value => "Two\nlines" #flattened~ test_partial "text_area", :value => "Two\nlines" .hithere ~ "Foo bar" ~ "
    foo bar
    " ~ "
    foo\nbar
    " %p~ "
    foo\nbar
    " %p~ "foo\nbar" .foo ~ 13 ~ "".each_line do |l| - haml_concat l.strip #whitespace_test = test_partial "text_area", :value => "Oneline" = test_partial "text_area", :value => "Two\nlines" = find_and_preserve test_partial("text_area", :value => "Oneline") = find_and_preserve test_partial("text_area", :value => "Two\nlines") #flattened= find_and_preserve test_partial("text_area", :value => "Two\nlines") .hithere = find_and_preserve("Foo bar") = find_and_preserve("
    foo bar
    ") = find_and_preserve("
    foo\nbar
    ") %p= find_and_preserve("
    foo\nbar
    ") %p= find_and_preserve("foo\nbar") %pre :preserve ___ ,o88888 ,o8888888' ,:o:o:oooo. ,8O88Pd8888" ,.::.::o:ooooOoOoO. ,oO8O8Pd888'" ,.:.::o:ooOoOoOO8O8OOo.8OOPd8O8O" , ..:.::o:ooOoOOOO8OOOOo.FdO8O8" , ..:.::o:ooOoOO8O888O8O,COCOO" , . ..:.::o:ooOoOOOO8OOOOCOCO" . ..:.::o:ooOoOoOO8O8OCCCC"o . ..:.::o:ooooOoCoCCC"o:o . ..:.::o:o:,cooooCo"oo:o: ` . . ..:.:cocoooo"'o:o:::' .` . ..::ccccoc"'o:o:o:::' :.:. ,c:cccc"':.:.:.:.:.' ..:.:"'`::::c:"'..:.:.:.:.:.' http://www.chris.com/ASCII/ ...:.'.:.::::"' . . . . .' .. . ....:."' ` . . . '' . . . ...."' .. . ."' -hrr- . It's a planet! %strong This shouldn't be bold! %strong This should! %textarea :preserve ___ ___ ___ ___ /\__\ /\ \ /\__\ /\__\ /:/ / /::\ \ /::| | /:/ / /:/__/ /:/\:\ \ /:|:| | /:/ / /::\ \ ___ /::\~\:\ \ /:/|:|__|__ /:/ / /:/\:\ /\__\ /:/\:\ \:\__\ /:/ |::::\__\ /:/__/ \/__\:\/:/ / \/__\:\/:/ / \/__/~~/:/ / \:\ \ \::/ / \::/ / /:/ / \:\ \ /:/ / /:/ / /:/ / \:\ \ /:/ / /:/ / /:/ / \:\__\ \/__/ \/__/ \/__/ \/__/ Many thanks to http://www.network-science.de/ascii/ %strong indeed! .foo = find_and_preserve(13) %pre :preserve __ ______ __ ______ .----.| |--.|__ |.----.| |--..--------.| __ | | __|| ||__ || __|| < | || __ | |____||__|__||______||____||__|__||__|__|__||______| %pre :preserve foo bar ././@LongLink0000644000000000000000000000017100000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/nuke_inner_whitespace.hamlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/templates/nuke_i0000664000175000017500000000046412414640747032535 0ustar ebourgebourg%p %q< Foo %p %q{:a => 1 + 1}< Foo %p %q<= "Foo\nBar" %p %q{:a => 1 + 1}<= "Foo\nBar" %p %q< Foo Bar %p %q{:a => 1 + 1}< Foo Bar %p %q< %div Foo Bar %p %q{:a => 1 + 1}< %div Foo Bar -# Regression test %p %q<= "foo" %q{:a => 1 + 1} bar stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/0000775000175000017500000000000012414640747031037 5ustar ebourgebourg././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/helpful.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/helpful.0000664000175000017500000000062112414640747032476 0ustar ebourgebourg

    Hello

    World
    id
    class
    id class
    boo
    moo
    foo
    ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/partial_layout.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/partial_0000664000175000017500000000024112414640747032552 0ustar ebourgebourg

    Partial layout used with for block:

    This is inside a partial layout

    Some content within a layout

    ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/list.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/list.xht0000664000175000017500000000022012414640747032531 0ustar ebourgebourg!Not a Doctype!
    • a
    • b
    • c
    • d
    • e
    • f
    • g
    • h
    • i
    ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/filters.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/filters.0000664000175000017500000000157712414640747032522 0ustar ebourgebourg TESTING HAHAHAHA!

    This Is Plain Text %strong right? #{not interpolated} \3 \#{also not} \\

    This pre is pretty deeply
          nested.
       Does interpolation work?
        This one is, too.
    Nested, that is.
    

    • a
    • b
    • c
    • d
    • e
    • f
    • g
    • h
    • i
    • j
    178
    Text! Hello, World! How are you doing today? <div class="foo"> <p>I think &mdash; or do I?</p> </div> ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/tag_parsing.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/tag_pars0000664000175000017500000000105112414640747032557 0ustar ebourgebourg
    1 2 3 4 5 6 7 8 9 10 11

    a
    b
    c
    d
    e
    f
    g
    ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/nuke_inner_whitespace.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/nuke_inn0000664000175000017500000000050712414640747032572 0ustar ebourgebourg

    Foo

    Foo

    Foo Bar

    Foo Bar

    Foo Bar

    Foo Bar

    Foo Bar

    Foo Bar

    foo bar

    ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/helpers.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/helpers.0000664000175000017500000000217012414640747032502 0ustar ebourgebourg&&&&&&&&&&&

    Title

    Woah this is really crazy I mean wow, man.

    Title

    Woah this is really crazy I mean wow, man.

    Title

    Woah this is really crazy I mean wow, man.

    foo

    reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally loooooooooooooooooong

    Big!

    Small

    foo

    bar

    (parentheses!)
    *Not really click here.

    baz

    boom

    foo
  • google
  • foo

    bar
    boom baz boom, again

    strong! data more_data

    ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/silent_script.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/silent_s0000664000175000017500000000162512414640747032606 0ustar ebourgebourg

    I can count!

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

    I know my ABCs!

    • a
    • b
    • c
    • d
    • e
    • f
    • g
    • h
    • i
    • j
    • k
    • l
    • m
    • n
    • o
    • p
    • q
    • r
    • s
    • t
    • u
    • v
    • w
    • x
    • y
    • z

    I can catch errors!

    Oh no! "undefined method `silly' for String:Class" happened!

    "false" is: false

    Even! Odd! Even! Odd! Even!
    foobar
    0 1 2 3 4

    boom

    ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/original_engine.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/original0000664000175000017500000000124512414640747032570 0ustar ebourgebourg Stop. haml time

    This is a title!

    Lorem ipsum dolor sit amet, consectetur adipisicing elit

    Cigarettes!

    Man alive!

    • Slippers
    • Shoes
    • Bathrobe
    • Coffee
    This is some text that's in a pre block!
          Let's see what happens when it's rendered! What about now, since we're on a new line?
    ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/nuke_outer_whitespace.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/nuke_out0000664000175000017500000000255012414640747032615 0ustar ebourgebourg

    Foo

    Foo

    Foo

    Foo

    Foo

    Foo

    Foo

    Foo

    Foo Bar

    Foo Bar

    Foo Bar

    Foo Bar

    foo Foo bar

    foo Foo bar

    fooFoobar

    fooFoobar

    foo Foo bar

    foo Foo bar

    fooFoobar

    fooFoobar

    foo Foo Bar bar

    foo Foo Bar bar

    foo Foo Bar bar

    foo Foo Bar bar

    ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/render_layout.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/render_l0000664000175000017500000000002412414640747032550 0ustar ebourgebourgBefore During After ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/eval_suppressed.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/eval_sup0000664000175000017500000000017412414640747032602 0ustar ebourgebourg

    Me!

    All


    This

    Should render
    ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/very_basic.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/very_bas0000664000175000017500000000025112414640747032572 0ustar ebourgebourg ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/whitespace_handling.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/whitespa0000664000175000017500000000767312414640747032623 0ustar ebourgebourg
    Foo bar
    foo bar
    foo
    bar

    foo
    bar

    foo bar

    13
    Foo bar
    foo bar
    foo
    bar

    foo
    bar

    foo bar

                                                     ___
                                                  ,o88888
                                               ,o8888888'
                         ,:o:o:oooo.        ,8O88Pd8888"
                     ,.::.::o:ooooOoOoO. ,oO8O8Pd888'"
                   ,.:.::o:ooOoOoOO8O8OOo.8OOPd8O8O"
                  , ..:.::o:ooOoOOOO8OOOOo.FdO8O8"
                 , ..:.::o:ooOoOO8O888O8O,COCOO"
                , . ..:.::o:ooOoOOOO8OOOOCOCO"
                 . ..:.::o:ooOoOoOO8O8OCCCC"o
                    . ..:.::o:ooooOoCoCCC"o:o
                    . ..:.::o:o:,cooooCo"oo:o:
                 `   . . ..:.:cocoooo"'o:o:::'
                 .`   . ..::ccccoc"'o:o:o:::'
                :.:.    ,c:cccc"':.:.:.:.:.'
              ..:.:"'`::::c:"'..:.:.:.:.:.'  http://www.chris.com/ASCII/
            ...:.'.:.::::"'    . . . . .'
           .. . ....:."' `   .  . . ''
         . . . ...."'
         .. . ."'     -hrr-
        .
    
    
                                                  It's a planet!
    %strong This shouldn't be bold!
    This should!
    13
           __     ______        __               ______
    .----.|  |--.|__    |.----.|  |--..--------.|  __  |
    |  __||     ||__    ||  __||    < |        ||  __  |
    |____||__|__||______||____||__|__||__|__|__||______|
    foo
    bar
    ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/just_stuff.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/just_stu0000664000175000017500000000377012414640747032651 0ustar ebourgebourg Boo! Embedded? false! Embedded? true! Embedded? true! Embedded? twice! true! Embedded? one af"t"er another!

    Embedded? false!

    Embedded? true!

    Embedded? true!

    Embedded? twice! true!

    Embedded? one af"t"er another!

    stuff followed by whitespace block with whitespace

    Escape - character %p foo yee\ha

    class attribute should appear!

    this attribute shouldn't appear

    testtest


    Nested content

    Blah

    Blah

    Blah

    Blump

    Whee

    Woah inner quotes

    hello

    ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/partials.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/partials0000664000175000017500000000025212414640747032600 0ustar ebourgebourg

    @foo = value one

    @foo = value two

    @foo = value two

    Toplevel? false

    @foo = value three

    @foo = value three

    ././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/content_for_layout.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/content_0000664000175000017500000000045712414640747032601 0ustar ebourgebourg
    Lorem ipsum dolor sit amet
    Lorem ipsum dolor sit amet
    ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/standard.xhtmlstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/results/standard0000664000175000017500000000445012414640747032565 0ustar ebourgebourg Hampton Catlin Is Totally Awesome
    Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! 20
    Quotes should be loved! Just like people!
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 Wow.|

    Holy cow multiline tags! A pipe (|) even! PipesIgnored|PipesIgnored|PipesIgnored| 1|2|3

    this shouldn't evaluate but now it should!
    • a
    • b
    • c
    • d
    • e
    • f
    with this text
    foo stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/template_test.rb0000775000175000017500000002677712414640747032563 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' require 'sass/plugin' require File.dirname(__FILE__) + '/mocks/article' require 'action_pack/version' module Haml::Filters::Test include Haml::Filters::Base def render(text) "TESTING HAHAHAHA!" end end module Haml::Helpers def test_partial(name, locals = {}) Haml::Engine.new(File.read(File.join(TemplateTest::TEMPLATE_PATH, "_#{name}.haml"))).render(self, locals) end end class Egocentic def method_missing(*args) self end end class DummyController attr_accessor :logger def initialize @logger = Egocentic.new end def self.controller_path '' end def controller_path '' end end class TemplateTest < Test::Unit::TestCase TEMPLATE_PATH = File.join(File.dirname(__FILE__), "templates") TEMPLATES = %w{ very_basic standard helpers whitespace_handling original_engine list helpful silent_script tag_parsing just_stuff partials filters nuke_outer_whitespace nuke_inner_whitespace render_layout } # partial layouts were introduced in 2.0.0 TEMPLATES << 'partial_layout' unless ActionPack::VERSION::MAJOR < 2 def setup @base = create_base # filters template uses :sass Sass::Plugin.options.update(:line_comments => true, :style => :compact) end def create_base vars = { 'article' => Article.new, 'foo' => 'value one' } unless Haml::Util.has?(:instance_method, ActionView::Base, :finder) base = ActionView::Base.new(TEMPLATE_PATH, vars) else # Rails 2.1.0 base = ActionView::Base.new([], vars) base.finder.append_view_path(TEMPLATE_PATH) end if Haml::Util.has?(:private_method, base, :evaluate_assigns) # Rails < 3.0 base.send(:evaluate_assigns) elsif Haml::Util.has?(:private_method, base, :_evaluate_assigns_and_ivars) # Rails 2.2 base.send(:_evaluate_assigns_and_ivars) end # This is needed by RJS in (at least) Rails 3 base.instance_variable_set('@template', base) # This is used by form_for. # It's usually provided by ActionController::Base. def base.protect_against_forgery?; false; end # In Rails <= 2.1, a fake controller object was needed # to provide the controller path. if ActionPack::VERSION::MAJOR < 2 || (ActionPack::VERSION::MAJOR == 2 && ActionPack::VERSION::MINOR < 2) base.controller = DummyController.new end base end def render(text, opts = {}) return @base.render(:inline => text, :type => :haml) if opts == :action_view Haml::Engine.new(text, opts).to_html(@base) end def load_result(name) @result = '' File.new(File.dirname(__FILE__) + "/results/#{name}.xhtml").each_line { |l| @result += l } @result end def assert_renders_correctly(name, &render_method) old_options = Haml::Template.options.dup Haml::Template.options[:escape_html] = false if ActionPack::VERSION::MAJOR < 2 || (ActionPack::VERSION::MAJOR == 2 && ActionPack::VERSION::MINOR < 2) render_method ||= proc { |name| @base.render(name) } else render_method ||= proc { |name| @base.render(:file => name) } end load_result(name).split("\n").zip(render_method[name].split("\n")).each_with_index do |pair, line| message = "template: #{name}\nline: #{line}" assert_equal(pair.first, pair.last, message) end rescue Haml::Util.av_template_class(:Error) => e if e.message =~ /Can't run [\w:]+ filter; required (one of|file) ((?:'\w+'(?: or )?)+)(, but none were found| not found)/ puts "\nCouldn't require #{$2}; skipping a test." else raise e end ensure Haml::Template.options = old_options end def test_empty_render_should_remain_empty assert_equal('', render('')) end TEMPLATES.each do |template| define_method "test_template_should_render_correctly [template: #{template}] " do assert_renders_correctly template end end def test_templates_should_render_correctly_with_render_proc assert_renders_correctly("standard") do |name| engine = Haml::Engine.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.haml")) engine.render_proc(@base).call end end def test_templates_should_render_correctly_with_def_method assert_renders_correctly("standard") do |name| engine = Haml::Engine.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.haml")) engine.def_method(@base, "render_standard") @base.render_standard end end if ActionPack::VERSION::MAJOR < 3 # Rails 3.0.0 deprecates the use of yield with a layout # for calls to render :file def test_action_view_templates_render_correctly proc = lambda do @base.content_for(:layout) {'Lorem ipsum dolor sit amet'} assert_renders_correctly 'content_for_layout' end if @base.respond_to?(:with_output_buffer) @base.with_output_buffer("", &proc) else proc.call end end end def test_instance_variables_should_work_inside_templates @base.instance_variable_set("@content_for_layout", 'something') assert_equal("

    something

    ", render("%p= @content_for_layout").chomp) @base.instance_eval("@author = 'Hampton Catlin'") assert_equal("
    Hampton Catlin
    ", render(".author= @author").chomp) @base.instance_eval("@author = 'Hampton'") assert_equal("Hampton", render("= @author").chomp) @base.instance_eval("@author = 'Catlin'") assert_equal("Catlin", render("= @author").chomp) end def test_instance_variables_should_work_inside_attributes @base.instance_eval("@author = 'hcatlin'") assert_equal("

    foo

    ", render("%p{:class => @author} foo").chomp) end def test_template_renders_should_eval assert_equal("2\n", render("= 1+1")) end unless Haml::Util.ap_geq_3? def test_form_for_error_return assert_raise(Haml::Error) { render(< '' do |f| Title: = f.text_field :title Body: = f.text_field :body HAML end def test_form_tag_error_return assert_raise(Haml::Error) { render(< true))

    foo baz

    HTML %p foo -# Parenthesis required due to Rails 3.0 deprecation of block helpers -# that return strings. - (with_output_buffer do bar = "foo".gsub(/./) do |s| - "flup" - end; nil) baz HAML end def test_exceptions_should_work_correctly begin render("- raise 'oops!'") rescue Exception => e assert_equal("oops!", e.message) assert_match(/^\(haml\):1/, e.backtrace[0]) else assert false end template = < e assert_match(/^\(haml\):5/, e.backtrace[0]) else assert false end end if defined?(ActionView::OutputBuffer) && Haml::Util.has?(:instance_method, ActionView::OutputBuffer, :append_if_string=) def test_av_block_deprecation_warning assert_warning(/^DEPRECATION WARNING: - style block helpers are deprecated\. Please use =\./) do assert_equal <#{rails_form_opener} Title: Body: HTML - form_for #{form_for_calling_convention(:article)}, :url => '' do |f| Title: = f.text_field :title Body: = f.text_field :body HAML end end end ## XSS Protection Tests # In order to enable these, either test against Rails 3.0 # or test against Rails 2.2.5+ with the rails_xss plugin # (http://github.com/NZKoz/rails_xss) in test/plugins. if Haml::Util.rails_xss_safe? def test_escape_html_option_set assert Haml::Template.options[:escape_html] end def test_xss_protection assert_equal("Foo & Bar\n", render('= "Foo & Bar"', :action_view)) end def test_xss_protection_with_safe_strings assert_equal("Foo & Bar\n", render('= Haml::Util.html_safe("Foo & Bar")', :action_view)) end def test_xss_protection_with_bang assert_equal("Foo & Bar\n", render('!= "Foo & Bar"', :action_view)) end def test_xss_protection_in_interpolation assert_equal("Foo & Bar\n", render('Foo #{"&"} Bar', :action_view)) end def test_xss_protection_with_bang_in_interpolation assert_equal("Foo & Bar\n", render('! Foo #{"&"} Bar', :action_view)) end def test_xss_protection_with_safe_strings_in_interpolation assert_equal("Foo & Bar\n", render('Foo #{Haml::Util.html_safe("&")} Bar', :action_view)) end def test_xss_protection_with_mixed_strings_in_interpolation assert_equal("Foo & Bar & Baz\n", render('Foo #{Haml::Util.html_safe("&")} Bar #{"&"} Baz', :action_view)) end def test_rendered_string_is_html_safe assert(render("Foo").html_safe?) end def test_rendered_string_is_html_safe_with_action_view assert(render("Foo", :action_view).html_safe?) end def test_xss_html_escaping_with_non_strings assert_equal("4\n", render("= html_escape(4)")) end def test_xss_protection_with_concat assert_equal("Foo & Bar", render('- concat "Foo & Bar"', :action_view)) end def test_xss_protection_with_concat_with_safe_string assert_equal("Foo & Bar", render('- concat(Haml::Util.html_safe("Foo & Bar"))', :action_view)) end if Haml::Util.has?(:instance_method, ActionView::Helpers::TextHelper, :safe_concat) def test_xss_protection_with_safe_concat assert_equal("Foo & Bar", render('- safe_concat "Foo & Bar"', :action_view)) end end ## Regression def test_xss_protection_with_nested_haml_tag assert_equal(<
    • Content!
    HTML - haml_tag :div do - haml_tag :ul do - haml_tag :li, "Content!" HAML end def test_xss_protection_with_form_for assert_equal(<#{rails_form_opener} Title: Body: HTML #{rails_block_helper_char} form_for #{form_for_calling_convention(:article)}, :url => '' do |f| Title: = f.text_field :title Body: = f.text_field :body HAML end def test_rjs assert_equal(<' html(:xmlns=>'http://www.w3.org/1999/xhtml', 'xml:lang'=>'en-US') do head do title "Hampton Catlin Is Totally Awesome" meta("http-equiv" => "Content-Type", :content => "text/html; charset=utf-8") end body do # You're In my house now! div :class => "header" do self << %|Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah!| self << 1 + 9 + 8 + 2 #numbers should work and this should be ignored end div(:id => "body") { self << "Quotes should be loved! Just like people!"} 120.times do |number| number end self << "Wow.|" p do self << "Holy cow " + "multiline " + "tags! " + "A pipe (|) even!" self << [1, 2, 3].collect { |n| "PipesIgnored|" } self << [1, 2, 3].collect { |n| n.to_s }.join("|") end div(:class => "silent") do foo = String.new foo << "this" foo << " shouldn't" foo << " evaluate" self << foo + " but now it should!" # Woah crap a comment! end # That was a line that shouldn't close everything. ul(:class => "really cool") do ('a'..'f').each do |a| li a end end div((@should_eval = "with this text"), :id => "combo", :class => "of_divs_with_underscore") [ 104, 101, 108, 108, 111 ].map do |byte| byte.chr end div(:class => "footer") do strong("This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works", :class => "shout") end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/spec_test.rb0000775000175000017500000000221212414640747031654 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' begin require 'json' rescue LoadError end class SpecTest < Test::Unit::TestCase spec_file = File.dirname(__FILE__) + '/spec/tests.json' if !File.exists?(spec_file) error = < "Illegal nesting: nesting within a header command is illegal.", "a\n b" => "Illegal nesting: nesting within plain text is illegal.", "/ a\n b" => "Illegal nesting: nesting within a tag that already has content is illegal.", "% a" => 'Invalid tag: "% a".', "%p a\n b" => "Illegal nesting: content can't be both given on the same line as %p and nested within it.", "%p=" => "There's no Ruby code for = to evaluate.", "%p~" => "There's no Ruby code for ~ to evaluate.", "~" => "There's no Ruby code for ~ to evaluate.", "=" => "There's no Ruby code for = to evaluate.", "%p/\n a" => "Illegal nesting: nesting within a self-closing tag is illegal.", ":a\n b" => ['Filter "a" is not defined.', 1], ":a= b" => 'Invalid filter name ":a= b".', "." => "Illegal element: classes and ids must have values.", ".#" => "Illegal element: classes and ids must have values.", ".{} a" => "Illegal element: classes and ids must have values.", ".() a" => "Illegal element: classes and ids must have values.", ".= a" => "Illegal element: classes and ids must have values.", "%p..a" => "Illegal element: classes and ids must have values.", "%a/ b" => "Self-closing tags can't have content.", "%p{:a => 'b',\n:c => 'd'}/ e" => ["Self-closing tags can't have content.", 2], "%p{:a => 'b',\n:c => 'd'}=" => ["There's no Ruby code for = to evaluate.", 2], "%p.{:a => 'b',\n:c => 'd'} e" => ["Illegal element: classes and ids must have values.", 1], "%p{:a => 'b',\n:c => 'd',\n:e => 'f'}\n%p/ a" => ["Self-closing tags can't have content.", 4], "%p{:a => 'b',\n:c => 'd',\n:e => 'f'}\n- raise 'foo'" => ["foo", 4], "%p{:a => 'b',\n:c => raise('foo'),\n:e => 'f'}" => ["foo", 2], "%p{:a => 'b',\n:c => 'd',\n:e => raise('foo')}" => ["foo", 3], " %p foo" => "Indenting at the beginning of the document is illegal.", " %p foo" => "Indenting at the beginning of the document is illegal.", "- end" => < ["Indenting at the beginning of the document is illegal.", 3], "\n\n %p foo" => ["Indenting at the beginning of the document is illegal.", 3], "%p\n foo\n foo" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of the document was indented using 2 spaces.", 3], "%p\n foo\n%p\n foo" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of the document was indented using 2 spaces.", 4], "%p\n\t\tfoo\n\tfoo" => ["Inconsistent indentation: 1 tab was used for indentation, but the rest of the document was indented using 2 tabs.", 3], "%p\n foo\n foo" => ["Inconsistent indentation: 3 spaces were used for indentation, but the rest of the document was indented using 2 spaces.", 3], "%p\n foo\n %p\n bar" => ["Inconsistent indentation: 3 spaces were used for indentation, but the rest of the document was indented using 2 spaces.", 4], "%p\n :plain\n bar\n \t baz" => ['Inconsistent indentation: " \t " was used for indentation, but the rest of the document was indented using 2 spaces.', 4], "%p\n foo\n%p\n bar" => ["The line was indented 2 levels deeper than the previous line.", 4], "%p\n foo\n %p\n bar" => ["The line was indented 3 levels deeper than the previous line.", 4], "%p\n \tfoo" => ["Indentation can't use both tabs and spaces.", 2], "%p(" => "Invalid attribute list: \"(\".", "%p(foo=\nbar)" => ["Invalid attribute list: \"(foo=\".", 1], "%p(foo=)" => "Invalid attribute list: \"(foo=)\".", "%p(foo 'bar')" => "Invalid attribute list: \"(foo 'bar')\".", "%p(foo 'bar'\nbaz='bang')" => ["Invalid attribute list: \"(foo 'bar'\".", 1], "%p(foo='bar'\nbaz 'bang'\nbip='bop')" => ["Invalid attribute list: \"(foo='bar' baz 'bang'\".", 2], "%p{:foo => 'bar' :bar => 'baz'}" => :compile, "%p{:foo => }" => :compile, "%p{=> 'bar'}" => :compile, "%p{:foo => 'bar}" => :compile, "%p{'foo => 'bar'}" => :compile, "%p{:foo => 'bar\"}" => :compile, # Regression tests "- raise 'foo'\n\n\n\nbar" => ["foo", 1], "= 'foo'\n-raise 'foo'" => ["foo", 2], "\n\n\n- raise 'foo'" => ["foo", 4], "%p foo |\n bar |\n baz |\nbop\n- raise 'foo'" => ["foo", 5], "foo\n\n\n bar" => ["Illegal nesting: nesting within plain text is illegal.", 4], "%p/\n\n bar" => ["Illegal nesting: nesting within a self-closing tag is illegal.", 3], "%p foo\n\n bar" => ["Illegal nesting: content can't be both given on the same line as %p and nested within it.", 3], "/ foo\n\n bar" => ["Illegal nesting: nesting within a tag that already has content is illegal.", 3], "!!!\n\n bar" => ["Illegal nesting: nesting within a header command is illegal.", 3], "foo\n:ruby\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6], "foo\n:erb\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6], "foo\n:plain\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6], "foo\n:plain\n 1\n 2\n 3\n4\n- raise 'foo'" => ["foo", 7], "foo\n:plain\n 1\n 2\n 3\#{''}\n- raise 'foo'" => ["foo", 6], "foo\n:plain\n 1\n 2\n 3\#{''}\n4\n- raise 'foo'" => ["foo", 7], "foo\n:plain\n 1\n 2\n \#{raise 'foo'}" => ["foo", 5], "= raise 'foo'\nfoo\nbar\nbaz\nbang" => ["foo", 1], "- case 1\n\n- when 1\n - raise 'foo'" => ["foo", 4], } User = Struct.new('User', :id) class CustomHamlClass < Struct.new(:id) def haml_object_ref "my_thing" end end def render(text, options = {}, &block) scope = options.delete(:scope) || Object.new locals = options.delete(:locals) || {} engine(text, options).to_html(scope, locals, &block) end def engine(text, options = {}) unless options[:filename] # use caller method name as fake filename. useful for debugging i = -1 caller[i+=1] =~ /`(.+?)'/ until $1 and $1.index('test_') == 0 options[:filename] = "(#{$1})" end Haml::Engine.new(text, options) end def setup return if Haml::Util.ruby1_8? @old_default_internal = Encoding.default_internal Encoding.default_internal = nil end def teardown return if Haml::Util.ruby1_8? Encoding.default_internal = @old_default_internal end def test_empty_render assert_equal "", render("") end def test_flexible_tabulation assert_equal("

    \n foo\n

    \n\n bar\n \n baz\n \n\n", render("%p\n foo\n%q\n bar\n %a\n baz")) assert_equal("

    \n foo\n

    \n\n bar\n \n baz\n \n\n", render("%p\n\tfoo\n%q\n\tbar\n\t%a\n\t\tbaz")) assert_equal("

    \n \t \t bar\n baz\n

    \n", render("%p\n :plain\n \t \t bar\n baz")) end def test_empty_render_should_remain_empty assert_equal('', render('')) end def test_attributes_should_render_correctly assert_equal("
    ", render(".atlantis{:style => 'ugly'}").chomp) end def test_css_id_as_attribute_should_be_appended_with_underscore assert_equal("
    ", render("#my_id{:id => '1'}").chomp) assert_equal("
    ", render("#my_id{:id => 1}").chomp) end def test_ruby_code_should_work_inside_attributes author = 'hcatlin' assert_equal("

    foo

    ", render("%p{:class => 1+2} foo").chomp) end def test_class_attr_with_array assert_equal("

    foo

    \n", render("%p{:class => %w[a b]} foo")) # basic assert_equal("

    foo

    \n", render("%p.css{:class => %w[a b]} foo")) # merge with css assert_equal("

    foo

    \n", render("%p.css{:class => %w[css b]} foo")) # merge uniquely assert_equal("

    foo

    \n", render("%p{:class => [%w[a b], %w[c d]]} foo")) # flatten assert_equal("

    foo

    \n", render("%p{:class => [:a, :b] } foo")) # stringify assert_equal("

    foo

    \n", render("%p{:class => [nil, false] } foo")) # strip falsey assert_equal("

    foo

    \n", render("%p{:class => :a} foo")) # single stringify assert_equal("

    foo

    \n", render("%p{:class => false} foo")) # single falsey assert_equal("

    foo

    \n", render("%p(class='html'){:class => %w[a b]} foo")) # html attrs end def test_id_attr_with_array assert_equal("

    foo

    \n", render("%p{:id => %w[a b]} foo")) # basic assert_equal("

    foo

    \n", render("%p#css{:id => %w[a b]} foo")) # merge with css assert_equal("

    foo

    \n", render("%p{:id => [%w[a b], %w[c d]]} foo")) # flatten assert_equal("

    foo

    \n", render("%p{:id => [:a, :b] } foo")) # stringify assert_equal("

    foo

    \n", render("%p{:id => [nil, false] } foo")) # strip falsey assert_equal("

    foo

    \n", render("%p{:id => :a} foo")) # single stringify assert_equal("

    foo

    \n", render("%p{:id => false} foo")) # single falsey assert_equal("

    foo

    \n", render("%p(id='html'){:id => %w[a b]} foo")) # html attrs end def test_colon_in_class_attr assert_equal("

    \n", render("%p.foo:bar/")) end def test_colon_in_id_attr assert_equal("

    \n", render("%p#foo:bar/")) end def test_dynamic_attributes_with_no_content assert_equal(<

    HTML %p %a{:href => "http://" + "haml-lang.com"} HAML end def test_attributes_with_to_s assert_equal(<

    HTML %p#foo{:id => 1+1} %p.foo{:class => 1+1} %p{:blaz => 1+1} %p{(1+1) => 1+1} HAML end def test_nil_should_render_empty_tag assert_equal("
    ", render(".no_attributes{:nil => nil}").chomp) end def test_strings_should_get_stripped_inside_tags assert_equal("
    This should have no spaces in front of it
    ", render(".stripped This should have no spaces in front of it").chomp) end def test_one_liner_should_be_one_line assert_equal("

    Hello

    ", render('%p Hello').chomp) end def test_one_liner_with_newline_shouldnt_be_one_line assert_equal("

    \n foo\n bar\n

    ", render('%p= "foo\nbar"').chomp) end def test_multi_render engine = engine("%strong Hi there!") assert_equal("Hi there!\n", engine.to_html) assert_equal("Hi there!\n", engine.to_html) assert_equal("Hi there!\n", engine.to_html) end def test_interpolation assert_equal("

    Hello World

    \n", render('%p Hello #{who}', :locals => {:who => 'World'})) assert_equal("

    \n Hello World\n

    \n", render("%p\n Hello \#{who}", :locals => {:who => 'World'})) end def test_interpolation_in_the_middle_of_a_string assert_equal("\"title 'Title'. \"\n", render("\"title '\#{\"Title\"}'. \"")) end def test_interpolation_at_the_beginning_of_a_line assert_equal("

    2

    \n", render('%p #{1 + 1}')) assert_equal("

    \n 2\n

    \n", render("%p\n \#{1 + 1}")) end def test_escaped_interpolation assert_equal("

    Foo & Bar & Baz

    \n", render('%p& Foo #{"&"} Bar & Baz')) end def test_nil_tag_value_should_render_as_empty assert_equal("

    \n", render("%p= nil")) end def test_tag_with_failed_if_should_render_as_empty assert_equal("

    \n", render("%p= 'Hello' if false")) end def test_static_attributes_with_empty_attr assert_equal("\n", render("%img{:src => '/foo.png', :alt => ''}")) end def test_dynamic_attributes_with_empty_attr assert_equal("\n", render("%img{:width => nil, :src => '/foo.png', :alt => String.new}")) end def test_attribute_hash_with_newlines assert_equal("

    foop

    \n", render("%p{:a => 'b',\n :c => 'd'} foop")) assert_equal("

    \n foop\n

    \n", render("%p{:a => 'b',\n :c => 'd'}\n foop")) assert_equal("

    \n", render("%p{:a => 'b',\n :c => 'd'}/")) assert_equal("

    \n", render("%p{:a => 'b',\n :c => 'd',\n :e => 'f'}")) end def test_attr_hashes_not_modified hash = {:color => 'red'} assert_equal(< {:hash => hash}))
    HTML %div{hash} .special{hash} %div{hash} HAML assert_equal(hash, {:color => 'red'}) end def test_ugly_semi_prerendered_tags assert_equal(< true))

    foo

    foo

    foo bar

    foo bar

    foo

    HTML %p{:a => 1 + 1} %p{:a => 1 + 1} foo %p{:a => 1 + 1}/ %p{:a => 1 + 1}= "foo" %p{:a => 1 + 1}= "foo\\nbar" %p{:a => 1 + 1}~ "foo\\nbar" %p{:a => 1 + 1} foo HAML end def test_end_of_file_multiline assert_equal("

    0

    \n

    1

    \n

    2

    \n", render("- for i in (0...3)\n %p= |\n i |")) end def test_cr_newline assert_equal("

    foo

    \n

    bar

    \n

    baz

    \n

    boom

    \n", render("%p foo\r%p bar\r\n%p baz\n\r%p boom")) end def test_textareas assert_equal("\n", render('%textarea= "Foo\n bar\n baz"')) assert_equal("
    Foo
      bar
       baz
    \n", render('%pre= "Foo\n bar\n baz"')) assert_equal("\n", render("%textarea #{'a' * 100}")) assert_equal("

    \n \n

    \n", render(<Foo bar baz HTML %pre %code :preserve Foo bar baz HAML end def test_boolean_attributes assert_equal("

    \n", render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :html4)) assert_equal("

    \n", render("%p{:foo => 'bar', :bar => true, :baz => 'true'}", :format => :xhtml)) assert_equal("

    \n", render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :html4)) assert_equal("

    \n", render("%p{:foo => 'bar', :bar => false, :baz => 'false'}", :format => :xhtml)) end def test_both_whitespace_nukes_work_together assert_equal(<Foo Bar

    RESULT %p %q><= "Foo\\nBar" SOURCE end def test_nil_option assert_equal("

    \n", render('%p{:foo => "bar"}', :attr_wrapper => nil)) end # Regression tests def test_whitespace_nuke_with_both_newlines assert_equal("

    foo

    \n", render('%p<= "\nfoo\n"')) assert_equal(<

    foo

    HTML %p %p<= "\\nfoo\\n" HAML end def test_whitespace_nuke_with_tags_and_else assert_equal(< foo HTML %a %b< - if false = "foo" - else foo HAML assert_equal(< foo HTML %a %b - if false = "foo" - else foo HAML end def test_outer_whitespace_nuke_with_empty_script assert_equal(< foo

    HTML %p foo = " " %a> HAML end def test_both_case_indentation_work_with_deeply_nested_code result = < other RESULT assert_equal(result, render(< true)) = capture_haml do foo HAML end def test_plain_equals_with_ugly assert_equal("foo\nbar\n", render(< true)) = "foo" bar HAML end def test_inline_if assert_equal(<One

    Three

    HTML - for name in ["One", "Two", "Three"] %p= name unless name == "Two" HAML end def test_end_with_method_call assert_equal(< 2|3|4 b-a-r

    HTML %p = [1, 2, 3].map do |i| - i + 1 - end.join("|") = "bar".gsub(/./) do |s| - s + "-" - end.gsub(/-$/) do |s| - '' HAML end def test_silent_end_with_stuff assert_equal(<hi!

    HTML - if true %p hi! - end if "foo".gsub(/f/) do - "z" - end + "bar" HAML end def test_multiline_with_colon_after_filter assert_equal(< "Bar", | :b => "Baz" }[:a] | HAML assert_equal(< "Bar", | :b => "Baz" }[:a] | HAML end def test_multiline_in_filter assert_equal(< false))
    bar
    HTML #foo{:class => ''} bar HAML end def test_escape_attrs_always assert_equal(< :always))
    bar
    HTML #foo{:class => '"<>&"'} bar HAML end def test_escape_html html = < true)) &= "&" != "&" = "&" HAML assert_equal(html, render(< true)) &~ "&" !~ "&" ~ "&" HAML assert_equal(html, render(< true)) & \#{"&"} ! \#{"&"} \#{"&"} HAML assert_equal(html, render(< true)) &== \#{"&"} !== \#{"&"} == \#{"&"} HAML tag_html = <&

    &

    &

    HTML assert_equal(tag_html, render(< true)) %p&= "&" %p!= "&" %p= "&" HAML assert_equal(tag_html, render(< true)) %p&~ "&" %p!~ "&" %p~ "&" HAML assert_equal(tag_html, render(< true)) %p& \#{"&"} %p! \#{"&"} %p \#{"&"} HAML assert_equal(tag_html, render(< true)) %p&== \#{"&"} %p!== \#{"&"} %p== \#{"&"} HAML end def test_new_attrs_with_hash assert_equal("\n", render('%a(href="#")')) end def test_javascript_filter_with_dynamic_interp_and_escape_html assert_equal(< true)) HTML :javascript & < > \#{"&"} HAML end def test_html5_javascript_filter assert_equal(< :html5)) HTML :javascript foo bar HAML end def test_html5_css_filter assert_equal(< :html5)) HTML :css foo bar HAML end def test_erb_filter_with_multiline_expr assert_equal(< HAML end def test_silent_script_with_hyphen_case assert_equal("", render("- 'foo-case-bar-case'")) end def test_silent_script_with_hyphen_end assert_equal("", render("- 'foo-end-bar-end'")) end def test_silent_script_with_hyphen_end_and_block assert_equal(<foo-end

    bar-end

    HTML - ("foo-end-bar-end".gsub(/\\w+-end/) do |s| %p= s - end; nil) HAML end def test_if_without_content_and_else assert_equal(<Foo\n", render('%a(href="#" rel="top") Foo')) assert_equal("Foo\n", render('%a(href="#") #{"Foo"}')) assert_equal("\n", render('%a(href="#\\"")')) end def test_filter_with_newline_and_interp assert_equal(< true)) foo, HTML foo\#{"," if true} HAML end # HTML escaping tests def test_ampersand_equals_should_escape assert_equal("

    \n foo & bar\n

    \n", render("%p\n &= 'foo & bar'", :escape_html => false)) end def test_ampersand_equals_inline_should_escape assert_equal("

    foo & bar

    \n", render("%p&= 'foo & bar'", :escape_html => false)) end def test_ampersand_equals_should_escape_before_preserve assert_equal("\n", render('%textarea&= "foo\nbar"', :escape_html => false)) end def test_bang_equals_should_not_escape assert_equal("

    \n foo & bar\n

    \n", render("%p\n != 'foo & bar'", :escape_html => true)) end def test_bang_equals_inline_should_not_escape assert_equal("

    foo & bar

    \n", render("%p!= 'foo & bar'", :escape_html => true)) end def test_static_attributes_should_be_escaped assert_equal("\n", render("%img.atlantis{:style => 'ugly&stupid'}")) assert_equal("
    foo
    \n", render(".atlantis{:style => 'ugly&stupid'} foo")) assert_equal("

    foo

    \n", render("%p.atlantis{:style => 'ugly&stupid'}= 'foo'")) assert_equal("

    \n", render("%p.atlantis{:style => \"ugly\\nstupid\"}")) end def test_dynamic_attributes_should_be_escaped assert_equal("\n", render("%img{:width => nil, :src => '&foo.png', :alt => String.new}")) assert_equal("

    foo

    \n", render("%p{:width => nil, :src => '&foo.png', :alt => String.new} foo")) assert_equal("
    foo
    \n", render("%div{:width => nil, :src => '&foo.png', :alt => String.new}= 'foo'")) assert_equal("\n", render("%img{:width => nil, :src => \"foo\\n.png\", :alt => String.new}")) end def test_string_double_equals_should_be_esaped assert_equal("

    4&<

    \n", render("%p== \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    4&<

    \n", render("%p== \#{2+2}&\#{'<'}", :escape_html => false)) end def test_escaped_inline_string_double_equals assert_equal("

    4&<

    \n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    4&<

    \n", render("%p&== \#{2+2}&\#{'<'}", :escape_html => false)) end def test_unescaped_inline_string_double_equals assert_equal("

    4&<

    \n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    4&<

    \n", render("%p!== \#{2+2}&\#{'<'}", :escape_html => false)) end def test_escaped_string_double_equals assert_equal("

    \n 4&<\n

    \n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    \n 4&<\n

    \n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => false)) end def test_unescaped_string_double_equals assert_equal("

    \n 4&<\n

    \n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    \n 4&<\n

    \n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => false)) end def test_string_interpolation_should_be_esaped assert_equal("

    4&<

    \n", render("%p \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    4&<

    \n", render("%p \#{2+2}&\#{'<'}", :escape_html => false)) end def test_escaped_inline_string_interpolation assert_equal("

    4&<

    \n", render("%p& \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    4&<

    \n", render("%p& \#{2+2}&\#{'<'}", :escape_html => false)) end def test_unescaped_inline_string_interpolation assert_equal("

    4&<

    \n", render("%p! \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    4&<

    \n", render("%p! \#{2+2}&\#{'<'}", :escape_html => false)) end def test_escaped_string_interpolation assert_equal("

    \n 4&<\n

    \n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    \n 4&<\n

    \n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => false)) end def test_unescaped_string_interpolation assert_equal("

    \n 4&<\n

    \n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true)) assert_equal("

    \n 4&<\n

    \n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => false)) end def test_scripts_should_respect_escape_html_option assert_equal("

    \n foo & bar\n

    \n", render("%p\n = 'foo & bar'", :escape_html => true)) assert_equal("

    \n foo & bar\n

    \n", render("%p\n = 'foo & bar'", :escape_html => false)) end def test_inline_scripts_should_respect_escape_html_option assert_equal("

    foo & bar

    \n", render("%p= 'foo & bar'", :escape_html => true)) assert_equal("

    foo & bar

    \n", render("%p= 'foo & bar'", :escape_html => false)) end def test_script_ending_in_comment_should_render_when_html_is_escaped assert_equal("foo&bar\n", render("= 'foo&bar' #comment", :escape_html => true)) end def test_script_with_if_shouldnt_output assert_equal(<foo

    HTML %p= "foo" %p= "bar" if false HAML end # Options tests def test_filename_and_line begin render("\n\n = abc", :filename => 'test', :line => 2) rescue Exception => e assert_kind_of Haml::SyntaxError, e assert_match(/test:4/, e.backtrace.first) end begin render("\n\n= 123\n\n= nil[]", :filename => 'test', :line => 2) rescue Exception => e assert_kind_of NoMethodError, e assert_match(/test:6/, e.backtrace.first) end end def test_stop_eval assert_equal("", render("= 'Hello'", :suppress_eval => true)) assert_equal("", render("- haml_concat 'foo'", :suppress_eval => true)) assert_equal("
    \n", render("#foo{:yes => 'no'}/", :suppress_eval => true)) assert_equal("
    \n", render("#foo{:yes => 'no', :call => a_function() }/", :suppress_eval => true)) assert_equal("
    \n", render("%div[1]/", :suppress_eval => true)) assert_equal("", render(":ruby\n Kernel.puts 'hello'", :suppress_eval => true)) end def test_doctypes assert_equal('', render('!!!', :format => :html5).strip) assert_equal('', render('!!! 5').strip) assert_equal('', render('!!! strict').strip) assert_equal('', render('!!! frameset').strip) assert_equal('', render('!!! mobile').strip) assert_equal('', render('!!! basic').strip) assert_equal('', render('!!! transitional').strip) assert_equal('', render('!!!').strip) assert_equal('', render('!!! strict', :format => :html4).strip) assert_equal('', render('!!! frameset', :format => :html4).strip) assert_equal('', render('!!! transitional', :format => :html4).strip) assert_equal('', render('!!!', :format => :html4).strip) end def test_attr_wrapper assert_equal("

    \n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*')) assert_equal("

    \n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"')) assert_equal("

    \n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"')) assert_equal("

    \n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"')) assert_equal("\n", render("!!! XML", :attr_wrapper => '"')) end def test_autoclose_option assert_equal("\n", render("%flaz{:foo => 'bar'}", :autoclose => ["flaz"])) assert_equal(< [/^flaz/])) HTML %flaz %flaznicate %flan HAML end def test_attrs_parsed_correctly assert_equal("

    biddly='bar => baz'>

    \n", render("%p{'boom=>biddly' => 'bar => baz'}")) assert_equal("

    \n", render("%p{'foo,bar' => 'baz, qux'}")) assert_equal("

    \n", render("%p{ :escaped => \"quo\\nte\"}")) assert_equal("

    \n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}")) end def test_correct_parsing_with_brackets assert_equal("

    {tada} foo

    \n", render("%p{:class => 'foo'} {tada} foo")) assert_equal("

    deep {nested { things }}

    \n", render("%p{:class => 'foo'} deep {nested { things }}")) assert_equal("

    {a { d

    \n", render("%p{{:class => 'foo'}, :class => 'bar'} {a { d")) assert_equal("

    a}

    \n", render("%p{:foo => 'bar'} a}")) foo = [] foo[0] = Struct.new('Foo', :id).new assert_equal("

    New User]

    \n", render("%p[foo[0]] New User]", :locals => {:foo => foo})) assert_equal("

    New User]

    \n", render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo})) foo[0].id = 1 assert_equal("

    New User]

    \n", render("%p[foo[0]] New User]", :locals => {:foo => foo})) assert_equal("

    New User]

    \n", render("%p[foo[0], :prefix] New User]", :locals => {:foo => foo})) end def test_empty_attrs assert_equal("

    empty

    \n", render("%p{ :attr => '' } empty")) assert_equal("

    empty

    \n", render("%p{ :attr => x } empty", :locals => {:x => ''})) end def test_nil_attrs assert_equal("

    nil

    \n", render("%p{ :attr => nil } nil")) assert_equal("

    nil

    \n", render("%p{ :attr => x } nil", :locals => {:x => nil})) end def test_nil_id_with_syntactic_id assert_equal("

    nil

    \n", render("%p#foo{:id => nil} nil")) assert_equal("

    nil

    \n", render("%p#foo{{:id => 'bar'}, :id => nil} nil")) assert_equal("

    nil

    \n", render("%p#foo{{:id => nil}, :id => 'bar'} nil")) end def test_nil_class_with_syntactic_class assert_equal("

    nil

    \n", render("%p.foo{:class => nil} nil")) assert_equal("

    nil

    \n", render("%p.bar.foo{:class => nil} nil")) assert_equal("

    nil

    \n", render("%p.foo{{:class => 'bar'}, :class => nil} nil")) assert_equal("

    nil

    \n", render("%p.foo{{:class => nil}, :class => 'bar'} nil")) end def test_locals assert_equal("

    Paragraph!

    \n", render("%p= text", :locals => { :text => "Paragraph!" })) end def test_dynamic_attrs_shouldnt_register_as_literal_values assert_equal("

    \n", render('%p{:a => "b#{1 + 1}c"}')) assert_equal("

    \n", render("%p{:a => 'b' + (1 + 1).to_s + 'c'}")) end def test_dynamic_attrs_with_self_closed_tag assert_equal("\nc\n", render("%a{'b' => 1 + 1}/\n= 'c'\n")) end EXCEPTION_MAP.each do |key, value| define_method("test_exception (#{key.inspect})") do begin render(key, :filename => __FILE__) rescue Exception => err value = [value] unless value.is_a?(Array) expected_message, line_no = value line_no ||= key.split("\n").length if expected_message == :compile if Haml::Util.ruby1_8? assert_match(/^compile error\n/, err.message, "Line: #{key}") else assert_match(/^#{Regexp.quote __FILE__}:#{line_no}: syntax error,/, err.message, "Line: #{key}") end else assert_equal(expected_message, err.message, "Line: #{key}") end if Haml::Util.ruby1_8? # Sometimes, the first backtrace entry is *only* in the message. # No idea why. bt = if expected_message == :compile && err.message.include?("\n") err.message.split("\n", 2)[1] else err.backtrace[0] end assert_match(/^#{Regexp.escape(__FILE__)}:#{line_no}/, bt, "Line: #{key}") end else assert(false, "Exception not raised for\n#{key}") end end end def test_exception_line render("a\nb\n!!!\n c\nd") rescue Haml::SyntaxError => e assert_equal("(test_exception_line):4", e.backtrace[0]) else assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception') end def test_exception render("%p\n hi\n %a= undefined\n= 12") rescue Exception => e assert_match("(test_exception):3", e.backtrace[0]) else # Test failed... should have raised an exception assert(false) end def test_compile_error render("a\nb\n- fee)\nc") rescue Exception => e assert_match(/\(test_compile_error\):3: syntax error/i, e.message) else assert(false, '"a\nb\n- fee)\nc" doesn\'t produce an exception!') end def test_unbalanced_brackets render('foo #{1 + 5} foo #{6 + 7 bar #{8 + 9}') rescue Haml::SyntaxError => e assert_equal("Unbalanced brackets.", e.message) end def test_balanced_conditional_comments assert_equal("\n", render("/[if !(IE 6)|(IE 7)] Bracket: ]")) end def test_empty_filter assert_equal(< // END end def test_ugly_filter assert_equal(< true)) #foo { bar: baz; } END end def test_css_filter assert_equal(< /**/ HTML :css #foo { bar: baz; } HAML end def test_local_assigns_dont_modify_class assert_equal("bar\n", render("= foo", :locals => {:foo => 'bar'})) assert_equal(nil, defined?(foo)) end def test_object_ref_with_nil_id user = User.new assert_equal("

    New User

    \n", render("%p[user] New User", :locals => {:user => user})) end def test_object_ref_before_attrs user = User.new 42 assert_equal("

    New User

    \n", render("%p[user]{:style => 'width: 100px;'} New User", :locals => {:user => user})) end def test_object_ref_with_custom_haml_class custom = CustomHamlClass.new 42 assert_equal("

    My Thing

    \n", render("%p[custom]{:style => 'width: 100px;'} My Thing", :locals => {:custom => custom})) end def test_non_literal_attributes assert_equal("

    \n", render("%p{a2, a1, :a3 => 'baz'}/", :locals => {:a1 => {:a1 => 'foo'}, :a2 => {:a2 => 'bar'}})) end def test_render_should_accept_a_binding_as_scope string = "This is a string!" string.instance_variable_set("@var", "Instance variable") b = string.instance_eval do var = "Local variable" binding end assert_equal("

    THIS IS A STRING!

    \n

    Instance variable

    \n

    Local variable

    \n", render("%p= upcase\n%p= @var\n%p= var", :scope => b)) end def test_yield_should_work_with_binding assert_equal("12\nFOO\n", render("= yield\n= upcase", :scope => "foo".instance_eval{binding}) { 12 }) end def test_yield_should_work_with_def_method s = "foo" engine("= yield\n= upcase").def_method(s, :render) assert_equal("12\nFOO\n", s.render { 12 }) end def test_def_method_with_module engine("= yield\n= upcase").def_method(String, :render_haml) assert_equal("12\nFOO\n", "foo".render_haml { 12 }) end def test_def_method_locals obj = Object.new engine("%p= foo\n.bar{:baz => baz}= boom").def_method(obj, :render, :foo, :baz, :boom) assert_equal("

    1

    \n
    3
    \n", obj.render(:foo => 1, :baz => 2, :boom => 3)) end def test_render_proc_locals proc = engine("%p= foo\n.bar{:baz => baz}= boom").render_proc(Object.new, :foo, :baz, :boom) assert_equal("

    1

    \n
    3
    \n", proc[:foo => 1, :baz => 2, :boom => 3]) end def test_render_proc_with_binding assert_equal("FOO\n", engine("= upcase").render_proc("foo".instance_eval{binding}).call) end def test_haml_buffer_gets_reset_even_with_exception scope = Object.new render("- raise Haml::Error", :scope => scope) assert(false, "Expected exception") rescue Exception assert_nil(scope.send(:haml_buffer)) end def test_def_method_haml_buffer_gets_reset_even_with_exception scope = Object.new engine("- raise Haml::Error").def_method(scope, :render) scope.render assert(false, "Expected exception") rescue Exception assert_nil(scope.send(:haml_buffer)) end def test_render_proc_haml_buffer_gets_reset_even_with_exception scope = Object.new proc = engine("- raise Haml::Error").render_proc(scope) proc.call assert(false, "Expected exception") rescue Exception assert_nil(scope.send(:haml_buffer)) end def test_ugly_true assert_equal("
    \n
    \n

    hello world

    \n
    \n
    \n", render("#outer\n #inner\n %p hello world", :ugly => true)) assert_equal("

    #{'s' * 75}

    \n", render("%p #{'s' * 75}", :ugly => true)) assert_equal("

    #{'s' * 75}

    \n", render("%p= 's' * 75", :ugly => true)) end def test_auto_preserve_unless_ugly assert_equal("
    foo
    bar
    \n", render('%pre="foo\nbar"')) assert_equal("
    foo\nbar
    \n", render("%pre\n foo\n bar")) assert_equal("
    foo\nbar
    \n", render('%pre="foo\nbar"', :ugly => true)) assert_equal("
    foo\nbar
    \n", render("%pre\n foo\n bar", :ugly => true)) end def test_xhtml_output_option assert_equal "

    \n
    \n

    \n", render("%p\n %br", :format => :xhtml) assert_equal "
    \n", render("%a/", :format => :xhtml) end def test_arbitrary_output_option assert_raise_message(Haml::Error, "Invalid output format :html1") do engine("%br", :format => :html1) end end def test_static_hashes assert_equal("\n", render("%a{:b => 'a => b'}", :suppress_eval => true)) assert_equal("\n", render("%a{:b => 'a, b'}", :suppress_eval => true)) assert_equal("\n", render('%a{:b => "a\tb"}', :suppress_eval => true)) assert_equal("\n", render('%a{:b => "a\\#{foo}b"}', :suppress_eval => true)) end def test_dynamic_hashes_with_suppress_eval assert_equal("\n", render('%a{:b => "a #{1 + 1} b", :c => "d"}', :suppress_eval => true)) end def test_utf8_attrs assert_equal("\n", render("%a{:href => 'héllo'}")) assert_equal("\n", render("%a(href='héllo')")) end # HTML 4.0 def test_html_has_no_self_closing_tags assert_equal "

    \n
    \n

    \n", render("%p\n %br", :format => :html4) assert_equal "
    \n", render("%br/", :format => :html4) end def test_html_renders_empty_node_with_closing_tag assert_equal "
    \n", render(".foo", :format => :html4) end def test_html_doesnt_add_slash_to_self_closing_tags assert_equal "\n", render("%a/", :format => :html4) assert_equal "\n", render("%a{:foo => 1 + 1}/", :format => :html4) assert_equal "\n", render("%meta", :format => :html4) assert_equal "\n", render("%meta{:foo => 1 + 1}", :format => :html4) end def test_html_ignores_xml_prolog_declaration assert_equal "", render('!!! XML', :format => :html4) end def test_html_has_different_doctype assert_equal %{\n}, render('!!!', :format => :html4) end # because anything before the doctype triggers quirks mode in IE def test_xml_prolog_and_doctype_dont_result_in_a_leading_whitespace_in_html assert_no_match(/^\s+/, render("!!! xml\n!!!", :format => :html4)) end # HTML5 def test_html5_doctype assert_equal %{\n}, render('!!!', :format => :html5) end # HTML5 custom data attributes def test_html5_data_attributes assert_equal("
    \n", render("%div{:data => {:author_id => 123, :foo => 'bar', :biz => 'baz'}}")) assert_equal("
    \n", render("%div{:data => {:one_plus_one => 1+1}}")) assert_equal("
    \n", render(%{%div{:data => {:foo => %{Here's a "quoteful" string.}}}})) #' end def test_html5_data_attributes_with_multiple_defs # Should always use the more-explicit attribute assert_equal("
    \n", render("%div{:data => {:foo => 'first'}, 'data-foo' => 'second'}")) assert_equal("
    \n", render("%div{'data-foo' => 'first', :data => {:foo => 'second'}}")) end def test_html5_data_attributes_with_attr_method Haml::Helpers.module_eval do def data_hash {:data => {:foo => "bar", :baz => "bang"}} end def data_val {:data => "dat"} end end assert_equal("
    \n", render("%div{data_hash, :data => {:foo => 'blip', :brat => 'wurst'}}")) assert_equal("
    \n", render("%div{data_hash, 'data-foo' => 'blip'}")) assert_equal("
    \n", render("%div{data_hash, :data => 'dat'}")) assert_equal("
    \n", render("%div{data_val, :data => {:foo => 'blip', :brat => 'wurst'}}")) end # New attributes def test_basic_new_attributes assert_equal("
    bar\n", render("%a() bar")) assert_equal("bar\n", render("%a(href='foo') bar")) assert_equal("baz\n", render(%q{%a(b="c" c='d' d="e") baz})) end def test_new_attribute_ids assert_equal("
    \n", render("#foo(id='bar')")) assert_equal("
    \n", render("#foo{:id => 'bar'}(id='baz')")) assert_equal("
    \n", render("#foo(id='baz'){:id => 'bar'}")) foo = User.new(42) assert_equal("
    \n", render("#foo(id='baz'){:id => 'bar'}[foo]", :locals => {:foo => foo})) assert_equal("
    \n", render("#foo(id='baz')[foo]{:id => 'bar'}", :locals => {:foo => foo})) assert_equal("
    \n", render("#foo[foo](id='baz'){:id => 'bar'}", :locals => {:foo => foo})) assert_equal("
    \n", render("#foo[foo]{:id => 'bar'}(id='baz')", :locals => {:foo => foo})) end def test_new_attribute_classes assert_equal("
    \n", render(".foo(class='bar')")) assert_equal("
    \n", render(".foo{:class => 'bar'}(class='baz')")) assert_equal("
    \n", render(".foo(class='baz'){:class => 'bar'}")) foo = User.new(42) assert_equal("
    \n", render(".foo(class='baz'){:class => 'bar'}[foo]", :locals => {:foo => foo})) assert_equal("
    \n", render(".foo[foo](class='baz'){:class => 'bar'}", :locals => {:foo => foo})) assert_equal("
    \n", render(".foo[foo]{:class => 'bar'}(class='baz')", :locals => {:foo => foo})) end def test_dynamic_new_attributes assert_equal("bar\n", render("%a(href=foo) bar", :locals => {:foo => 12})) assert_equal("bar\n", render("%a(b=b c='13' d=d) bar", :locals => {:b => 12, :d => 14})) end def test_new_attribute_interpolation assert_equal("bar\n", render('%a(href="1#{1 + 1}") bar')) assert_equal("bar\n", render(%q{%a(href='2: #{1 + 1}, 3: #{foo}') bar}, :locals => {:foo => 3})) assert_equal(%Q{bar\n}, render('%a(href="1\#{1 + 1}") bar')) end def test_truthy_new_attributes assert_equal("bar\n", render("%a(href) bar")) assert_equal("bar\n", render("%a(href bar='baz') bar", :format => :html5)) assert_equal("bar\n", render("%a(href=true) bar")) assert_equal("bar\n", render("%a(href=false) bar")) end def test_new_attribute_parsing assert_equal("bar\n", render("%a(a2=b2) bar", :locals => {:b2 => 'b2'})) assert_equal(%Q{bar\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #' assert_equal(%Q{bar\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #' assert_equal(%Q{bar\n}, render(%q{%a(a='foo"bar') bar})) assert_equal(%Q{bar\n}, render(%q{%a(a="foo'bar") bar})) assert_equal("bar\n", render("%a(a:b='foo') bar")) assert_equal("bar\n", render("%a(a = 'foo' b = 'bar') bar")) assert_equal("bar\n", render("%a(a = foo b = bar) bar", :locals => {:foo => 'foo', :bar => 'bar'})) assert_equal("(b='bar')\n", render("%a(a='foo')(b='bar')")) assert_equal("baz\n", render("%a(a='foo)bar') baz")) assert_equal("baz\n", render("%a( a = 'foo' ) baz")) end def test_new_attribute_escaping assert_equal(%Q{bar\n}, render(%q{%a(a="foo \" bar") bar})) assert_equal(%Q{bar\n}, render(%q{%a(a="foo \\\\\" bar") bar})) assert_equal(%Q{bar\n}, render(%q{%a(a='foo \' bar') bar})) assert_equal(%Q{bar\n}, render(%q{%a(a='foo \\\\\' bar') bar})) assert_equal(%Q{bar\n}, render(%q{%a(a="foo \\\\ bar") bar})) assert_equal(%Q{bar\n}, render(%q{%a(a="foo \#{1 + 1} bar") bar})) end def test_multiline_new_attribute assert_equal("bar\n", render("%a(a='b'\n c='d') bar")) assert_equal("bar\n", render("%a(a='b' b='c'\n c='d' d=e\n e='f' f='j') bar", :locals => {:e => 'e'})) end def test_new_and_old_attributes assert_equal("bar\n", render("%a(a='b'){:c => 'd'} bar")) assert_equal("bar\n", render("%a{:c => 'd'}(a='b') bar")) assert_equal("bar\n", render("%a(c='d'){:a => 'b'} bar")) assert_equal("bar\n", render("%a{:a => 'b'}(c='d') bar")) # Old-style always takes precedence over new-style, # because theoretically old-style could have arbitrary end-of-method-call syntax. assert_equal("bar\n", render("%a{:a => 'b'}(a='d') bar")) assert_equal("bar\n", render("%a(a='d'){:a => 'b'} bar")) assert_equal("bar\n", render("%a{:a => 'b',\n:b => 'c'}(c='d'\nd='e') bar")) locals = {:b => 'b', :d => 'd'} assert_equal("

    \n", render("%p{:a => b}(c=d)", :locals => locals)) assert_equal("

    \n", render("%p(a=b){:c => d}", :locals => locals)) end # Ruby Multiline def test_silent_ruby_multiline assert_equal(<foo

    HTML - foo = ["bar", "baz", "bang"] = foo.join(", ") %p foo HAML end def test_loud_ruby_multiline assert_equal(<foo

    bar

    HTML = ["bar", "baz", "bang"].join(", ") %p foo %p bar HAML end def test_escaped_loud_ruby_multiline assert_equal(<foo

    bar

    HTML &= ["bar<", "baz", "bang"].join(", ") %p foo %p bar HAML end def test_unescaped_loud_ruby_multiline assert_equal(< true)) bar<, baz, bang

    foo

    bar

    HTML != ["bar<", "baz", "bang"].join(", ") %p foo %p bar HAML end def test_flattened_loud_ruby_multiline assert_equal(<bar baz bang

    foo

    bar

    HTML ~ "
    " + ["bar",
                 "baz",
                 "bang"].join("\\n") + "
    " %p foo %p bar HAML end def test_loud_ruby_multiline_with_block assert_equal(<foo

    bar

    HTML = ["bar", "baz", "bang"].map do |str| - str.gsub("ba", "fa") %p foo %p bar HAML end def test_silent_ruby_multiline_with_block assert_equal(<foo

    bar

    HTML - ["bar", "baz", "bang"].map do |str| = str.gsub("ba", "fa") %p foo %p bar HAML end def test_ruby_multiline_in_tag assert_equal(<foo, bar, baz

    foo

    bar

    HTML %p= ["foo", "bar", "baz"].join(", ") %p foo %p bar HAML end def test_escaped_ruby_multiline_in_tag assert_equal(<foo<, bar, baz

    foo

    bar

    HTML %p&= ["foo<", "bar", "baz"].join(", ") %p foo %p bar HAML end def test_unescaped_ruby_multiline_in_tag assert_equal(< true))

    foo<, bar, baz

    foo

    bar

    HTML %p!= ["foo<", "bar", "baz"].join(", ") %p foo %p bar HAML end def test_ruby_multiline_with_normal_multiline assert_equal(<foo

    bar

    HTML = "foo" + | "bar" + | ["bar", | "baz", "bang"].join(", ") %p foo %p bar HAML end def test_ruby_multiline_after_filter assert_equal(<foo

    bar

    HTML :plain foo bar = ["bar", "baz", "bang"].join(", ") %p foo %p bar HAML end # Encodings def test_utf_8_bom assert_equal <

    baz

    HTML \xEF\xBB\xBF.foo %p baz HAML end unless Haml::Util.ruby1_8? def test_default_encoding assert_equal(Encoding.find("utf-8"), render(< "ascii-8bit"))

    bâr

    föö

    HTML %p bâr %p föö HAML end def test_convert_template_render_proc assert_converts_template_properly {|e| e.render_proc.call} end def test_convert_template_render assert_converts_template_properly {|e| e.render} end def test_convert_template_def_method assert_converts_template_properly do |e| o = Object.new e.def_method(o, :render) o.render end end def test_encoding_error render("foo\nbar\nb\xFEaz".force_encoding("utf-8")) assert(false, "Expected exception") rescue Haml::Error => e assert_equal(3, e.line) assert_equal('Invalid UTF-8 character "\xFE"', e.message) end def test_ascii_incompatible_encoding_error template = "foo\nbar\nb_z".encode("utf-16le") template[9] = "\xFE".force_encoding("utf-16le") render(template) assert(false, "Expected exception") rescue Haml::Error => e assert_equal(3, e.line) assert_equal('Invalid UTF-16LE character "\xFE"', e.message) end def test_same_coding_comment_as_encoding assert_renders_encoded(<bâr

    föö

    HTML -# coding: utf-8 %p bâr %p föö HAML end def test_coding_comments assert_valid_encoding_comment("-# coding: ibm866") assert_valid_encoding_comment("-# CodINg: IbM866") assert_valid_encoding_comment("-#coding:ibm866") assert_valid_encoding_comment("-# CodINg= ibm866") assert_valid_encoding_comment("-# foo BAR FAOJcoding: ibm866") assert_valid_encoding_comment("-# coding: ibm866 ASFJ (&(&#!$") assert_valid_encoding_comment("-# -*- coding: ibm866") assert_valid_encoding_comment("-# coding: ibm866 -*- coding: blah") assert_valid_encoding_comment("-# -*- coding: ibm866 -*-") assert_valid_encoding_comment("-# -*- encoding: ibm866 -*-") assert_valid_encoding_comment('-# -*- coding: "ibm866" -*-') assert_valid_encoding_comment("-#-*-coding:ibm866-*-") assert_valid_encoding_comment("-#-*-coding:ibm866-*-") assert_valid_encoding_comment("-# -*- foo: bar; coding: ibm866; baz: bang -*-") assert_valid_encoding_comment("-# foo bar coding: baz -*- coding: ibm866 -*-") assert_valid_encoding_comment("-# -*- coding: ibm866 -*- foo bar coding: baz") end def test_different_coding_than_system assert_renders_encoded(<тАЬ

    HTML %p тАЬ HAML end end private def assert_valid_encoding_comment(comment) assert_renders_encoded(<ЖЛЫ

    тАЬ

    HTML #{comment} %p ЖЛЫ %p тАЬ HAML end def assert_converts_template_properly engine = Haml::Engine.new(< "macRoman") %p bâr %p föö HAML assert_encoded_equal(<bâr

    föö

    HTML end def assert_renders_encoded(html, haml) result = render(haml) assert_encoded_equal html, result end def assert_encoded_equal(expected, actual) assert_equal expected.encoding, actual.encoding assert_equal expected, actual end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/erb/0000775000175000017500000000000012414640747030106 5ustar ebourgebourg././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/erb/action_view.erbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/erb/action_view.0000664000175000017500000000424012414640747032416 0ustar ebourgebourg Hampton Catlin Is Totally Awesome

    This is very much like the standard template, except that it has some ActionView-specific stuff. It's only used for benchmarking.

    <%= render :partial => 'haml/erb/av_partial_1' %>
    Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! <%= 1 + 9 + 8 + 2 %> <%# numbers should work and this should be ignored %>
    <% 120.times do |number| -%> <%= number %> <% end -%>
    <%= " Quotes should be loved! Just like people!" %>
    Wow.

    <%= "Holy cow " + "multiline " + "tags! " + "A pipe (|) even!" %> <%= [1, 2, 3].collect { |n| "PipesIgnored|" } %> <%= [1, 2, 3].collect { |n| n.to_s }.join("|") %>

    <% foo = String.new foo << "this" foo << " shouldn't" foo << " evaluate" %> <%= foo + "but now it should!" %> <%# Woah crap a comment! %>
      <% ('a'..'f').each do |a|%>
    • <%= a %> <% end %>
      <%= @should_eval = "with this text" %>
      <%= [ 104, 101, 108, 108, 111 ].map do |byte| byte.chr end %> stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/erb/standard.erb0000664000175000017500000000371712414640747032410 0ustar ebourgebourg Hampton Catlin Is Totally Awesome
      Yes, ladies and gentileman. He is just that egotistical. Fantastic! This should be multi-line output The question is if this would translate! Ahah! <%= 1 + 9 + 8 + 2 %> <%# numbers should work and this should be ignored %>
      <% 120.times do |number| -%> <%= number %> <% end -%>
      <%= " Quotes should be loved! Just like people!" %>
      Wow.

      <%= "Holy cow " + "multiline " + "tags! " + "A pipe (|) even!" %> <%= [1, 2, 3].collect { |n| "PipesIgnored|" }.join %> <%= [1, 2, 3].collect { |n| n.to_s }.join("|") %>

      <% bar = 17 %>
      <% foo = String.new foo << "this" foo << " shouldn't" foo << " evaluate" %> <%= foo + "but now it should!" %> <%# Woah crap a comment! %>
        <% ('a'..'f').each do |a|%>
      • <%= a %>
      • <% end %>
        <%= @should_eval = "with this text" %>
        <%= "foo".each_line do |line| nil end %> ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/erb/_av_partial_1.erbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/erb/_av_partial_0000664000175000017500000000045012414640747032450 0ustar ebourgebourg

        This is a pretty complicated partial

        It has several nested partials,

          <% 5.times do %>
        • Partial: <% @nesting = 5 %> <%= render :partial => 'haml/erb/av_partial_2' %> <% end %>
        ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/erb/_av_partial_2.erbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/erb/_av_partial_0000664000175000017500000000037212414640747032453 0ustar ebourgebourg<% @nesting -= 1 %>

        This is a crazy deep-nested partial.

        Nesting level <%= @nesting %>

        <% if @nesting > 0 %> <%= render :partial => 'haml/erb/av_partial_2' %> <% end %>
        stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/spec/0000775000175000017500000000000012414640747030270 5ustar ebourgebourg././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/spec/ruby_haml_test.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/spec/ruby_haml_t0000664000175000017500000000126312414640747032522 0ustar ebourgebourgrequire "test/unit" require "json" require "haml" class HamlTest < Test::Unit::TestCase contexts = JSON.parse(File.read(File.dirname(__FILE__) + "/tests.json")) contexts.each do |context| context[1].each do |name, test| class_eval(<<-EOTEST) def test_#{name.gsub(/\s+|[^a-zA-Z0-9_]/, "_")} locals = Hash[*(#{test}["locals"] || {}).collect {|k, v| [k.to_sym, v] }.flatten] options = Hash[*(#{test}["config"] || {}).collect {|k, v| [k.to_sym, v.to_sym] }.flatten] engine = Haml::Engine.new(#{test}["haml"], options) assert_equal(engine.render(Object.new, locals).chomp, #{test}["html"]) end EOTEST end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/spec/README.md0000664000175000017500000000737112414640747031557 0ustar ebourgebourg# Haml Spec # Haml Spec provides a basic suite of tests for Haml interpreters. It is intented for developers who are creating or maintaining an implementation of the [Haml](http://haml-lang.com) markup language. At the moment, there are test runners for the [original Haml](http://github.com/nex3/haml) in Ruby, and for [Lua Haml](http://github.com/norman/lua-haml). Support for other versions of Haml will be added if their developers/maintainers are interested in using it. ## The Tests ## The tests are kept in JSON format for portability across languages. Each test is a JSON object with expected input, output, local variables and configuration parameters (see below). The test suite only provides tests for features which are portable, therefore no tests for script are provided, nor for external filters such as :markdown or :textile. The one major exception to this are the tests for interpolation, which you may need to modify with a regular expression to run under PHP or Perl, which require a symbol before variable names. These tests are included despite being less than 100% portable because interpolation is an important part of Haml and can be tricky to implement. ## Running the Tests ## ### Ruby ### In order to make it as easy as possible for non-Ruby programmers to run the Ruby Haml tests, the Ruby test runner uses test/unit, rather than something fancier like Rspec. To run them you probably only need to install `haml`, and possibly `ruby` if your platform doesn't come with it by default. If you're using Ruby 1.8.x, you'll also need to install `json`: sudo gem install haml # for Ruby 1.8.x; check using "ruby --version" if unsure sudo gem install json Then, running the Ruby test suite is easy: ruby ruby_haml_test.rb ### Lua ### The Lua test depends on [Telescope](http://telescope.luaforge.net/), [jason4lua](http://json.luaforge.net/), and [Lua Haml](http://github.com/norman/lua-haml). Install and run `tsc lua_haml_spec.lua`. ## Contributing ## ### Getting it ### You can access the [Git repository](http://github.com/norman/haml-spec) at: git://github.com/norman/haml-spec.git Patches are *very* welcome, as are test runners for your Haml implementation. As long as any test you add run against Ruby Haml and are not redundant, I'll be very happy to add them. ### Test JSON format ### "test name" : { "haml" : "haml input", "html" : "expected html output", "result" : "expected test result", "locals" : "local vars", "config" : "config params" } * test name: This should be a *very* brief description of what's being tested. It can be used by the test runners to name test methods, or to exclude certain tests from being run. * haml: The Haml code to be evaluated. Always required. * html: The HTML output that should be generated. Required unless "result" is "error". * result: Can be "pass" or "error". If it's absent, then "pass" is assumed. If it's "error", then the goal of the test is to make sure that malformed Haml code generates an error. * locals: An object containing local variables needed for the test. * config: An object containing configuration parameters used to run the test. The configuration parameters should be usable directly by Ruby's Haml with no modification. If your implementation uses config parameters with different names, you may need to process them to make them match your implementation. If your implementation has options that do not exist in Ruby's Haml, then you should add tests for this in your implementation's test rather than here. ## License ## This project is released under the [WTFPL](http://sam.zoy.org/wtfpl/) in order to be as usable as possible in any project, commercial or free. ## Author ## [Norman Clarke](mailto:norman@njclarke.com) stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/spec/tests.json0000664000175000017500000002772012414640747032335 0ustar ebourgebourg{ "headers" : { "an XHTML XML prolog" : { "haml" : "!!! XML", "html" : "" }, "an XHTML default (transitional) doctype" : { "haml" : "!!!", "html" : "" }, "an XHTML 1.1 doctype" : { "haml" : "!!! 1.1", "html" : "" }, "an XHTML 1.2 mobile doctype" : { "haml" : "!!! mobile", "html" : "" }, "an XHTML 1.1 basic doctype" : { "haml" : "!!! basic", "html" : "" }, "an XHTML 1.0 frameset doctype" : { "haml" : "!!! frameset", "html" : "" }, "an HTML 5 doctype with XHTML syntax" : { "haml" : "!!! 5", "html" : "" }, "an HTML 5 XML prolog (silent)" : { "haml" : "!!! XML", "html" : "", "config" : { "format" : "html5" } }, "an HTML 5 doctype" : { "haml" : "!!!", "html" : "", "config" : { "format" : "html5" } }, "an HTML 4 XML prolog (silent)" : { "haml" : "!!! XML", "html" : "", "config" : { "format" : "html4" } }, "an HTML 4 default (transitional) doctype" : { "haml" : "!!!", "html" : "", "config" : { "format" : "html4" } }, "an HTML 4 frameset doctype" : { "haml" : "!!! frameset", "html" : "", "config" : { "format" : "html4" } }, "an HTML 4 strict doctype" : { "haml" : "!!! strict", "html" : "", "config" : { "format" : "html4" } } }, "basic Haml tags and CSS": { "a simple Haml tag" : { "haml" : "%p", "html" : "

        " }, "a self-closing tag (XHTML)" : { "haml" : "%meta", "html" : "" }, "a self-closing tag (HTML4)" : { "haml" : "%meta", "html" : "", "config" : { "format" : "html4" } }, "a self-closing tag (HTML5)" : { "haml" : "%meta", "html" : "", "config" : { "format" : "html5" } }, "a tag with a CSS class" : { "haml" : "%p.class1", "html" : "

        " }, "a tag with multiple CSS classes" : { "haml" : "%p.class1.class2", "html" : "

        " }, "a tag with a CSS id" : { "haml" : "%p#id1", "html" : "

        " }, "a tag with multiple CSS id's" : { "haml" : "%p#id1#id2", "html" : "

        " }, "a tag with a class followed by an id" : { "haml" : "%p.class1#id1", "html" : "

        " }, "a tag with an id followed by a class" : { "haml" : "%p#id1.class1", "html" : "

        " }, "an implicit div with a CSS id" : { "haml" : "#id1", "html" : "
        " }, "an implicit div with a CSS class" : { "haml" : ".class1", "html" : "
        " }, "multiple simple Haml tags" : { "haml" : "%div\n %div\n %p", "html" : "
        \n
        \n

        \n
        \n
        " } }, "tags with unusual HTML characters" : { "a tag with colons" : { "haml" : "%ns:tag", "html" : "" }, "a tag with underscores" : { "haml" : "%snake_case", "html" : "" }, "a tag with dashes" : { "haml" : "%dashed-tag", "html" : "" }, "a tag with camelCase" : { "haml" : "%camelCase", "html" : "" }, "a tag with PascalCase" : { "haml" : "%PascalCase", "html" : "" } }, "tags with unusual CSS identifiers" : { "an all-numeric class" : { "haml" : ".123", "html" : "
        " }, "a class with underscores" : { "haml" : ".__", "html" : "
        " }, "a class with dashes" : { "haml" : ".--", "html" : "
        " } }, "tags with inline content" : { "a simple tag" : { "haml" : "%p hello", "html" : "

        hello

        " }, "a tag with CSS" : { "haml" : "%p.class1 hello", "html" : "

        hello

        " }, "multiple simple tags" : { "haml" : "%div\n %div\n %p text", "html" : "
        \n
        \n

        text

        \n
        \n
        " } }, "tags with nested content" : { "a simple tag" : { "haml" : "%p\n hello", "html" : "

        \n hello\n

        " }, "a tag with CSS" : { "haml" : "%p.class1\n hello", "html" : "

        \n hello\n

        " }, "multiple simple tags" : { "haml" : "%div\n %div\n %p\n text", "html" : "
        \n
        \n

        \n text\n

        \n
        \n
        " } }, "tags with HTML-style attributes": { "one attribute" : { "haml" : "%p(a='b')", "html" : "

        " }, "multiple attributes" : { "haml" : "%p(a='b' c='d')", "html" : "

        " }, "attributes separated with newlines" : { "haml" : "%p(a='b'\n c='d')", "html" : "

        " }, "an interpolated attribute" : { "haml" : "%p(a=\"#{var}\")", "html" : "

        ", "locals" : { "var" : "value" } }, "'class' as an attribute" : { "haml" : "%p(class='class1')", "html" : "

        " }, "a tag with a CSS class and 'class' as an attribute" : { "haml" : "%p.class2(class='class1')", "html" : "

        " }, "a tag with 'id' as an attribute" : { "haml" : "%p(id='1')", "html" : "

        " }, "a tag with a CSS id and 'id' as an attribute" : { "haml" : "%p#id(id='1')", "html" : "

        " }, "a tag with a variable attribute" : { "haml" : "%p(class=var)", "html" : "

        ", "locals" : { "var" : "hello" } }, "a tag with a CSS class and 'class' as a variable attribute" : { "haml" : ".hello(class=var)", "html" : "
        ", "locals" : { "var" : "world" } }, "a tag multiple CSS classes (sorted correctly)" : { "haml" : ".z(class=var)", "html" : "
        ", "locals" : { "var" : "a" } } }, "tags with Ruby-style attributes": { "one attribute" : { "haml" : "%p{:a => 'b'}", "html" : "

        " }, "attributes hash with whitespace" : { "haml" : "%p{ :a => 'b' }", "html" : "

        " }, "an interpolated attribute" : { "haml" : "%p{:a =>\"#{var}\"}", "html" : "

        ", "locals" : { "var" : "value" } }, "multiple attributes" : { "haml" : "%p{ :a => 'b', 'c' => 'd' }", "html" : "

        " }, "attributes separated with newlines" : { "haml" : "%p{ :a => 'b',\n 'c' => 'd' }", "html" : "

        " }, "'class' as an attribute" : { "haml" : "%p{:class => 'class1'}", "html" : "

        " }, "a tag with a CSS class and 'class' as an attribute" : { "haml" : "%p.class2{:class => 'class1'}", "html" : "

        " }, "a tag with 'id' as an attribute" : { "haml" : "%p{:id => '1'}", "html" : "

        " }, "a tag with a CSS id and 'id' as an attribute" : { "haml" : "%p#id{:id => '1'}", "html" : "

        " }, "a tag with a CSS id and a numeric 'id' as an attribute" : { "haml" : "%p#id{:id => 1}", "html" : "

        " }, "a tag with a variable attribute" : { "haml" : "%p{:class => var}", "html" : "

        ", "locals" : { "var" : "hello" } }, "a tag with a CSS class and 'class' as a variable attribute" : { "haml" : ".hello{:class => var}", "html" : "
        ", "locals" : { "var" : "world" } }, "a tag multiple CSS classes (sorted correctly)" : { "haml" : ".z{:class => var}", "html" : "
        ", "locals" : { "var" : "a" } } }, "silent comments" : { "an inline comment" : { "haml" : "-# hello", "html" : "" }, "a nested comment" : { "haml" : "-#\n hello", "html" : "" } }, "markup comments" : { "an inline comment" : { "haml" : "/ comment", "html" : "" }, "a nested comment" : { "haml" : "/\n comment\n comment2", "html" : "" } }, "conditional comments": { "a conditional comment" : { "haml" : "/[if IE]\n %p a", "html" : "" } }, "internal filters": { "content in an 'escaped' filter" : { "haml" : ":escaped\n <&\">", "html" : "<&">" }, "content in a 'preserve' filter" : { "haml" : ":preserve\n hello\n\n%p", "html" : "hello \n

        " }, "content in a 'plain' filter" : { "haml" : ":plain\n hello\n\n%p", "html" : "hello\n

        " }, "content in a 'javascript' filter" : { "haml" : ":javascript\n a();\n%p", "html" : "\n

        " } }, "interpolation": { "interpolation inside inline content" : { "haml" : "%p #{var}", "html" : "

        value

        ", "locals" : { "var" : "value" } }, "no interpolation when escaped" : { "haml" : "%p \\#{var}", "html" : "

        #{var}

        " }, "interpolation when the escape character is escaped" : { "haml" : "%p \\\\#{var}", "html" : "

        \\value

        ", "locals" : { "var" : "value" } }, "interpolation inside filtered content" : { "haml" : ":plain\n #{var} interpolated: #{var}", "html" : "value interpolated: value", "locals" : { "var" : "value" } } }, "HTML escaping" : { "code following '&='" : { "haml" : "&= '<\"&>'", "html" : "<"&>" }, "code following '=' when escape_haml is set to true" : { "haml" : "= '<\"&>'", "html" : "<"&>", "config" : { "escape_html" : "true" } }, "code following '!=' when escape_haml is set to true" : { "haml" : "!= '<\"&>'", "html" : "<\"&>", "config" : { "escape_html" : "true" } } }, "Boolean attributes" : { "boolean attribute with XHTML" : { "haml" : "%input(checked=true)", "html" : "", "config" : { "format" : "xhtml" } }, "boolean attribute with HTML" : { "haml" : "%input(checked=true)", "html" : "", "config" : { "format" : "html5" } } } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/spec/lua_haml_spec.luastapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/haml/spec/lua_haml_sp0000664000175000017500000000155412414640747032504 0ustar ebourgebourgrequire 'luarocks.require' require 'json' require 'telescope' require 'haml' local function get_tests(filename) local self = debug.getinfo(1).short_src if self:match("/") then return "./" .. self:gsub("[^/]*%.lua$", "/" .. filename) elseif self:match("\\") then return self:gsub("[^\\]*%.lua$", "\\" .. filename) else return filename end end local fh = assert(io.open(get_tests("tests.json"))) local input = fh:read '*a' fh:close() local contexts = json.decode(input) describe("LuaHaml", function() for context, expectations in pairs(contexts) do describe("When handling " .. context, function() for name, exp in pairs(expectations) do it(string.format("should correctly render %s", name), function() assert_equal(haml.render(exp.haml, exp.config or {}, exp.locals or {}), exp.html) end) end end) end end) stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/test/linked_rails.rb0000664000175000017500000000232112414640747031400 0ustar ebourgebourg# allows testing with edge Rails by creating a test/rails symlink linked_rails = File.dirname(__FILE__) + '/rails' if File.exists?(linked_rails) && !$:.include?(linked_rails + '/activesupport/lib') puts "[ using linked Rails ]" $:.unshift linked_rails + '/activesupport/lib' $:.unshift linked_rails + '/actionpack/lib' $:.unshift linked_rails + '/railties/lib' end require 'rubygems' require 'action_controller' require 'action_view' begin # Necessary for Rails 3 require 'rails' rescue LoadError # Necessary for Rails 2.3.7 require 'initializer' rescue LoadError end if defined?(Rails::Application) # Rails 3 class TestApp < Rails::Application config.root = File.join(File.dirname(__FILE__), "../..") end Rails.application = TestApp elsif defined?(RAILS_ROOT) RAILS_ROOT.replace(File.join(File.dirname(__FILE__), "../..")) else RAILS_ROOT = File.join(File.dirname(__FILE__), "../..") end ActionController::Base.logger = Logger.new(nil) # Load plugins from test/plugins. # This will only work with very basic plugins, # since we don't want to load the entirety of Rails. Dir[File.dirname(__FILE__) + '/plugins/*'].each do |plugin| $: << plugin + '/lib' eval(File.read(plugin + '/init.rb')) end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/extra/0000775000175000017500000000000012414640747026561 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/extra/update_watch.rb0000664000175000017500000000051312414640747031555 0ustar ebourgebourgrequire 'rubygems' require 'sinatra' require 'json' set :port, 3123 set :environment, :production enable :lock Dir.chdir(File.dirname(__FILE__) + "/..") post "/" do puts "Recieved payload!" puts "Rev: #{`git name-rev HEAD`.strip}" system %{rake handle_update --trace REF=#{JSON.parse(params["payload"])["ref"].inspect}} end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/Rakefile0000664000175000017500000002535612414640747027116 0ustar ebourgebourg# ----- Utility Functions ----- def scope(path) File.join(File.dirname(__FILE__), path) end # ----- Benchmarking ----- desc < :"test:rails_compatibility" else task :default => :test end require 'rake/testtask' Rake::TestTask.new do |t| t.libs << 'lib' test_files = FileList[scope('test/**/*_test.rb')] test_files.exclude(scope('test/rails/*')) test_files.exclude(scope('test/plugins/*')) test_files.exclude(scope('test/haml/spec/*')) t.test_files = test_files t.verbose = true end Rake::Task[:test].send(:add_comment, < [:revision_file, :submodules, :permissions] do version = get_version File.open(scope('VERSION'), 'w') {|f| f.puts(version)} load scope('haml.gemspec') Gem::Builder.new(HAML_GEMSPEC).build sh %{git checkout VERSION} pkg = "#{HAML_GEMSPEC.name}-#{HAML_GEMSPEC.version}" mkdir_p "pkg" verbose(true) {mv "#{pkg}.gem", "pkg/#{pkg}.gem"} sh %{rm -f pkg/#{pkg}.tar.gz} verbose(false) {HAML_GEMSPEC.files.each {|f| sh %{tar rf pkg/#{pkg}.tar #{f}}}} sh %{gzip pkg/#{pkg}.tar} end task :permissions do sh %{chmod -R a+rx bin} sh %{chmod -R a+r .} require 'shellwords' Dir.glob('test/**/*_test.rb') do |file| next if file =~ %r{^test/haml/spec/} sh %{chmod a+rx #{file}} end end task :revision_file do require 'lib/haml' release = Rake.application.top_level_tasks.include?('release') || File.exist?(scope('EDGE_GEM_VERSION')) if Haml.version[:rev] && !release File.open(scope('REVISION'), 'w') { |f| f.puts Haml.version[:rev] } elsif release File.open(scope('REVISION'), 'w') { |f| f.puts "(release)" } else File.open(scope('REVISION'), 'w') { |f| f.puts "(unknown)" } end end # We also need to get rid of this file after packaging. at_exit { File.delete(scope('REVISION')) rescue nil } desc "Install Haml as a gem. Use SUDO=1 to install with sudo." task :install => [:package] do gem = RUBY_PLATFORM =~ /java/ ? 'jgem' : 'gem' sh %{#{'sudo ' if ENV["SUDO"]}#{gem} install --no-ri pkg/haml-#{get_version}} end desc "Release a new Haml package to Rubyforge." task :release => [:check_release, :package] do name = File.read(scope("VERSION_NAME")).strip version = File.read(scope("VERSION")).strip sh %{rubyforge add_release haml haml "#{name} (v#{version})" pkg/haml-#{version}.gem} sh %{rubyforge add_file haml haml "#{name} (v#{version})" pkg/haml-#{version}.tar.gz} sh %{gem push pkg/haml-#{version}.gem} end # Ensures that the VERSION file has been updated for a new release. task :check_release do version = File.read(scope("VERSION")).strip raise "There have been changes since current version (#{version})" if changed_since?(version) raise "VERSION_NAME must not be 'Bleeding Edge'" if File.read(scope("VERSION_NAME")) == "Bleeding Edge" end # Reads a password from the command line. # # @param name [String] The prompt to use to read the password def read_password(prompt) require 'readline' system "stty -echo" Readline.readline("#{prompt}: ").strip ensure system "stty echo" puts end # Returns whether or not the repository, or specific files, # has/have changed since a given revision. # # @param rev [String] The revision to check against # @param files [Array] The files to check. # If this is empty, checks the entire repository def changed_since?(rev, *files) IO.popen("git diff --exit-code #{rev} #{files.join(' ')}") {} return !$?.success? end task :submodules do if File.exist?(File.dirname(__FILE__) + "/.git") sh %{git submodule sync} sh %{git submodule update --init --recursive} end end task :release_edge do ensure_git_cleanup do puts "#{'=' * 50} Running rake release_edge" sh %{git checkout master} sh %{git reset --hard origin/master} sh %{rake package} version = get_version sh %{rubyforge add_release haml haml "Bleeding Edge (v#{version})" pkg/haml-#{version}.gem} sh %{gem push pkg/haml-#{version}.gem} end end # Get the version string. If this is being installed from Git, # this includes the proper prerelease version. def get_version written_version = File.read(scope('VERSION').strip) return written_version unless File.exist?(scope('.git')) # Get the current master branch version version = written_version.split('.') version.map! {|n| n =~ /^[0-9]+$/ ? n.to_i : n} return written_version unless version.size == 5 && version[3] == "alpha" # prerelease return written_version if (commit_count = `git log --pretty=oneline --first-parent stable.. | wc -l`).empty? version[4] = commit_count.strip version.join('.') end task :watch_for_update do sh %{ruby extra/update_watch.rb} end # ----- Documentation ----- task :rdoc do puts '=' * 100, < :yard task :redoc => :yard rescue LoadError desc "Generate Documentation" task :doc => :rdoc task :yard => :rdoc end task :pages do puts "#{'=' * 50} Running rake pages" ensure_git_cleanup do sh %{git checkout haml-pages} sh %{git reset --hard origin/haml-pages} Dir.chdir("/var/www/haml-pages") do sh %{git fetch origin} sh %{git checkout stable} sh %{git reset --hard origin/stable} sh %{git checkout haml-pages} sh %{git reset --hard origin/haml-pages} sh %{rake build --trace} sh %{mkdir -p tmp} sh %{touch tmp/restart.txt} end end end # ----- Coverage ----- begin require 'rcov/rcovtask' Rcov::RcovTask.new do |t| t.test_files = FileList[scope('test/**/*_test.rb')] t.rcov_opts << '-x' << '"^\/"' if ENV['NON_NATIVE'] t.rcov_opts << "--no-rcovrt" end t.verbose = true end rescue LoadError; end # ----- Profiling ----- begin require 'ruby-prof' desc < e IO.popen("sendmail nex342@gmail.com", "w") do |sm| sm << "From: nex3@nex-3.com\n" << "To: nex342@gmail.com\n" << "Subject: Exception when running rake #{Rake.application.top_level_tasks.join(', ')}\n" << e.message << "\n\n" << e.backtrace.join("\n") end ensure raise e if e end def ensure_git_cleanup email_on_error {yield} ensure sh %{git reset --hard HEAD} sh %{git clean -xdf} sh %{git checkout master} end task :handle_update do email_on_error do unless ENV["REF"] =~ %r{^refs/heads/(master|stable|haml-pages)$} puts "#{'=' * 20} Ignoring rake handle_update REF=#{ENV["REF"].inspect}" next end branch = $1 puts puts puts '=' * 150 puts "Running rake handle_update REF=#{ENV["REF"].inspect}" sh %{git fetch origin} sh %{git checkout stable} sh %{git reset --hard origin/stable} sh %{git checkout master} sh %{git reset --hard origin/master} case branch when "master" sh %{rake release_edge --trace} when "stable", "haml-pages" sh %{rake pages --trace} end puts 'Done running handle_update' puts '=' * 150 end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/REVISION0000664000175000017500000000001212414640747026610 0ustar ebourgebourg(release) stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/0000775000175000017500000000000012414640747026204 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/sass.rb0000664000175000017500000000026712414640747027507 0ustar ebourgebourgdir = File.dirname(__FILE__) $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir) require 'haml' unless Haml::Util.try_sass load Haml::Util.scope('vendor/sass/lib/sass.rb') end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml.rb0000664000175000017500000000321712414640747027455 0ustar ebourgebourgdir = File.dirname(__FILE__) $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir) require 'haml/version' # The module that contains everything Haml-related: # # * {Haml::Engine} is the class used to render Haml within Ruby code. # * {Haml::Helpers} contains Ruby helpers available within Haml templates. # * {Haml::Template} interfaces with web frameworks (Rails in particular). # * {Haml::Error} is raised when Haml encounters an error. # * {Haml::HTML} handles conversion of HTML to Haml. # # Also see the {file:HAML_REFERENCE.md full Haml reference}. module Haml # Initializes Haml for Rails. # # This method is called by `init.rb`, # which is run by Rails on startup. # We use it rather than putting stuff straight into `init.rb` # so we can change the initialization behavior # without modifying the file itself. # # @param binding [Binding] The context of the `init.rb` file. # This isn't actually used; # it's just passed in in case it needs to be used in the future def self.init_rails(binding) # 2.2 <= Rails < 3 if defined?(Rails) && Rails.respond_to?(:configuration) && Rails.configuration.respond_to?(:after_initialize) && !Haml::Util.ap_geq_3? Rails.configuration.after_initialize do next if defined?(Sass) autoload(:Sass, 'sass/rails2_shim') # resolve autoload if it looks like they're using Sass without options Sass if File.exist?(File.join(RAILS_ROOT, 'public/stylesheets/sass')) end end # No &method here for Rails 2.1 compatibility %w[haml/template].each {|f| require f} end end require 'haml/util' require 'haml/engine' require 'haml/railtie' stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/0000775000175000017500000000000012414640747027125 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/compiler.rb0000664000175000017500000003660512414640747031276 0ustar ebourgebourgrequire 'cgi' module Haml module Compiler include Haml::Util private # Returns the precompiled string with the preamble and postamble def precompiled_with_ambles(local_names) preamble = < @node.value[:preserve], :escape_html => @node.value[:escape_html], &block) end def compile_silent_script return if @options[:suppress_eval] push_silent(@node.value[:text]) keyword = @node.value[:keyword] ruby_block = block_given? && !keyword if block_given? # Store these values because for conditional statements, # we want to restore them for each branch @node.value[:dont_indent_next_line] = @dont_indent_next_line @node.value[:dont_tab_up_next_text] = @dont_tab_up_next_text yield push_silent("end", :can_suppress) unless @node.value[:dont_push_end] elsif keyword == "end" if @node.parent.children.last.equal?(@node) # Since this "end" is ending the block, # we don't need to generate an additional one @node.parent.value[:dont_push_end] = true end # Don't restore dont_* for end because it isn't a conditional branch. elsif Parser::MID_BLOCK_KEYWORDS.include?(keyword) # Restore dont_* for this conditional branch @dont_indent_next_line = @node.parent.value[:dont_indent_next_line] @dont_tab_up_next_text = @node.parent.value[:dont_tab_up_next_text] end end def compile_haml_comment; end def compile_tag t = @node.value # Get rid of whitespace outside of the tag if we need to rstrip_buffer! if t[:nuke_outer_whitespace] dont_indent_next_line = (t[:nuke_outer_whitespace] && !block_given?) || (t[:nuke_inner_whitespace] && block_given?) if @options[:suppress_eval] object_ref = "nil" parse = false value = t[:parse] ? nil : t[:value] attributes_hashes = {} preserve_script = false else object_ref = t[:object_ref] parse = t[:parse] value = t[:value] attributes_hashes = t[:attributes_hashes] preserve_script = t[:preserve_script] end # Check if we can render the tag directly to text and not process it in the buffer if object_ref == "nil" && attributes_hashes.empty? && !preserve_script tag_closed = !block_given? && !t[:self_closing] && !parse open_tag = prerender_tag(t[:name], t[:self_closing], t[:attributes]) if tag_closed open_tag << "#{value}" open_tag << "\n" unless t[:nuke_outer_whitespace] elsif !(parse || t[:nuke_inner_whitespace] || (t[:self_closing] && t[:nuke_outer_whitespace])) open_tag << "\n" end push_merged_text(open_tag, tag_closed || t[:self_closing] || t[:nuke_inner_whitespace] ? 0 : 1, !t[:nuke_outer_whitespace]) @dont_indent_next_line = dont_indent_next_line return if tag_closed else if attributes_hashes.empty? attributes_hashes = '' elsif attributes_hashes.size == 1 attributes_hashes = ", #{attributes_hashes.first}" else attributes_hashes = ", (#{attributes_hashes.join(").merge(")})" end push_merged_text "<#{t[:name]}", 0, !t[:nuke_outer_whitespace] push_generated_script( "_hamlout.attributes(#{inspect_obj(t[:attributes])}, #{object_ref}#{attributes_hashes})") concat_merged_text( if t[:self_closing] && xhtml? " />" + (t[:nuke_outer_whitespace] ? "" : "\n") else ">" + ((if t[:self_closing] && html? t[:nuke_outer_whitespace] else !block_given? || t[:preserve_tag] || t[:nuke_inner_whitespace] end) ? "" : "\n") end) if value && !parse concat_merged_text("#{value}#{t[:nuke_outer_whitespace] ? "" : "\n"}") else @to_merge << [:text, '', 1] unless t[:nuke_inner_whitespace] end @dont_indent_next_line = dont_indent_next_line end return if t[:self_closing] if value.nil? @output_tabs += 1 unless t[:nuke_inner_whitespace] yield if block_given? @output_tabs -= 1 unless t[:nuke_inner_whitespace] rstrip_buffer! if t[:nuke_inner_whitespace] push_merged_text("" + (t[:nuke_outer_whitespace] ? "" : "\n"), t[:nuke_inner_whitespace] ? 0 : -1, !t[:nuke_inner_whitespace]) @dont_indent_next_line = t[:nuke_outer_whitespace] return end if parse push_script(value, t.merge(:in_tag => true)) concat_merged_text("" + (t[:nuke_outer_whitespace] ? "" : "\n")) end end def compile_comment open = "" : "-->"}") return end push_text(open, 1) @output_tabs += 1 yield if block_given? @output_tabs -= 1 push_text(@node.value[:conditional] ? "" : "-->", -1) end def compile_doctype doctype = text_for_doctype push_text doctype if doctype end def compile_filter unless filter = Filters.defined[@node.value[:name]] raise Error.new("Filter \"#{@node.value[:name]}\" is not defined.", @node.line - 1) end filter.internal_compile(self, @node.value[:text]) end def text_for_doctype if @node.value[:type] == "xml" return nil if html? wrapper = @options[:attr_wrapper] return "" end if html5? '' else if xhtml? if @node.value[:version] == "1.1" '' elsif @node.value[:version] == "5" '' else case @node.value[:type] when "strict"; '' when "frameset"; '' when "mobile"; '' when "rdfa"; '' when "basic"; '' else '' end end elsif html4? case @node.value[:type] when "strict"; '' when "frameset"; '' else '' end end end end # Evaluates `text` in the context of the scope object, but # does not output the result. def push_silent(text, can_suppress = false) flush_merged_text return if can_suppress && options[:suppress_eval] @precompiled << "#{resolve_newlines}#{text}\n" @output_line += text.count("\n") + 1 end # Adds `text` to `@buffer` with appropriate tabulation # without parsing it. def push_merged_text(text, tab_change = 0, indent = true) text = !indent || @dont_indent_next_line || @options[:ugly] ? text : "#{' ' * @output_tabs}#{text}" @to_merge << [:text, text, tab_change] @dont_indent_next_line = false end # Concatenate `text` to `@buffer` without tabulation. def concat_merged_text(text) @to_merge << [:text, text, 0] end def push_text(text, tab_change = 0) push_merged_text("#{text}\n", tab_change) end def flush_merged_text return if @to_merge.empty? str = "" mtabs = 0 @to_merge.each do |type, val, tabs| case type when :text str << inspect_obj(val)[1...-1] mtabs += tabs when :script if mtabs != 0 && !@options[:ugly] val = "_hamlout.adjust_tabs(#{mtabs}); " + val end str << "\#{#{val}}" mtabs = 0 else raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.") end end unless str.empty? @precompiled << if @options[:ugly] "_hamlout.buffer << \"#{str}\";" else "_hamlout.push_text(\"#{str}\", #{mtabs}, #{@dont_tab_up_next_text.inspect});" end end @to_merge = [] @dont_tab_up_next_text = false end # Causes `text` to be evaluated in the context of # the scope object and the result to be added to `@buffer`. # # If `opts[:preserve_script]` is true, Haml::Helpers#find_and_flatten is run on # the result before it is added to `@buffer` def push_script(text, opts = {}) return if options[:suppress_eval] args = %w[preserve_script in_tag preserve_tag escape_html nuke_inner_whitespace] args.map! {|name| opts[name.to_sym]} args << !block_given? << @options[:ugly] no_format = @options[:ugly] && !(opts[:preserve_script] || opts[:preserve_tag] || opts[:escape_html]) output_expr = "(#{text}\n)" static_method = "_hamlout.#{static_method_name(:format_script, *args)}" # Prerender tabulation unless we're in a tag push_merged_text '' unless opts[:in_tag] unless block_given? push_generated_script(no_format ? "#{text}\n" : "#{static_method}(#{output_expr});") concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace] return end flush_merged_text push_silent "haml_temp = #{text}" yield push_silent('end', :can_suppress) unless @node.value[:dont_push_end] @precompiled << "_hamlout.buffer << #{no_format ? "haml_temp.to_s;" : "#{static_method}(haml_temp);"}" concat_merged_text("\n") unless opts[:in_tag] || opts[:nuke_inner_whitespace] || @options[:ugly] end def push_generated_script(text) @to_merge << [:script, resolve_newlines + text] @output_line += text.count("\n") end # This is a class method so it can be accessed from Buffer. def self.build_attributes(is_html, attr_wrapper, escape_attrs, attributes = {}) quote_escape = attr_wrapper == '"' ? """ : "'" other_quote_char = attr_wrapper == '"' ? "'" : '"' if attributes['data'].is_a?(Hash) attributes = attributes.dup attributes = Haml::Util.map_keys(attributes.delete('data')) {|name| "data-#{name}"}.merge(attributes) end result = attributes.collect do |attr, value| next if value.nil? value = filter_and_join(value, ' ') if attr == 'class' value = filter_and_join(value, '_') if attr == 'id' if value == true next " #{attr}" if is_html next " #{attr}=#{attr_wrapper}#{attr}#{attr_wrapper}" elsif value == false next end escaped = if escape_attrs == :once Haml::Helpers.escape_once(value.to_s) elsif escape_attrs CGI.escapeHTML(value.to_s) else value.to_s end value = Haml::Helpers.preserve(escaped) if escape_attrs # We want to decide whether or not to escape quotes value.gsub!('"', '"') this_attr_wrapper = attr_wrapper if value.include? attr_wrapper if value.include? other_quote_char value = value.gsub(attr_wrapper, quote_escape) else this_attr_wrapper = other_quote_char end end else this_attr_wrapper = attr_wrapper end " #{attr}=#{this_attr_wrapper}#{value}#{this_attr_wrapper}" end result.compact.sort.join end def self.filter_and_join(value, separator) return "" if value == "" value = [value] unless value.is_a?(Array) value = value.flatten.collect {|item| item ? item.to_s : nil}.compact.join(separator) return !value.empty? && value end def prerender_tag(name, self_close, attributes) attributes_string = Compiler.build_attributes( html?, @options[:attr_wrapper], @options[:escape_attrs], attributes) "<#{name}#{attributes_string}#{self_close && xhtml? ? ' /' : ''}>" end def resolve_newlines diff = @node.line - @output_line return "" if diff <= 0 @output_line = @node.line "\n" * [diff, 0].max end # Get rid of and whitespace at the end of the buffer # or the merged text def rstrip_buffer!(index = -1) last = @to_merge[index] if last.nil? push_silent("_hamlout.rstrip!", false) @dont_tab_up_next_text = true return end case last.first when :text last[1].rstrip! if last[1].empty? @to_merge.slice! index rstrip_buffer! index end when :script last[1].gsub!(/\(haml_temp, (.*?)\);$/, '(haml_temp.rstrip, \1);') rstrip_buffer! index - 1 else raise SyntaxError.new("[HAML BUG] Undefined entry in Haml::Compiler@to_merge.") end end def compile(node) parent, @node = @node, node block = proc {node.children.each {|c| compile c}} send("compile_#{node.type}", &(block unless node.children.empty?)) ensure @node = parent end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/exec.rb0000664000175000017500000002613612414640747030406 0ustar ebourgebourgrequire 'optparse' require 'fileutils' module Haml # This module handles the various Haml executables (`haml` and `haml-convert`). module Exec # An abstract class that encapsulates the executable code for all three executables. class Generic # @param args [Array] The command-line arguments def initialize(args) @args = args @options = {} end # Parses the command-line arguments and runs the executable. # Calls `Kernel#exit` at the end, so it never returns. # # @see #parse def parse! begin parse rescue Exception => e raise e if @options[:trace] || e.is_a?(SystemExit) $stderr.print "#{e.class}: " unless e.class == RuntimeError $stderr.puts "#{e.message}" $stderr.puts " Use --trace for backtrace." exit 1 end exit 0 end # Parses the command-line arguments and runs the executable. # This does not handle exceptions or exit the program. # # @see #parse! def parse @opts = OptionParser.new(&method(:set_opts)) @opts.parse!(@args) process_result @options end # @return [String] A description of the executable def to_s @opts.to_s end protected # Finds the line of the source template # on which an exception was raised. # # @param exception [Exception] The exception # @return [String] The line number def get_line(exception) # SyntaxErrors have weird line reporting # when there's trailing whitespace, # which there is for Haml documents. return (exception.message.scan(/:(\d+)/).first || ["??"]).first if exception.is_a?(::SyntaxError) (exception.backtrace[0].scan(/:(\d+)/).first || ["??"]).first end # Tells optparse how to parse the arguments # available for all executables. # # This is meant to be overridden by subclasses # so they can add their own options. # # @param opts [OptionParser] def set_opts(opts) opts.on('-s', '--stdin', :NONE, 'Read input from standard input instead of an input file') do @options[:input] = $stdin end opts.on('--trace', :NONE, 'Show a full traceback on error') do @options[:trace] = true end opts.on('--unix-newlines', 'Use Unix-style newlines in written files.') do @options[:unix_newlines] = true if ::Haml::Util.windows? end opts.on_tail("-?", "-h", "--help", "Show this message") do puts opts exit end opts.on_tail("-v", "--version", "Print version") do puts("Haml #{::Haml.version[:string]}") exit end end # Processes the options set by the command-line arguments. # In particular, sets `@options[:input]` and `@options[:output]` # to appropriate IO streams. # # This is meant to be overridden by subclasses # so they can run their respective programs. def process_result input, output = @options[:input], @options[:output] args = @args.dup input ||= begin filename = args.shift @options[:filename] = filename open_file(filename) || $stdin end output ||= open_file(args.shift, 'w') || $stdout @options[:input], @options[:output] = input, output end COLORS = { :red => 31, :green => 32, :yellow => 33 } # Prints a status message about performing the given action, # colored using the given color (via terminal escapes) if possible. # # @param name [#to_s] A short name for the action being performed. # Shouldn't be longer than 11 characters. # @param color [Symbol] The name of the color to use for this action. # Can be `:red`, `:green`, or `:yellow`. def puts_action(name, color, arg) return if @options[:for_engine][:quiet] printf color(color, "%11s %s\n"), name, arg end # Same as \{Kernel.puts}, but doesn't print anything if the `--quiet` option is set. # # @param args [Array] Passed on to \{Kernel.puts} def puts(*args) return if @options[:for_engine][:quiet] Kernel.puts(*args) end # Wraps the given string in terminal escapes # causing it to have the given color. # If terminal esapes aren't supported on this platform, # just returns the string instead. # # @param color [Symbol] The name of the color to use. # Can be `:red`, `:green`, or `:yellow`. # @param str [String] The string to wrap in the given color. # @return [String] The wrapped string. def color(color, str) raise "[BUG] Unrecognized color #{color}" unless COLORS[color] # Almost any real Unix terminal will support color, # so we just filter for Windows terms (which don't set TERM) # and not-real terminals, which aren't ttys. return str if ENV["TERM"].nil? || ENV["TERM"].empty? || !STDOUT.tty? return "\e[#{COLORS[color]}m#{str}\e[0m" end private def open_file(filename, flag = 'r') return if filename.nil? flag = 'wb' if @options[:unix_newlines] && flag == 'w' File.open(filename, flag) end def handle_load_error(err) dep = err.message[/^no such file to load -- (.*)/, 1] raise err if @options[:trace] || dep.nil? || dep.empty? $stderr.puts <] The command-line arguments def initialize(args) super @options[:for_engine] = {} @options[:requires] = [] @options[:load_paths] = [] end # Tells optparse how to parse the arguments. # # @param opts [OptionParser] def set_opts(opts) super opts.banner = < e raise "#{e.is_a?(::Haml::SyntaxError) ? "Syntax error" : "Error"} on line " + "#{get_line e}: #{e.message}" rescue LoadError => err handle_load_error(err) end end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/railtie.rb0000664000175000017500000000122612414640747031104 0ustar ebourgebourgif Haml::Util.ap_geq_3? && !Haml::Util.ap_geq?("3.0.0.beta4") raise < page_class} My Div # # would become # #
        My Div
        # # Then, in a stylesheet (shown here as [Sass](http://sass-lang.com)), # you could refer to this specific action: # # .entry.show # font-weight: bold # # or to all actions in the entry controller: # # .entry # color: #00f # # @return [String] The class name for the current page def page_class controller.controller_name + " " + controller.action_name end alias_method :generate_content_class_names, :page_class # Treats all input to \{Haml::Helpers#haml\_concat} within the block # as being HTML safe for Rails' XSS protection. # This is useful for wrapping blocks of code that concatenate HTML en masse. # # This has no effect if Rails' XSS protection isn't enabled. # # @yield A block in which all input to `#haml_concat` is treated as raw. # @see Haml::Util#rails_xss_safe? def with_raw_haml_concat @_haml_concat_raw, old = true, @_haml_concat_raw yield ensure @_haml_concat_raw = old end end include ActionViewExtensions end end ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/helpers/xss_mods.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/helpers/xss_mods.0000664000175000017500000001277512414640747032443 0ustar ebourgebourgmodule Haml module Helpers # This module overrides Haml helpers to work properly # in the context of ActionView. # Currently it's only used for modifying the helpers # to work with Rails' XSS protection methods. module XssMods def self.included(base) %w[html_escape find_and_preserve preserve list_of surround precede succeed capture_haml haml_concat haml_indent haml_tag escape_once].each do |name| base.send(:alias_method, "#{name}_without_haml_xss", name) base.send(:alias_method, name, "#{name}_with_haml_xss") end end # Don't escape text that's already safe, # output is always HTML safe def html_escape_with_haml_xss(text) str = text.to_s return text if str.html_safe? Haml::Util.html_safe(html_escape_without_haml_xss(str)) end # Output is always HTML safe def find_and_preserve_with_haml_xss(*args, &block) Haml::Util.html_safe(find_and_preserve_without_haml_xss(*args, &block)) end # Output is always HTML safe def preserve_with_haml_xss(*args, &block) Haml::Util.html_safe(preserve_without_haml_xss(*args, &block)) end # Output is always HTML safe def list_of_with_haml_xss(*args, &block) Haml::Util.html_safe(list_of_without_haml_xss(*args, &block)) end # Input is escaped, output is always HTML safe def surround_with_haml_xss(front, back = front, &block) Haml::Util.html_safe( surround_without_haml_xss( haml_xss_html_escape(front), haml_xss_html_escape(back), &block)) end # Input is escaped, output is always HTML safe def precede_with_haml_xss(str, &block) Haml::Util.html_safe(precede_without_haml_xss(haml_xss_html_escape(str), &block)) end # Input is escaped, output is always HTML safe def succeed_with_haml_xss(str, &block) Haml::Util.html_safe(succeed_without_haml_xss(haml_xss_html_escape(str), &block)) end # Output is always HTML safe def capture_haml_with_haml_xss(*args, &block) Haml::Util.html_safe(capture_haml_without_haml_xss(*args, &block)) end # Input is escaped def haml_concat_with_haml_xss(text = "") haml_concat_without_haml_xss(@_haml_concat_raw ? text : haml_xss_html_escape(text)) end # Output is always HTML safe def haml_indent_with_haml_xss Haml::Util.html_safe(haml_indent_without_haml_xss) end # Input is escaped, haml_concat'ed output is always HTML safe def haml_tag_with_haml_xss(name, *rest, &block) name = haml_xss_html_escape(name.to_s) rest.unshift(haml_xss_html_escape(rest.shift.to_s)) unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t} with_raw_haml_concat {haml_tag_without_haml_xss(name, *rest, &block)} end # Output is always HTML safe def escape_once_with_haml_xss(*args) Haml::Util.html_safe(escape_once_without_haml_xss(*args)) end private # Escapes the HTML in the text if and only if # Rails XSS protection is enabled *and* the `:escape_html` option is set. def haml_xss_html_escape(text) return text unless Haml::Util.rails_xss_safe? && haml_buffer.options[:escape_html] html_escape(text) end end class ErrorReturn # Any attempt to treat ErrorReturn as a string should cause it to blow up. alias_method :html_safe, :to_s alias_method :html_safe?, :to_s alias_method :html_safe!, :to_s end end end module ActionView module Helpers module CaptureHelper def with_output_buffer_with_haml_xss(*args, &block) res = with_output_buffer_without_haml_xss(*args, &block) case res when Array; res.map {|s| Haml::Util.html_safe(s)} when String; Haml::Util.html_safe(res) else; res end end alias_method :with_output_buffer_without_haml_xss, :with_output_buffer alias_method :with_output_buffer, :with_output_buffer_with_haml_xss end module FormTagHelper def form_tag_with_haml_xss(*args, &block) res = form_tag_without_haml_xss(*args, &block) res = Haml::Util.html_safe(res) unless block_given? res end alias_method :form_tag_without_haml_xss, :form_tag alias_method :form_tag, :form_tag_with_haml_xss end module FormHelper def form_for_with_haml_xss(*args, &block) res = form_for_without_haml_xss(*args, &block) return Haml::Util.html_safe(res) if res.is_a?(String) return res end alias_method :form_for_without_haml_xss, :form_for alias_method :form_for, :form_for_with_haml_xss end module TextHelper def concat_with_haml_xss(string) if is_haml? haml_buffer.buffer.concat(haml_xss_html_escape(string)) else concat_without_haml_xss(string) end end alias_method :concat_without_haml_xss, :concat alias_method :concat, :concat_with_haml_xss # safe_concat was introduced in Rails 3.0 if Haml::Util.has?(:instance_method, self, :safe_concat) def safe_concat_with_haml_xss(string) if is_haml? haml_buffer.buffer.concat(string) else safe_concat_without_haml_xss(string) end end alias_method :safe_concat_without_haml_xss, :safe_concat alias_method :safe_concat, :safe_concat_with_haml_xss end end end end ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/helpers/action_view_mods.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/helpers/action_vi0000664000175000017500000002070012414640747032464 0ustar ebourgebourgmodule ActionView class Base def render_with_haml(*args, &block) options = args.first # If render :layout is used with a block, # it concats rather than returning a string # so we need it to keep thinking it's Haml # until it hits the sub-render if is_haml? && !(options.is_a?(Hash) && options[:layout] && block_given?) return non_haml { render_without_haml(*args, &block) } end render_without_haml(*args, &block) end alias_method :render_without_haml, :render alias_method :render, :render_with_haml # Rails >2.1 if Haml::Util.has?(:instance_method, self, :output_buffer) def output_buffer_with_haml return haml_buffer.buffer if is_haml? output_buffer_without_haml end alias_method :output_buffer_without_haml, :output_buffer alias_method :output_buffer, :output_buffer_with_haml def set_output_buffer_with_haml(new) if is_haml? new = String.new(new) if Haml::Util.rails_xss_safe? && new.is_a?(Haml::Util.rails_safe_buffer_class) haml_buffer.buffer = new else set_output_buffer_without_haml new end end alias_method :set_output_buffer_without_haml, :output_buffer= alias_method :output_buffer=, :set_output_buffer_with_haml end end module Helpers # In Rails <=2.1, we've got to override considerable capturing infrastructure. # In Rails >2.1, we can make do with only overriding #capture # (which no longer behaves differently in helper contexts). unless Haml::Util.has?(:instance_method, ActionView::Base, :output_buffer) module CaptureHelper def capture_with_haml(*args, &block) # Rails' #capture helper will just return the value of the block # if it's not actually in the template context, # as detected by the existance of an _erbout variable. # We've got to do the same thing for compatibility. if is_haml? && block_is_haml?(block) capture_haml(*args, &block) else capture_without_haml(*args, &block) end end alias_method :capture_without_haml, :capture alias_method :capture, :capture_with_haml def capture_erb_with_buffer_with_haml(buffer, *args, &block) if is_haml? capture_haml(*args, &block) else capture_erb_with_buffer_without_haml(buffer, *args, &block) end end alias_method :capture_erb_with_buffer_without_haml, :capture_erb_with_buffer alias_method :capture_erb_with_buffer, :capture_erb_with_buffer_with_haml end module TextHelper def concat_with_haml(string, binding = nil) if is_haml? haml_buffer.buffer.concat(string) else concat_without_haml(string, binding) end end alias_method :concat_without_haml, :concat alias_method :concat, :concat_with_haml end else module CaptureHelper def capture_with_haml(*args, &block) if Haml::Helpers.block_is_haml?(block) str = capture_haml(*args, &block) return ActionView::NonConcattingString.new(str) if defined?(ActionView::NonConcattingString) return str else capture_without_haml(*args, &block) end end alias_method :capture_without_haml, :capture alias_method :capture, :capture_with_haml end end module TagHelper def content_tag_with_haml(name, *args, &block) return content_tag_without_haml(name, *args, &block) unless is_haml? preserve = haml_buffer.options[:preserve].include?(name.to_s) if block_given? && block_is_haml?(block) && preserve return content_tag_without_haml(name, *args) {preserve(&block)} end content = content_tag_without_haml(name, *args, &block) content = Haml::Helpers.preserve(content) if preserve && content content end alias_method :content_tag_without_haml, :content_tag alias_method :content_tag, :content_tag_with_haml end class InstanceTag # Includes TagHelper def haml_buffer @template_object.send :haml_buffer end def is_haml? @template_object.send :is_haml? end def content_tag(*args) html_tag = content_tag_with_haml(*args) return html_tag unless respond_to?(:error_wrapping) return error_wrapping(html_tag) if method(:error_wrapping).arity == 1 return html_tag unless object.respond_to?(:errors) && object.errors.respond_to?(:on) return error_wrapping(html_tag, object.errors.on(@method_name)) end end if Haml::Util.ap_geq_3? module FormTagHelper def form_tag_with_haml(url_for_options = {}, options = {}, *parameters_for_url, &proc) if is_haml? wrap_block = block_given? && block_is_haml?(proc) if wrap_block oldproc = proc proc = haml_bind_proc do |*args| concat "\n" with_tabs(1) {oldproc.call(*args)} end end res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) + "\n" res << "\n" if wrap_block res else form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) end end alias_method :form_tag_without_haml, :form_tag alias_method :form_tag, :form_tag_with_haml end module FormHelper def form_for_with_haml(object_name, *args, &proc) wrap_block = block_given? && is_haml? && block_is_haml?(proc) if wrap_block oldproc = proc proc = proc {|*args| with_tabs(1) {oldproc.call(*args)}} end res = form_for_without_haml(object_name, *args, &proc) res << "\n" if wrap_block res end alias_method :form_for_without_haml, :form_for alias_method :form_for, :form_for_with_haml end module CacheHelper # This is a workaround for a Rails 3 bug # that's present at least through beta 3. # Their fragment_for assumes that the block # will return its contents as a string, # which is not always the case. # Luckily, it only makes this assumption if caching is disabled, # so we only override that case. def fragment_for_with_haml(*args, &block) return fragment_for_without_haml(*args, &block) if controller.perform_caching capture(&block) end alias_method :fragment_for_without_haml, :fragment_for alias_method :fragment_for, :fragment_for_with_haml end else module FormTagHelper def form_tag_with_haml(url_for_options = {}, options = {}, *parameters_for_url, &proc) if is_haml? wrap_block = block_given? && block_is_haml?(proc) if wrap_block oldproc = proc proc = haml_bind_proc do |*args| concat "\n" tab_up oldproc.call(*args) tab_down concat haml_indent end concat haml_indent end res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) + "\n" if block_given? concat "\n" return Haml::Helpers::ErrorReturn.new("form_tag") end res else form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) end end alias_method :form_tag_without_haml, :form_tag alias_method :form_tag, :form_tag_with_haml end module FormHelper def form_for_with_haml(object_name, *args, &proc) wrap_block = block_given? && is_haml? && block_is_haml?(proc) if wrap_block oldproc = proc proc = haml_bind_proc do |*args| tab_up oldproc.call(*args) tab_down concat haml_indent end concat haml_indent end form_for_without_haml(object_name, *args, &proc) concat "\n" if wrap_block Haml::Helpers::ErrorReturn.new("form_for") if is_haml? end alias_method :form_for_without_haml, :form_for alias_method :form_for, :form_for_with_haml end end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/version.rb0000664000175000017500000000661312414640747031145 0ustar ebourgebourgrequire 'haml/util' module Haml # Handles Haml version-reporting. # Haml not only reports the standard three version numbers, # but its Git revision hash as well, # if it was installed from Git. module Version include Haml::Util # Returns a hash representing the version of Haml. # The `:major`, `:minor`, and `:teeny` keys have their respective numbers as Fixnums. # The `:name` key has the name of the version. # The `:string` key contains a human-readable string representation of the version. # The `:number` key is the major, minor, and teeny keys separated by periods. # If Haml is checked out from Git, the `:rev` key will have the revision hash. # For example: # # { # :string => "2.1.0.9616393", # :rev => "9616393b8924ef36639c7e82aa88a51a24d16949", # :number => "2.1.0", # :major => 2, :minor => 1, :teeny => 0 # } # # If a prerelease version of Haml is being used, # the `:string` and `:number` fields will reflect the full version # (e.g. `"2.2.beta.1"`), and the `:teeny` field will be `-1`. # A `:prerelease` key will contain the name of the prerelease (e.g. `"beta"`), # and a `:prerelease_number` key will contain the rerelease number. # For example: # # { # :string => "3.0.beta.1", # :number => "3.0.beta.1", # :major => 3, :minor => 0, :teeny => -1, # :prerelease => "beta", # :prerelease_number => 1 # } # # @return [{Symbol => String/Fixnum}] The version hash def version return @@version if defined?(@@version) numbers = File.read(scope('VERSION')).strip.split('.'). map {|n| n =~ /^[0-9]+$/ ? n.to_i : n} name = File.read(scope('VERSION_NAME')).strip @@version = { :major => numbers[0], :minor => numbers[1], :teeny => numbers[2], :name => name } if numbers[3].is_a?(String) @@version[:teeny] = -1 @@version[:prerelease] = numbers[3] @@version[:prerelease_number] = numbers[4] end @@version[:number] = numbers.join('.') @@version[:string] = @@version[:number].dup if rev = revision_number @@version[:rev] = rev unless rev[0] == ?( @@version[:string] << "." << rev[0...7] end end @@version[:string] << " (#{name})" @@version end private def revision_number if File.exists?(scope('REVISION')) rev = File.read(scope('REVISION')).strip return rev unless rev =~ /^([a-f0-9]+|\(.*\))$/ || rev == '(unknown)' end return unless File.exists?(scope('.git/HEAD')) rev = File.read(scope('.git/HEAD')).strip return rev unless rev =~ /^ref: (.*)$/ ref_name = $1 ref_file = scope(".git/#{ref_name}") info_file = scope(".git/info/refs") return File.read(ref_file).strip if File.exists?(ref_file) return unless File.exists?(info_file) File.open(info_file) do |f| f.each do |l| sha, ref = l.strip.split("\t", 2) next unless ref == ref_name return sha end end return nil end end extend Haml::Version # A string representing the version of Haml. # A more fine-grained representation is available from Haml.version. # @api public VERSION = version[:string] unless defined?(Haml::VERSION) end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/shared.rb0000664000175000017500000000557312414640747030732 0ustar ebourgebourgrequire 'strscan' module Haml # This module contains functionality that's shared between Haml and Sass. module Shared extend self # Scans through a string looking for the interoplation-opening `#{` # and, when it's found, yields the scanner to the calling code # so it can handle it properly. # # The scanner will have any backslashes immediately in front of the `#{` # as the second capture group (`scan[2]`), # and the text prior to that as the first (`scan[1]`). # # @yieldparam scan [StringScanner] The scanner scanning through the string # @return [String] The text remaining in the scanner after all `#{`s have been processed def handle_interpolation(str) scan = StringScanner.new(str) yield scan while scan.scan(/(.*?)(\\*)\#\{/) scan.rest end # Moves a scanner through a balanced pair of characters. # For example: # # Foo (Bar (Baz bang) bop) (Bang (bop bip)) # ^ ^ # from to # # @param scanner [StringScanner] The string scanner to move # @param start [Character] The character opening the balanced pair. # A `Fixnum` in 1.8, a `String` in 1.9 # @param finish [Character] The character closing the balanced pair. # A `Fixnum` in 1.8, a `String` in 1.9 # @param count [Fixnum] The number of opening characters matched # before calling this method # @return [(String, String)] The string matched within the balanced pair # and the rest of the string. # `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above. def balance(scanner, start, finish, count = 0) str = '' scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE) while scanner.scan(regexp) str << scanner.matched count += 1 if scanner.matched[-1] == start count -= 1 if scanner.matched[-1] == finish return [str.strip, scanner.rest] if count == 0 end end # Formats a string for use in error messages about indentation. # # @param indentation [String] The string used for indentation # @param was [Boolean] Whether or not to add `"was"` or `"were"` # (depending on how many characters were in `indentation`) # @return [String] The name of the indentation (e.g. `"12 spaces"`, `"1 tab"`) def human_indentation(indentation, was = false) if !indentation.include?(?\t) noun = 'space' elsif !indentation.include?(?\s) noun = 'tab' else return indentation.inspect + (was ? ' was' : '') end singular = indentation.length == 1 if was was = singular ? ' was' : ' were' else was = '' end "#{indentation.length} #{noun}#{'s' unless singular}#{was}" end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/buffer.rb0000664000175000017500000002321212414640747030723 0ustar ebourgebourgmodule Haml # This class is used only internally. It holds the buffer of HTML that # is eventually output as the resulting document. # It's called from within the precompiled code, # and helps reduce the amount of processing done within `instance_eval`ed code. class Buffer include Haml::Helpers include Haml::Util # The string that holds the compiled HTML. This is aliased as # `_erbout` for compatibility with ERB-specific code. # # @return [String] attr_accessor :buffer # The options hash passed in from {Haml::Engine}. # # @return [{String => Object}] # @see Haml::Engine#options_for_buffer attr_accessor :options # The {Buffer} for the enclosing Haml document. # This is set for partials and similar sorts of nested templates. # It's `nil` at the top level (see \{#toplevel?}). # # @return [Buffer] attr_accessor :upper # nil if there's no capture_haml block running, # and the position at which it's beginning the capture if there is one. # # @return [Fixnum, nil] attr_accessor :capture_position # @return [Boolean] # @see #active? attr_writer :active # @return [Boolean] Whether or not the format is XHTML def xhtml? not html? end # @return [Boolean] Whether or not the format is any flavor of HTML def html? html4? or html5? end # @return [Boolean] Whether or not the format is HTML4 def html4? @options[:format] == :html4 end # @return [Boolean] Whether or not the format is HTML5. def html5? @options[:format] == :html5 end # @return [Boolean] Whether or not this buffer is a top-level template, # as opposed to a nested partial def toplevel? upper.nil? end # Whether or not this buffer is currently being used to render a Haml template. # Returns `false` if a subtemplate is being rendered, # even if it's a subtemplate of this buffer's template. # # @return [Boolean] def active? @active end # @return [Fixnum] The current indentation level of the document def tabulation @real_tabs + @tabulation end # Sets the current tabulation of the document. # # @param val [Fixnum] The new tabulation def tabulation=(val) val = val - @real_tabs @tabulation = val > -1 ? val : 0 end # @param upper [Buffer] The parent buffer # @param options [{Symbol => Object}] An options hash. # See {Haml::Engine#options\_for\_buffer} def initialize(upper = nil, options = {}) @active = true @upper = upper @options = options @buffer = ruby1_8? ? "" : "".encode(Encoding.find(options[:encoding])) @tabulation = 0 # The number of tabs that Engine thinks we should have # @real_tabs + @tabulation is the number of tabs actually output @real_tabs = 0 end # Appends text to the buffer, properly tabulated. # Also modifies the document's indentation. # # @param text [String] The text to append # @param tab_change [Fixnum] The number of tabs by which to increase # or decrease the document's indentation # @param dont_tab_up [Boolean] If true, don't indent the first line of `text` def push_text(text, tab_change, dont_tab_up) if @tabulation > 0 # Have to push every line in by the extra user set tabulation. # Don't push lines with just whitespace, though, # because that screws up precompiled indentation. text.gsub!(/^(?!\s+$)/m, tabs) text.sub!(tabs, '') if dont_tab_up end @buffer << text @real_tabs += tab_change end # Modifies the indentation of the document. # # @param tab_change [Fixnum] The number of tabs by which to increase # or decrease the document's indentation def adjust_tabs(tab_change) @real_tabs += tab_change end Haml::Util.def_static_method(self, :format_script, [:result], :preserve_script, :in_tag, :preserve_tag, :escape_html, :nuke_inner_whitespace, :interpolated, :ugly, < <% unless ugly %> # If we're interpolated, # then the custom tabulation is handled in #push_text. # The easiest way to avoid it here is to reset @tabulation. <% if interpolated %> old_tabulation = @tabulation @tabulation = 0 <% end %> tabulation = @real_tabs result = <%= result_name %>.<% if nuke_inner_whitespace %>strip<% else %>rstrip<% end %> <% else %> result = <%= result_name %><% if nuke_inner_whitespace %>.strip<% end %> <% end %> <% if preserve_tag %> result = Haml::Helpers.preserve(result) <% elsif preserve_script %> result = Haml::Helpers.find_and_preserve(result, options[:preserve]) <% end %> <% if ugly %> return result <% else %> has_newline = result.include?("\\n") <% if in_tag && !nuke_inner_whitespace %> <% unless preserve_tag %> if !has_newline <% end %> @real_tabs -= 1 <% if interpolated %> @tabulation = old_tabulation <% end %> return result <% unless preserve_tag %> end <% end %> <% end %> # Precompiled tabulation may be wrong <% if !interpolated && !in_tag %> result = tabs + result if @tabulation > 0 <% end %> if has_newline result = result.gsub "\\n", "\\n" + tabs(tabulation) # Add tabulation if it wasn't precompiled <% if in_tag && !nuke_inner_whitespace %> result = tabs(tabulation) + result <% end %> end <% if in_tag && !nuke_inner_whitespace %> result = "\\n\#{result}\\n\#{tabs(tabulation-1)}" @real_tabs -= 1 <% end %> <% if interpolated %> @tabulation = old_tabulation <% end %> result <% end %> RUBY def attributes(class_id, obj_ref, *attributes_hashes) attributes = class_id attributes_hashes.each do |old| self.class.merge_attrs(attributes, to_hash(old.map {|k, v| [k.to_s, v]})) end self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref Compiler.build_attributes( html?, @options[:attr_wrapper], @options[:escape_attrs], attributes) end # Remove the whitespace from the right side of the buffer string. # Doesn't do anything if we're at the beginning of a capture_haml block. def rstrip! if capture_position.nil? buffer.rstrip! return end buffer << buffer.slice!(capture_position..-1).rstrip end # Merges two attribute hashes. # This is the same as `to.merge!(from)`, # except that it merges id, class, and data attributes. # # ids are concatenated with `"_"`, # and classes are concatenated with `" "`. # data hashes are simply merged. # # Destructively modifies both `to` and `from`. # # @param to [{String => String}] The attribute hash to merge into # @param from [{String => #to_s}] The attribute hash to merge from # @return [{String => String}] `to`, after being merged def self.merge_attrs(to, from) from['id'] = Compiler.filter_and_join(from['id'], '_') if from['id'] if to['id'] && from['id'] to['id'] << '_' << from.delete('id').to_s elsif to['id'] || from['id'] from['id'] ||= to['id'] end from['class'] = Compiler.filter_and_join(from['class'], ' ') if from['class'] if to['class'] && from['class'] # Make sure we don't duplicate class names from['class'] = (from['class'].to_s.split(' ') | to['class'].split(' ')).sort.join(' ') elsif to['class'] || from['class'] from['class'] ||= to['class'] end from_data = from['data'].is_a?(Hash) to_data = to['data'].is_a?(Hash) if from_data && to_data to['data'] = to['data'].merge(from['data']) elsif to_data to = Haml::Util.map_keys(to.delete('data')) {|name| "data-#{name}"}.merge(to) elsif from_data from = Haml::Util.map_keys(from.delete('data')) {|name| "data-#{name}"}.merge(from) end to.merge!(from) end private @@tab_cache = {} # Gets `count` tabs. Mostly for internal use. def tabs(count = 0) tabs = [count + @tabulation, 0].max @@tab_cache[tabs] ||= ' ' * tabs end # Takes an array of objects and uses the class and id of the first # one to create an attributes hash. # The second object, if present, is used as a prefix, # just like you can do with `dom_id()` and `dom_class()` in Rails def parse_object_ref(ref) prefix = ref[1] ref = ref[0] # Let's make sure the value isn't nil. If it is, return the default Hash. return {} if ref.nil? class_name = if ref.respond_to?(:haml_object_ref) ref.haml_object_ref else underscore(ref.class) end id = "#{class_name}_#{ref.id || 'new'}" if prefix class_name = "#{ prefix }_#{ class_name}" id = "#{ prefix }_#{ id }" end {'id' => id, 'class' => class_name} end # Changes a word from camel case to underscores. # Based on the method of the same name in Rails' Inflector, # but copied here so it'll run properly without Rails. def underscore(camel_cased_word) camel_cased_word.to_s.gsub(/::/, '_'). gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). gsub(/([a-z\d])([A-Z])/,'\1_\2'). tr("-", "_"). downcase end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/error.rb0000664000175000017500000000115012414640747030600 0ustar ebourgebourgmodule Haml # An exception raised by Haml code. class Error < StandardError # The line of the template on which the error occurred. # # @return [Fixnum] attr_reader :line # @param message [String] The error message # @param line [Fixnum] See \{#line} def initialize(message = nil, line = nil) super(message) @line = line end end # SyntaxError is the type of exception raised when Haml encounters an # ill-formatted document. # It's not particularly interesting, # except in that it's a subclass of {Haml::Error}. class SyntaxError < Haml::Error; end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/parser.rb0000664000175000017500000005525212414640747030757 0ustar ebourgebourgrequire 'strscan' require 'haml/shared' module Haml module Parser include Haml::Util # Designates an XHTML/XML element. ELEMENT = ?% # Designates a `
        ` element with the given class. DIV_CLASS = ?. # Designates a `
        ` element with the given id. DIV_ID = ?# # Designates an XHTML/XML comment. COMMENT = ?/ # Designates an XHTML doctype or script that is never HTML-escaped. DOCTYPE = ?! # Designates script, the result of which is output. SCRIPT = ?= # Designates script that is always HTML-escaped. SANITIZE = ?& # Designates script, the result of which is flattened and output. FLAT_SCRIPT = ?~ # Designates script which is run but not output. SILENT_SCRIPT = ?- # When following SILENT_SCRIPT, designates a comment that is not output. SILENT_COMMENT = ?# # Designates a non-parsed line. ESCAPE = ?\\ # Designates a block of filtered text. FILTER = ?: # Designates a non-parsed line. Not actually a character. PLAIN_TEXT = -1 # Keeps track of the ASCII values of the characters that begin a # specially-interpreted line. SPECIAL_CHARACTERS = [ ELEMENT, DIV_CLASS, DIV_ID, COMMENT, DOCTYPE, SCRIPT, SANITIZE, FLAT_SCRIPT, SILENT_SCRIPT, ESCAPE, FILTER ] # The value of the character that designates that a line is part # of a multiline string. MULTILINE_CHAR_VALUE = ?| MID_BLOCK_KEYWORDS = %w[else elsif rescue ensure end when] START_BLOCK_KEYWORDS = %w[if begin case] # Try to parse assignments to block starters as best as possible START_BLOCK_KEYWORD_REGEX = /(?:\w+(?:,\s*\w+)*\s*=\s*)?(#{START_BLOCK_KEYWORDS.join('|')})/ BLOCK_KEYWORD_REGEX = /^-\s*(?:(#{MID_BLOCK_KEYWORDS.join('|')})|#{START_BLOCK_KEYWORD_REGEX.source})\b/ # The Regex that matches a Doctype command. DOCTYPE_REGEX = /(\d(?:\.\d)?)?[\s]*([a-z]*)\s*([^ ]+)?/i # The Regex that matches a literal string or symbol value LITERAL_VALUE_REGEX = /:(\w*)|(["'])((?![\\#]|\2).|\\.)*\2/ private # @private class Line < Struct.new(:text, :unstripped, :full, :index, :compiler, :eod) alias_method :eod?, :eod # @private def tabs line = self @tabs ||= compiler.instance_eval do break 0 if line.text.empty? || !(whitespace = line.full[/^\s+/]) if @indentation.nil? @indentation = whitespace if @indentation.include?(?\s) && @indentation.include?(?\t) raise SyntaxError.new("Indentation can't use both tabs and spaces.", line.index) end @flat_spaces = @indentation * (@template_tabs+1) if flat? break 1 end tabs = whitespace.length / @indentation.length break tabs if whitespace == @indentation * tabs break @template_tabs + 1 if flat? && whitespace =~ /^#{@flat_spaces}/ raise SyntaxError.new(< 1 raise SyntaxError.new("The line was indented #{@next_line.tabs - @line.tabs} levels deeper than the previous line.", @next_line.index) end @line = @next_line end # Close all the open tags close until @parent.type == :root @root end # Processes and deals with lowering indentation. def process_indent(line) return unless line.tabs <= @template_tabs && @template_tabs > 0 to_close = @template_tabs - line.tabs to_close.times {|i| close unless to_close - 1 - i == 0 && mid_block_keyword?(line.text)} end # Processes a single line of Haml. # # This method doesn't return anything; it simply processes the line and # adds the appropriate code to `@precompiled`. def process_line(text, index) @index = index + 1 case text[0] when DIV_CLASS; push div(text) when DIV_ID return push plain(text) if text[1] == ?{ push div(text) when ELEMENT; push tag(text) when COMMENT; push comment(text[1..-1].strip) when SANITIZE return push plain(text[3..-1].strip, :escape_html) if text[1..2] == "==" return push script(text[2..-1].strip, :escape_html) if text[1] == SCRIPT return push flat_script(text[2..-1].strip, :escape_html) if text[1] == FLAT_SCRIPT return push plain(text[1..-1].strip, :escape_html) if text[1] == ?\s push plain(text) when SCRIPT return push plain(text[2..-1].strip) if text[1] == SCRIPT push script(text[1..-1]) when FLAT_SCRIPT; push flat_script(text[1..-1]) when SILENT_SCRIPT; push silent_script(text) when FILTER; push filter(text[1..-1].downcase) when DOCTYPE return push doctype(text) if text[0...3] == '!!!' return push plain(text[3..-1].strip, !:escape_html) if text[1..2] == "==" return push script(text[2..-1].strip, !:escape_html) if text[1] == SCRIPT return push flat_script(text[2..-1].strip, !:escape_html) if text[1] == FLAT_SCRIPT return push plain(text[1..-1].strip, !:escape_html) if text[1] == ?\s push plain(text) when ESCAPE; push plain(text[1..-1]) else; push plain(text) end end def block_keyword(text) return unless keyword = text.scan(BLOCK_KEYWORD_REGEX)[0] keyword[0] || keyword[1] end def mid_block_keyword?(text) MID_BLOCK_KEYWORDS.include?(block_keyword(text)) end def push(node) @parent.children << node node.parent = @parent end def plain(text, escape_html = nil) if block_opened? raise SyntaxError.new("Illegal nesting: nesting within plain text is illegal.", @next_line.index) end unless contains_interpolation?(text) return ParseNode.new(:plain, @index, :text => text) end escape_html = @options[:escape_html] if escape_html.nil? script(unescape_interpolation(text, escape_html), !:escape_html) end def script(text, escape_html = nil, preserve = false) raise SyntaxError.new("There's no Ruby code for = to evaluate.") if text.empty? text = handle_ruby_multiline(text) escape_html = @options[:escape_html] if escape_html.nil? ParseNode.new(:script, @index, :text => text, :escape_html => escape_html, :preserve => preserve) end def flat_script(text, escape_html = nil) raise SyntaxError.new("There's no Ruby code for ~ to evaluate.") if text.empty? script(text, escape_html, :preserve) end def silent_script(text) return haml_comment(text[2..-1]) if text[1] == SILENT_COMMENT raise SyntaxError.new(< text[1..-1], :keyword => keyword) end def haml_comment(text) @haml_comment = block_opened? ParseNode.new(:haml_comment, @index, :text => text) end def tag(line) tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace, nuke_inner_whitespace, action, value, last_line = parse_tag(line) preserve_tag = @options[:preserve].include?(tag_name) nuke_inner_whitespace ||= preserve_tag preserve_tag = false if @options[:ugly] escape_html = (action == '&' || (action != '!' && @options[:escape_html])) case action when '/'; self_closing = true when '~'; parse = preserve_script = true when '=' parse = true if value[0] == ?= value = unescape_interpolation(value[1..-1].strip, escape_html) escape_html = false end when '&', '!' if value[0] == ?= || value[0] == ?~ parse = true preserve_script = (value[0] == ?~) if value[1] == ?= value = unescape_interpolation(value[2..-1].strip, escape_html) escape_html = false else value = value[1..-1].strip end elsif contains_interpolation?(value) value = unescape_interpolation(value, escape_html) parse = true escape_html = false end else if contains_interpolation?(value) value = unescape_interpolation(value, escape_html) parse = true escape_html = false end end attributes = Parser.parse_class_and_id(attributes) attributes_list = [] if attributes_hashes[:new] static_attributes, attributes_hash = attributes_hashes[:new] Buffer.merge_attrs(attributes, static_attributes) if static_attributes attributes_list << attributes_hash end if attributes_hashes[:old] static_attributes = parse_static_hash(attributes_hashes[:old]) Buffer.merge_attrs(attributes, static_attributes) if static_attributes attributes_list << attributes_hashes[:old] unless static_attributes || @options[:suppress_eval] end attributes_list.compact! raise SyntaxError.new("Illegal nesting: nesting within a self-closing tag is illegal.", @next_line.index) if block_opened? && self_closing raise SyntaxError.new("There's no Ruby code for #{action} to evaluate.", last_line - 1) if parse && value.empty? raise SyntaxError.new("Self-closing tags can't have content.", last_line - 1) if self_closing && !value.empty? if block_opened? && !value.empty? && !is_ruby_multiline?(value) raise SyntaxError.new("Illegal nesting: content can't be both given on the same line as %#{tag_name} and nested within it.", @next_line.index) end self_closing ||= !!(!block_opened? && value.empty? && @options[:autoclose].any? {|t| t === tag_name}) value = nil if value.empty? && (block_opened? || self_closing) value = handle_ruby_multiline(value) if parse ParseNode.new(:tag, @index, :name => tag_name, :attributes => attributes, :attributes_hashes => attributes_list, :self_closing => self_closing, :nuke_inner_whitespace => nuke_inner_whitespace, :nuke_outer_whitespace => nuke_outer_whitespace, :object_ref => object_ref, :escape_html => escape_html, :preserve_tag => preserve_tag, :preserve_script => preserve_script, :parse => parse, :value => value) end # Renders a line that creates an XHTML tag and has an implicit div because of # `.` or `#`. def div(line) tag('%div' + line) end # Renders an XHTML comment. def comment(line) conditional, line = balance(line, ?[, ?]) if line[0] == ?[ line.strip! conditional << ">" if conditional if block_opened? && !line.empty? raise SyntaxError.new('Illegal nesting: nesting within a tag that already has content is illegal.', @next_line.index) end ParseNode.new(:comment, @index, :conditional => conditional, :text => line) end # Renders an XHTML doctype or XML shebang. def doctype(line) raise SyntaxError.new("Illegal nesting: nesting within a header command is illegal.", @next_line.index) if block_opened? version, type, encoding = line[3..-1].strip.downcase.scan(DOCTYPE_REGEX)[0] ParseNode.new(:doctype, @index, :version => version, :type => type, :encoding => encoding) end def filter(name) raise Error.new("Invalid filter name \":#{name}\".") unless name =~ /^\w+$/ @filter_buffer = String.new if filter_opened? @flat = true # If we don't know the indentation by now, it'll be set in Line#tabs @flat_spaces = @indentation * (@template_tabs+1) if @indentation end ParseNode.new(:filter, @index, :name => name, :text => @filter_buffer) end def close node, @parent = @parent, @parent.parent @template_tabs -= 1 send("close_#{node.type}", node) if respond_to?("close_#{node.type}", :include_private) end def close_filter(_) @flat = false @flat_spaces = nil @filter_buffer = nil end def close_haml_comment(_) @haml_comment = false end def close_silent_script(node) # Post-process case statements to normalize the nesting of "when" clauses return unless node.value[:keyword] == "case" return unless first = node.children.first return unless first.type == :silent_script && first.value[:keyword] == "when" return if first.children.empty? # If the case node has a "when" child with children, it's the # only child. Then we want to put everything nested beneath it # beneath the case itself (just like "if"). node.children = [first, *first.children] first.children = [] end # This is a class method so it can be accessed from {Haml::Helpers}. # # Iterates through the classes and ids supplied through `.` # and `#` syntax, and returns a hash with them as attributes, # that can then be merged with another attributes hash. def self.parse_class_and_id(list) attributes = {} list.scan(/([#.])([-:_a-zA-Z0-9]+)/) do |type, property| case type when '.' if attributes['class'] attributes['class'] += " " else attributes['class'] = "" end attributes['class'] += property when '#'; attributes['id'] = property end end attributes end def parse_static_hash(text) attributes = {} scanner = StringScanner.new(text) scanner.scan(/\s+/) until scanner.eos? return unless key = scanner.scan(LITERAL_VALUE_REGEX) return unless scanner.scan(/\s*=>\s*/) return unless value = scanner.scan(LITERAL_VALUE_REGEX) return unless scanner.scan(/\s*(?:,|$)\s*/) attributes[eval(key).to_s] = eval(value).to_s end attributes end # Parses a line into tag_name, attributes, attributes_hash, object_ref, action, value def parse_tag(line) raise SyntaxError.new("Invalid tag: \"#{line}\".") unless match = line.scan(/%([-:\w]+)([-:\w\.\#]*)(.*)/)[0] tag_name, attributes, rest = match raise SyntaxError.new("Illegal element: classes and ids must have values.") if attributes =~ /[\.#](\.|#|\z)/ new_attributes_hash = old_attributes_hash = last_line = nil object_ref = "nil" attributes_hashes = {} while rest case rest[0] when ?{ break if old_attributes_hash old_attributes_hash, rest, last_line = parse_old_attributes(rest) attributes_hashes[:old] = old_attributes_hash when ?( break if new_attributes_hash new_attributes_hash, rest, last_line = parse_new_attributes(rest) attributes_hashes[:new] = new_attributes_hash when ?[ break unless object_ref == "nil" object_ref, rest = balance(rest, ?[, ?]) else; break end end if rest nuke_whitespace, action, value = rest.scan(/(<>|><|[><])?([=\/\~&!])?(.*)?/)[0] nuke_whitespace ||= '' nuke_outer_whitespace = nuke_whitespace.include? '>' nuke_inner_whitespace = nuke_whitespace.include? '<' end value = value.to_s.strip [tag_name, attributes, attributes_hashes, object_ref, nuke_outer_whitespace, nuke_inner_whitespace, action, value, last_line || @index] end def parse_old_attributes(line) line = line.dup last_line = @index begin attributes_hash, rest = balance(line, ?{, ?}) rescue SyntaxError => e if line.strip[-1] == ?, && e.message == "Unbalanced brackets." line << "\n" << @next_line.text last_line += 1 next_line retry end raise e end attributes_hash = attributes_hash[1...-1] if attributes_hash return attributes_hash, rest, last_line end def parse_new_attributes(line) line = line.dup scanner = StringScanner.new(line) last_line = @index attributes = {} scanner.scan(/\(\s*/) loop do name, value = parse_new_attribute(scanner) break if name.nil? if name == false text = (Haml::Shared.balance(line, ?(, ?)) || [line]).first raise Haml::SyntaxError.new("Invalid attribute list: #{text.inspect}.", last_line - 1) end attributes[name] = value scanner.scan(/\s*/) if scanner.eos? line << " " << @next_line.text last_line += 1 next_line scanner.scan(/\s*/) end end static_attributes = {} dynamic_attributes = "{" attributes.each do |name, (type, val)| if type == :static static_attributes[name] = val else dynamic_attributes << inspect_obj(name) << " => " << val << "," end end dynamic_attributes << "}" dynamic_attributes = nil if dynamic_attributes == "{}" return [static_attributes, dynamic_attributes], scanner.rest, last_line end def parse_new_attribute(scanner) unless name = scanner.scan(/[-:\w]+/) return if scanner.scan(/\)/) return false end scanner.scan(/\s*/) return name, [:static, true] unless scanner.scan(/=/) #/end scanner.scan(/\s*/) unless quote = scanner.scan(/["']/) return false unless var = scanner.scan(/(@@?|\$)?\w+/) return name, [:dynamic, var] end re = /((?:\\.|\#(?!\{)|[^#{quote}\\#])*)(#{quote}|#\{)/ content = [] loop do return false unless scanner.scan(re) content << [:str, scanner[1].gsub(/\\(.)/, '\1')] break if scanner[2] == quote content << [:ruby, balance(scanner, ?{, ?}, 1).first[0...-1]] end return name, [:static, content.first[1]] if content.size == 1 return name, [:dynamic, '"' + content.map {|(t, v)| t == :str ? inspect_obj(v)[1...-1] : "\#{#{v}}"}.join + '"'] end def raw_next_line text = @template.shift return unless text index = @template_index @template_index += 1 return text, index end def next_line text, index = raw_next_line return unless text # :eod is a special end-of-document marker line = if text == :eod Line.new '-#', '-#', '-#', index, self, true else Line.new text.strip, text.lstrip.chomp, text, index, self, false end # `flat?' here is a little outdated, # so we have to manually check if either the previous or current line # closes the flat block, as well as whether a new block is opened. @line.tabs if @line unless (flat? && !closes_flat?(line) && !closes_flat?(@line)) || (@line && @line.text[0] == ?: && line.full =~ %r[^#{@line.full[/^\s+/]}\s]) return next_line if line.text.empty? handle_multiline(line) end @next_line = line end def closes_flat?(line) line && !line.text.empty? && line.full !~ /^#{@flat_spaces}/ end def un_next_line(line) @template.unshift line @template_index -= 1 end def handle_multiline(line) return unless is_multiline?(line.text) line.text.slice!(-1) while new_line = raw_next_line.first break if new_line == :eod next if new_line.strip.empty? break unless is_multiline?(new_line.strip) line.text << new_line.strip[0...-1] end un_next_line new_line end # Checks whether or not `line` is in a multiline sequence. def is_multiline?(text) text && text.length > 1 && text[-1] == MULTILINE_CHAR_VALUE && text[-2] == ?\s end def handle_ruby_multiline(text) text = text.rstrip return text unless is_ruby_multiline?(text) un_next_line @next_line.full begin new_line = raw_next_line.first break if new_line == :eod next if new_line.strip.empty? text << " " << new_line.strip end while is_ruby_multiline?(new_line.strip) next_line text end def is_ruby_multiline?(text) text && text.length > 1 && text[-1] == ?, && text[-2] != ?? && text[-3..-2] != "?\\" end def contains_interpolation?(str) str.include?('#{') end def unescape_interpolation(str, escape_html = nil) res = '' rest = Haml::Shared.handle_interpolation str.dump do |scan| escapes = (scan[2].size - 1) / 2 res << scan.matched[0...-3 - escapes] if escapes % 2 == 1 res << '#{' else content = eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"') content = "Haml::Helpers.html_escape((#{content}))" if escape_html res << '#{' + content + "}"# Use eval to get rid of string escapes end end res + rest end def balance(*args) res = Haml::Shared.balance(*args) return res if res raise SyntaxError.new("Unbalanced brackets.") end def block_opened? @next_line.tabs > @line.tabs end # Same semantics as block_opened?, except that block_opened? uses Line#tabs, # which doesn't interact well with filter lines def filter_opened? @next_line.full =~ (@indentation ? /^#{@indentation * @template_tabs}/ : /^\s/) end def flat? @flat end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/engine.rb0000664000175000017500000002623112414640747030723 0ustar ebourgebourgrequire 'haml/helpers' require 'haml/buffer' require 'haml/parser' require 'haml/compiler' require 'haml/filters' require 'haml/error' module Haml # This is the frontend for using Haml programmatically. # It can be directly used by the user by creating a # new instance and calling \{#render} to render the template. # For example: # # template = File.read('templates/really_cool_template.haml') # haml_engine = Haml::Engine.new(template) # output = haml_engine.render # puts output class Engine include Parser include Compiler # The options hash. # See {file:HAML_REFERENCE.md#haml_options the Haml options documentation}. # # @return [{Symbol => Object}] attr_accessor :options # The indentation used in the Haml document, # or `nil` if the indentation is ambiguous # (for example, for a single-level document). # # @return [String] attr_accessor :indentation # @return [Boolean] Whether or not the format is XHTML. def xhtml? not html? end # @return [Boolean] Whether or not the format is any flavor of HTML. def html? html4? or html5? end # @return [Boolean] Whether or not the format is HTML4. def html4? @options[:format] == :html4 end # @return [Boolean] Whether or not the format is HTML5. def html5? @options[:format] == :html5 end # The source code that is evaluated to produce the Haml document. # # In Ruby 1.9, this is automatically converted to the correct encoding # (see {file:HAML_REFERENCE.md#encoding-option the `:encoding` option}). # # @return [String] def precompiled return @precompiled if ruby1_8? encoding = Encoding.find(@options[:encoding]) return @precompiled.force_encoding(encoding) if encoding == Encoding::BINARY return @precompiled.encode(encoding) end # Precompiles the Haml template. # # @param template [String] The Haml template # @param options [{Symbol => Object}] An options hash; # see {file:HAML_REFERENCE.md#haml_options the Haml options documentation} # @raise [Haml::Error] if there's a Haml syntax error in the template def initialize(template, options = {}) @options = { :suppress_eval => false, :attr_wrapper => "'", # Don't forget to update the docs in doc-src/HAML_REFERENCE.md # if you update these :autoclose => %w[meta img link br hr input area param col base], :preserve => %w[textarea pre code], :filename => '(haml)', :line => 1, :ugly => false, :format => :xhtml, :escape_html => false, :escape_attrs => true, } template = check_haml_encoding(template) do |msg, line| raise Haml::Error.new(msg, line) end unless ruby1_8? @options[:encoding] = Encoding.default_internal || template.encoding @options[:encoding] = "utf-8" if @options[:encoding].name == "US-ASCII" end @options.merge! options.reject {|k, v| v.nil?} @index = 0 unless [:xhtml, :html4, :html5].include?(@options[:format]) raise Haml::Error, "Invalid output format #{@options[:format].inspect}" end if @options[:encoding] && @options[:encoding].is_a?(Encoding) @options[:encoding] = @options[:encoding].name end # :eod is a special end-of-document marker @template = (template.rstrip).split(/\r\n|\r|\n/) + [:eod, :eod] @template_index = 0 @to_close_stack = [] @output_tabs = 0 @template_tabs = 0 @flat = false @newlines = 0 @precompiled = '' @to_merge = [] @tab_change = 0 compile(parse) rescue Haml::Error => e if @index || e.line e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}" end raise end # Processes the template and returns the result as a string. # # `scope` is the context in which the template is evaluated. # If it's a `Binding` or `Proc` object, # Haml uses it as the second argument to `Kernel#eval`; # otherwise, Haml just uses its `#instance_eval` context. # # Note that Haml modifies the evaluation context # (either the scope object or the `self` object of the scope binding). # It extends {Haml::Helpers}, and various instance variables are set # (all prefixed with `haml_`). # For example: # # s = "foobar" # Haml::Engine.new("%p= upcase").render(s) #=> "

        FOOBAR

        " # # # s now extends Haml::Helpers # s.respond_to?(:html_attrs) #=> true # # `locals` is a hash of local variables to make available to the template. # For example: # # Haml::Engine.new("%p= foo").render(Object.new, :foo => "Hello, world!") #=> "

        Hello, world!

        " # # If a block is passed to render, # that block is run when `yield` is called # within the template. # # Due to some Ruby quirks, # if `scope` is a `Binding` or `Proc` object and a block is given, # the evaluation context may not be quite what the user expects. # In particular, it's equivalent to passing `eval("self", scope)` as `scope`. # This won't have an effect in most cases, # but if you're relying on local variables defined in the context of `scope`, # they won't work. # # @param scope [Binding, Proc, Object] The context in which the template is evaluated # @param locals [{Symbol => Object}] Local variables that will be made available # to the template # @param block [#to_proc] A block that can be yielded to within the template # @return [String] The rendered template def render(scope = Object.new, locals = {}, &block) buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer) if scope.is_a?(Binding) || scope.is_a?(Proc) scope_object = eval("self", scope) scope = scope_object.instance_eval{binding} if block_given? else scope_object = scope scope = scope_object.instance_eval{binding} end set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object) scope_object.instance_eval do extend Haml::Helpers @haml_buffer = buffer end eval(precompiled + ";" + precompiled_method_return_value, scope, @options[:filename], @options[:line]) ensure # Get rid of the current buffer scope_object.instance_eval do @haml_buffer = buffer.upper if buffer end end alias_method :to_html, :render # Returns a proc that, when called, # renders the template and returns the result as a string. # # `scope` works the same as it does for render. # # The first argument of the returned proc is a hash of local variable names to values. # However, due to an unfortunate Ruby quirk, # the local variables which can be assigned must be pre-declared. # This is done with the `local_names` argument. # For example: # # # This works # Haml::Engine.new("%p= foo").render_proc(Object.new, :foo).call :foo => "Hello!" # #=> "

        Hello!

        " # # # This doesn't # Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!" # #=> NameError: undefined local variable or method `foo' # # The proc doesn't take a block; any yields in the template will fail. # # @param scope [Binding, Proc, Object] The context in which the template is evaluated # @param local_names [Array] The names of the locals that can be passed to the proc # @return [Proc] The proc that will run the template def render_proc(scope = Object.new, *local_names) if scope.is_a?(Binding) || scope.is_a?(Proc) scope_object = eval("self", scope) else scope_object = scope scope = scope_object.instance_eval{binding} end eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" + precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line]) end # Defines a method on `object` with the given name # that renders the template and returns the result as a string. # # If `object` is a class or module, # the method will instead by defined as an instance method. # For example: # # t = Time.now # Haml::Engine.new("%p\n Today's date is\n .date= self.to_s").def_method(t, :render) # t.render #=> "

        \n Today's date is\n

        Fri Nov 23 18:28:29 -0800 2007
        \n

        \n" # # Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div) # "foobar".upcased_div #=> "
        FOOBAR
        \n" # # The first argument of the defined method is a hash of local variable names to values. # However, due to an unfortunate Ruby quirk, # the local variables which can be assigned must be pre-declared. # This is done with the `local_names` argument. # For example: # # # This works # obj = Object.new # Haml::Engine.new("%p= foo").def_method(obj, :render, :foo) # obj.render(:foo => "Hello!") #=> "

        Hello!

        " # # # This doesn't # obj = Object.new # Haml::Engine.new("%p= foo").def_method(obj, :render) # obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo' # # Note that Haml modifies the evaluation context # (either the scope object or the `self` object of the scope binding). # It extends {Haml::Helpers}, and various instance variables are set # (all prefixed with `haml_`). # # @param object [Object, Module] The object on which to define the method # @param name [String, Symbol] The name of the method to define # @param local_names [Array] The names of the locals that can be passed to the proc def def_method(object, name, *local_names) method = object.is_a?(Module) ? :module_eval : :instance_eval object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end", @options[:filename], @options[:line]) end protected # Returns a subset of \{#options}: those that {Haml::Buffer} cares about. # All of the values here are such that when `#inspect` is called on the hash, # it can be `Kernel#eval`ed to get the same result back. # # See {file:HAML_REFERENCE.md#haml_options the Haml options documentation}. # # @return [{Symbol => Object}] The options hash def options_for_buffer { :autoclose => @options[:autoclose], :preserve => @options[:preserve], :attr_wrapper => @options[:attr_wrapper], :ugly => @options[:ugly], :format => @options[:format], :encoding => @options[:encoding], :escape_html => @options[:escape_html], :escape_attrs => @options[:escape_attrs], } end private def set_locals(locals, scope, scope_object) scope_object.send(:instance_variable_set, '@_haml_locals', locals) set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n") eval(set_locals, scope) end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/util.rb0000664000175000017500000007116612414640747030442 0ustar ebourgebourgrequire 'erb' require 'set' require 'enumerator' require 'stringio' require 'strscan' require 'rbconfig' require 'haml/root' module Haml # A module containing various useful functions. module Util extend self # An array of ints representing the Ruby version number. # @api public RUBY_VERSION = ::RUBY_VERSION.split(".").map {|s| s.to_i} # The Ruby engine we're running under. Defaults to `"ruby"` # if the top-level constant is undefined. # @api public RUBY_ENGINE = defined?(::RUBY_ENGINE) ? ::RUBY_ENGINE : "ruby" # Returns the path of a file relative to the Haml root directory. # # @param file [String] The filename relative to the Haml root # @return [String] The filename relative to the the working directory def scope(file) File.join(Haml::ROOT_DIR, file) end # Converts an array of `[key, value]` pairs to a hash. # # @example # to_hash([[:foo, "bar"], [:baz, "bang"]]) # #=> {:foo => "bar", :baz => "bang"} # @param arr [Array<(Object, Object)>] An array of pairs # @return [Hash] A hash def to_hash(arr) Hash[arr.compact] end # Maps the keys in a hash according to a block. # # @example # map_keys({:foo => "bar", :baz => "bang"}) {|k| k.to_s} # #=> {"foo" => "bar", "baz" => "bang"} # @param hash [Hash] The hash to map # @yield [key] A block in which the keys are transformed # @yieldparam key [Object] The key that should be mapped # @yieldreturn [Object] The new value for the key # @return [Hash] The mapped hash # @see #map_vals # @see #map_hash def map_keys(hash) to_hash(hash.map {|k, v| [yield(k), v]}) end # Maps the values in a hash according to a block. # # @example # map_values({:foo => "bar", :baz => "bang"}) {|v| v.to_sym} # #=> {:foo => :bar, :baz => :bang} # @param hash [Hash] The hash to map # @yield [value] A block in which the values are transformed # @yieldparam value [Object] The value that should be mapped # @yieldreturn [Object] The new value for the value # @return [Hash] The mapped hash # @see #map_keys # @see #map_hash def map_vals(hash) to_hash(hash.map {|k, v| [k, yield(v)]}) end # Maps the key-value pairs of a hash according to a block. # # @example # map_hash({:foo => "bar", :baz => "bang"}) {|k, v| [k.to_s, v.to_sym]} # #=> {"foo" => :bar, "baz" => :bang} # @param hash [Hash] The hash to map # @yield [key, value] A block in which the key-value pairs are transformed # @yieldparam [key] The hash key # @yieldparam [value] The hash value # @yieldreturn [(Object, Object)] The new value for the `[key, value]` pair # @return [Hash] The mapped hash # @see #map_keys # @see #map_vals def map_hash(hash, &block) to_hash(hash.map(&block)) end # Computes the powerset of the given array. # This is the set of all subsets of the array. # # @example # powerset([1, 2, 3]) #=> # Set[Set[], Set[1], Set[2], Set[3], Set[1, 2], Set[2, 3], Set[1, 3], Set[1, 2, 3]] # @param arr [Enumerable] # @return [Set] The subsets of `arr` def powerset(arr) arr.inject([Set.new].to_set) do |powerset, el| new_powerset = Set.new powerset.each do |subset| new_powerset << subset new_powerset << subset + [el] end new_powerset end end # Restricts a number to falling within a given range. # Returns the number if it falls within the range, # or the closest value in the range if it doesn't. # # @param value [Numeric] # @param range [Range] # @return [Numeric] def restrict(value, range) [[value, range.first].max, range.last].min end # Concatenates all strings that are adjacent in an array, # while leaving other elements as they are. # # @example # merge_adjacent_strings([1, "foo", "bar", 2, "baz"]) # #=> [1, "foobar", 2, "baz"] # @param arr [Array] # @return [Array] The enumerable with strings merged def merge_adjacent_strings(arr) # Optimize for the common case of one element return arr if arr.size < 2 arr.inject([]) do |a, e| if e.is_a?(String) if a.last.is_a?(String) a.last << e else a << e.dup end else a << e end a end end # Intersperses a value in an enumerable, as would be done with `Array#join` # but without concatenating the array together afterwards. # # @param enum [Enumerable] # @param val # @return [Array] def intersperse(enum, val) enum.inject([]) {|a, e| a << e << val}[0...-1] end # Substitutes a sub-array of one array with another sub-array. # # @param ary [Array] The array in which to make the substitution # @param from [Array] The sequence of elements to replace with `to` # @param to [Array] The sequence of elements to replace `from` with def substitute(ary, from, to) res = ary.dup i = 0 while i < res.size if res[i...i+from.size] == from res[i...i+from.size] = to end i += 1 end res end # Destructively strips whitespace from the beginning and end # of the first and last elements, respectively, # in the array (if those elements are strings). # # @param arr [Array] # @return [Array] `arr` def strip_string_array(arr) arr.first.lstrip! if arr.first.is_a?(String) arr.last.rstrip! if arr.last.is_a?(String) arr end # Return an array of all possible paths through the given arrays. # # @param arrs [Array] # @return [Array] # # @example # paths([[1, 2], [3, 4], [5]]) #=> # # [[1, 3, 5], # # [2, 3, 5], # # [1, 4, 5], # # [2, 4, 5]] def paths(arrs) arrs.inject([[]]) do |paths, arr| flatten(arr.map {|e| paths.map {|path| path + [e]}}, 1) end end # Computes a single longest common subsequence for `x` and `y`. # If there are more than one longest common subsequences, # the one returned is that which starts first in `x`. # # @param x [Array] # @param y [Array] # @yield [a, b] An optional block to use in place of a check for equality # between elements of `x` and `y`. # @yieldreturn [Object, nil] If the two values register as equal, # this will return the value to use in the LCS array. # @return [Array] The LCS def lcs(x, y, &block) x = [nil, *x] y = [nil, *y] block ||= proc {|a, b| a == b && a} lcs_backtrace(lcs_table(x, y, &block), x, y, x.size-1, y.size-1, &block) end # Returns information about the caller of the previous method. # # @param entry [String] An entry in the `#caller` list, or a similarly formatted string # @return [[String, Fixnum, (String, nil)]] An array containing the filename, line, and method name of the caller. # The method name may be nil def caller_info(entry = caller[1]) info = entry.scan(/^(.*?):(-?.*?)(?::.*`(.+)')?$/).first info[1] = info[1].to_i # This is added by Rubinius to designate a block, but we don't care about it. info[2].sub!(/ \{\}\Z/, '') if info[2] info end # Returns whether one version string represents a more recent version than another. # # @param v1 [String] A version string. # @param v2 [String] Another version string. # @return [Boolean] def version_gt(v1, v2) # Construct an array to make sure the shorter version is padded with nil Array.new([v1.length, v2.length].max).zip(v1.split("."), v2.split(".")) do |_, p1, p2| p1 ||= "0" p2 ||= "0" release1 = p1 =~ /^[0-9]+$/ release2 = p2 =~ /^[0-9]+$/ if release1 && release2 # Integer comparison if both are full releases p1, p2 = p1.to_i, p2.to_i next if p1 == p2 return p1 > p2 elsif !release1 && !release2 # String comparison if both are prereleases next if p1 == p2 return p1 > p2 else # If only one is a release, that one is newer return release1 end end end # Returns whether one version string represents the same or a more # recent version than another. # # @param v1 [String] A version string. # @param v2 [String] Another version string. # @return [Boolean] def version_geq(v1, v2) version_gt(v1, v2) || !version_gt(v2, v1) end # A wrapper for `Marshal.dump` that calls `#_before_dump` on the object # before dumping it, `#_after_dump` afterwards. # It also calls `#_around_dump` and passes it a block in which the object is dumped. # # If any of these methods are undefined, they are not called. # # @param obj [Object] The object to dump. # @return [String] The dumped data. def dump(obj) obj._before_dump if obj.respond_to?(:_before_dump) return Marshal.dump(obj) unless obj.respond_to?(:_around_dump) res = nil obj._around_dump {res = Marshal.dump(obj)} res ensure obj._after_dump if obj.respond_to?(:_after_dump) end # A wrapper for `Marshal.load` that calls `#_after_load` on the object # after loading it, if it's defined. # # @param data [String] The data to load. # @return [Object] The loaded object. def load(data) obj = Marshal.load(data) obj._after_load if obj.respond_to?(:_after_load) obj end # Throws a NotImplementedError for an abstract method. # # @param obj [Object] `self` # @raise [NotImplementedError] def abstract(obj) raise NotImplementedError.new("#{obj.class} must implement ##{caller_info[2]}") end # Silence all output to STDERR within a block. # # @yield A block in which no output will be printed to STDERR def silence_warnings the_real_stderr, $stderr = $stderr, StringIO.new yield ensure $stderr = the_real_stderr end @@silence_warnings = false # Silences all Haml warnings within a block. # # @yield A block in which no Haml warnings will be printed def silence_haml_warnings old_silence_warnings = @@silence_warnings @@silence_warnings = true yield ensure @@silence_warnings = old_silence_warnings end # The same as `Kernel#warn`, but is silenced by \{#silence\_haml\_warnings}. # # @param msg [String] def haml_warn(msg) return if @@silence_warnings warn(msg) end # Try loading Sass. If the `sass` gem isn't installed, # print a warning and load from the vendored gem. # # @return [Boolean] True if Sass was successfully loaded from the `sass` gem, # false otherwise. def try_sass return true if defined?(::SASS_BEGUN_TO_LOAD) begin require 'sass/version' loaded = Sass.respond_to?(:version) && Sass.version[:major] && Sass.version[:minor] && ((Sass.version[:major] > 3 && Sass.version[:minor] > 1) || ((Sass.version[:major] == 3 && Sass.version[:minor] == 1) && (Sass.version[:prerelease] || Sass.version[:name] != "Bleeding Edge"))) rescue LoadError => e loaded = false end unless loaded haml_warn(<= 3 return false unless defined?(ActionPack) && defined?(ActionPack::VERSION) && defined?(ActionPack::VERSION::STRING) version_geq(ActionPack::VERSION::STRING, version) end # Returns an ActionView::Template* class. # In pre-3.0 versions of Rails, most of these classes # were of the form `ActionView::TemplateFoo`, # while afterwards they were of the form `ActionView;:Template::Foo`. # # @param name [#to_s] The name of the class to get. # For example, `:Error` will return `ActionView::TemplateError` # or `ActionView::Template::Error`. def av_template_class(name) return ActionView.const_get("Template#{name}") if ActionView.const_defined?("Template#{name}") return ActionView::Template.const_get(name.to_s) end ## Rails XSS Safety # Whether or not ActionView's XSS protection is available and enabled, # as is the default for Rails 3.0+, and optional for version 2.3.5+. # Overridden in haml/template.rb if this is the case. # # @return [Boolean] def rails_xss_safe? false end # Returns the given text, marked as being HTML-safe. # With older versions of the Rails XSS-safety mechanism, # this destructively modifies the HTML-safety of `text`. # # @param text [String, nil] # @return [String, nil] `text`, marked as HTML-safe def html_safe(text) return unless text return text.html_safe if defined?(ActiveSupport::SafeBuffer) text.html_safe! end # Assert that a given object (usually a String) is HTML safe # according to Rails' XSS handling, if it's loaded. # # @param text [Object] def assert_html_safe!(text) return unless rails_xss_safe? && text && !text.to_s.html_safe? raise Haml::Error.new("Expected #{text.inspect} to be HTML-safe.") end # The class for the Rails SafeBuffer XSS protection class. # This varies depending on Rails version. # # @return [Class] def rails_safe_buffer_class # It's important that we check ActiveSupport first, # because in Rails 2.3.6 ActionView::SafeBuffer exists # but is a deprecated proxy object. return ActiveSupport::SafeBuffer if defined?(ActiveSupport::SafeBuffer) return ActionView::SafeBuffer end ## Cross-OS Compatibility # Whether or not this is running on Windows. # # @return [Boolean] def windows? RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw/i end # Whether or not this is running on IronRuby. # # @return [Boolean] def ironruby? RUBY_ENGINE == "ironruby" end ## Cross-Ruby-Version Compatibility # Whether or not this is running under Ruby 1.8 or lower. # # Note that IronRuby counts as Ruby 1.8, # because it doesn't support the Ruby 1.9 encoding API. # # @return [Boolean] def ruby1_8? # IronRuby says its version is 1.9, but doesn't support any of the encoding APIs. # We have to fall back to 1.8 behavior. ironruby? || (Haml::Util::RUBY_VERSION[0] == 1 && Haml::Util::RUBY_VERSION[1] < 9) end # Whether or not this is running under Ruby 1.8.6 or lower. # Note that lower versions are not officially supported. # # @return [Boolean] def ruby1_8_6? ruby1_8? && Haml::Util::RUBY_VERSION[2] < 7 end # Checks that the encoding of a string is valid in Ruby 1.9 # and cleans up potential encoding gotchas like the UTF-8 BOM. # If it's not, yields an error string describing the invalid character # and the line on which it occurrs. # # @param str [String] The string of which to check the encoding # @yield [msg] A block in which an encoding error can be raised. # Only yields if there is an encoding error # @yieldparam msg [String] The error message to be raised # @return [String] `str`, potentially with encoding gotchas like BOMs removed def check_encoding(str) if ruby1_8? return str.gsub(/\A\xEF\xBB\xBF/, '') # Get rid of the UTF-8 BOM elsif str.valid_encoding? # Get rid of the Unicode BOM if possible if str.encoding.name =~ /^UTF-(8|16|32)(BE|LE)?$/ return str.gsub(Regexp.new("\\A\uFEFF".encode(str.encoding.name)), '') else return str end end encoding = str.encoding newlines = Regexp.new("\r\n|\r|\n".encode(encoding).force_encoding("binary")) str.force_encoding("binary").split(newlines).each_with_index do |line, i| begin line.encode(encoding) rescue Encoding::UndefinedConversionError => e yield < true # # Method collections like `Class#instance_methods` # return strings in Ruby 1.8 and symbols in Ruby 1.9 and on, # so this handles checking for them in a compatible way. # # @param attr [#to_s] The (singular) name of the method-collection method # (e.g. `:instance_methods`, `:private_methods`) # @param klass [Module] The class to check the methods of which to check # @param method [String, Symbol] The name of the method do check for # @return [Boolean] Whether or not the given collection has the given method def has?(attr, klass, method) klass.send("#{attr}s").include?(ruby1_8? ? method.to_s : method.to_sym) end # A version of `Enumerable#enum_with_index` that works in Ruby 1.8 and 1.9. # # @param enum [Enumerable] The enumerable to get the enumerator for # @return [Enumerator] The with-index enumerator def enum_with_index(enum) ruby1_8? ? enum.enum_with_index : enum.each_with_index end # A version of `Enumerable#enum_cons` that works in Ruby 1.8 and 1.9. # # @param enum [Enumerable] The enumerable to get the enumerator for # @param n [Fixnum] The size of each cons # @return [Enumerator] The consed enumerator def enum_cons(enum, n) ruby1_8? ? enum.enum_cons(n) : enum.each_cons(n) end # A version of `Enumerable#enum_slice` that works in Ruby 1.8 and 1.9. # # @param enum [Enumerable] The enumerable to get the enumerator for # @param n [Fixnum] The size of each slice # @return [Enumerator] The consed enumerator def enum_slice(enum, n) ruby1_8? ? enum.enum_slice(n) : enum.each_slice(n) end # Returns the ASCII code of the given character. # # @param c [String] All characters but the first are ignored. # @return [Fixnum] The ASCII code of `c`. def ord(c) ruby1_8? ? c[0] : c.ord end # Flattens the first `n` nested arrays in a cross-version manner. # # @param arr [Array] The array to flatten # @param n [Fixnum] The number of levels to flatten # @return [Array] The flattened array def flatten(arr, n) return arr.flatten(n) unless ruby1_8_6? return arr if n == 0 arr.inject([]) {|res, e| e.is_a?(Array) ? res.concat(flatten(e, n - 1)) : res << e} end # Returns the hash code for a set in a cross-version manner. # Aggravatingly, this is order-dependent in Ruby 1.8.6. # # @param set [Set] # @return [Fixnum] The order-independent hashcode of `set` def set_hash(set) return set.hash unless ruby1_8_6? set.map {|e| e.hash}.uniq.sort.hash end # Tests the hash-equality of two sets in a cross-version manner. # Aggravatingly, this is order-dependent in Ruby 1.8.6. # # @param set1 [Set] # @param set2 [Set] # @return [Boolean] Whether or not the sets are hashcode equal def set_eql?(set1, set2) return set1.eql?(set2) unless ruby1_8_6? set1.to_a.uniq.sort_by {|e| e.hash}.eql?(set2.to_a.uniq.sort_by {|e| e.hash}) end # Like `Object#inspect`, but preserves non-ASCII characters rather than escaping them under Ruby 1.9.2. # This is necessary so that the precompiled Haml template can be `#encode`d into `@options[:encoding]` # before being evaluated. # # @param obj {Object} # @return {String} def inspect_obj(obj) return obj.inspect unless version_geq(::RUBY_VERSION, "1.9.2") return ':' + inspect_obj(obj.to_s) if obj.is_a?(Symbol) return obj.inspect unless obj.is_a?(String) '"' + obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]} + '"' end ## Static Method Stuff # The context in which the ERB for \{#def\_static\_method} will be run. class StaticConditionalContext # @param set [#include?] The set of variables that are defined for this context. def initialize(set) @set = set end # Checks whether or not a variable is defined for this context. # # @param name [Symbol] The name of the variable # @return [Boolean] def method_missing(name, *args, &block) super unless args.empty? && block.nil? @set.include?(name) end end # This is used for methods in {Haml::Buffer} that need to be very fast, # and take a lot of boolean parameters # that are known at compile-time. # Instead of passing the parameters in normally, # a separate method is defined for every possible combination of those parameters; # these are then called using \{#static\_method\_name}. # # To define a static method, an ERB template for the method is provided. # All conditionals based on the static parameters # are done as embedded Ruby within this template. # For example: # # def_static_method(Foo, :my_static_method, [:foo, :bar], :baz, :bang, < # return foo + bar # <% elsif baz || bang %> # return foo - bar # <% else %> # return 17 # <% end %> # RUBY # # \{#static\_method\_name} can be used to call static methods. # # @overload def_static_method(klass, name, args, *vars, erb) # @param klass [Module] The class on which to define the static method # @param name [#to_s] The (base) name of the static method # @param args [Array] The names of the arguments to the defined methods # (**not** to the ERB template) # @param vars [Array] The names of the static boolean variables # to be made available to the ERB template # @param erb [String] The template for the method code def def_static_method(klass, name, args, *vars) erb = vars.pop info = caller_info powerset(vars).each do |set| context = StaticConditionalContext.new(set).instance_eval {binding} klass.class_eval(<] The static variable assignment # @return [String] The real name of the static method def static_method_name(name, *vars) "#{name}_#{vars.map {|v| !!v}.join('_')}" end private # Calculates the memoization table for the Least Common Subsequence algorithm. # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS) def lcs_table(x, y) c = Array.new(x.size) {[]} x.size.times {|i| c[i][0] = 0} y.size.times {|j| c[0][j] = 0} (1...x.size).each do |i| (1...y.size).each do |j| c[i][j] = if yield x[i], y[j] c[i-1][j-1] + 1 else [c[i][j-1], c[i-1][j]].max end end end return c end # Computes a single longest common subsequence for arrays x and y. # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS) def lcs_backtrace(c, x, y, i, j, &block) return [] if i == 0 || j == 0 if v = yield(x[i], y[j]) return lcs_backtrace(c, x, y, i-1, j-1, &block) << v end return lcs_backtrace(c, x, y, i, j-1, &block) if c[i][j-1] > c[i-1][j] return lcs_backtrace(c, x, y, i-1, j, &block) end # Parses a magic comment at the beginning of a Haml file. # The parsing rules are basically the same as Ruby's. # # @return [(Boolean, String or nil)] # Whether the document begins with a UTF-8 BOM, # and the declared encoding of the document (or nil if none is declared) def parse_haml_magic_comment(str) scanner = StringScanner.new(str.dup.force_encoding("BINARY")) bom = scanner.scan(/\xEF\xBB\xBF/n) return bom unless scanner.scan(/-\s*#\s*/n) if coding = try_parse_haml_emacs_magic_comment(scanner) return bom, coding end return bom unless scanner.scan(/.*?coding[=:]\s*([\w-]+)/in) return bom, scanner[1] end def try_parse_haml_emacs_magic_comment(scanner) pos = scanner.pos return unless scanner.scan(/.*?-\*-\s*/n) # From Ruby's parse.y return unless scanner.scan(/([^\s'":;]+)\s*:\s*("(?:\\.|[^"])*"|[^"\s;]+?)[\s;]*-\*-/n) name, val = scanner[1], scanner[2] return unless name =~ /(en)?coding/in val = $1 if val =~ /^"(.*)"$/n return val ensure scanner.pos = pos end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/helpers.rb0000664000175000017500000004456112414640747031126 0ustar ebourgebourgmodule Haml # This module contains various helpful methods to make it easier to do various tasks. # {Haml::Helpers} is automatically included in the context # that a Haml template is parsed in, so all these methods are at your # disposal from within the template. module Helpers # An object that raises an error when \{#to\_s} is called. # It's used to raise an error when the return value of a helper is used # when it shouldn't be. class ErrorReturn # @param message [String] The error message to raise when \{#to\_s} is called def initialize(method) @message = < e e.backtrace.shift # If the ErrorReturn is used directly in the template, # we don't want Haml's stuff to get into the backtrace, # so we get rid of the format_script line. # # We also have to subtract one from the Haml line number # since the value is passed to format_script the line after # it's actually used. if e.backtrace.first =~ /^\(eval\):\d+:in `format_script/ e.backtrace.shift e.backtrace.first.gsub!(/^\(haml\):(\d+)/) {|s| "(haml):#{$1.to_i - 1}"} end raise e end # @return [String] A human-readable string representation def inspect "Haml::Helpers::ErrorReturn(#{@message.inspect})" end end self.extend self @@action_view_defined = false # @return [Boolean] Whether or not ActionView is loaded def self.action_view? @@action_view_defined end # Note: this does **not** need to be called when using Haml helpers # normally in Rails. # # Initializes the current object as though it were in the same context # as a normal ActionView instance using Haml. # This is useful if you want to use the helpers in a context # other than the normal setup with ActionView. # For example: # # context = Object.new # class << context # include Haml::Helpers # end # context.init_haml_helpers # context.haml_tag :p, "Stuff" # def init_haml_helpers @haml_buffer = Haml::Buffer.new(@haml_buffer, Haml::Engine.new('').send(:options_for_buffer)) nil end # Runs a block of code in a non-Haml context # (i.e. \{#is\_haml?} will return false). # # This is mainly useful for rendering sub-templates such as partials in a non-Haml language, # particularly where helpers may behave differently when run from Haml. # # Note that this is automatically applied to Rails partials. # # @yield A block which won't register as Haml def non_haml was_active = @haml_buffer.active? @haml_buffer.active = false yield ensure @haml_buffer.active = was_active end # Uses \{#preserve} to convert any newlines inside whitespace-sensitive tags # into the HTML entities for endlines. # # @param tags [Array] Tags that should have newlines escaped # # @overload find_and_preserve(input, tags = haml_buffer.options[:preserve]) # Escapes newlines within a string. # # @param input [String] The string within which to escape newlines # @overload find_and_preserve(tags = haml_buffer.options[:preserve]) # Escapes newlines within a block of Haml code. # # @yield The block within which to escape newlines def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block) return find_and_preserve(capture_haml(&block), input || tags) if block input.to_s.gsub(/<(#{tags.map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im) do "<#{$1}#{$2}>#{preserve($3)}" end end # Takes any string, finds all the newlines, and converts them to # HTML entities so they'll render correctly in # whitespace-sensitive tags without screwing up the indentation. # # @overload perserve(input) # Escapes newlines within a string. # # @param input [String] The string within which to escape all newlines # @overload perserve # Escapes newlines within a block of Haml code. # # @yield The block within which to escape newlines def preserve(input = nil, &block) return preserve(capture_haml(&block)) if block input.to_s.chomp("\n").gsub(/\n/, ' ').gsub(/\r/, '') end alias_method :flatten, :preserve # Takes an `Enumerable` object and a block # and iterates over the enum, # yielding each element to a Haml block # and putting the result into `
      • ` elements. # This creates a list of the results of the block. # For example: # # = list_of([['hello'], ['yall']]) do |i| # = i[0] # # Produces: # #
      • hello
      • #
      • yall
      • # # And # # = list_of({:title => 'All the stuff', :description => 'A book about all the stuff.'}) do |key, val| # %h3= key.humanize # %p= val # # Produces: # #
      • #

        Title

        #

        All the stuff

        #
      • #
      • #

        Description

        #

        A book about all the stuff.

        #
      • # # @param enum [Enumerable] The list of objects to iterate over # @yield [item] A block which contains Haml code that goes within list items # @yieldparam item An element of `enum` def list_of(enum, &block) to_return = enum.collect do |i| result = capture_haml(i, &block) if result.count("\n") > 1 result.gsub!("\n", "\n ") result = "\n #{result.strip}\n" else result.strip! end "
      • #{result}
      • " end to_return.join("\n") end # Returns a hash containing default assignments for the `xmlns`, `lang`, and `xml:lang` # attributes of the `html` HTML element. # For example, # # %html{html_attrs} # # becomes # # # # @param lang [String] The value of `xml:lang` and `lang` # @return [{#to_s => String}] The attribute hash def html_attrs(lang = 'en-US') {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang} end # Increments the number of tabs the buffer automatically adds # to the lines of the template. # For example: # # %h1 foo # - tab_up # %p bar # - tab_down # %strong baz # # Produces: # #

        foo

        #

        bar

        # baz # # @param i [Fixnum] The number of tabs by which to increase the indentation # @see #tab_down def tab_up(i = 1) haml_buffer.tabulation += i end # Decrements the number of tabs the buffer automatically adds # to the lines of the template. # # @param i [Fixnum] The number of tabs by which to decrease the indentation # @see #tab_up def tab_down(i = 1) haml_buffer.tabulation -= i end # Sets the number of tabs the buffer automatically adds # to the lines of the template, # but only for the duration of the block. # For example: # # %h1 foo # - with_tabs(2) do # %p bar # %strong baz # # Produces: # #

        foo

        #

        bar

        # baz # # # @param i [Fixnum] The number of tabs to use # @yield A block in which the indentation will be `i` spaces def with_tabs(i) old_tabs = haml_buffer.tabulation haml_buffer.tabulation = i yield ensure haml_buffer.tabulation = old_tabs end # Surrounds a block of Haml code with strings, # with no whitespace in between. # For example: # # = surround '(', ')' do # %a{:href => "food"} chicken # # Produces: # # (chicken) # # and # # = surround '*' do # %strong angry # # Produces: # # *angry* # # @param front [String] The string to add before the Haml # @param back [String] The string to add after the Haml # @yield A block of Haml to surround def surround(front, back = front, &block) output = capture_haml(&block) "#{front}#{output.chomp}#{back}\n" end # Prepends a string to the beginning of a Haml block, # with no whitespace between. # For example: # # = precede '*' do # %span.small Not really # # Produces: # # *Not really # # @param str [String] The string to add before the Haml # @yield A block of Haml to prepend to def precede(str, &block) "#{str}#{capture_haml(&block).chomp}\n" end # Appends a string to the end of a Haml block, # with no whitespace between. # For example: # # click # = succeed '.' do # %a{:href=>"thing"} here # # Produces: # # click # here. # # @param str [String] The string to add after the Haml # @yield A block of Haml to append to def succeed(str, &block) "#{capture_haml(&block).chomp}#{str}\n" end # Captures the result of a block of Haml code, # gets rid of the excess indentation, # and returns it as a string. # For example, after the following, # # .foo # - foo = capture_haml(13) do |a| # %p= a # # the local variable `foo` would be assigned to `"

        13

        \n"`. # # @param args [Array] Arguments to pass into the block # @yield [args] A block of Haml code that will be converted to a string # @yieldparam args [Array] `args` def capture_haml(*args, &block) buffer = eval('_hamlout', block.binding) rescue haml_buffer with_haml_buffer(buffer) do position = haml_buffer.buffer.length haml_buffer.capture_position = position block.call(*args) captured = haml_buffer.buffer.slice!(position..-1) return captured if haml_buffer.options[:ugly] captured = captured.split(/^/) min_tabs = nil captured.each do |line| tabs = line.index(/[^ ]/) || line.length min_tabs ||= tabs min_tabs = min_tabs > tabs ? tabs : min_tabs end captured.map do |line| line[min_tabs..-1] end.join end ensure haml_buffer.capture_position = nil end # Outputs text directly to the Haml buffer, with the proper indentation. # # @param text [#to_s] The text to output def haml_concat(text = "") unless haml_buffer.options[:ugly] || haml_indent == 0 haml_buffer.buffer << haml_indent << text.to_s.gsub("\n", "\n" + haml_indent) << "\n" else haml_buffer.buffer << text.to_s << "\n" end ErrorReturn.new("haml_concat") end # @return [String] The indentation string for the current line def haml_indent ' ' * haml_buffer.tabulation end # Creates an HTML tag with the given name and optionally text and attributes. # Can take a block that will run between the opening and closing tags. # If the block is a Haml block or outputs text using \{#haml\_concat}, # the text will be properly indented. # # `name` can be a string using the standard Haml class/id shorthand # (e.g. "span#foo.bar", "#foo"). # Just like standard Haml tags, these class and id values # will be merged with manually-specified attributes. # # `flags` is a list of symbol flags # like those that can be put at the end of a Haml tag # (`:/`, `:<`, and `:>`). # Currently, only `:/` and `:<` are supported. # # `haml_tag` outputs directly to the buffer; # its return value should not be used. # If you need to get the results as a string, # use \{#capture\_haml\}. # # For example, # # haml_tag :table do # haml_tag :tr do # haml_tag 'td.cell' do # haml_tag :strong, "strong!" # haml_concat "data" # end # haml_tag :td do # haml_concat "more_data" # end # end # end # # outputs # # # # # # #
        # # strong! # # data # # more_data #
        # # @param name [#to_s] The name of the tag # @param flags [Array] Haml end-of-tag flags # # @overload haml_tag(name, *flags, attributes = {}) # @yield The block of Haml code within the tag # @overload haml_tag(name, text, *flags, attributes = {}) # @param text [#to_s] The text within the tag def haml_tag(name, *rest, &block) ret = ErrorReturn.new("haml_tag") text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t} flags = [] flags << rest.shift while rest.first.is_a? Symbol attrs = Haml::Util.map_keys(rest.shift || {}) {|key| key.to_s} name, attrs = merge_name_and_attributes(name.to_s, attrs) attributes = Haml::Compiler.build_attributes(haml_buffer.html?, haml_buffer.options[:attr_wrapper], haml_buffer.options[:escape_attrs], attrs) if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/)) haml_concat "<#{name}#{attributes} />" return ret end if flags.include?(:/) raise Error.new("Self-closing tags can't have content.") if text raise Error.new("Illegal nesting: nesting within a self-closing tag is illegal.") if block end tag = "<#{name}#{attributes}>" if block.nil? text = text.to_s if text.include?("\n") haml_concat tag tab_up haml_concat text tab_down haml_concat "" else tag << text << "" haml_concat tag end return ret end if text raise Error.new("Illegal nesting: content can't be both given to haml_tag :#{name} and nested within it.") end if flags.include?(:<) tag << capture_haml(&block).strip << "" haml_concat tag return ret end haml_concat tag tab_up block.call tab_down haml_concat "" ret end # Characters that need to be escaped to HTML entities from user input HTML_ESCAPE = { '&'=>'&', '<'=>'<', '>'=>'>', '"'=>'"', "'"=>''', } # Returns a copy of `text` with ampersands, angle brackets and quotes # escaped into HTML entities. # # Note that if ActionView is loaded and XSS protection is enabled # (as is the default for Rails 3.0+, and optional for version 2.3.5+), # this won't escape text declared as "safe". # # @param text [String] The string to sanitize # @return [String] The sanitized string def html_escape(text) Haml::Util.silence_warnings {text.to_s.gsub(/[\"><&]/n) {|s| HTML_ESCAPE[s]}} end # Escapes HTML entities in `text`, but without escaping an ampersand # that is already part of an escaped entity. # # @param text [String] The string to sanitize # @return [String] The sanitized string def escape_once(text) Haml::Util.silence_warnings do text.to_s.gsub(/[\"><]|&(?!(?:[a-zA-Z]+|(#\d+));)/n) {|s| HTML_ESCAPE[s]} end end # Returns whether or not the current template is a Haml template. # # This function, unlike other {Haml::Helpers} functions, # also works in other `ActionView` templates, # where it will always return false. # # @return [Boolean] Whether or not the current template is a Haml template def is_haml? !@haml_buffer.nil? && @haml_buffer.active? end # Returns whether or not `block` is defined directly in a Haml template. # # @param block [Proc] A Ruby block # @return [Boolean] Whether or not `block` is defined directly in a Haml template def block_is_haml?(block) eval('_hamlout', block.binding) true rescue false end private # Parses the tag name used for \{#haml\_tag} # and merges it with the Ruby attributes hash. def merge_name_and_attributes(name, attributes_hash = {}) # skip merging if no ids or classes found in name return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/ return $1 || "div", Buffer.merge_attrs( Haml::Parser.parse_class_and_id($2), attributes_hash) end # Runs a block of code with the given buffer as the currently active buffer. # # @param buffer [Haml::Buffer] The Haml buffer to use temporarily # @yield A block in which the given buffer should be used def with_haml_buffer(buffer) @haml_buffer, old_buffer = buffer, @haml_buffer old_buffer.active, old_was_active = false, old_buffer.active? if old_buffer @haml_buffer.active, was_active = true, @haml_buffer.active? yield ensure @haml_buffer.active = was_active old_buffer.active = old_was_active if old_buffer @haml_buffer = old_buffer end # The current {Haml::Buffer} object. # # @return [Haml::Buffer] def haml_buffer @haml_buffer end # Gives a proc the same local `_hamlout` and `_erbout` variables # that the current template has. # # @param proc [#call] The proc to bind # @return [Proc] A new proc with the new variables bound def haml_bind_proc(&proc) _hamlout = haml_buffer _erbout = _hamlout.buffer proc { |*args| proc.call(*args) } end end end # @private class Object # Haml overrides various `ActionView` helpers, # which call an \{#is\_haml?} method # to determine whether or not the current context object # is a proper Haml context. # Because `ActionView` helpers may be included in non-`ActionView::Base` classes, # it's a good idea to define \{#is\_haml?} for all objects. def is_haml? false end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/filters.rb0000664000175000017500000003052212414640747031124 0ustar ebourgebourgmodule Haml # The module containing the default Haml filters, # as well as the base module, {Haml::Filters::Base}. # # @see Haml::Filters::Base module Filters # @return [{String => Haml::Filters::Base}] a hash of filter names to classes def self.defined @defined ||= {} end # The base module for Haml filters. # User-defined filters should be modules including this module. # The name of the filter is taken by downcasing the module name. # For instance, if the module is named `FooBar`, the filter will be `:foobar`. # # A user-defined filter should override either \{#render} or {\#compile}. # \{#render} is the most common. # It takes a string, the filter source, # and returns another string, the result of the filter. # For example, the following will define a filter named `:sass`: # # module Haml::Filters::Sass # include Haml::Filters::Base # # def render(text) # ::Sass::Engine.new(text).render # end # end # # For details on overriding \{#compile}, see its documentation. # # Note that filters overriding \{#render} automatically support `#{}` # for interpolating Ruby code. # Those overriding \{#compile} will need to add such support manually # if it's desired. module Base # This method is automatically called when {Base} is included in a module. # It automatically defines a filter # with the downcased name of that module. # For example, if the module is named `FooBar`, the filter will be `:foobar`. # # @param base [Module, Class] The module that this is included in def self.included(base) Filters.defined[base.name.split("::").last.downcase] = base base.extend(base) end # Takes the source text that should be passed to the filter # and returns the result of running the filter on that string. # # This should be overridden in most individual filter modules # to render text with the given filter. # If \{#compile} is overridden, however, \{#render} doesn't need to be. # # @param text [String] The source text for the filter to process # @return [String] The filtered result # @raise [Haml::Error] if it's not overridden def render(text) raise Error.new("#{self.inspect}#render not defined!") end # Same as \{#render}, but takes a {Haml::Engine} options hash as well. # It's only safe to rely on options made available in {Haml::Engine#options\_for\_buffer}. # # @see #render # @param text [String] The source text for the filter to process # @return [String] The filtered result # @raise [Haml::Error] if it or \{#render} isn't overridden def render_with_options(text, options) render(text) end # Same as \{#compile}, but requires the necessary files first. # *This is used by {Haml::Engine} and is not intended to be overridden or used elsewhere.* # # @see #compile def internal_compile(*args) resolve_lazy_requires compile(*args) end # This should be overridden when a filter needs to have access to the Haml evaluation context. # Rather than applying a filter to a string at compile-time, # \{#compile} uses the {Haml::Compiler} instance to compile the string to Ruby code # that will be executed in the context of the active Haml template. # # Warning: the {Haml::Compiler} interface is neither well-documented # nor guaranteed to be stable. # If you want to make use of it, you'll probably need to look at the source code # and should test your filter when upgrading to new Haml versions. # # @param compiler [Haml::Compiler] The compiler instance # @param text [String] The text of the filter # @raise [Haml::Error] if none of \{#compile}, \{#render}, and \{#render_with_options} are overridden def compile(compiler, text) resolve_lazy_requires filter = self compiler.instance_eval do if contains_interpolation?(text) return if options[:suppress_eval] text = unescape_interpolation(text).gsub(/(\\+)n/) do |s| escapes = $1.size next s if escapes % 2 == 0 ("\\" * (escapes - 1)) + "\n" end # We need to add a newline at the beginning to get the # filter lines to line up (since the Haml filter contains # a line that doesn't show up in the source, namely the # filter name). Then we need to escape the trailing # newline so that the whole filter block doesn't take up # too many. text = "\n" + text.sub(/\n"\Z/, "\\n\"") push_script < false find_and_preserve(#{filter.inspect}.render_with_options(#{text}, _hamlout.options)) RUBY return end rendered = Haml::Helpers::find_and_preserve(filter.render_with_options(text, compiler.options), compiler.options[:preserve]) if !options[:ugly] push_text(rendered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}")) else push_text(rendered.rstrip) end end end # This becomes a class method of modules that include {Base}. # It allows the module to specify one or more Ruby files # that Haml should try to require when compiling the filter. # # The first file specified is tried first, then the second, etc. # If none are found, the compilation throws an exception. # # For example: # # module Haml::Filters::Markdown # lazy_require 'rdiscount', 'peg_markdown', 'maruku', 'bluecloth' # # ... # end # # @param reqs [Array] The requires to run def lazy_require(*reqs) @lazy_requires = reqs end private def resolve_lazy_requires return unless @lazy_requires @lazy_requires[0...-1].each do |req| begin @required = req require @required return rescue LoadError; end # RCov doesn't see this, but it is run end begin @required = @lazy_requires[-1] require @required rescue LoadError => e classname = self.name.match(/\w+$/)[0] if @lazy_requires.size == 1 raise Error.new("Can't run #{classname} filter; required file '#{@lazy_requires.first}' not found") else raise Error.new("Can't run #{classname} filter; required #{@lazy_requires.map { |r| "'#{r}'" }.join(' or ')}, but none were found") end end end end end end begin require 'rubygems' rescue LoadError; end module Haml module Filters # Does not parse the filtered text. # This is useful for large blocks of text without HTML tags, # when you don't want lines starting with `.` or `-` # to be parsed. module Plain include Base # @see Base#render def render(text); text; end end # Surrounds the filtered text with ` END end end # Surrounds the filtered text with ` END end end # Surrounds the filtered text with CDATA tags. module Cdata include Base # @see Base#render def render(text) "" end end # Works the same as {Plain}, but HTML-escapes the text # before placing it in the document. module Escaped include Base # @see Base#render def render(text) Haml::Helpers.html_escape text end end # Parses the filtered text with the normal Ruby interpreter. # All output sent to `$stdout`, such as with `puts`, # is output into the Haml document. # Not available if the {file:HAML_REFERENCE.md#suppress_eval-option `:suppress_eval`} option is set to true. # The Ruby code is evaluated in the same context as the Haml template. module Ruby include Base lazy_require 'stringio' # @see Base#compile def compile(compiler, text) return if compiler.options[:suppress_eval] compiler.instance_eval do push_silent <<-FIRST.gsub("\n", ';') + text + <<-LAST.gsub("\n", ';') _haml_old_stdout = $stdout $stdout = StringIO.new(_hamlout.buffer, 'a') FIRST _haml_old_stdout, $stdout = $stdout, _haml_old_stdout _haml_old_stdout.close LAST end end end # Inserts the filtered text into the template with whitespace preserved. # `preserve`d blocks of text aren't indented, # and newlines are replaced with the HTML escape code for newlines, # to preserve nice-looking output. # # @see Haml::Helpers#preserve module Preserve include Base # @see Base#render def render(text) Haml::Helpers.preserve text end end # Parses the filtered text with {Sass} to produce CSS output. module Sass include Base lazy_require 'sass/plugin' # @see Base#render def render(text) ::Sass::Engine.new(text, ::Sass::Plugin.engine_options).render end end # Parses the filtered text with ERB. # Not available if the {file:HAML_REFERENCE.md#suppress_eval-option `:suppress_eval`} option is set to true. # Embedded Ruby code is evaluated in the same context as the Haml template. module ERB include Base lazy_require 'erb' # @see Base#compile def compile(compiler, text) return if compiler.options[:suppress_eval] src = ::ERB.new(text).src.sub(/^#coding:.*?\n/, ''). sub(/^_erbout = '';/, "") compiler.send(:push_silent, src) end end # Parses the filtered text with [Textile](http://www.textism.com/tools/textile). # Only works if [RedCloth](http://redcloth.org) is installed. module Textile include Base lazy_require 'redcloth' # @see Base#render def render(text) ::RedCloth.new(text).to_html(:textile) end end # An alias for the Textile filter, # since the only available Textile parser is RedCloth. # @api public RedCloth = Textile Filters.defined['redcloth'] = RedCloth # Parses the filtered text with [Markdown](http://daringfireball.net/projects/markdown). # Only works if [RDiscount](http://github.com/rtomayko/rdiscount), # [RPeg-Markdown](http://github.com/rtomayko/rpeg-markdown), # [Maruku](http://maruku.rubyforge.org), # or [BlueCloth](www.deveiate.org/projects/BlueCloth) are installed. module Markdown include Base lazy_require 'rdiscount', 'peg_markdown', 'maruku', 'bluecloth' # @see Base#render def render(text) engine = case @required when 'rdiscount' ::RDiscount when 'peg_markdown' ::PEGMarkdown when 'maruku' ::Maruku when 'bluecloth' ::BlueCloth end engine.new(text).to_html end end # Parses the filtered text with [Maruku](http://maruku.rubyforge.org), # which has some non-standard extensions to Markdown. module Maruku include Base lazy_require 'maruku' # @see Base#render def render(text) ::Maruku.new(text).to_html end end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/html/0000775000175000017500000000000012414640747030071 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/html/erb.rb0000664000175000017500000001212612414640747031170 0ustar ebourgebourgrequire 'cgi' require 'erubis' require 'ruby_parser' module Haml class HTML # A class for converting ERB code into a format that's easier # for the {Haml::HTML} Hpricot-based parser to understand. # # Uses [Erubis](http://www.kuwata-lab.com/erubis)'s extensible parsing powers # to parse the ERB in a reliable way, # and [ruby_parser](http://parsetree.rubyforge.org/)'s Ruby knowledge # to figure out whether a given chunk of Ruby code starts a block or not. # # The ERB tags are converted to HTML tags in the following way. # `<% ... %>` is converted into ` ... `. # `<%= ... %>` is converted into ` ... `. # Finally, if either of these opens a Ruby block, # ` ... ` will wrap the entire contents of the block - # that is, everything that should be indented beneath the previous silent or loud tag. class ERB < Erubis::Basic::Engine # Compiles an ERB template into a HTML document containing `haml:` tags. # # @param template [String] The ERB template # @return [String] The output document # @see Haml::HTML::ERB def self.compile(template) new(template).src end # `html2haml` doesn't support HTML-escaped expressions. def escaped_expr(code) raise Haml::Error.new("html2haml doesn't support escaped expressions.") end # The ERB-to-Hamlized-HTML conversion has no preamble. def add_preamble(src); end # The ERB-to-Hamlized-HTML conversion has no postamble. def add_postamble(src); end # Concatenates the text onto the source buffer. # # @param src [String] The source buffer # @param text [String] The raw text to add to the buffer def add_text(src, text) src << text end # Concatenates a silent Ruby statement onto the source buffer. # This uses the `` tag, # and may close and/or open a Ruby block with the `` tag. # # In particular, a block is closed if this statement is some form of `end`, # opened if it's a block opener like `do`, `if`, or `begin`, # and both closed and opened if it's a mid-block keyword # like `else` or `when`. # # @param src [String] The source buffer # @param code [String] The Ruby statement to add to the buffer def add_stmt(src, code) src << '' if block_closer?(code) || mid_block?(code) src << '' << h(code) << '' unless code.strip == "end" src << '' if block_opener?(code) || mid_block?(code) end # Concatenates a Ruby expression that's printed to the document # onto the source buffer. # This uses the `` tag, # and may open a Ruby block with the `` tag. # An expression never closes a block. # # @param src [String] The source buffer # @param code [String] The Ruby expression to add to the buffer def add_expr_literal(src, code) src << '' << h(code) << '' src << '' if block_opener?(code) end # `html2haml` doesn't support debugging expressions. def add_expr_debug(src, code) raise Haml::Error.new("html2haml doesn't support debugging expressions.") end private # HTML-escaped some text (in practice, always Ruby code). # A utility method. # # @param text [String] The text to escape # @return [String] The escaped text def h(text) CGI.escapeHTML(text) end # Returns whether the code is valid Ruby code on its own. # # @param code [String] Ruby code to check # @return [Boolean] def valid_ruby?(code) RubyParser.new.parse(code) rescue Racc::ParseError => e false end # Checks if a string of Ruby code opens a block. # This could either be something like `foo do |a|` # or a keyword that requires a matching `end` # like `if`, `begin`, or `case`. # # @param code [String] Ruby code to check # @return [Boolean] def block_opener?(code) valid_ruby?(code + "\nend") || valid_ruby?(code + "\nwhen foo\nend") end # Checks if a string of Ruby code closes a block. # This is always `end` followed optionally by some method calls. # # @param code [String] Ruby code to check # @return [Boolean] def block_closer?(code) valid_ruby?("begin\n" + code) end # Checks if a string of Ruby code comes in the middle of a block. # This could be a keyword like `else`, `rescue`, or `when`, # or even `end` with a method call that takes a block. # # @param code [String] Ruby code to check # @return [Boolean] def mid_block?(code) return if valid_ruby?(code) valid_ruby?("if foo\n#{code}\nend") || # else, elsif valid_ruby?("begin\n#{code}\nend") || # rescue, ensure valid_ruby?("case foo\n#{code}\nend") # when end end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/html.rb0000664000175000017500000003153612414640747030426 0ustar ebourgebourgrequire File.dirname(__FILE__) + '/../haml' require 'haml/engine' require 'rubygems' require 'cgi' require 'hpricot' # Haml monkeypatches various Hpricot classes # to add methods for conversion to Haml. # @private module Hpricot # @see Hpricot module Node # Whether this node has already been converted to Haml. # Only used for text nodes and elements. # # @return [Boolean] attr_accessor :converted_to_haml # Returns the Haml representation of the given node. # # @param tabs [Fixnum] The indentation level of the resulting Haml. # @option options (see Haml::HTML#initialize) def to_haml(tabs, options) return "" if converted_to_haml || to_s.strip.empty? text = uninterp(self.to_s) node = next_node while node.is_a?(::Hpricot::Elem) && node.name == "haml:loud" node.converted_to_haml = true text << '#{' << CGI.unescapeHTML(node.inner_text).gsub(/\n\s*/, ' ').strip << '}' if node.next_node.is_a?(::Hpricot::Text) node = node.next_node text << uninterp(node.to_s) node.converted_to_haml = true end node = node.next_node end return parse_text_with_interpolation(text, tabs) end private def erb_to_interpolation(text, options) return text unless options[:erb] text = CGI.escapeHTML(uninterp(text)) %w[ ].each {|str| text.gsub!(CGI.escapeHTML(str), str)} ::Hpricot::XML(text).children.inject("") do |str, elem| if elem.is_a?(::Hpricot::Text) str + CGI.unescapeHTML(elem.to_s) else # element str + '#{' + CGI.unescapeHTML(elem.innerText.strip) + '}' end end end def tabulate(tabs) ' ' * tabs end def uninterp(text) text.gsub('#{', '\#{') #' end def attr_hash attributes.to_hash end def parse_text(text, tabs) parse_text_with_interpolation(uninterp(text), tabs) end def parse_text_with_interpolation(text, tabs) text.strip! return "" if text.empty? text.split("\n").map do |line| line.strip! "#{tabulate(tabs)}#{'\\' if Haml::Engine::SPECIAL_CHARACTERS.include?(line[0])}#{line}\n" end.join end end end # @private HAML_TAGS = %w[haml:block haml:loud haml:silent] HAML_TAGS.each do |t| Hpricot::ElementContent[t] = {} Hpricot::ElementContent.keys.each do |key| Hpricot::ElementContent[t][key.hash] = true end end Hpricot::ElementContent.keys.each do |k| HAML_TAGS.each do |el| val = Hpricot::ElementContent[k] val[el.hash] = true if val.is_a?(Hash) end end module Haml # Converts HTML documents into Haml templates. # Depends on [Hpricot](http://github.com/whymirror/hpricot) for HTML parsing. # If ERB conversion is being used, also depends on # [Erubis](http://www.kuwata-lab.com/erubis) to parse the ERB # and [ruby_parser](http://parsetree.rubyforge.org/) to parse the Ruby code. # # Example usage: # # Haml::HTML.new("Blat").render # #=> "%a{:href => 'http://google.com'} Blat" class HTML # @param template [String, Hpricot::Node] The HTML template to convert # @option options :erb [Boolean] (false) Whether or not to parse # ERB's `<%= %>` and `<% %>` into Haml's `=` and `-` # @option options :xhtml [Boolean] (false) Whether or not to parse # the HTML strictly as XHTML def initialize(template, options = {}) @options = options if template.is_a? Hpricot::Node @template = template else if template.is_a? IO template = template.read end template = Haml::Util.check_encoding(template) {|msg, line| raise Haml::Error.new(msg, line)} if @options[:erb] require 'haml/html/erb' template = ERB.compile(template) end method = @options[:xhtml] ? Hpricot.method(:XML) : method(:Hpricot) @template = method.call(template.gsub('&', '&')) end end # Processes the document and returns the result as a string # containing the Haml template. def render @template.to_haml(0, @options) end alias_method :to_haml, :render TEXT_REGEXP = /^(\s*).*$/ # @see Hpricot # @private class ::Hpricot::Doc # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) (children || []).inject('') {|s, c| s << c.to_haml(0, options)} end end # @see Hpricot # @private class ::Hpricot::XMLDecl # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) "#{tabulate(tabs)}!!! XML\n" end end # @see Hpricot # @private class ::Hpricot::CData # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) content = parse_text_with_interpolation( erb_to_interpolation(self.content, options), tabs + 1) "#{tabulate(tabs)}:cdata\n#{content}" end end # @see Hpricot # @private class ::Hpricot::DocType # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) attrs = public_id.nil? ? ["", "", ""] : public_id.scan(/DTD\s+([^\s]+)\s*([^\s]*)\s*([^\s]*)\s*\/\//)[0] raise Haml::SyntaxError.new("Invalid doctype") if attrs == nil type, version, strictness = attrs.map { |a| a.downcase } if type == "html" version = "" strictness = "strict" if strictness == "" end if version == "1.0" || version.empty? version = nil end if strictness == 'transitional' || strictness.empty? strictness = nil end version = " #{version.capitalize}" if version strictness = " #{strictness.capitalize}" if strictness "#{tabulate(tabs)}!!!#{version}#{strictness}\n" end end # @see Hpricot # @private class ::Hpricot::Comment # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) content = self.content if content =~ /\A(\[[^\]]+\])>(.*) 1 # Multiline script block # Normalize the indentation so that the last line is the base indent_str = lines.last[/^[ \t]*/] indent_re = /^[ \t]{0,#{indent_str.count(" ") + 8 * indent_str.count("\t")}}/ lines.map! {|s| s.gsub!(indent_re, '')} # Add an extra " " to make it indented relative to "= " lines[1..-1].each {|s| s.gsub!(/^/, " ")} # Add | at the end, properly aligned length = lines.map {|s| s.size}.max + 1 lines.map! {|s| "%#{-length}s|" % s} if next_sibling && next_sibling.is_a?(Hpricot::Elem) && next_sibling.name == "haml:loud" && next_sibling.inner_text.split("\n").reject {|s| s.strip.empty?}.size > 1 lines << "-#" end end return lines.map {|s| output + s + "\n"}.join when "silent" return CGI.unescapeHTML(inner_text).split("\n").map do |line| next "" if line.strip.empty? "#{output}- #{line.strip}\n" end.join when "block" return render_children("", tabs, options) end end if self.next && self.next.text? && self.next.content =~ /\A[^\s]/ if self.previous.nil? || self.previous.text? && (self.previous.content =~ /[^\s]\Z/ || self.previous.content =~ /\A\s*\Z/ && self.previous.previous.nil?) nuke_outer_whitespace = true else output << "= succeed #{self.next.content.slice!(/\A[^\s]+/).dump} do\n" tabs += 1 output << tabulate(tabs) end end output << "%#{name}" unless name == 'div' && (static_id?(options) || static_classname?(options) && attr_hash['class'].split(' ').any?(&method(:haml_css_attr?))) if attr_hash if static_id?(options) output << "##{attr_hash['id']}" remove_attribute('id') end if static_classname?(options) leftover = attr_hash['class'].split(' ').reject do |c| next unless haml_css_attr?(c) output << ".#{c}" end remove_attribute('class') set_attribute('class', leftover.join(' ')) unless leftover.empty? end output << haml_attributes(options) if attr_hash.length > 0 end output << ">" if nuke_outer_whitespace output << "/" if empty? && !etag if children && children.size == 1 child = children.first if child.is_a?(::Hpricot::Text) if !child.to_s.include?("\n") text = child.to_haml(tabs + 1, options) return output + " " + text.lstrip.gsub(/^\\/, '') unless text.chomp.include?("\n") return output + "\n" + text elsif ["pre", "textarea"].include?(name) || (name == "code" && parent.is_a?(::Hpricot::Elem) && parent.name == "pre") return output + "\n#{tabulate(tabs + 1)}:preserve\n" + innerText.gsub(/^/, tabulate(tabs + 2)) end elsif child.is_a?(::Hpricot::Elem) && child.name == "haml:loud" return output + child.to_haml(tabs + 1, options).lstrip end end render_children(output + "\n", tabs, options) end private def render_children(so_far, tabs, options) (self.children || []).inject(so_far) do |output, child| output + child.to_haml(tabs + 1, options) end end def dynamic_attributes @dynamic_attributes ||= begin Haml::Util.map_hash(attr_hash) do |name, value| next if value.empty? full_match = nil ruby_value = value.gsub(%r{\s*(.+?)\s*}) do full_match = $`.empty? && $'.empty? CGI.unescapeHTML(full_match ? $1: "\#{#{$1}}") end next if ruby_value == value [name, full_match ? ruby_value : %("#{ruby_value}")] end end end def to_haml_filter(filter, tabs, options) content = if children.first.is_a?(::Hpricot::CData) children.first.content else CGI.unescapeHTML(self.innerText) end content = erb_to_interpolation(content, options) content.gsub!(/\A\s*\n(\s*)/, '\1') original_indent = content[/\A(\s*)/, 1] if content.split("\n").all? {|l| l.strip.empty? || l =~ /^#{original_indent}/} content.gsub!(/^#{original_indent}/, tabulate(tabs + 1)) end "#{tabulate(tabs)}:#{filter}\n#{content}" end def static_attribute?(name, options) attr_hash[name] && !dynamic_attribute?(name, options) end def dynamic_attribute?(name, options) options[:erb] and dynamic_attributes.key?(name) end def static_id?(options) static_attribute?('id', options) && haml_css_attr?(attr_hash['id']) end def static_classname?(options) static_attribute?('class', options) end def haml_css_attr?(attr) attr =~ /^[-:\w]+$/ end # Returns a string representation of an attributes hash # that's prettier than that produced by Hash#inspect def haml_attributes(options) attrs = attr_hash.sort.map do |name, value| value = dynamic_attribute?(name, options) ? dynamic_attributes[name] : value.inspect name = name.index(/\W/) ? name.inspect : ":#{name}" "#{name} => #{value}" end "{#{attrs.join(', ')}}" end end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/template.rb0000664000175000017500000000713512414640747031273 0ustar ebourgebourgrequire 'haml/template/options' require 'haml/engine' require 'haml/helpers/action_view_mods' require 'haml/helpers/action_view_extensions' if defined?(ActionPack::VERSION::STRING) && ActionPack::VERSION::STRING == "2.3.6" raise "Haml does not support Rails 2.3.6. Please upgrade to 2.3.7 or later." end module Haml # The class that keeps track of the global options for Haml within Rails. module Template # Enables integration with the Rails 2.2.5+ XSS protection, # if it's available and enabled. # # @return [Boolean] Whether the XSS integration was enabled. def try_enabling_xss_integration return false unless (ActionView::Base.respond_to?(:xss_safe?) && ActionView::Base.xss_safe?) || # We check for ActiveSupport#on_load here because if we're loading Haml that way, it means: # A) we're in Rails 3 so XSS support is always on, and # B) we might be in Rails 3 beta 3 where the load order is broken and xss_safe? is undefined (defined?(ActiveSupport) && Haml::Util.has?(:public_method, ActiveSupport, :on_load)) Haml::Template.options[:escape_html] = true Haml::Util.module_eval {def rails_xss_safe?; true; end} require 'haml/helpers/xss_mods' Haml::Helpers.send(:include, Haml::Helpers::XssMods) Haml::Compiler.module_eval do def precompiled_method_return_value_with_haml_xss "::Haml::Util.html_safe(#{precompiled_method_return_value_without_haml_xss})" end alias_method :precompiled_method_return_value_without_haml_xss, :precompiled_method_return_value alias_method :precompiled_method_return_value, :precompiled_method_return_value_with_haml_xss end true end end end unless Haml::Util.rails_env == "development" Haml::Template.options[:ugly] ||= true end if Haml::Util.ap_geq_3? Haml::Template.options[:format] ||= :html5 end # Decide how we want to load Haml into Rails. # Patching was necessary for versions <= 2.0.1, # but we can make it a normal handler for higher versions. if defined?(ActionView::TemplateHandler) || (defined?(ActionView::Template) && defined?(ActionView::Template::Handler)) require 'haml/template/plugin' else require 'haml/template/patch' end # Enable XSS integration. Use Rails' after_initialize method # so that integration will be checked after the rails_xss plugin is loaded # (for Rails 2.3.* where it's not enabled by default). # # If we're running under Rails 3, though, we don't want to use after_intialize, # since Haml loading has already been deferred via ActiveSupport.on_load. if defined?(Rails.configuration.after_initialize) && !(defined?(ActiveSupport) && Haml::Util.has?(:public_method, ActiveSupport, :on_load)) Rails.configuration.after_initialize {Haml::Template.try_enabling_xss_integration} else Haml::Template.try_enabling_xss_integration end if Haml::Util.rails_root # Update init.rb to the current version # if it's out of date. # # We can probably remove this as of v1.9, # because the new init file is sufficiently flexible # to not need updating. rails_init_file = File.join(Haml::Util.rails_root, 'vendor', 'plugins', 'haml', 'init.rb') haml_init_file = Haml::Util.scope('init.rb') begin if File.exists?(rails_init_file) require 'fileutils' FileUtils.cp(haml_init_file, rails_init_file) unless FileUtils.cmp(rails_init_file, haml_init_file) end rescue SystemCallError Haml::Util.haml_warn < Object}] attr_accessor :options end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/template/patch.rb0000664000175000017500000000467712414640747032402 0ustar ebourgebourg# This file makes Haml work with Rails # by monkeypatching the core template-compilation methods. # This is necessary for versions <= 2.0.1 because the template handler API # wasn't sufficiently powerful to deal with caching and so forth. # This module refers to the ActionView module that's part of Ruby on Rails. # Haml can be used as an alternate templating engine for it, # and includes several modifications to make it more Haml-friendly. # The documentation can be found # here[http://rubyonrails.org/api/classes/ActionView/Base.html]. module ActionView class Base def delegate_template_exists_with_haml(template_path) template_exists?(template_path, :haml) && [:haml] end alias_method :delegate_template_exists_without_haml, :delegate_template_exists? alias_method :delegate_template_exists?, :delegate_template_exists_with_haml def compile_template_with_haml(extension, template, file_name, local_assigns) return compile_haml(template, file_name, local_assigns) if extension.to_s == "haml" compile_template_without_haml(extension, template, file_name, local_assigns) end alias_method :compile_template_without_haml, :compile_template alias_method :compile_template, :compile_template_with_haml def compile_haml(template, file_name, local_assigns) render_symbol = assign_method_name(:haml, template, file_name) locals = local_assigns.keys @@template_args[render_symbol] ||= {} locals_keys = @@template_args[render_symbol].keys | locals @@template_args[render_symbol] = Haml::Util.to_hash(locals_keys.map {|k| [k, true]}) options = Haml::Template.options.dup options[:filename] = file_name || 'compiled-template' begin Haml::Engine.new(template, options).def_method(CompiledTemplates, render_symbol, *locals_keys) rescue Exception => e if logger logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}" logger.debug "Backtrace: #{e.backtrace.join("\n")}" end base_path = if defined?(extract_base_path_from) # Rails 2.0.x extract_base_path_from(file_name) || view_paths.first else # Rails <=1.2.6 @base_path end raise ActionView::TemplateError.new(base_path, file_name || template, @assigns, template, e) end @@compile_time[render_symbol] = Time.now end end end ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/template/plugin.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/haml/template/plugin.r0000664000175000017500000001170712414640747032427 0ustar ebourgebourg# This file makes Haml work with Rails # using the > 2.0.1 template handler API. module Haml # In Rails 3.1+, template handlers don't inherit from anything. In <= 3.0, they do. # To avoid messy logic figuring this out, we just inherit from whatever the ERB handler does. class Plugin < Haml::Util.av_template_class(:Handlers)::ERB.superclass if ((defined?(ActionView::TemplateHandlers) && defined?(ActionView::TemplateHandlers::Compilable)) || (defined?(ActionView::Template) && defined?(ActionView::Template::Handlers) && defined?(ActionView::Template::Handlers::Compilable))) && # In Rails 3.1+, we don't need to include Compilable. Haml::Util.av_template_class(:Handlers)::ERB.include?( Haml::Util.av_template_class(:Handlers)::Compilable) include Haml::Util.av_template_class(:Handlers)::Compilable end def handles_encoding?; true; end def compile(template) options = Haml::Template.options.dup # template is a template object in Rails >=2.1.0, # a source string previously if template.respond_to? :source # Template has a generic identifier in Rails >=3.0.0 options[:filename] = template.respond_to?(:identifier) ? template.identifier : template.filename source = template.source else source = template end Haml::Engine.new(source, options).send(:precompiled_with_ambles, []) end # In Rails 3.1+, #call takes the place of #compile def self.call(template) new.compile(template) end def cache_fragment(block, name = {}, options = nil) @view.fragment_for(block, name, options) do eval("_hamlout.buffer", block.binding) end end end # Rails 3.0 prints a deprecation warning when block helpers # return strings that go unused. # We want to print the same deprecation warning, # so we have to compile in a method call to check for it. # # I don't like having this in the compilation pipeline, # and I'd like to get rid of it once Rails 3.1 is well-established. if defined?(ActionView::OutputBuffer) && Haml::Util.has?(:instance_method, ActionView::OutputBuffer, :append_if_string=) module Compiler def compile_silent_script_with_haml_block_deprecation(&block) unless block && !@node.value[:keyword] && @node.value[:text] =~ ActionView::Template::Handlers::Erubis::BLOCK_EXPR return compile_silent_script_without_haml_block_deprecation(&block) end @node.value[:text] = "_hamlout.append_if_string= #{@node.value[:text]}" compile_silent_script_without_haml_block_deprecation(&block) end alias_method :compile_silent_script_without_haml_block_deprecation, :compile_silent_script alias_method :compile_silent_script, :compile_silent_script_with_haml_block_deprecation end class Buffer def append_if_string=(value) if value.is_a?(String) && !value.is_a?(ActionView::NonConcattingString) ActiveSupport::Deprecation.warn("- style block helpers are deprecated. Please use =", caller) buffer << value end end end end end if defined? ActionView::Template and ActionView::Template.respond_to? :register_template_handler ActionView::Template else ActionView::Base end.register_template_handler(:haml, Haml::Plugin) # In Rails 2.0.2, ActionView::TemplateError took arguments # that we can't fill in from the Haml::Plugin context. # Thus, we've got to monkeypatch ActionView::Base to catch the error. if defined?(ActionView::TemplateError) && ActionView::TemplateError.instance_method(:initialize).arity == 5 class ActionView::Base def compile_template(handler, template, file_name, local_assigns) render_symbol = assign_method_name(handler, template, file_name) # Move begin up two lines so it captures compilation exceptions. begin render_source = create_template_source(handler, template, render_symbol, local_assigns.keys) line_offset = @@template_args[render_symbol].size + handler.line_offset file_name = 'compiled-template' if file_name.blank? CompiledTemplates.module_eval(render_source, file_name, -line_offset) rescue Exception => e # errors from template code if logger logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}" logger.debug "Function body: #{render_source}" logger.debug "Backtrace: #{e.backtrace.join("\n")}" end # There's no way to tell Haml about the filename, # so we've got to insert it ourselves. e.backtrace[0].gsub!('(haml)', file_name) if e.is_a?(Haml::Error) raise ActionView::TemplateError.new(extract_base_path_from(file_name) || view_paths.first, file_name || template, @assigns, template, e) end @@compile_time[render_symbol] = Time.now # logger.debug "Compiled template #{file_name || template}\n ==> #{render_symbol}" if logger end end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/sass/0000775000175000017500000000000012414640747027155 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/lib/sass/rails2_shim.rb0000664000175000017500000000032312414640747031714 0ustar ebourgebourgHaml::Util.try_sass Haml::Util.haml_warn(< e # gems:install may be run to install Haml with the skeleton plugin # but not the gem itself installed. # Don't die if this is the case. raise e unless defined?(Rake) && (Rake.application.top_level_tasks.include?('gems') || Rake.application.top_level_tasks.include?('gems:install')) end end # Load Sass. # Sass may be undefined if we're running gems:install. require 'sass/plugin' if defined?(Sass) stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/rails/0000775000175000017500000000000012414640747031016 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/rails/init.rb0000664000175000017500000000007712414640747032312 0ustar ebourgebourgKernel.load File.join(File.dirname(__FILE__), '..', 'init.rb') stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/bin/0000775000175000017500000000000012414640747030454 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/bin/scss0000775000175000017500000000025012414640747031352 0ustar ebourgebourg#!/usr/bin/env ruby # The command line Sass parser. require File.dirname(__FILE__) + '/../lib/sass' require 'sass/exec' opts = Sass::Exec::Scss.new(ARGV) opts.parse! ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/bin/sass-convertstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/bin/sass-conve0000775000175000017500000000021712414640747032463 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../lib/sass' require 'sass/exec' opts = Sass::Exec::SassConvert.new(ARGV) opts.parse! stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/bin/sass0000775000175000017500000000025012414640747031350 0ustar ebourgebourg#!/usr/bin/env ruby # The command line Sass parser. require File.dirname(__FILE__) + '/../lib/sass' require 'sass/exec' opts = Sass::Exec::Sass.new(ARGV) opts.parse! stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/TODO0000664000175000017500000000267712414640747030410 0ustar ebourgebourg# -*- mode: org -*- #+STARTUP: nofold * Documentation Redo tutorial? Syntax highlighting? * Code Keep track of error offsets everywhere Use this to show error location in messages Just clean up SassScript syntax errors in general Lexer errors in particular are icky See in particular error changes made in c07b5c8 ** Sass Benchmark the effects of storing the raw template in sassc If it's expensive, overload RootNode dumping/loading to dup and set @template to nil Then fall back on reading from actual file Make Rack middleware the default for Rails and Merb versions that support it CSS superset Classes are mixins Can refer to specific property values? Syntax? Pull in Compass watcher stuff Internationalization Particularly word constituents in Regexps Optimization http://csstidy.sourceforge.net/ http://developer.yahoo.com/yui/compressor/ Also comma-folding identical rules where possible Multiple levels 0: No optimization 1: Nothing that changes doc structure No comma-folding 2: Anything that keeps functionality identical to O2 (default) 3: Assume order of rules doesn't matter Comma-fold even if there are intervening rules that might interfere CSS3 Add (optional) support for http://www.w3.org/TR/css3-values/#calc Cross-unit arithmetic should compile into this Should we use "mod" in Sass for consistency? stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/README.md0000664000175000017500000001505012414640747031164 0ustar ebourgebourg# Sass **Sass makes CSS fun again**. Sass is an extension of CSS3, adding nested rules, variables, mixins, selector inheritance, and more. It's translated to well-formatted, standard CSS using the command line tool or a web-framework plugin. Sass has two syntaxes. The new main syntax (as of Sass 3) is known as "SCSS" (for "Sassy CSS"), and is a superset of CSS3's syntax. This means that every valid CSS3 stylesheet is valid SCSS as well. SCSS files use the extension `.scss`. The second, older syntax is known as the indented syntax (or just "Sass"). Inspired by Haml's terseness, it's intended for people who prefer conciseness over similarity to CSS. Instead of brackets and semicolons, it uses the indentation of lines to specify blocks. Although no longer the primary syntax, the indented syntax will continue to be supported. Files in the indented syntax use the extension `.sass`. ## Using Sass can be used from the command line or as part of a web framework. The first step is to install the gem: gem install sass After you convert some CSS to Sass, you can run sass style.scss to compile it back to CSS. For more information on these commands, check out sass --help To install Sass in Rails 2, just add `config.gem "sass"` to `config/environment.rb`. In Rails 3, add `gem "sass"` to your Gemfile instead. `.sass` or `.scss` files should be placed in `public/stylesheets/sass`, where they'll be automatically compiled to corresponding CSS files in `public/stylesheets` when needed (the Sass template directory is customizable... see [the Sass reference](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#template_location-option) for details). Sass can also be used with any Rack-enabled web framework. To do so, just add require 'sass/plugin/rack' use Sass::Plugin::Rack to `config.ru`. Then any Sass files in `public/stylesheets/sass` will be compiled CSS files in `public/stylesheets` on every request. To use Sass programatically, check out the [YARD documentation](http://sass-lang.com/docs/yardoc/). ## Formatting Sass is an extension of CSS that adds power and elegance to the basic language. It allows you to use [variables][vars], [nested rules][nested], [mixins][mixins], [inline imports][imports], and more, all with a fully CSS-compatible syntax. Sass helps keep large stylesheets well-organized, and get small stylesheets up and running quickly, particularly with the help of [the Compass style library](http://compass-style.org). [vars]: http://beta.sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#variables_ [nested]: http://beta.sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#nested_rules_ [mixins]: http://beta.sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#mixins [imports]: http://beta.sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#import Sass has two syntaxes. The one presented here, known as "SCSS" (for "Sassy CSS"), is fully CSS-compatible. The other (older) syntax, known as the indented syntax or just "Sass", is whitespace-sensitive and indentation-based. For more information, see the [reference documentation][syntax]. [syntax]: http://beta.sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#syntax To run the following examples and see the CSS they produce, put them in a file called `test.scss` and run `sass test.scss`. ### Nesting Sass avoids repetition by nesting selectors within one another. The same thing works for properties. table.hl { margin: 2em 0; td.ln { text-align: right; } } li { font: { family: serif; weight: bold; size: 1.2em; } } ### Variables Use the same color all over the place? Need to do some math with height and width and text size? Sass supports variables, math operations, and many useful functions. $blue: #3bbfce; $margin: 16px; .content_navigation { border-color: $blue; color: darken($blue, 10%); } .border { padding: $margin / 2; margin: $margin / 2; border-color: $blue; } ### Mixins Even more powerful than variables, mixins allow you to re-use whole chunks of CSS, properties or selectors. You can even give them arguments. @mixin table-scaffolding { th { text-align: center; font-weight: bold; } td, th { padding: 2px; } } @mixin left($dist) { float: left; margin-left: $dist; } #data { @include left(10px); @include table-scaffolding; } A comprehensive list of features is available in the [Sass reference](http://beta.sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html). ## Executables The Sass gem includes several executables that are useful for dealing with Sass from the command line. ### `sass` The `sass` executable transforms a source Sass file into CSS. See `sass --help` for further information and options. ### `sass-convert` The `sass-convert` executable converts between CSS, Sass, and SCSS. When converting from CSS to Sass or SCSS, nesting is applied where appropriate. See `sass-convert --help` for further information and options. ## Authors Sass was envisioned by [Hampton Catlin](http://hamptoncatlin.com) (hcatlin). However, Hampton doesn't even know his way around the code anymore and now occasionally consults on the language issues. Hampton lives in Jacksonville, Florida and is the lead mobile developer for Wikimedia. [Nathan Weizenbaum](http://nex-3.com) is the primary developer and architect of Sass. His hard work has kept the project alive by endlessly answering forum posts, fixing bugs, refactoring, finding speed improvements, writing documentation, implementing new features, and getting Hampton coffee (a fitting task for a boy-genius). Nathan lives in Seattle, Washington and while not being a student at the University of Washington or working at an internship, he consults for Unspace Interactive. [Chris Eppstein](http://acts-as-architect.blogspot.com) is a core contributor to Sass and the creator of Compass, the first Sass-based framework. Chris focuses on making Sass more powerful, easy to use, and on ways to speed its adoption through the web development community. Chris lives in San Jose, California with his wife and daughter. He is the Software Architect for [Caring.com](http://caring.com), a website devoted to the 34 Million caregivers whose parents are sick or elderly, that uses Haml and Sass. If you use this software, you must pay Hampton a compliment. And buy Nathan some jelly beans. Maybe pet a kitten. Yeah. Pet that kitty. Beyond that, the implementation is licensed under the MIT License. Okay, fine, I guess that means compliments aren't __required__. stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/ext/0000775000175000017500000000000012414640747030504 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/ext/extconf.rb0000664000175000017500000000037012414640747032477 0ustar ebourgebourgroot = File.expand_path("../..", __FILE__) File.open(File.expand_path("lib/sass/root.rb", root), "w") do |f| f << <<-RUBY module Sass ROOT_DIR = #{root.inspect} end RUBY end File.open('Makefile', 'w') { |f| f.puts("install:\n\t$(exit 0)") } stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/0000775000175000017500000000000012414640747030643 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/0000775000175000017500000000000012414640747032267 5ustar ebourgebourg././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/fulldoc/stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/f0000775000175000017500000000000012414640747032435 5ustar ebourgebourg././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/fulldoc/html/stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/f0000775000175000017500000000000012414640747032435 5ustar ebourgebourg././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/fulldoc/html/css/stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/f0000775000175000017500000000000012414640747032435 5ustar ebourgebourg././@LongLink0000644000000000000000000000020000000000000011573 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/fulldoc/html/css/common.sassstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/f0000664000175000017500000000071412414640747032441 0ustar ebourgebourg.maruku_toc background: #ddd border: 1px solid #ccc margin-right: 2em float: left ul padding: 0 1em #frequently_asked_questions + & float: none margin: 0 2em #filecontents *:target, dt:target + dd background-color: #ccf border: 1px solid #88b dt font-weight: bold dd margin: left: 0 bottom: 0.7em padding-left: 3em dt:target border-bottom-style: none & + dd border-top-style: none ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/layout/stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/l0000775000175000017500000000000012414640747032443 5ustar ebourgebourg././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/layout/html/stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/l0000775000175000017500000000000012414640747032443 5ustar ebourgebourg././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/layout/html/footer.erbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/default/l0000664000175000017500000000075512414640747032454 0ustar ebourgebourg<%= superb :footer %> <% if ENV["ANALYTICS"] %> <% end %> ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/inherited_hash.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/inherited0000664000175000017500000000272312414640747032545 0ustar ebourgebourgclass InheritedHashHandler < YARD::Handlers::Ruby::Legacy::Base handles /\Ainherited_hash(\s|\()/ def process hash_name = tokval(statement.tokens[2]) name = statement.comments.first.strip type = statement.comments[1].strip o = register(MethodObject.new(namespace, hash_name, scope)) o.docstring = [ "Gets a #{name} from this {Environment} or one of its \\{#parent}s.", "@param name [String] The name of the #{name}", "@return [#{type}] The #{name} value", ] o.signature = true o.parameters = ["name"] o = register(MethodObject.new(namespace, "set_#{hash_name}", scope)) o.docstring = [ "Sets a #{name} in this {Environment} or one of its \\{#parent}s.", "If the #{name} is already defined in some environment,", "that one is set; otherwise, a new one is created in this environment.", "@param name [String] The name of the #{name}", "@param value [#{type}] The value of the #{name}", "@return [#{type}] `value`", ] o.signature = true o.parameters = ["name", "value"] o = register(MethodObject.new(namespace, "set_local_#{hash_name}", scope)) o.docstring = [ "Sets a #{name} in this {Environment}.", "Ignores any parent environments.", "@param name [String] The name of the #{name}", "@param value [#{type}] The value of the #{name}", "@return [#{type}] `value`", ] o.signature = true o.parameters = ["name", "value"] end end ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/callbacks.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/yard/callbacks0000664000175000017500000000146012414640747032506 0ustar ebourgebourgclass CallbacksHandler < YARD::Handlers::Ruby::Legacy::Base handles /\Adefine_callback(\s|\()/ def process callback_name = tokval(statement.tokens[2]) attr_index = statement.comments.each_with_index {|c, i| break i if c[0] == ?@} if attr_index.is_a?(Fixnum) docstring = statement.comments[0...attr_index] attrs = statement.comments[attr_index..-1] else docstring = statement.comments attrs = [] end yieldparams = "" attrs.reject! do |a| next unless a =~ /^@yield *(\[.*?\])/ yieldparams = $1 true end o = register(MethodObject.new(namespace, "on_#{callback_name}", scope)) o.docstring = docstring + [ "@return [void]", "@yield #{yieldparams} When the callback is run" ] + attrs o.signature = true end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/CONTRIBUTING0000664000175000017500000000020112414640747031527 0ustar ebourgebourgContributions are welcomed. Please see the following sites for guidelines: http://sass-lang.com/development.html#contributing stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/VERSION_NAME0000664000175000017500000000001512414640747031550 0ustar ebourgebourgBrainy Betty stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/0000775000175000017500000000000012414640747031236 5ustar ebourgebourgstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/FAQ.md0000664000175000017500000000260012414640747032165 0ustar ebourgebourg# Frequently Asked Questions * Table of contents {:toc} ## Can I use a variable from my controller in my Sass file? {#q-ruby-code} No. Sass files aren't views. They're compiled once into static CSS files, then left along until they're changed and need to be compiled again. Not only don't you want to be running a full request cycle every time someone requests a stylesheet, but it's not a great idea to put much logic in there anyway due to how browsers handle them. If you really need some sort of dynamic CSS, you can define your own {Sass::Script::Functions Sass functions} using Ruby that can access the database or other configuration. *Be aware when doing this that Sass files are by default only compiled once and then served statically.* If you really, really need to compile Sass on each request, first make sure you have adequate caching set up. Then you can use {Sass::Engine} to render the code, using the {file:SASS_REFERENCE.md#custom-option `:custom` option} to pass in data that {Sass::Script::Functions::EvaluationContext#options can be accessed} from your Sass functions. # You still haven't answered my question! Sorry! Try looking at the [Sass](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html) reference, If you can't find an answer there, feel free to ask in `#sass` on irc.freenode.net or send an email to the [mailing list](http://groups.google.com/group/sass-lang). ././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/SCSS_FOR_SASS_USERS.mdstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/SCSS_F0000664000175000017500000001026212414640747032202 0ustar ebourgebourg# Intro to SCSS for Sass Users Sass 3 introduces a new syntax known as SCSS which is fully compatible with the syntax of CSS3, while still supporting the full power of Sass. This means that every valid CSS3 stylesheet is a valid SCSS file with the same meaning. In addition, SCSS understands most CSS hacks and vendor-specific syntax, such as [IE's old `filter` syntax](http://msdn.microsoft.com/en-us/library/ms533754%28VS.85%29.aspx). Since SCSS is a CSS extension, everything that works in CSS works in SCSS. This means that for a Sass user to understand it, they need only understand how the Sass extensions work. Most of these, such as variables, parent references, and directives work the same; the only difference is that SCSS requires semicolons and brackets instead of newlines and indentation. For example, a simple rule in Sass: #sidebar width: 30% background-color: #faa could be converted to SCSS just by adding brackets and semicolons: #sidebar { width: 30%; background-color: #faa; } In addition, SCSS is completely whitespace-insensitive. That means the above could also be written as: #sidebar {width: 30%; background-color: #faa} There are some differences that are slightly more complicated. These are detailed below. Note, though, that SCSS uses all the {file:SASS_CHANGELOG.md#3-0-0-syntax-changes syntax changes in Sass 3}, so make sure you understand those before going forward. ## Nested Selectors To nest selectors, simply define a new ruleset inside an existing ruleset: #sidebar { a { text-decoration: none; } } Of course, white space is insignificant and the last trailing semicolon is optional so you can also do it like this: #sidebar { a { text-decoration: none } } ## Nested Properties To nest properties, simply create a new property set after an existing property's colon: #footer { border: { width: 1px; color: #ccc; style: solid; } } This compiles to: #footer { border-width: 1px; border-color: #cccccc; border-style: solid; } ## Mixins A mixin is declared with the `@mixin` directive: @mixin rounded($amount) { -moz-border-radius: $amount; -webkit-border-radius: $amount; border-radius: $amount; } A mixin is used with the `@include` directive: .box { border: 3px solid #777; @include rounded(0.5em); } This syntax is also available in the indented syntax, although the old `=` and `+` syntax still works. This is rather verbose compared to the `=` and `+` characters used in Sass syntax. This is because the SCSS format is designed for CSS compatibility rather than conciseness, and creating new syntax when the CSS directive syntax already exists adds new syntax needlessly and could create incompatibilities with future versions of CSS. ## Comments Like Sass, SCSS supports both comments that are preserved in the CSS output and comments that aren't. However, SCSS's comments are significantly more flexible. It supports standard multiline CSS comments with `/* */`, which are preserved where possible in the output. These comments can have whatever formatting you like; Sass will do its best to format them nicely. SCSS also uses `//` for comments that are thrown away, like Sass. Unlike Sass, though, `//` comments in SCSS may appear anywhere and last only until the end of the line. For example: /* This comment is * several lines long. * since it uses the CSS comment syntax, * it will appear in the CSS output. */ body { color: black; } // These comments are only one line long each. // They won't appear in the CSS output, // since they use the single-line comment syntax. a { color: green; } is compiled to: /* This comment is * several lines long. * since it uses the CSS comment syntax, * it will appear in the CSS output. */ body { color: black; } a { color: green; } ## `@import` The `@import` directive in SCSS functions just like that in Sass, except that it takes a quoted string to import. For example, this Sass: @import themes/dark @import font.sass would be this SCSS: @import "themes/dark"; @import "font.sass"; ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/SASS_CHANGELOG.mdstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/SASS_C0000664000175000017500000021350212414640747032177 0ustar ebourgebourg# Sass Changelog * Table of contents {:toc} ## 3.1.0 (Unreleased) * Add an {Sass::Script::Functions#invert `invert` function} that takes the inverse of colors. * A new sass function called `if` can be used to emit one of two values based on the truth value of the first argument. For example, `if(true, 1px, 2px)` returns `1px` and `if(false, 1px, 2px)` returns `2px`. * Compass users can now use the `--compass` flag to make the Compass libraries available for import. This will also load the Compass project configuration if run from the project root. * Many performance optimizations have been made by [thedarkone](http://github.com/thedarkone). * Allow selectors to contain extra commas to make them easier to modify. Extra commas will be removed when the selectors are converted to CSS. * `@import` may now be used within CSS or `@media` rules. The imported file will be treated as though it were nested within the rule. Files with mixins may not be imported in nested contexts. * If a comment starts with `!`, that comment will now be interpolated (`#{...}` will be replaced with the resulting value of the expression inside) and the comment will always be printed out in the generated CSS file -- even with compressed output. This is useful for adding copyright notices to your stylesheets. * A new executable named `scss` is now available. It is exactly like the `sass` executable except it defaults to assuming input is in the SCSS syntax. Both programs will use the source file's extension to determine the syntax where possible. ### Sass-based Functions While it has always been possible to add functions to Sass with Ruby, this release adds the ability to define new functions within Sass files directly. For example: $grid-width: 40px; $gutter-width: 10px; @function grid-width($n) { @return $n * $grid-width + ($n - 1) * $gutter-width; } #sidebar { width: grid-width(5); } Becomes: #sidebar { width: 240px; } ### Keyword Arguments Both mixins and Sass functions now support the ability to pass in keyword arguments. For example, with mixins: @mixin border-radius($value, $moz: true, $webkit: true, $css3: true) { @if $moz { -moz-border-radius: $value } @if $webkit { -webkit-border-radius: $value } @if $css3 { border-radius: $value } } @include border-radius(10px, $webkit: false); And with functions: p { color: hsl($hue: 180, $saturation: 78%, $lightness: 57%); } Keyword arguments are of the form `$name: value` and come after normal arguments. They can be used for either optional or required arguments. For mixins, the names are the same as the argument names for the mixins. For functions, the names are defined along with the functions. The argument names for the built-in functions are listed {Sass::Script::Functions in the function documentation}. Sass functions defined in Ruby can use the {Sass::Script::Functions.declare} method to declare the names of the arguments they take. #### New Keyword Functions The new keyword argument functionality enables new Sass color functions that use keywords to encompass a large amount of functionality in one function. * The {Sass::Script::Functions#adjust_color adjust-color} function works like the old `lighten`, `saturate`, and `adjust-hue` methods. It increases and/or decreases the values of a color's properties by fixed amounts. For example, `adjust-color($color, $lightness: 10%)` is the same as `lighten($color, 10%)`: it returns `$color` with its lightness increased by 10%. * The {Sass::Script::Functions#scale_color scale_color} function is similar to {Sass::Script::Functions#adjust adjust}, but instead of increasing and/or decreasing a color's properties by fixed amounts, it scales them fluidly by percentages. The closer the percentage is to 100% (or -100%), the closer the new property value will be to its maximum (or minimum). For example, `scale-color(hsl(120, 70, 80), $lightness: 50%)` will change the lightness from 80% to 90%, because 90% is halfway between 80% and 100%. Similarly, `scale-color(hsl(120, 70, 50), $lightness: 50%)` will change the lightness from 50% to 75%. * The {Sass::Script::Functions#change_color change-color} function simply changes a color's properties regardless of their old values. For example `change-color($color, $lightness: 10%)` returns `$color` with 10% lightness, and `change-color($color, $alpha: 0.7)` returns color with opacity 0.7. Each keyword function accepts `$hue`, `$saturation`, `$value`, `$red`, `$green`, `$blue`, and `$alpha` keywords, with the exception of `scale-color()` which doesn't accept `$hue`. These keywords modify the respective properties of the given color. Each keyword function can modify multiple properties at once. For example, `adjust-color($color, $lightness: 15%, $saturation: -10%)` both lightens and desaturates `$color`. HSL properties cannot be modified at the same time as RGB properties, though. ### Lists Lists are now a first-class data type in Sass, alongside strings, numbers, colors, and booleans. They can be assigned to variables, passed to mixins, and used in CSS declarations. Just like the other data types (except booleans), Sass lists look just like their CSS counterparts. They can be separated either by spaces (e.g. `1px 2px 0 10px`) or by commas (e.g. `Helvetica, Arial, sans-serif`). In addition, individual values count as single-item lists. Lists won't behave any differently in Sass 3.1 than they did in 3.0. However, you can now do more with them using the new {file:Sass/Script/Functions.html#list-functions list functions}: * The {Sass::Script::Functions#nth `nth($list, $n)` function} returns the nth item in a list. For example, `nth(1px 2px 10px, 2)` returns the second item, `2px`. Note that lists in Sass start at 1, not at 0 like they do in some other languages. * The {Sass::Script::Functions#join `join($list1, $list2)` function} joins together two lists into one. For example, `join(1px 2px, 10px 5px)` returns `1px 2px 10px 5px`. * The {Sass::Script::Functions#append `append($list, $val)` function} appends values to the end of a list. For example, `append(1px 2px, 10px)` returns `1px 2px 10px`. * The {Sass::Script::Functions#join `length($list)` function} returns the length of a list. For example, `length(1px 2px 10px 5px)` returns `4`. For more details about lists see {file:SASS_REFERENCE.md#lists the reference}. #### `@each` There's also a new directive that makes use of lists. The {file:SASS_REFERENCE.md#each-directive `@each` directive} assigns a variable to each item in a list in turn, like `@for` does for numbers. This is useful for writing a bunch of similar styles without having to go to the trouble of creating a mixin. For example: @each $animal in puma, sea-slug, egret, salamander { .#{$animal}-icon { background-image: url('/images/#{$animal}.png'); } } is compiled to: .puma-icon { background-image: url('/images/puma.png'); } .sea-slug-icon { background-image: url('/images/sea-slug.png'); } .egret-icon { background-image: url('/images/egret.png'); } .salamander-icon { background-image: url('/images/salamander.png'); } ### `@media` Bubbling Modern stylesheets often use `@media` rules to target styles at certain sorts of devices, screen resolutions, or even orientations. They're also useful for print and aural styling. Unfortunately, it's annoying and repetitive to break the flow of a stylesheet and add a `@media` rule containing selectors you've already written just to tweak the style a little. Thus, Sass 3.1 now allows you to nest `@media` rules within selectors. It will automatically bubble them up to the top level, putting all the selectors on the way inside the rule. For example: .sidebar { width: 300px; @media screen and (orientation: landscape) { width: 500px; } } is compiled to: .sidebar { width: 300px; } @media screen and (orientation: landscape) { .sidebar { width: 500px; } } You can also nest `@media` directives within one another. The queries will then be combined using the `and` operator. For example: @media screen { .sidebar { @media (orientation: landscape) { width: 500px; } } } is compiled to: @media screen and (orientation: landscape) { .sidebar { width: 500px; } } ### Nested `@import` The `@import` statement can now be nested within other structures such as CSS rules and `@media` rules. For example: @media print { @import "print"; } This imports `print.scss` and places all rules so imported within the `@media print` block. This makes it easier to create stylesheets for specific media or sections of the document and distributing those stylesheets across multiple files. ### Backwards Incompatibilities -- Must Read! * When `@import` is given a path without `.sass`, `.scss`, or `.css` extension, and no file exists at that path, it will now throw an error. The old behavior of becoming a plain-CSS `@import` was deprecated and has now been removed. * Get rid of the `--rails` flag for the `sass` executable. This flag hasn't been necessary since Rails 2.0. Existing Rails 2.0 installations will continue to work. * Removed deprecated support for ! prefixed variables. Use $ to prefix variables now. * Removed the deprecated css2sass executable. Use sass-convert now. * Removed support for the equals operator in variable assignment. Use : now. * Removed the sass2 mode from sass-convert. Users who have to migrate from sass2 should install Sass 3.0 and quiet all deprecation warnings before installing Sass 3.1. ### Sass Internals * It is now possible to define a custom importer that can be used to find imports using different import semantics than the default filesystem importer that Sass provides. For instance, you can use this to generate imports on the fly, look them up from a database, or implement different file naming conventions. See the {Sass::Importers::Base Importer Base class} for more information. * It is now possible to define a custom cache store to allow for efficient caching of Sass files using alternative cache stores like memcached in environments where a writable filesystem is not available or where the cache need to be shared across many servers for dynamically generated stylesheet environments. See the {Sass::CacheStores::Base CacheStore Base class} for more information. ## 3.0.26 (Unreleased) * Fix a performance bug in large SCSS stylesheets with many nested selectors. This should dramatically decrease compilation time of such stylesheets. * Upgrade the bundled FSSM to version 0.2.3. This means `sass --watch` will work out of the box with Rubinius. ## 3.0.25 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.25). * When displaying a Sass error in an imported stylesheet, use the imported stylesheet's contents rather than the top-level stylesheet. * Fix a bug that caused some lines with non-ASCII characters to be ignored in Ruby 1.8. * Fix a bug where boolean operators (`and`, `or`, and `not`) wouldn't work at the end of a line in a multiline SassScript expression. * When using `sass --update`, only update individual files when they've changed. ## 3.0.24 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.24). * Raise an error when `@else` appears without an `@if` in SCSS. * Fix some cases where `@if` rules were causing the line numbers in error reports to become incorrect. ## 3.0.23 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.23). * Fix the error message for unloadable modules when running the executables under Ruby 1.9.2. ### `@charset` Change The behavior of `@charset` has changed in version 3.0.23 in order to work around a bug in Safari, where `@charset` declarations placed anywhere other than the beginning of the document cause some CSS rules to be ignored. This change also makes `@charset`s in imported files behave in a more useful way. #### Ruby 1.9 When using Ruby 1.9, which keeps track of the character encoding of the Sass document internally, `@charset` directive in the Sass stylesheet and any stylesheets it imports are no longer directly output to the generated CSS. They're still used for determining the encoding of the input and output stylesheets, but they aren't rendered in the same way other directives are. Instead, Sass adds a single `@charset` directive at the beginning of the output stylesheet if necessary, whether or not the input stylesheet had a `@charset` directive. It will add this directive if and only if the output stylesheet contains non-ASCII characters. By default, the declared charset will be UTF-8, but if the Sass stylesheet declares a different charset then that will be used instead if possible. One important consequence of this scheme is that it's possible for a Sass file to import partials with different encodings (e.g. one encoded as UTF-8 and one as IBM866). The output will then be UTF-8, unless the importing stylesheet declares a different charset. #### Ruby 1.8 Ruby 1.8 doesn't have good support for encodings, so it uses a simpler but less accurate scheme for figuring out what `@charset` declaration to use for the output stylesheet. It just takes the first `@charset` declaration to appear in the stylesheet or any of its imports and moves it to the beginning of the document. This means that under Ruby 1.8 it's *not* safe to import files with different encodings. ## 3.0.22 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.22). * Remove `vendor/sass`, which snuck into the gem by mistake and was causing trouble for Heroku users (thanks to [Jacques Crocker](http://railsjedi.com/)). * `sass-convert` now understands better when it's acceptable to remove parentheses from expressions. ## 3.0.21 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.21). * Fix the permissions errors for good. * Fix more `#options` attribute errors. ## 3.0.20 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.20). * Fix some permissions errors. * Fix `#options` attribute errors when CSS functions were used with commas. ## 3.0.19 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.19). * Make the alpha value for `rgba` colors respect {Sass::Script::Number::PRECISION}. * Remove all newlines in selectors in `:compressed` mode. * Make color names case-insensitive. * Properly detect SCSS files when using `sass -c`. * Remove spaces after commas in `:compressed` mode. * Allow the `--unix-newlines` flag to work on Unix, where it's a no-op. ## 3.0.18 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.18). * Don't require `rake` in the gemspec, for bundler compatibility under JRuby. Thanks to [Gordon McCreight](http://www.gmccreight.com/blog). * Add a command-line option `--stop-on-error` that causes Sass to exit when a file fails to compile using `--watch` or `--update`. * Fix a bug in `haml_tag` that would allow duplicate attributes to be added and make `data-` attributes not work. * Get rid of the annoying RDoc errors on install. * Disambiguate references to the `Rails` module when `haml-rails` is installed. * Allow `@import` in SCSS to import multiple files in the same `@import` rule. ## 3.0.17 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.17). * Disallow `#{}` interpolation in `@media` queries or unrecognized directives. This was never allowed, but now it explicitly throws an error rather than just producing invalid CSS. * Make `sass --watch` not throw an error when passed a single file or directory. * Understand that mingw counts as Windows. * Make `sass --update` return a non-0 exit code if one or more files being updated contained an error. ## 3.0.16 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.16). * Fix a bug where certain sorts of comments would get improperly rendered in the `:compact` style. * Always allow a trailing `*/` in loud comments in the indented syntax. * Fix a performance issue with SCSS parsing in rare cases. Thanks to [Chris Eppstein](http://chriseppstein.github.com). * Use better heuristics for figuring out when someone might be using the wrong syntax with `sass --watch`. ## 3.0.15 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.15). * Fix a bug where `sass --watch` and `sass --update` were completely broken. * Allow `@import`ed values to contain commas. ## 3.0.14 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.14). * Properly parse paths with drive letters on Windows (e.g. `C:\Foo\Bar.sass`) in the Sass executable. * Compile Sass files in a deterministic order. * Fix a bug where comments after `@if` statements in SCSS weren't getting passed through to the output document. ## 3.0.13 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.13). ## CSS `@import` Directives Sass is now more intelligent about when to compile `@import` directives to plain CSS. Any of the following conditions will cause a literal CSS `@import`: * Importing a path with a `.css` extension (e.g. `@import "foo.css"`). * Importing a path with a media type (e.g. `@import "foo" screen;`). * Importing an HTTP path (e.g. `@import "http://foo.com/style.css"`). * Importing any URL (e.g. `@import url(foo)`). The former two conditions always worked, but the latter two are new. ## `-moz-calc` Support The new [`-moz-calc()` function](http://hacks.mozilla.org/2010/06/css3-calc/) in Firefox 4 will now be properly parsed by Sass. `calc()` was already supported, but because the parsing rules are different than for normal CSS functions, this had to be expanded to include `-moz-calc`. In anticipation of wider browser support, in fact, *any* function named `-*-calc` (such as `-webkit-calc` or `-ms-calc`) will be parsed the same as the `calc` function. ## `:-moz-any` Support The [`:-moz-any` pseudoclass selector](http://hacks.mozilla.org/2010/05/moz-any-selector-grouping/) is now parsed by Sass. ## `--require` Flag The Sass command-line executable can now require Ruby files using the `--require` flag (or `-r` for short). ## Rails Support Make sure the default Rails options take precedence over the default non-Rails options. This makes `./script/server --daemon` work again. ### Rails 3 Support Support for Rails 3 versions prior to beta 4 has been removed. Upgrade to Rails 3.0.0.beta4 if you haven't already. ## 3.0.12 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.12). ## Rails 3 Support Apparently the last version broke in new and exciting ways under Rails 3, due to the inconsistent load order caused by certain combinations of gems. 3.0.12 hacks around that inconsistency, and *should* be fully Rails 3-compatible. ### Deprecated: Rails 3 Beta 3 Haml's support for Rails 3.0.0.beta.3 has been deprecated. Haml 3.0.13 will only support 3.0.0.beta.4. ## 3.0.11 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.11). There were no changes made to Haml between versions 3.0.10 and 3.0.11. ## Rails 3 Support Make sure Sass *actually* regenerates stylesheets under Rails 3. The fix in 3.0.10 didn't work because the Rack stack we were modifying wasn't reloaded at the proper time. ## Bug Fixes * Give a decent error message when `--recursive` is used in `sass-convert` without a directory. ## 3.0.10 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.10). ### Appengine-JRuby Support The way we determine the location of the Haml installation no longer breaks the version of JRuby used by [`appengine-jruby`](http://code.google.com/p/appengine-jruby/). ### Rails 3 Support Sass will regenerate stylesheets under Rails 3 even when no controllers are being accessed. ### Other Improvements * When using `sass-convert --from sass2 --to sass --recursive`, suggest the use of `--in-place` as well. ## 3.0.9 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.9). There were no changes made to Sass between versions 3.0.8 and 3.0.9. A bug in Gemcutter caused the gem to be uploaded improperly. ## 3.0.8 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.8). * Fix a bug with Rails versions prior to Rails 3. ## 3.0.7 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.7). ### Encoding Support Sass 3.0.7 adds support for `@charset` for declaring the encoding of a stylesheet. For details see {file:SASS_REFERENCE.md#encodings the reference}. The `sass` and `sass-convert` executables also now take an `-E` option for specifying the encoding of Sass/SCSS/CSS files. ### Bug Fixes * When compiling a file named `.sass` but with SCSS syntax specified, use the latter (and vice versa). * Fix a bug where interpolation would cause some selectors to render improperly. * If a line in a Sass comment starts with `*foo`, render it as `*foo` rather than `* *foo`. ## 3.0.6 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.6). There were no changes made to Sass between versions 3.0.5 and 3.0.6. ## 3.0.5 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.5). ### `#{}` Interpolation in Properties Previously, using `#{}` in some places in properties would cause a syntax error. Now it can be used just about anywhere. Note that when `#{}` is used near operators like `/`, those operators are treated as plain CSS rather than math operators. For example: p { $font-size: 12px; $line-height: 30px; font: #{$font-size}/#{$line-height}; } is compiled to: p { font: 12px/30px; } This is useful, since normally {file:SASS_REFERENCE.md#division-and-slash a slash with variables is treated as division}. ### Recursive Mixins Mixins that include themselves will now print much more informative error messages. For example: @mixin foo {@include bar} @mixin bar {@include foo} @include foo will print: An @include loop has been found: foo includes bar bar includes foo Although it was previously possible to use recursive mixins without causing infinite looping, this is now disallowed, since there's no good reason to do it. ### Rails 3 Support Fix Sass configuration under Rails 3. Thanks [Dan Cheail](http://github.com/codeape). ### `sass --no-cache` Make the `--no-cache` flag properly forbid Sass from writing `.sass-cache` files. ## 3.0.4 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.4). * Raise an informative error when function arguments have a mispaced comma, as in `foo(bar, )`. * Fix a performance problem when using long function names such as `-moz-linear-gradient`. ## 3.0.3 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.3). ### Rails 3 Support Make sure Sass is loaded properly when using Rails 3 along with non-Rails-3-compatible plugins like some versions of `will_paginate`. Also, In order to make some Rails loading errors like the above easier to debug, Sass will now raise an error if `Rails.root` is `nil` when Sass is loading. Previously, this would just cause the paths to be mis-set. ### Merb Support Merb, including 1.1.0 as well as earlier versions, should *really* work with this release. ### Bug Fixes * Raise an informative error when mixin arguments have a mispaced comma, as in `@include foo(bar, )`. * Make sure SassScript subtraction happens even when nothing else dynamic is going on. * Raise an error when colors are used with the wrong number of digits. ## 3.0.2 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.2). ### Merb 1.1.0 Support Fixed a bug inserting the Sass plugin into the Merb 1.1.0 Rack application. ### Bug Fixes * Allow identifiers to begin with multiple underscores. * Don't raise an error when using `haml --rails` with older Rails versions. ## 3.0.1 [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.1). ### Installation in Rails `haml --rails` is no longer necessary for installing Sass in Rails. Now all you need to do is add `gem "haml"` to the Gemfile for Rails 3, or add `config.gem "haml"` to `config/environment.rb` for previous versions. `haml --rails` will still work, but it has been deprecated and will print an error message. It will not work in the next version of Sass. ### Rails 3 Beta Integration * Make sure manually importing the Sass Rack plugin still works with Rails, even though it's not necessary now. * Allow Sass to be configured in Rails even when it's being lazy-loaded. ### `:template_location` Methods The {file:SASS_REFERENCE.md#template_location-option `:template_location` option} can be either a String, a Hash, or an Array. This makes it difficult to modify or use with confidence. Thus, three new methods have been added for handling it: * {Sass::Plugin::Configuration#template_location_array Sass::Plugin#template_location_array} -- Returns the template locations and CSS locations formatted as an array. * {Sass::Plugin::Configuration#add_template_location Sass::Plugin#add_template_location} -- Converts the template location option to an array and adds a new location. * {Sass::Plugin::Configuration#remove_template_location Sass::Plugin#remove_template_location} -- Converts the template location option to an array and removes an existing location. ## 3.0.0 {#3-0-0} [Tagged on GitHub](http://github.com/nex3/haml/commit/3.0.0). ### Deprecations -- Must Read! {#3-0-0-deprecations} * Using `=` for SassScript properties and variables is deprecated, and will be removed in Sass 3.2. Use `:` instead. See also [this changelog entry](#3-0-0-sass-script-context) * Because of the above, property values using `:` will be parsed more thoroughly than they were before. Although all valid CSS3 properties as well as most hacks and proprietary syntax should be supported, it's possible that some properties will break. If this happens, please report it to [the Sass mailing list](http://groups.google.com/group/haml). * In addition, setting the default value of variables with `||=` is now deprecated and will be removed in Sass 3.2. Instead, add `!default` to the end of the value. See also [this changelog entry](#3-0-0-default-flag) * The `!` prefix for variables is deprecated, and will be removed in Sass 3.2. Use `$` as a prefix instead. See also [this changelog entry](#3-0-0-dollar-prefix). * The `css2sass` command-line tool has been deprecated, and will be removed in Sass 3.2. Use the new `sass-convert` tool instead. See also [this changelog entry](#3-0-0-sass-convert). * Selector parent references using `&` can now only be used where element names are valid. This is because Sass 3 fully parses selectors to support the new [`@extend` directive](#3-0-0-extend), and it's possible that the `&` could be replaced by an element name. ### SCSS (Sassy CSS) Sass 3 introduces a new syntax known as SCSS which is fully compatible with the syntax of CSS3, while still supporting the full power of Sass. This means that every valid CSS3 stylesheet is a valid SCSS file with the same meaning. In addition, SCSS understands most CSS hacks and vendor-specific syntax, such as [IE's old `filter` syntax](http://msdn.microsoft.com/en-us/library/ms533754%28VS.85%29.aspx). SCSS files use the `.scss` extension. They can import `.sass` files, and vice-versa. Their syntax is fully described in the {file:SASS_REFERENCE.md Sass reference}; if you're already familiar with Sass, though, you may prefer the {file:SCSS_FOR_SASS_USERS.md intro to SCSS for Sass users}. Since SCSS is a much more approachable syntax for those new to Sass, it will be used as the default syntax for the reference, as well as for most other Sass documentation. The indented syntax will continue to be fully supported, however. Sass files can be converted to SCSS using the new `sass-convert` command-line tool. For example: # Convert a Sass file to SCSS $ sass-convert style.sass style.scss **Note that if you're converting a Sass file written for Sass 2**, you should use the `--from sass2` flag. For example: # Convert a Sass file to SCSS $ sass-convert --from sass2 style.sass style.scss # Convert all Sass files to SCSS $ sass-convert --recursive --in-place --from sass2 --to scss stylesheets/ ### Syntax Changes {#3-0-0-syntax-changes} #### SassScript Context {#3-0-0-sass-script-context} The `=` character is no longer required for properties that use SassScript (that is, variables and operations). All properties now use SassScript automatically; this means that `:` should be used instead. Variables should also be set with `:`. For example, what used to be // Indented syntax .page color = 5px + 9px should now be // Indented syntax .page color: 5px + 9px This means that SassScript is now an extension of the CSS3 property syntax. All valid CSS3 properties are valid SassScript, and will compile without modification (some invalid properties work as well, such as Microsoft's proprietary `filter` syntax). This entails a few changes to SassScript to make it fully CSS3-compatible, which are detailed below. This also means that Sass will now be fully parsing all property values, rather than passing them through unchanged to the CSS. Although care has been taken to support all valid CSS3, as well as hacks and proprietary syntax, it's possible that a property that worked in Sass 2 won't work in Sass 3. If this happens, please report it to [the Sass mailing list](http://groups.google.com/group/haml). Note that if `=` is used, SassScript will be interpreted as backwards-compatibly as posssible. In particular, the changes listed below don't apply in an `=` context. The `sass-convert` command-line tool can be used to upgrade Sass files to the new syntax using the `--in-place` flag. For example: # Upgrade style.sass: $ sass-convert --in-place style.sass # Upgrade all Sass files: $ sass-convert --recursive --in-place --from sass2 --to sass stylesheets/ ##### Quoted Strings Quoted strings (e.g. `"foo"`) in SassScript now render with quotes. In addition, unquoted strings are no longer deprecated, and render without quotes. This means that almost all strings that had quotes in Sass 2 should not have quotes in Sass 3. Although quoted strings render with quotes when used with `:`, they do not render with quotes when used with `#{}`. This allows quoted strings to be used for e.g. selectors that are passed to mixins. Strings can be forced to be quoted and unquoted using the new \{Sass::Script::Functions#unquote unquote} and \{Sass::Script::Functions#quote quote} functions. ##### Division and `/` Two numbers separated by a `/` character are allowed as property syntax in CSS, e.g. for the `font` property. SassScript also uses `/` for division, however, which means it must decide what to do when it encounters numbers separated by `/`. For CSS compatibility, SassScript does not perform division by default. However, division will be done in almost all cases where division is intended. In particular, SassScript will perform division in the following three situations: 1. If the value, or any part of it, is stored in a variable. 2. If the value is surrounded by parentheses. 3. If the value is used as part of another arithmetic expression. For example: p font: 10px/8px $width: 1000px width: $width/2 height: (500px/2) margin-left: 5px + 8px/2px is compiled to: p { font: 10px/8px; width: 500px; height: 250px; margin-left: 9px; } ##### Variable Defaults Since `=` is no longer used for variable assignment, assigning defaults to variables with `||=` no longer makes sense. Instead, the `!default` flag should be added to the end of the variable value. This syntax is meant to be similar to CSS's `!important` flag. For example: $var: 12px !default; #### Variable Prefix Character {#3-0-0-dollar-prefix} The Sass variable character has been changed from `!` to the more aesthetically-appealing `$`. For example, what used to be !width = 13px .icon width = !width should now be $width: 13px .icon width: $width The `sass-convert` command-line tool can be used to upgrade Sass files to the new syntax using the `--in-place` flag. For example: # Upgrade style.sass: $ sass-convert --in-place style.sass # Upgrade all Sass files: $ sass-convert --recursive --in-place --from sass2 --to sass stylesheets/ `!` may still be used, but it's deprecated and will print a warning. It will be removed in the next version of Sass, 3.2. #### Variable and Mixin Names SassScript variable and mixin names may now contain hyphens. In fact, they may be any valid CSS3 identifier. For example: $prettiest-color: #542FA9 =pretty-text color: $prettiest-color In order to allow frameworks like [Compass](http://compass-style.org) to use hyphens in variable names while maintaining backwards-compatibility, variables and mixins using hyphens may be referred to with underscores, and vice versa. For example: $prettiest-color: #542FA9 .pretty // Using an underscore instead of a hyphen works color: $prettiest_color #### Single-Quoted Strings SassScript now supports single-quoted strings. They behave identically to double-quoted strings, except that single quotes need to be backslash-escaped and double quotes do not. #### Mixin Definition and Inclusion Sass now supports the `@mixin` directive as a way of defining mixins (like `=`), as well as the `@include` directive as a way of including them (like `+`). The old syntax is *not* deprecated, and the two are fully compatible. For example: @mixin pretty-text color: $prettiest-color a @include pretty-text is the same as: =pretty-text color: $prettiest-color a +pretty-text #### Sass Properties New-style properties (with the colon after the name) in indented syntax now allow whitespace before the colon. For example: foo color : blue #### Sass `@import` The Sass `@import` statement now allows non-CSS files to be specified with quotes, for similarity with the SCSS syntax. For example, `@import "foo.sass"` will now import the `foo.sass` file, rather than compiling to `@import "foo.sass";`. ### `@extend` {#3-0-0-extend} There are often cases when designing a page when one class should have all the styles of another class, as well as its own specific styles. The most common way of handling this is to use both the more general class and the more specific class in the HTML. For example, suppose we have a design for a normal error and also for a serious error. We might write our markup like so:
        Oh no! You've been hacked!
        And our styles like so: .error { border: 1px #f00; background-color: #fdd; } .seriousError { border-width: 3px; } Unfortunately, this means that we have to always remember to use `.error` with `.seriousError`. This is a maintenance burden, leads to tricky bugs, and can bring non-semantic style concerns into the markup. The `@extend` directive avoids these problems by telling Sass that one selector should inherit the styles of another selector. For example: .error { border: 1px #f00; background-color: #fdd; } .seriousError { @extend .error; border-width: 3px; } This means that all styles defined for `.error` are also applied to `.seriousError`, in addition to the styles specific to `.seriousError`. In effect, everything with class `.seriousError` also has class `.error`. Other rules that use `.error` will work for `.seriousError` as well. For example, if we have special styles for errors caused by hackers: .error.intrusion { background-image: url("/image/hacked.png"); } Then `
        ` will have the `hacked.png` background image as well. #### How it Works `@extend` works by inserting the extending selector (e.g. `.seriousError`) anywhere in the stylesheet that the extended selector (.e.g `.error`) appears. Thus the example above: .error { border: 1px #f00; background-color: #fdd; } .error.intrusion { background-image: url("/image/hacked.png"); } .seriousError { @extend .error; border-width: 3px; } is compiled to: .error, .seriousError { border: 1px #f00; background-color: #fdd; } .error.intrusion, .seriousError.intrusion { background-image: url("/image/hacked.png"); } .seriousError { border-width: 3px; } When merging selectors, `@extend` is smart enough to avoid unnecessary duplication, so something like `.seriousError.seriousError` gets translated to `.seriousError`. In addition, it won't produce selectors that can't match anything, like `#main#footer`. See also {file:SASS_REFERENCE.md#extend the `@extend` reference documentation}. ### Colors SassScript color values are much more powerful than they were before. Support was added for alpha channels, and most of Chris Eppstein's [compass-colors](http://chriseppstein.github.com/compass-colors) plugin was merged in, providing color-theoretic functions for modifying colors. One of the most interesting of these functions is {Sass::Script::Functions#mix mix}, which mixes two colors together. This provides a much better way of combining colors and creating themes than standard color arithmetic. #### Alpha Channels Sass now supports colors with alpha channels, constructed via the {Sass::Script::Functions#rgba rgba} and {Sass::Script::Functions#hsla hsla} functions. Alpha channels are unaffected by color arithmetic. However, the {Sass::Script::Functions#opacify opacify} and {Sass::Script::Functions#transparentize transparentize} functions allow colors to be made more and less opaque, respectively. Sass now also supports functions that return the values of the {Sass::Script::Functions#red red}, {Sass::Script::Functions#blue blue}, {Sass::Script::Functions#green green}, and {Sass::Script::Functions#alpha alpha} components of colors. #### HSL Colors Sass has many new functions for using the HSL values of colors. For an overview of HSL colors, check out [the CSS3 Spec](http://www.w3.org/TR/css3-color/#hsl-color). All these functions work just as well on RGB colors as on colors constructed with the {Sass::Script::Functions#hsl hsl} function. * The {Sass::Script::Functions#lighten lighten} and {Sass::Script::Functions#darken darken} functions adjust the lightness of a color. * The {Sass::Script::Functions#saturate saturate} and {Sass::Script::Functions#desaturate desaturate} functions adjust the saturation of a color. * The {Sass::Script::Functions#adjust_hue adjust-hue} function adjusts the hue of a color. * The {Sass::Script::Functions#hue hue}, {Sass::Script::Functions#saturation saturation}, and {Sass::Script::Functions#lightness lightness} functions return the corresponding HSL values of the color. * The {Sass::Script::Functions#grayscale grayscale} function converts a color to grayscale. * The {Sass::Script::Functions#complement complement} function returns the complement of a color. ### Other New Functions Several other new functions were added to make it easier to have more flexible arguments to mixins and to enable deprecation of obsolete APIs. * {Sass::Script::Functions#type_of `type-of`} -- Returns the type of a value. * {Sass::Script::Functions#unit `unit`} -- Returns the units associated with a number. * {Sass::Script::Functions#unitless `unitless`} -- Returns whether a number has units or not. * {Sass::Script::Functions#comparable `comparable`} -- Returns whether two numbers can be added or compared. ### Watching for Updates {#3-0-0-watch} The `sass` command-line utility has a new flag: `--watch`. `sass --watch` monitors files or directories for updated Sass files and compiles those files to CSS automatically. This will allow people not using Ruby or [Compass](http://compass-style.org) to use Sass without having to manually recompile all the time. Here's the syntax for watching a directory full of Sass files: sass --watch app/stylesheets:public/stylesheets This will watch every Sass file in `app/stylesheets`. Whenever one of them changes, the corresponding CSS file in `public/stylesheets` will be regenerated. Any files that import that file will be regenerated, too. The syntax for watching individual files is the same: sass --watch style.sass:out.css You can also omit the output filename if you just want it to compile to name.css. For example: sass --watch style.sass This will update `style.css` whenever `style.sass` changes. You can list more than one file and/or directory, and all of them will be watched: sass --watch foo/style:public/foo bar/style:public/bar sass --watch screen.sass print.sass awful-hacks.sass:ie.css sass --watch app/stylesheets:public/stylesheets public/stylesheets/test.sass File and directory watching is accessible from Ruby, using the {Sass::Plugin::Compiler#watch Sass::Plugin#watch} function. #### Bulk Updating Another new flag for the `sass` command-line utility is `--update`. It checks a group of Sass files to see if their CSS needs to be updated, and updates if so. The syntax for `--update` is just like watch: sass --update app/stylesheets:public/stylesheets sass --update style.sass:out.css sass --watch screen.sass print.sass awful-hacks.sass:ie.css In fact, `--update` work exactly the same as `--watch`, except that it doesn't continue watching the files after the first check. ### `sass-convert` (née `css2sass`) {#3-0-0-sass-convert} The `sass-convert` tool, which used to be known as `css2sass`, has been greatly improved in various ways. It now uses a full-fledged CSS3 parser, so it should be able to handle any valid CSS3, as well as most hacks and proprietary syntax. `sass-convert` can now convert between Sass and SCSS. This is normally inferred from the filename, but it can also be specified using the `--from` and `--to` flags. For example: $ generate-sass | sass-convert --from sass --to scss | consume-scss It's also now possible to convert a file in-place -- that is, overwrite the old file with the new file. This is useful for converting files in the [Sass 2 syntax](#3-0-0-deprecations) to the new Sass 3 syntax, e.g. by doing `sass-convert --in-place --from sass2 style.sass`. #### `--recursive` The `--recursive` option allows `sass-convert` to convert an entire directory of files. `--recursive` requires both the `--from` and `--to` flags to be specified. For example: # Convert all .sass files in stylesheets/ to SCSS. # "sass2" means that these files are assumed to use the Sass 2 syntax. $ sass-convert --recursive --from sass2 --to scss stylesheets/ #### `--dasherize` The `--dasherize` options converts all underscores to hyphens, which are now allowed as part of identifiers in Sass. Note that since underscores may still be used in place of hyphens when referring to mixins and variables, this won't cause any backwards-incompatibilities. #### Convert Less to SCSS `sass-convert` can also convert [Less](http://lesscss.org) files to SCSS (or the indented syntax, although I anticipate less interest in that). For example: # Convert all .less files in the current directory into .scss files sass-convert --from less --to scss --recursive . This is done using the Less parser, so it requires that the `less` RubyGem be installed. ##### Incompatibilities Because of the reasonably substantial differences between Sass and Less, there are some things that can't be directly translated, and one feature that can't be translated at all. In the tests I've run on open-source Less stylesheets, none of these have presented issues, but it's good to be aware of them. First, Less doesn't distinguish fully between mixins and selector inheritance. In Less, all classes and some other selectors may be used as mixins, alongside more Sass-like mixins. If a class is being used as a mixin, it may also be used directly in the HTML, so it's not safe to translate it into a Sass mixin. What `sass-convert` does instead is leave the class in the stylesheet as a class, and use {file:SASS_REFERENCE.md#extend `@extend`} rather than {file:SASS_REFERENCE.md#including_a_mixin `@include`} to take on the styles of that class. Although `@extend` and mixins work quite differently, using `@extend` here doesn't actually seem to make a difference in practice. Another issue with Less mixins is that Less allows nested selectors (such as `.body .button` or `.colors > .teal`) to be used as a means of "namespacing" mixins. Sass's `@extend` doesn't work that way, so it does away with the namespacing and just extends the base class (so `.colors > .teal` becomes simply `@extend .teal`). In practice, this feature doesn't seem to be widely-used, but `sass-convert` will print a warning and leave a comment when it encounters it just in case. Finally, Less has the ability to directly access variables and property values defined in other selectors, which Sass does not support. Whenever such an accessor is used, `sass-convert` will print a warning and comment it out in the SCSS output. Like namespaced mixins, though, this does not seem to be a widely-used feature. ### `@warn` Directive A new directive `@warn` has been added that allows Sass libraries to emit warnings. This can be used to issue deprecation warnings, discourage sloppy use of mixins, etc. `@warn` takes a single argument: a SassScript expression that will be displayed on the console along with a stylesheet trace for locating the warning. For example: @mixin blue-text { @warn "The blue-text mixin is deprecated. Use new-blue-text instead."; color: #00f; } Warnings may be silenced with the new `--quiet` command line option, or the corresponding {file:SASS_REFERENCE.md#quiet-option `:quiey` Sass option}. This option will also affect warnings printed by Sass itself. Warnings are off by default in the Rails, Rack, and Merb production environments. ### Sass::Plugin API {Sass::Plugin} now has a large collection of callbacks that allow users to run code when various actions are performed. For example: Sass::Plugin.on_updating_stylesheet do |template, css| puts "#{template} has been compiled to #{css}!" end For a full list of callbacks and usage notes, see the {Sass::Plugin} documentation. {Sass::Plugin} also has a new method, {Sass::Plugin#force_update_stylesheets force_update_stylesheets}. This works just like {Sass::Plugin#update_stylesheets}, except that it doesn't check modification times and doesn't use the cache; all stylesheets are always compiled anew. ### Output Formatting Properties with a value and *also* nested properties are now rendered with the nested properties indented. For example: margin: auto top: 10px bottom: 20px is now compiled to: margin: auto; margin-top: 10px; margin-bottom: 20px; #### `:compressed` Style When the `:compressed` style is used, colors will be output as the minimal possible representation. This means whichever is smallest of the HTML4 color name and the hex representation (shortened to the three-letter version if possible). ### Stylesheet Updating Speed Several caching layers were added to Sass's stylesheet updater. This means that it should run significantly faster. This benefit will be seen by people using Sass in development mode with Rails, Rack, and Merb, as well as people using `sass --watch` from the command line, and to a lesser (but still significant) extent `sass --update`. Thanks to [thedarkone](http://github.com/thedarkone). ### Error Backtraces Numerous bugs were fixed with the backtraces given for Sass errors, especially when importing files and using mixins. All imports and mixins will now show up in the Ruby backtrace, with the proper filename and line number. In addition, when the `sass` executable encounters an error, it now prints the filename where the error occurs, as well as a backtrace of Sass imports and mixins. ### Ruby 1.9 Support * Sass and `css2sass` now produce more descriptive errors when given a template with invalid byte sequences for that template's encoding, including the line number and the offending character. * Sass and `css2sass` now accept Unicode documents with a [byte-order-mark](http://en.wikipedia.org/wiki/Byte_order_mark). ### Firebug Support A new {file:SASS_REFERENCE.md#debug_info-option `:debug_info` option} has been added that emits line-number and filename information to the CSS file in a browser-readable format. This can be used with the new [FireSass Firebug extension](https://addons.mozilla.org/en-US/firefox/addon/103988) to report the Sass filename and line number for generated CSS files. This is also available via the `--debug-info` command-line flag. ### Minor Improvements * If a CSS or Sass function is used that has the name of a color, it will now be parsed as a function rather than as a color. For example, `fuchsia(12)` now renders as `fuchsia(12)` rather than `fuchsia 12`, and `tealbang(12)` now renders as `tealbang(12)` rather than `teal bang(12)`. * The Sass Rails and Merb plugins now use Rack middleware by default. * Haml is now compatible with the [Rip](http://hellorip.com/) package management system. Thanks to [Josh Peek](http://joshpeek.com/). * Indented-syntax `/*` comments may now include `*` on lines beyond the first. * A {file:SASS_REFERENCE.md#read_cache-option `:read_cache`} option has been added to allow the Sass cache to be read from but not written to. * Stylesheets are no longer checked during each request when running tests in Rails. This should speed up some tests significantly. ## 2.2.24 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.24). * Parent references -- the `&` character -- may only be placed at the beginning of simple selector sequences in Sass 3. Placing them elsewhere is deprecated in 2.2.24 and will print a warning. For example, `foo &.bar` is allowed, but `foo .bar&` is not. ## 2.2.23 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.23). * Don't crash when `rake gems` is run in Rails with Sass installed. Thanks to [Florian Frank](http://github.com/flori). * When raising a file-not-found error, add a list of load paths that were checked. * If an import isn't found for a cached Sass file and the {file:SASS_REFERENCE.md#full_exception `:full_exception option`} is enabled, print the full exception rather than raising it. * Fix a bug with a weird interaction with Haml, DataMapper, and Rails 3 that caused some tag helpers to go into infinite recursion. ## 2.2.22 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.22). * Add a railtie so Haml and Sass will be automatically loaded in Rails 3. Thanks to [Daniel Neighman](http://pancakestacks.wordpress.com/). * Make loading the gemspec not crash on read-only filesystems like Heroku's. ## 2.2.21 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.21). * Fix a few bugs in the git-revision-reporting in {Sass::Version#version}. In particular, it will still work if `git gc` has been called recently, or if various files are missing. * Always use `__FILE__` when reading files within the Haml repo in the `Rakefile`. According to [this bug report](http://github.com/carlhuda/bundler/issues/issue/44), this should make Sass work better with Bundler. ## 2.2.20 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.20). * If the cache file for a given Sass file is corrupt because it doesn't have enough content, produce a warning and read the Sass file rather than letting the exception bubble up. This is consistent with other sorts of sassc corruption handling. * Calls to `defined?` shouldn't interfere with Rails' autoloading in very old versions (1.2.x). ## 2.2.19 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.18). There were no changes made to Sass between versions 2.2.18 and 2.2.19. ## 2.2.18 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.18). * Use `Rails.env` rather than `RAILS_ENV` when running under Rails 3.0. Thanks to [Duncan Grazier](http://duncangrazier.com/). * Support `:line_numbers` as an alias for {file:SASS_REFERENCE.md#line_numbers-option `:line_comments`}, since that's what the docs have said forever. Similarly, support `--line-numbers` as a command-line option. * Add a `--unix-newlines` flag to all executables for outputting Unix-style newlines on Windows. * Add a {file:SASS_REFERENCE.md#unix_newlines-option `:unix_newlines` option} for {Sass::Plugin} for outputting Unix-style newlines on Windows. * Fix the `--cache-location` flag, which was previously throwing errors. Thanks to [tav](http://tav.espians.com/). * Allow comments at the beginning of the document to have arbitrary indentation, just like comments elsewhere. Similarly, comment parsing is a little nicer than before. ## 2.2.17 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.16). * When the {file:SASS_REFERENCE.md#full_exception-option `:full_exception` option} is false, raise the error in Ruby code rather than swallowing it and printing something uninformative. * Fixed error-reporting when something goes wrong when loading Sass using the `sass` executable. This used to raise a NameError because `Sass::SyntaxError` wasn't defined. Now it'll raise the correct exception instead. * Report the filename in warnings about selectors without properties. * `nil` values for Sass options are now ignored, rather than raising errors. * Fix a bug that appears when Plugin template locations have multiple trailing slashes. Thanks to [Jared Grippe](http://jaredgrippe.com/). ### Must Read! * When `@import` is given a filename without an extension, the behavior of rendering a CSS `@import` if no Sass file is found is deprecated. In future versions, `@import foo` will either import the template or raise an error. ## 2.2.16 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.16). * Fixed a bug where modules containing user-defined Sass functions weren't made available when simply included in {Sass::Script::Functions} ({Sass::Script::Functions Functions} needed to be re-included in {Sass::Script::Functions::EvaluationContext Functions::EvaluationContext}). Now the module simply needs to be included in {Sass::Script::Functions}. ## 2.2.15 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.15). * Added {Sass::Script::Color#with} for a way of setting color channels that's easier than manually constructing a new color and is forwards-compatible with alpha-channel colors (to be introduced in Sass 2.4). * Added a missing require in Sass that caused crashes when it was being run standalone. ## 2.2.14 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.14). * All Sass functions now raise explicit errors if their inputs are of the incorrect type. * Allow the SassScript `rgb()` function to take percentages in addition to numerical values. * Fixed a bug where SassScript strings with `#` followed by `#{}` interpolation didn't evaluate the interpolation. ### SassScript Ruby API These changes only affect people defining their own Sass functions using {Sass::Script::Functions}. * Sass::Script::Color#value attribute is deprecated. Use {Sass::Script::Color#rgb} instead. The returned array is now frozen as well. * Add an `assert_type` function that's available to {Sass::Script::Functions}. This is useful for typechecking the inputs to functions. ### Rack Support Sass 2.2.14 includes Rack middleware for running Sass, meaning that all Rack-enabled frameworks can now use Sass. To activate this, just add require 'sass/plugin/rack' use Sass::Plugin::Rack to your `config.ru`. See the {Sass::Plugin::Rack} documentation for more details. ## 2.2.13 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.13). There were no changes made to Sass between versions 2.2.12 and 2.2.13. ## 2.2.12 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.12). * Fix a stupid bug introduced in 2.2.11 that broke the Sass Rails plugin. ## 2.2.11 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.11). * Added a note to errors on properties that could be pseudo-classes (e.g. `:focus`) indicating that they should be backslash-escaped. * Automatically interpret properties that could be pseudo-classes as such if {file:SASS_REFERENCE.md.html#property_syntax-option `:property_syntax`} is set to `:new`. * Fixed `css2sass`'s generation of pseudo-classes so that they're backslash-escaped. * Don't crash if the Haml plugin skeleton is installed and `rake gems:install` is run. * Don't use `RAILS_ROOT` directly. This no longer exists in Rails 3.0. Instead abstract this out as `Haml::Util.rails_root`. This changes makes Haml fully compatible with edge Rails as of this writing. * Make use of a Rails callback rather than a monkeypatch to check for stylesheet updates in Rails 3.0+. ## 2.2.10 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.10). * Add support for attribute selectors with spaces around the `=`. For example: a[href = http://google.com] color: blue ## 2.2.9 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.9). There were no changes made to Sass between versions 2.2.8 and 2.2.9. ## 2.2.8 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.8). There were no changes made to Sass between versions 2.2.7 and 2.2.8. ## 2.2.7 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.7). There were no changes made to Sass between versions 2.2.6 and 2.2.7. ## 2.2.6 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.6). * Don't crash when the `__FILE__` constant of a Ruby file is a relative path, as apparently happens sometimes in TextMate (thanks to [Karl Varga](http://github.com/kjvarga)). * Add "Sass" to the `--version` string for the executables. ## 2.2.5 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.5). There were no changes made to Sass between versions 2.2.4 and 2.2.5. ## 2.2.4 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.4). * Don't add `require 'rubygems'` to the top of init.rb when installed via `sass --rails`. This isn't necessary, and actually gets clobbered as soon as haml/template is loaded. * Document the previously-undocumented {file:SASS_REFERENCE.md#line-option `:line` option}, which allows the number of the first line of a Sass file to be set for error reporting. ## 2.2.3 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.3). Sass 2.2.3 prints line numbers for warnings about selectors with no properties. ## 2.2.2 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.2). Sass 2.2.2 is a minor bug-fix release. Notable changes include better parsing of mixin definitions and inclusions and better support for Ruby 1.9. ## 2.2.1 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.1). Sass 2.2.1 is a minor bug-fix release. ### Must Read! * It used to be acceptable to use `-` immediately following variable names, without any whitespace in between (for example, `!foo-!bar`). This is now deprecated, so that in the future variables with hyphens can be supported. Surround `-` with spaces. ## 2.2.0 [Tagged on GitHub](http://github.com/nex3/haml/commit/2.2.0). The 2.2 release marks a significant step in the evolution of the Sass language. The focus has been to increase the power of Sass to keep your stylesheets maintainable by allowing new forms of abstraction to be created within your stylesheets and the stylesheets provided by others that you can download and import into your own. The fundamental units of abstraction in Sass are variables and mixins. Please read below for a list of changes: ### Must Read! * Sass Comments (//) used to only comment out a single line. This was deprecated in 2.0.10 and starting in 2.2, Sass comments will comment out any lines indented under them. Upgrade to 2.0.10 in order to see deprecation warnings where this change affects you. * Implicit Strings within SassScript are now deprecated and will be removed in 2.4. For example: `border= !width solid #00F` should now be written as `border: #{!width} solid #00F` or as `border= !width "solid" #00F`. After upgrading to 2.2, you will see deprecation warnings if you have sass files that use implicit strings. ### Sass Syntax Changes #### Flexible Indentation The indentation of Sass documents is now flexible. The first indent that is detected will determine the indentation style for that document. Tabs and spaces may never be mixed, but within a document, you may choose to use tabs or a flexible number of spaces. #### Multiline Sass Comments Sass Comments (//) will now comment out whatever is indented beneath them. Previously they were single line when used at the top level of a document. Upgrading to the latest stable version will give you deprecation warnings if you have silent comments with indentation underneath them. #### Mixin Arguments Sass Mixins now accept any number of arguments. To define a mixin with arguments, specify the arguments as a comma-delimited list of variables like so: =my-mixin(!arg1, !arg2, !arg3) As before, the definition of the mixin is indented below the mixin declaration. The variables declared in the argument list may be used and will be bound to the values passed to the mixin when it is invoked. Trailing arguments may have default values as part of the declaration: =my-mixin(!arg1, !arg2 = 1px, !arg3 = blue) In the example above, the mixin may be invoked by passing 1, 2 or 3 arguments to it. A similar syntax is used to invoke a mixin that accepts arguments: div.foo +my-mixin(1em, 3px) When a mixin has no required arguments, the parenthesis are optional. The default values for mixin arguments are evaluated in the global context at the time when the mixin is invoked, they may also reference the previous arguments in the declaration. For example: !default_width = 30px =my-fancy-mixin(!width = !default_width, !height = !width) width= !width height= !height .default-box +my-fancy-mixin .square-box +my-fancy-mixin(50px) .rectangle-box +my-fancy-mixin(25px, 75px) !default_width = 10px .small-default-box +my-fancy-mixin compiles to: .default-box { width: 30px; height: 30px; } .square-box { width: 50px; height: 50px; } .rectangle-box { width: 25px; height: 75px; } .small-default-box { width: 10px; height: 10px; } ### Sass, Interactive The sass command line option -i now allows you to quickly and interactively experiment with SassScript expressions. The value of the expression you enter will be printed out after each line. Example: $ sass -i >> 5px 5px >> 5px + 10px 15px >> !five_pixels = 5px 5px >> !five_pixels + 10px 15px ### SassScript The features of SassScript have been greatly enhanced with new control directives, new fundamental data types, and variable scoping. #### New Data Types SassScript now has four fundamental data types: 1. Number 2. String 3. Boolean (New in 2.2) 4. Colors #### More Flexible Numbers Like JavaScript, SassScript numbers can now change between floating point and integers. No explicit casting or decimal syntax is required. When a number is emitted into a CSS file it will be rounded to the nearest thousandth, however the internal representation maintains much higher precision. #### Improved Handling of Units While Sass has long supported numbers with units, it now has a much deeper understanding of them. The following are examples of legal numbers in SassScript: 0, 1000, 6%, -2px, 5pc, 20em, or 2foo. Numbers of the same unit may always be added and subtracted. Numbers that have units that Sass understands and finds comparable, can be combined, taking the unit of the first number. Numbers that have non-comparable units may not be added nor subtracted -- any attempt to do so will cause an error. However, a unitless number takes on the unit of the other number during a mathematical operation. For example: >> 3mm + 4cm 43mm >> 4cm + 3mm 4.3cm >> 3cm + 2in 8.08cm >> 5foo + 6foo 11foo >> 4% + 5px SyntaxError: Incompatible units: 'px' and '%'. >> 5 + 10px 15px Sass allows compound units to be stored in any intermediate form, but will raise an error if you try to emit a compound unit into your css file. >> !em_ratio = 1em / 16px 0.063em/px >> !em_ratio * 32px 2em >> !em_ratio * 40px 2.5em #### Colors A color value can be declared using a color name, hexadecimal, shorthand hexadecimal, the rgb function, or the hsl function. When outputting a color into css, the color name is used, if any, otherwise it is emitted as hexadecimal value. Examples: > #fff white >> white white >> #FFFFFF white >> hsl(180, 100, 100) white >> rgb(255, 255, 255) white >> #AAA #aaaaaa Math on color objects is performed piecewise on the rgb components. However, these operations rarely have meaning in the design domain (mostly they make sense for gray-scale colors). >> #aaa + #123 #bbccdd >> #333 * 2 #666666 #### Booleans Boolean objects can be created by comparison operators or via the `true` and `false` keywords. Booleans can be combined using the `and`, `or`, and `not` keywords. >> true true >> true and false false >> 5 < 10 true >> not (5 < 10) false >> not (5 < 10) or not (10 < 5) true >> 30mm == 3cm true >> 1px == 1em false #### Strings Unicode escapes are now allowed within SassScript strings. ### Control Directives New directives provide branching and looping within a sass stylesheet based on SassScript expressions. See the [Sass Reference](SASS_REFERENCE.md.html#control_directives) for complete details. #### @for The `@for` directive loops over a set of numbers in sequence, defining the current number into the variable specified for each loop. The `through` keyword means that the last iteration will include the number, the `to` keyword means that it will stop just before that number. @for !x from 1px through 5px .border-#{!x} border-width= !x compiles to: .border-1px { border-width: 1px; } .border-2px { border-width: 2px; } .border-3px { border-width: 3px; } .border-4px { border-width: 4px; } .border-5px { border-width: 5px; } #### @if / @else if / @else The branching directives `@if`, `@else if`, and `@else` let you select between several branches of sass to be emitted, based on the result of a SassScript expression. Example: !type = "monster" p @if !type == "ocean" color: blue @else if !type == "matador" color: red @else if !type == "monster" color: green @else color: black is compiled to: p { color: green; } #### @while The `@while` directive lets you iterate until a condition is met. Example: !i = 6 @while !i > 0 .item-#{!i} width = 2em * !i !i = !i - 2 is compiled to: .item-6 { width: 12em; } .item-4 { width: 8em; } .item-2 { width: 4em; } ### Variable Scoping The term "constant" has been renamed to "variable." Variables can be declared at any scope (a.k.a. nesting level) and they will only be visible to the code until the next outdent. However, if a variable is already defined in a higher level scope, setting it will overwrite the value stored previously. In this code, the `!local_var` variable is scoped and hidden from other higher level scopes or sibling scopes: .foo .bar !local_var = 1px width= !local_var .baz // this will raise an undefined variable error. width= !local_var // as will this width= !local_var In this example, since the `!global_var` variable is first declared at a higher scope, it is shared among all lower scopes: !global_var = 1px .foo .bar !global_var = 2px width= !global_var .baz width= !global_var width= !global_var compiles to: .foo { width: 2px; } .foo .bar { width: 2px; } .foo .baz { width: 2px; } ### Interpolation Interpolation has been added. This allows SassScript to be used to create dynamic properties and selectors. It also cleans up some uses of dynamic values when dealing with compound properties. Using interpolation, the result of a SassScript expression can be placed anywhere: !x = 1 !d = 3 !property = "border" div.#{!property} #{!property}: #{!x + !d}px solid #{!property}-color: blue is compiled to: div.border { border: 4px solid; border-color: blue; } ### Sass Functions SassScript defines some useful functions that are called using the normal CSS function syntax: p color = hsl(0, 100%, 50%) is compiled to: #main { color: #ff0000; } The following functions are provided: `hsl`, `percentage`, `round`, `ceil`, `floor`, and `abs`. You can define additional functions in ruby. See {Sass::Script::Functions} for more information. ### New Options #### `:line_comments` To aid in debugging, You may set the `:line_comments` option to `true`. This will cause the sass engine to insert a comment before each selector saying where that selector was defined in your sass code. #### `:template_location` The {Sass::Plugin} `:template_location` option now accepts a hash of sass paths to corresponding css paths. Please be aware that it is possible to import sass files between these separate locations -- they are not isolated from each other. ### Miscellaneous Features #### `@debug` Directive The `@debug` directive accepts a SassScript expression and emits the value of that expression to the terminal (stderr). Example: @debug 1px + 2px During compilation the following will be printed: Line 1 DEBUG: 3px #### Ruby 1.9 Support Sass now fully supports Ruby 1.9.1. #### Sass Cache By default, Sass caches compiled templates and [partials](SASS_REFERENCE.md.html#partials). This dramatically speeds up re-compilation of large collections of Sass files, and works best if the Sass templates are split up into separate files that are all [`@import`](SASS_REFERENCE.md.html#import)ed into one large file. Without a framework, Sass puts the cached templates in the `.sass-cache` directory. In Rails and Merb, they go in `tmp/sass-cache`. The directory can be customized with the [`:cache_location`](#cache_location-option) option. If you don't want Sass to use caching at all, set the [`:cache`](#cache-option) option to `false`. ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/INDENTED_SYNTAX.mdstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/INDENT0000664000175000017500000001221012414640747032136 0ustar ebourgebourg# Sass Indented Syntax * Table of contents {:toc} Sass's indented syntax (also known simply as "Sass") is designed to provide a more concise and, for some, more aesthetically appealing alternative to the CSS-based SCSS syntax. It's not compatible with CSS; instead of using `{` and `}` to delimit blocks of styles, it uses indentation, and instead of using semicolons to separate statements it uses newlines. This usually leads to substantially less text when saying the same thing. Each statement in Sass, such as property declarations and selectors, must be placed on its own line. In addition, everything that would be within `{` and `}` after a statement must be on a new line and indented one level deeper than that statement. For example, this CSS: #main { color: blue; font-size: 0.3em; } would be this Sass: #main color: blue font-size: 0.3em Similarly, this SCSS: #main { color: blue; font-size: 0.3em; a { font: { weight: bold; family: serif; } &:hover { background-color: #eee; } } } would be this Sass: #main color: blue font-size: 0.3em a font: weight: bold family: serif &:hover background-color: #eee ## Sass Syntax Differences In general, most CSS and SCSS syntax works straightforwardly in Sass by using newlines instead of semicolons and indentation instead of braces. However, there are some cases where there are differences or subtleties, which are detailed below. ## Property Synax The indented syntax supports two ways of declaring CSS properties. The first is just like CSS, except without the semicolon. The second, however, places the colon *before* the property name. For example: #main :color blue :font-size 0.3em By default, both ways may be used. However, the {file:SASS_REFERENCE.md#property_syntax-option `:property_syntax` option} may be used to specify that only one property syntax is allowed. ### Multiline Selectors Normally in the indented syntax, a single selector must take up a single line. There is one exception, however: selectors can contain newlines as long as they only appear after commas. For example: .users #userTab, .posts #postTab width: 100px height: 30px ### Comments Like everything else in the indented syntax, comments are line-based. This means that they don't work the same way as in SCSS. They must take up an entire line, and they also encompass all text nested beneath them. Like SCSS, the indented syntax supports two kinds of comments. Comments beginning with `/*` are preserved in the CSS output, although unlike SCSS they don't require a closing `*/`. Comments beginning with `//` are removed entirely. For example: /* This comment will appear in the CSS output. This is nested beneath the comment, so it's part of it body color: black // This comment will not appear in the CSS output. This is nested beneath the comment as well, so it also won't appear a color: green is compiled to: /* This comment will appear in the CSS output. * This is nested beneath the comment, * so it's part of it */ body { color: black; } a { color: green; } ### `@import` The `@import` directive in Sass does not require quotes, although they may be used. For example, this SCSS: @import "themes/dark"; @import "font.sass"; would be this Sass: @import themes/dark @import font.sass ### Mixin Directives Sass supports shorthands for the `@mixin` and `@include` directives. Instead of writing `@mixin`, you can use the character `=`; instead of writing `@include`, you can use the character `+`. For example: =large-text font: family: Arial size: 20px weight: bold color: #ff0000 h1 +large-text is the same as: @mixin large-text font: family: Arial size: 20px weight: bold color: #ff0000 h1 @include large-text ## Deprecated Syntax Since the indented syntax has been around for a while, previous versions have made some syntactic decisions that have since been changed. Some of the old syntax still works, though, so it's documented here. **Note that this syntax is not recommended for use in new Sass files**. It will print a warning if it's used, and it will be removed in a future version. ### `=` for Properties and Variables `=` used to be used instead of `:` when setting variables and when setting properties to SassScript values. It has slightly different semantics than `:`; see {file:SASS_CHANGELOG.md#3-0-0-sass-script-context this changelog entry} for details. ### `||=` for Default Variables `||=` used to be used instead of `:` when setting the default value of a variable. The `!default` flag was not used. The variable value has the same semantics as `=`; see {file:SASS_CHANGELOG.md#3-0-0-sass-script-context this changelog entry} for details. ### `!` Prefix for Variables `!` used to be used as the variable prefix instead of `$`. This had no difference in functionality; it was a purely aesthetic change. ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/SASS_REFERENCE.mdstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/doc-src/SASS_R0000664000175000017500000016020712414640747032221 0ustar ebourgebourg# Sass (Syntactically Awesome StyleSheets) * Table of contents {:toc} Sass is an extension of CSS that adds power and elegance to the basic language. It allows you to use [variables](#variables_), [nested rules](#nested_rules), [mixins](#mixins), [inline imports](#import), and more, all with a fully CSS-compatible syntax. Sass helps keep large stylesheets well-organized, and get small stylesheets up and running quickly, particularly with the help of [the Compass style library](http://compass-style.org). ## Features * Fully CSS3-compatible * Language extensions such as variables, nesting, and mixins * Many {Sass::Script::Functions useful functions} for manipulating colors and other values * Advanced features like [control directives](#control_directives) for libraries * Well-formatted, customizable output * [Firebug integration](https://addons.mozilla.org/en-US/firefox/addon/103988) ## Syntax There are two syntaxes available for Sass. The first, known as SCSS (Sassy CSS) and used throughout this reference, is an extension of the syntax of CSS3. This means that every valid CSS3 stylesheet is a valid SCSS file with the same meaning. In addition, SCSS understands most CSS hacks and vendor-specific syntax, such as [IE's old `filter` syntax](http://msdn.microsoft.com/en-us/library/ms533754%28VS.85%29.aspx). This syntax is enhanced with the Sass features described below. Files using this syntax have the `.scss` extension. The second and older syntax, known as the indented syntax (or sometimes just "Sass"), provides a more concise way of writing CSS. It uses indentation rather than brackets to indicate nesting of selectors, and newlines rather than semicolons to separate properties. Some people find this to be easier to read and quicker to write than SCSS. The indented syntax has all the same features, although some of them have slightly different syntax; this is described in {file:INDENTED_SYNTAX.md the indented syntax reference}. Files using this syntax have the `.sass` extension. Either syntax can [import](#import) files written in the other. Files can be automatically converted from one syntax to the other using the `sass-convert` command line tool: # Convert Sass to SCSS $ sass-convert style.sass style.scss # Convert SCSS to Sass $ sass-convert style.scss style.sass ## Using Sass Sass can be used in three ways: as a command-line tool, as a standalone Ruby module, and as a plugin for any Rack-enabled framework, including Ruby on Rails and Merb. The first step for all of these is to install the Sass gem: gem install sass If you're using Windows, you may need to [install Ruby](http://rubyinstaller.org/download.html) first. To run Sass from the command line, just use sass input.scss output.css You can also tell Sass to watch the file and update the CSS every time the Sass file changes: sass --watch input.scss:output.css If you have a directory with many Sass files, you can also tell Sass to watch the entire directory: sass --watch app/sass:public/stylesheets Use `sass --help` for full documentation. Using Sass in Ruby code is very simple. After installing the Sass gem, you can use it by running `require "sass"` and using {Sass::Engine} like so: engine = Sass::Engine.new("#main {background-color: #0000ff}", :syntax => :scss) engine.render #=> "#main { background-color: #0000ff; }\n" ### Rack/Rails/Merb Plugin To enable Sass in Rails versions before Rails 3, add the following line to `environment.rb`: config.gem "sass" For Rails 3, instead add the following line to the Gemfile: gem "sass" To enable Sass in Merb, add the following line to `config/dependencies.rb`: dependency "merb-haml" To enable Sass in a Rack application, add require 'sass/plugin/rack' use Sass::Plugin::Rack to `config.ru`. Sass stylesheets don't work the same as views. They don't contain dynamic content, so the CSS only needs to be generated when the Sass file has been updated. By default, `.sass` and `.scss` files are placed in public/stylesheets/sass (this can be customized with the [`:template_location`](#template_location-option) option). Then, whenever necessary, they're compiled into corresponding CSS files in public/stylesheets. For instance, public/stylesheets/sass/main.scss would be compiled to public/stylesheets/main.css. ### Caching By default, Sass caches compiled templates and [partials](#partials). This dramatically speeds up re-compilation of large collections of Sass files, and works best if the Sass templates are split up into separate files that are all [`@import`](#import)ed into one large file. Without a framework, Sass puts the cached templates in the `.sass-cache` directory. In Rails and Merb, they go in `tmp/sass-cache`. The directory can be customized with the [`:cache_location`](#cache_location-option) option. If you don't want Sass to use caching at all, set the [`:cache`](#cache-option) option to `false`. ### Options Options can be set by setting the {Sass::Plugin::Configuration#options Sass::Plugin#options} hash in `environment.rb` in Rails or `config.ru` in Rack... Sass::Plugin.options[:style] = :compact ...or by setting the `Merb::Plugin.config[:sass]` hash in `init.rb` in Merb... Merb::Plugin.config[:sass][:style] = :compact ...or by passing an options hash to {Sass::Engine#initialize}. All relevant options are also available via flags to the `sass` and `scss` command-line executables. Available options are: {#style-option} `:style` : Sets the style of the CSS output. See [Output Style](#output_style). {#syntax-option} `:syntax` : The syntax of the input file, `:sass` for the indented syntax and `:scss` for the CSS-extension syntax. This is only useful when you're constructing {Sass::Engine} instances yourself; it's automatically set properly when using {Sass::Plugin}. Defaults to `:sass`. {#property_syntax-option} `:property_syntax` : Forces indented-syntax documents to use one syntax for properties. If the correct syntax isn't used, an error is thrown. `:new` forces the use of a colon or equals sign after the property name. For example: `color: #0f3` or `width: $main_width`. `:old` forces the use of a colon before the property name. For example: `:color #0f3` or `:width $main_width`. By default, either syntax is valid. This has no effect on SCSS documents. {#cache-option} `:cache` : Whether parsed Sass files should be cached, allowing greater speed. Defaults to true. {#read_cache-option} `:read_cache` : If this is set and `:cache` is not, only read the Sass cache if it exists, don't write to it if it doesn't. {#cache_store-option} `:cache_store` : If this is set to an instance of a subclass of {Sass::CacheStores::Base}, that cache store will be used to store and retrieve cached compilation results. Defaults to a {Sass::CacheStores::Filesystem} that is initialized using the [`:cache_location` option](#cache_location-option). {#never_update-option} `:never_update` : Whether the CSS files should never be updated, even if the template file changes. Setting this to true may give small performance gains. It always defaults to false. Only has meaning within Rack, Ruby on Rails, or Merb. {#always_update-option} `:always_update` : Whether the CSS files should be updated every time a controller is accessed, as opposed to only when the template has been modified. Defaults to false. Only has meaning within Rack, Ruby on Rails, or Merb. {#always_check-option} `:always_check` : Whether a Sass template should be checked for updates every time a controller is accessed, as opposed to only when the server starts. If a Sass template has been updated, it will be recompiled and will overwrite the corresponding CSS file. Defaults to false in production mode, true otherwise. Only has meaning within Rack, Ruby on Rails, or Merb. {#full_exception-option} `:full_exception` : Whether an error in the Sass code should cause Sass to provide a detailed description within the generated CSS file. If set to true, the error will be displayed along with a line number and source snippet both as a comment in the CSS file and at the top of the page (in supported browsers). Otherwise, an exception will be raised in the Ruby code. Defaults to false in production mode, true otherwise. Only has meaning within Rack, Ruby on Rails, or Merb. {#template_location-option} `:template_location` : A path to the root sass template directory for your application. If a hash, `:css_location` is ignored and this option designates a mapping between input and output directories. May also be given a list of 2-element lists, instead of a hash. Defaults to `css_location + "/sass"`. Only has meaning within Rack, Ruby on Rails, or Merb. Note that if multiple template locations are specified, all of them are placed in the import path, allowing you to import between them. **Note that due to the many possible formats it can take, this option should only be set directly, not accessed or modified. Use the {Sass::Plugin::Configuration#template_location_array Sass::Plugin#template_location_array}, {Sass::Plugin::Configuration#add_template_location Sass::Plugin#add_template_location}, and {Sass::Plugin::Configuration#remove_template_location Sass::Plugin#remove_template_location} methods instead**. {#css_location-option} `:css_location` : The path where CSS output should be written to. This option is ignored when `:template_location` is a Hash. Defaults to `"./public/stylesheets"`. Only has meaning within Rack, Ruby on Rails, or Merb. {#cache_location-option} `:cache_location` : The path where the cached `sassc` files should be written to. Defaults to `"./tmp/sass-cache"` in Rails and Merb, or `"./.sass-cache"` otherwise. If the [`:cache_store` option](#cache_location-option) is set, this is ignored. {#unix_newlines-option} `:unix_newlines` : If true, use Unix-style newlines when writing files. Only has meaning on Windows, and only when Sass is writing the files (in Rack, Rails, or Merb, when using {Sass::Plugin} directly, or when using the command-line executable). {#filename-option} `:filename` : The filename of the file being rendered. This is used solely for reporting errors, and is automatically set when using Rack, Rails, or Merb. {#line-option} `:line` : The number of the first line of the Sass template. Used for reporting line numbers for errors. This is useful to set if the Sass template is embedded in a Ruby file. {#load_paths-option} `:load_paths` : An array of filesystem paths or importers which should be searched for Sass templates imported with the [`@import`](#import) directive. These may be strings, `Pathname` objects, or subclasses of {Sass::Importers::Base}. This defaults to the working directory and, in Rack, Rails, or Merb, whatever `:template_location` is. {#filesystem_importer-option} `:filesystem_importer` : A {Sass::Importers::Base} subclass used to handle plain string load paths. This should import files from the filesystem. It should be a Class object inheriting from {Sass::Importers::Base} with a constructor that takes a single string argument (the load path). Defaults to {Sass::Importers::Filesystem}. {#line_numbers-option} `:line_numbers` : When set to true, causes the line number and file where a selector is defined to be emitted into the compiled CSS as a comment. Useful for debugging, especially when using imports and mixins. This option may also be called `:line_comments`. Automatically disabled when using the `:compressed` output style or the `:debug_info` option. {#debug_info-option} `:debug_info` : When set to true, causes the line number and file where a selector is defined to be emitted into the compiled CSS in a format that can be understood by the browser. Useful in conjunction with [the FireSass Firebug extension](https://addons.mozilla.org/en-US/firefox/addon/103988) for displaying the Sass filename and line number. Automatically disabled when using the `:compressed` output style. {#custom-option} `:custom` : An option that's available for individual applications to set to make data available to {Sass::Script::Functions custom Sass functions}. {#quiet-option} `:quiet` : When set to true, causes warnings to be disabled. ### Syntax Selection The Sass command-line tool will use the file extension to determine which syntax you are using, but there's not always a filename. The `sass` command-line program defaults to the indented syntax but you can pass the `--scss` option to it if the input should be interpreted as SCSS syntax. Alternatively, you can use the `scss` command-line program which is exactly like the `sass` program but it defaults to assuming the syntax is SCSS. ### Encodings When running on Ruby 1.9 and later, Sass is aware of the character encoding of documents and will handle them the same way that CSS would. By default, Sass assumes that all stylesheets are encoded using whatever coding system your operating system defaults to. For many users this will be `UTF-8`, the de facto standard for the web. For some users, though, it may be a more local encoding. If you want to use a different encoding for your stylesheet than your operating system default, you can use the `@charset` declaration just like in CSS. Add `@charset "encoding-name";` at the beginning of the stylesheet (before any whitespace or comments) and Sass will interpret it as the given encoding. Note that whatever encoding you use, it must be convertible to Unicode. Sass will also respect any Unicode BOMs and non-ASCII-compatible Unicode encodings [as specified by the CSS spec](http://www.w3.org/TR/CSS2/syndata.html#charset), although this is *not* the recommended way to specify the character set for a document. Note that Sass does not support the obscure `UTF-32-2143`, `UTF-32-3412`, `EBCDIC`, `IBM1026`, and `GSM 03.38` encodings, since Ruby does not have support for them and they're highly unlikely to ever be used in practice. #### Output Encoding In general, Sass will try to encode the output stylesheet using the same encoding as the input stylesheet. In order for it to do this, though, the input stylesheet must have a `@charset` declaration; otherwise, Sass will default to encoding the output stylesheet as UTF-8. In addition, it will add a `@charset` declaration to the output if it's not plain ASCII. When other stylesheets with `@charset` declarations are `@import`ed, Sass will convert them to the same encoding as the main stylesheet. Note that Ruby 1.8 does not have good support for character encodings, and so Sass behaves somewhat differently when running under it than under Ruby 1.9 and later. In Ruby 1.8, Sass simply uses the first `@charset` declaration in the stylesheet or any of the other stylesheets it `@import`s. ## CSS Extensions ### Nested Rules Sass allows CSS rules to be nested within one another. The inner rule then only applies within the outer rule's selector. For example: #main p { color: #00ff00; width: 97%; .redbox { background-color: #ff0000; color: #000000; } } is compiled to: #main p { color: #00ff00; width: 97%; } #main p .redbox { background-color: #ff0000; color: #000000; } This helps avoid repetition of parent selectors, and makes complex CSS layouts with lots of nested selectors much simpler. For example: #main { width: 97%; p, div { font-size: 2em; a { font-weight: bold; } } pre { font-size: 3em; } } is compiled to: #main { width: 97%; } #main p, #main div { font-size: 2em; } #main p a, #main div a { font-weight: bold; } #main pre { font-size: 3em; } ### Referencing Parent Selectors: `&` Sometimes it's useful to use a nested rule's parent selector in other ways than the default. For instance, you might want to have special styles for when that selector is hovered over or for when the body element has a certain class. In these cases, you can explicitly specify where the parent selector should be inserted using the `&` character. For example: a { font-weight: bold; text-decoration: none; &:hover { text-decoration: underline; } body.firefox & { font-weight: normal; } } is compiled to: a { font-weight: bold; text-decoration: none; } a:hover { text-decoration: underline; } body.firefox a { font-weight: normal; } `&` will be replaced with the parent selector as it appears in the CSS. This means that if you have a deeply nested rule, the parent selector will be fully resolved before the `&` is replaced. For example: #main { color: black; a { font-weight: bold; &:hover { color: red; } } } is compiled to: #main { color: black; } #main a { font-weight: bold; } #main a:hover { color: red; } ### Nested Properties CSS has quite a few properties that are in "namespaces;" for instance, `font-family`, `font-size`, and `font-weight` are all in the `font` namespace. In CSS, if you want to set a bunch of properties in the same namespace, you have to type it out each time. Sass provides a shortcut for this: just write the namespace one, then nest each of the sub-properties within it. For example: .funky { font: { family: fantasy; size: 30em; weight: bold; } } is compiled to: .funky { font-family: fantasy; font-size: 30em; font-weight: bold; } The property namespace itself can also have a value. For example: .funky { font: 2px/3px { family: fantasy; size: 30em; weight: bold; } } is compiled to: .funky { font: 2px/3px; font-family: fantasy; font-size: 30em; font-weight: bold; } ## Comments: `/* */` and `//` {#comments} Sass supports standard multiline CSS comments with `/* */`, as well as single-line comments with `//`. The multiline comments are preserved in the CSS output where possible, while the single-line comments are removed. For example: /* This comment is * several lines long. * since it uses the CSS comment syntax, * it will appear in the CSS output. */ body { color: black; } // These comments are only one line long each. // They won't appear in the CSS output, // since they use the single-line comment syntax. a { color: green; } is compiled to: /* This comment is * several lines long. * since it uses the CSS comment syntax, * it will appear in the CSS output. */ body { color: black; } a { color: green; } When the first letter of a comment is `!`, the comment will be interpolated and always rendered into css output even in compressed output modes. This is useful for adding Copyright notices to your generated CSS. ## SassScript {#sassscript} In addition to the plain CSS property syntax, Sass supports a small set of extensions called SassScript. SassScript allows properties to use variables, arithmetic, and extra functions. SassScript can be used in any property value. SassScript can also be used to generate selectors and property names, which is useful when writing [mixins](#mixins). This is done via [interpolation](#interpolation_). ### Interactive Shell You can easily experiment with SassScript using the interactive shell. To launch the shell run the sass command-line with the `-i` option. At the prompt, enter any legal SassScript expression to have it evaluated and the result printed out for you: $ sass -i >> "Hello, Sassy World!" "Hello, Sassy World!" >> 1px + 1px + 1px 3px >> #777 + #777 #eeeeee >> #777 + #888 white ### Variables: `$` {#variables_} The most straightforward way to use SassScript is to use variables. Variables begin with dollar signs, and are set like CSS properties: $width: 5em; You can then refer to them in properties: #main { width: $width; } Variables are only available within the level of nested selectors where they're defined. If they're defined outside of any nested selectors, they're available everywhere. Variables used to use the prefix character `!`; this still works, but it's deprecated and prints a warning. `$` is the recommended syntax. Variables also used to be defined with `=` rather than `:`; this still works, but it's deprecated and prints a warning. `:` is the recommended syntax. ### Data Types SassScript supports four main data types: * numbers (e.g. `1.2`, `13`, `10px`) * strings of text, with and without quotes (e.g. `"foo"`, `'bar'`, `baz`) * colors (e.g. `blue`, `#04a3f9`, `rgba(255, 0, 0, 0.5)`) * booleans (e.g. `true`, `false`) * lists of values, separated by spaces or commas (e.g. `1.5em 1em 0 2em`, `Helvetica, Arial, sans-serif`) SassScript also supports all other types of CSS property value, such as Unicode ranges and `!important` declarations. However, it has no special handling for these types. They're treated just like unquoted strings. #### Strings {#sass-script-strings} CSS specifies two kinds of strings: those with quotes, such as `"Lucida Grande"` or `'http://sass-lang.com'`, and those without quotes, such as `sans-serif` or `bold`. SassScript recognizes both kinds, and in general if one kind of string is used in the Sass document, that kind of string will be used in the resulting CSS. There is one exception to this, though: when using [`#{}` interpolation](#interpolation_), quoted strings are unquoted. This makes it easier to use e.g. selector names in [mixins](#mixins). For example: @mixin firefox-message($selector) { body.firefox #{$selector}:before { content: "Hi, Firefox users!"; } } @include firefox-message(".header"); is compiled to: body.firefox .header:before { content: "Hi, Firefox users!"; } It's also worth noting that when using the [deprecated `=` property syntax](#sassscript), all strings are interpreted as unquoted, regardless of whether or not they're written with quotes. #### Lists Lists are how Sass represents the values of CSS declarations like `margin: 10px 15px 0 0` or `font-face: Helvetica, Arial, sans-serif`. Lists are just a series of other values, separated by either spaces or commas. In fact, individual values count as lists, too: they're just lists with one item. On their own, lists don't do much, but the {file:Sass/Script/Functions.html#list-functions Sass list functions} make them useful. The {Sass::Script::Functions#nth nth function} can access items in a list, the {Sass::Script::Functions#join join function} can join multiple lists together, and the {Sass::Script::Functions#append append function} can add items to lists. The [`@each` rule](#each-directive) can also add styles for each item in a list. In addition to containing simple values, lists can contain other lists. For example, `1px 2px, 5px 6px` is a two-item list containing the list `1px 2px` and the list `5px 6px`. If the inner lists have the same separator as the outer list, you'll need to use parentheses to make it clear where the inner lists start and stop. For example, `(1px 2px) (5px 6px)` is also a two-item list containing the list `1px 2px` and the list `5px 6px`. The difference is that the outer list is space-separated, where before it was comma-separated. When lists are turned into plain CSS, Sass doesn't add any parentheses, since CSS doesn't understand them. That means that `(1px 2px) (5px 6px)` and `1px 2px 5px 6px` will look the same when they become CSS. However, they aren't the same when they're Sass: the first is a list containing two lists, while the second is a list containing four numbers. Lists can also have no items in them at all. These lists are represented as `()`. They can't be output directly to CSS; if you try to do e.g. `font-family: ()`, Sass will raise an error. If a list contains empty lists, as in `1px 2px () 3px`, the empty list will be removed before it's turned into CSS. ### Operations All types support equality operations (`==` and `!=`). In addition, each type has its own operations that it has special support for. #### Number Operations SassScript supports the standard arithmetic operations on numbers (`+`, `-`, `*`, `/`, `%`), and will automatically convert between units if it can: p { width: 1in + 8pt; } is compiled to: p { width: 1.111in; } Relational operators (`<`, `>`, `<=`, `>=`) are also supported for numbers, and equality operators (`==`, `!=`) are supported for all types. ##### Division and `/` {#division-and-slash} CSS allows `/` to appear in property values as a way of separating numbers. Since SassScript is an extension of the CSS property syntax, it must support this, while also allowing `/` to be used for division. This means that by default, if two numbers are separated by `/` in SassScript, then they will appear that way in the resulting CSS. However, there are three situations where the `/` will be interpreted as division. These cover the vast majority of cases where division is actually used. They are: 1. If the value, or any part of it, is stored in a variable. 2. If the value is surrounded by parentheses. 3. If the value is used as part of another arithmetic expression. For example: p { font: 10px/8px; // Plain CSS, no division $width: 1000px; width: $width/2; // Uses a variable, does division height: (500px/2); // Uses parentheses, does division margin-left: 5px + 8px/2px; // Uses +, does division } is compiled to: p { font: 10px/8px; width: 500px; height: 250px; margin-left: 9px; } If you want to use variables along with a plain CSS `/`, you can use `#{}` to insert them. For example: p { $font-size: 12px; $line-height: 30px; font: #{$font-size}/#{$line-height}; } is compiled to: p { font: 12px/30px; } #### Color Operations All arithmetic operations are supported for color values, where they work piecewise. This means that the operation is performed on the red, green, and blue components in turn. For example: p { color: #010203 + #040506; } computes `01 + 04 = 05`, `02 + 05 = 07`, and `03 + 06 = 09`, and is compiled to: p { color: #050709; } Often it's more useful to use {Sass::Script::Functions color functions} than to try to use color arithmetic to achieve the same effect. Arithmetic operations also work between numbers and colors, also piecewise. For example: p { color: #010203 * 2; } computes `01 * 2 = 02`, `02 * 2 = 04`, and `03 * 2 = 06`, and is compiled to: p { color: #020406; } Note that colors with an alpha channel (those created with the {Sass::Script::Functions#rgba rgba} or {Sass::Script::Functions#hsla hsla} functions) must have the same alpha value in order for color arithmetic to be done with them. The arithmetic doesn't affect the alpha value. For example: p { color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75); } is compiled to: p { color: rgba(255, 255, 0, 0.75); } The alpha channel of a color can be adjusted using the {Sass::Script::Functions#opacify opacify} and {Sass::Script::Functions#transparentize transparentize} functions. For example: $translucent-red: rgba(255, 0, 0, 0.5); p { color: opacify($translucent-red, 0.8); background-color: transparentize($translucent-red, 50%); } is compiled to: p { color: rgba(255, 0, 0, 0.9); background-color: rgba(255, 0, 0, 0.25); } #### String Operations The `+` operation can be used to concatenate strings: p { cursor: e + -resize; } is compiled to: p { cursor: e-resize; } Note that if a quoted string is added to an unquoted string (that is, the quoted string is to the left of the `+`), the result is a quoted string. Likewise, if an unquoted string is added to a quoted string (the unquoted string is to the left of the `+`), the result is an unquoted string. For example: p:before { content: "Foo " + Bar; font-family: sans- + "serif"; } is compiled to: p:before { content: "Foo Bar"; font-family: sans-serif; } By default, if two values are placed next to one another, they are concatenated with a space: p { margin: 3px + 4px auto; } is compiled to: p { margin: 7px auto; } Within a string of text, #{} style interpolation can be used to place dynamic values within the string: p:before { content: "I ate #{5 + 10} pies!"; } is compiled to: p:before { content: "I ate 15 pies!"; } #### Boolean Operations SassScript supports `and`, `or`, and `not` operators for boolean values. #### List Operations Lists don't support any special operations. Instead, they're manipulated using the {file:Sass/Script/Functions.html#list-functions list functions}. ### Parentheses Parentheses can be used to affect the order of operations: p { width: 1em + (2em * 3); } is compiled to: p { width: 7em; } ### Functions SassScript defines some useful functions that are called using the normal CSS function syntax: p { color: hsl(0, 100%, 50%); } is compiled to: p { color: #ff0000; } #### Keyword Arguments Sass functions can also be called using explicit keyword arguments. The above example can also be written as: p { color: hsl($hue: 0, $saturation: 100%, $lightness: 50%); } While this is less concise, it can make the stylesheet easier to read. It also allows functions to present more flexible interfaces, providing many arguments without becoming difficult to call. Named arguments can be passed in any order, and arguments with default values can be omitted. Since the named arguments are variable names, underscores and dashes can be used interchangeably. See {Sass::Script::Functions} for a full listing of Sass functions and their argument names, as well as instructions on defining your own in Ruby. ### Interpolation: `#{}` {#interpolation_} You can also use SassScript variables in selectors and property names using #{} interpolation syntax: $name: foo; $attr: border; p.#{$name} { #{$attr}-color: blue } is compiled to: p.foo { border-color: blue; } It's also possible to use `#{}` to put SassScript into property values. In most cases this isn't any better than using a variable, but using `#{}` does mean that any operations near it will be treated as plain CSS. For example: p { $font-size: 12px; $line-height: 30px; font: #{$font-size}/#{$line-height}; } is compiled to: p { font: 12px/30px; } ### Variable Defaults: `!default` You can assign to variables if they aren't already assigned by adding the `!default` flag to the end of the value. This means that if the variable has already been assigned to, it won't be re-assigned, but if it doesn't have a value yet, it will be given one. For example: $content: "First content"; $content: "Second content?" !default; $new_content: "First time reference" !default; #main { content: $content; new-content: $new_content; } is compiled to: #main { content: "First content"; new-content: "First time reference"; } ## `@`-Rules and Directives {#directives} Sass supports all CSS3 `@`-rules, as well as some additional Sass-specific ones known as "directives." These have various effects in Sass, detailed below. See also [control directives](#control-directives) and [mixin directives](#mixins). ### `@import` {#import} Sass extends the CSS `@import` rule to allow it to import SCSS and Sass files. All imported SCSS and Sass files will be merged together into a single CSS output file. In addition, any variables or [mixins](#mixins) defined in imported files can be used in the main file. Sass looks for other Sass files in the current directory, and the Sass file directory under Rack, Rails, or Merb. Additional search directories may be specified using the [`:load_paths`](#load_paths-option) option, or the `--load-path` option on the command line. `@import` takes a filename to import. By default, it looks for a Sass file to import directly, but there are a few circumstances under which it will compile to a CSS `@import` rule: * If the file's extension is `.css`. * If the filename begins with `http://`. * If the filename is a `url()`. * If the `@import` has any media queries. If none of the above conditions are met and the extension is `.scss` or `.sass`, then the named Sass or SCSS file will be imported. If there is no extension, Sass will try to find a file with that name and the `.scss` or `.sass` extension and import it. For example, @import "foo.scss"; or @import "foo"; would both import the file `foo.scss`, whereas @import "foo.css"; @import "foo" screen; @import "http://foo.com/bar"; @import url(foo); would all compile to @import "foo.css"; @import "foo" screen; @import "http://foo.com/bar"; @import url(foo); It's also possible to import multiple files in one `@import`. For example: @import "rounded-corners", "text-shadow"; would import both the `rounded-corners` and the `text-shadow` files. #### Partials {#partials} If you have a SCSS or Sass file that you want to import but don't want to compile to a CSS file, you can add an underscore to the beginning of the filename. This will tell Sass not to compile it to a normal CSS file. You can then import these files without using the underscore. For example, you might have `_colors.scss`. Then no `_colors.css` file would be created, and you can do @import "colors"; and `_colors.scss` would be imported. #### Nested `@import` {#nested-import} Although most of the time it's most useful to just have `@import`s at the top level of the document, it is possible to include them within CSS rules and `@media` rules. Like a base-level `@import`, this includes the contents of the `@import`ed file. However, the imported rules will be nested in the same place as the original `@import`. For example, if `example.scss` contains .example { color: red; } then #main { @import "example"; } would compile to #main .example { color: red; } Directives that are only allowed at the base level of a document, like `@mixin` or `@charset`, are not allowed in files that are `@import`ed in a nested context. It's not possible to nest `@import` within mixins or control directives. ### `@media` {#media} `@media` directives in Sass behave just like they do in plain CSS, with one extra capability: they can be nested in CSS rules. If a `@media` directive appears within a CSS rule, it will be bubbled up to the top level of the stylesheet, putting all the selectors on the way inside the rule. This makes it easy to add media-specific styles without having to repeat selectors or break the flow of the stylesheet. For example: .sidebar { width: 300px; @media screen and (orientation: landscape) { width: 500px; } } is compiled to: .sidebar { width: 300px; } @media screen and (orientation: landscape) { .sidebar { width: 500px; } } `@media` queries can also be nested within one another. The queries will then be combined using the `and` operator. For example: @media screen { .sidebar { @media (orientation: landscape) { width: 500px; } } } is compiled to: @media screen and (orientation: landscape) { .sidebar { width: 500px; } } ### `@extend` {#extend} There are often cases when designing a page when one class should have all the styles of another class, as well as its own specific styles. The most common way of handling this is to use both the more general class and the more specific class in the HTML. For example, suppose we have a design for a normal error and also for a serious error. We might write our markup like so:
        Oh no! You've been hacked!
        And our styles like so: .error { border: 1px #f00; background-color: #fdd; } .seriousError { border-width: 3px; } Unfortunately, this means that we have to always remember to use `.error` with `.seriousError`. This is a maintenance burden, leads to tricky bugs, and can bring non-semantic style concerns into the markup. The `@extend` directive avoids these problems by telling Sass that one selector should inherit the styles of another selector. For example: .error { border: 1px #f00; background-color: #fdd; } .seriousError { @extend .error; border-width: 3px; } This means that all styles defined for `.error` are also applied to `.seriousError`, in addition to the styles specific to `.seriousError`. In effect, everything with class `.seriousError` also has class `.error`. Other rules that use `.error` will work for `.seriousError` as well. For example, if we have special styles for errors caused by hackers: .error.intrusion { background-image: url("/image/hacked.png"); } Then `
        ` will have the `hacked.png` background image as well. #### How it Works `@extend` works by inserting the extending selector (e.g. `.seriousError`) anywhere in the stylesheet that the extended selector (.e.g `.error`) appears. Thus the example above: .error { border: 1px #f00; background-color: #fdd; } .error.intrusion { background-image: url("/image/hacked.png"); } .seriousError { @extend .error; border-width: 3px; } is compiled to: .error, .seriousError { border: 1px #f00; background-color: #fdd; } .error.intrusion, .seriousError.intrusion { background-image: url("/image/hacked.png"); } .seriousError { border-width: 3px; } When merging selectors, `@extend` is smart enough to avoid unnecessary duplication, so something like `.seriousError.seriousError` gets translated to `.seriousError`. In addition, it won't produce selectors that can't match anything, like `#main#footer`. #### Extending Complex Selectors Class selectors aren't the only things that can be extended. It's possible to extend any selector involving only a single element, such as `.special.cool`, `a:hover`, or `a.user[href^="http://"]`. For example: .hoverlink {@extend a:hover} Just like with classes, this means that all styles defined for `a:hover` are also applied to `.hoverlink`. For example: .hoverlink {@extend a:hover} a:hover {text-decoration: underline} is compiled to: a:hover, .hoverlink {text-decoration: underline} Just like with `.error.intrusion` above, any rule that uses `a:hover` will also work for `.hoverlink`, even if they have other selectors as well. For example: .hoverlink {@extend a:hover} .comment a.user:hover {font-weight: bold} is compiled to: .comment a.user:hover, .comment .hoverlink.user {font-weight: bold} #### Multiple Extends A single selector can extend more than one selector. This means that it inherits the styles of all the extended selectors. For example: .error { border: 1px #f00; background-color: #fdd; } .attention { font-size: 3em; background-color: #ff0; } .seriousError { @extend .error; @extend .attention; border-width: 3px; } is compiled to: .error, .seriousError { border: 1px #f00; background-color: #fdd; } .attention, .seriousError { font-size: 3em; background-color: #ff0; } .seriousError { border-width: 3px; } In effect, everything with class `.seriousError` also has class `.error` *and* class `.attention`. Thus, the styles defined later in the document take precedence: `.seriousError` has background color `#ff0` rather than `#fdd`, since `.attention` is defined later than `.error`. #### Chaining Extends It's possible for one selector to extend another selector that in turn extends a third. For example: .error { border: 1px #f00; background-color: #fdd; } .seriousError { @extend .error; border-width: 3px; } .criticalError { @extend .seriousError; position: fixed; top: 10%; bottom: 10%; left: 10%; right: 10%; } Now everything with class `.seriousError` also has class `.error`, and everything with class `.criticalError` has class `.seriousError` *and* class `.error`. It's compiled to: .error, .seriousError, .criticalError { border: 1px #f00; background-color: #fdd; } .seriousError, .criticalError { border-width: 3px; } .criticalError { position: fixed; top: 10%; bottom: 10%; left: 10%; right: 10%; } #### Selector Sequences Selector sequences, such as `.foo .bar` or `.foo + .bar`, currently can't be extended. However, it is possible for nested selectors themselves to use `@extend`. For example: #fake-links .link {@extend a} a { color: blue; &:hover {text-decoration: underline} } is compiled to a, #fake-links .link { color: blue; } a:hover, #fake-links .link:hover { text-decoration: underline; } ##### Merging Selector Sequences Sometimes a selector sequence extends another selector that appears in another sequence. In this case, the two sequences need to be merged. For example: #admin .tabbar a {font-weight: bold} #demo .overview .fakelink {@extend a} While it would technically be possible to generate all selectors that could possibly match either sequence, this would make the stylesheet far too large. The simple example above, for instance, would require ten selectors. Instead, Sass generates only selectors that are likely to be useful. When the two sequences being merged have no selectors in common, then two new selectors are generated: one with the first sequence before the second, and one with the second sequence before the first. For example: #admin .tabbar a {font-weight: bold} #demo .overview .fakelink {@extend a} is compiled to: #admin .tabbar a, #admin .tabbar #demo .overview .fakelink, #demo .overview #admin .tabbar .fakelink { font-weight: bold; } If the two sequences do share some selectors, then those selectors will be merged together and only the differences (if any still exist) will alternate. In this example, both sequences contain the id `#admin`, so the resulting selectors will merge those two ids: #admin .tabbar a {font-weight: bold} #admin .overview .fakelink {@extend a} This is compiled to: #admin .tabbar a, #admin .tabbar .overview .fakelink, #admin .overview .tabbar .fakelink { font-weight: bold; } ### `@debug` The `@debug` directive prints the value of a SassScript expression to the standard error output stream. It's useful for debugging Sass files that have complicated SassScript going on. For example: @debug 10em + 12em; outputs: Line 1 DEBUG: 22em ### `@warn` The `@warn` directive prints the value of a SassScript expression to the standard error output stream. It's useful for libraries that need to warn users of deprecations or recovering from minor mixin usage mistakes. There are two major distinctions between `@warn` and `@debug`: 1. You can turn warnings off with the `--quiet` command-line option or the `:quiet` Sass option. 2. A stylesheet trace will be printed out along with the message so that the user being warned can see where their styles caused the warning. Usage Example: @mixin adjust-location($x, $y) { @if unitless($x) { @warn "Assuming #{$x} to be in pixels"; $x: 1px * $x; } @if unitless($y) { @warn "Assuming #{$y} to be in pixels"; $y: 1px * $y; } position: relative; left: $x; top: $y; } ## Control Directives SassScript supports basic control directives for including styles only under some conditions or including the same style several times with variations. **Note that control directives are an advanced feature, and are not recommended in the course of day-to-day styling**. They exist mainly for use in [mixins](#mixins), particularly those that are part of libraries like [Compass](http://compass-style.org), and so require substantial flexibility. ### `@if` The `@if` directive takes a SassScript expression and uses the styles nested beneath it if the expression returns anything other than `false`: p { @if 1 + 1 == 2 { border: 1px solid; } @if 5 < 3 { border: 2px dotted; } } is compiled to: p { border: 1px solid; } The `@if` statement can be followed by several `@else if` statements and one `@else` statement. If the `@if` statement fails, the `@else if` statements are tried in order until one succeeds or the `@else` is reached. For example: $type: monster; p { @if $type == ocean { color: blue; } @else if $type == matador { color: red; } @else if $type == monster { color: green; } @else { color: black; } } is compiled to: p { color: green; } ### `@for` The `@for` directive has two forms: `@for $var from to ` or `@for $var from through `. `$var` can be any variable name, like `$i`, and `` and `` are SassScript expressions that should return integers. The `@for` statement sets `$var` to each number from `` to ``, including `` if `through` is used. Then it outputs the nested styles using that value of `$var`. For example: @for $i from 1 through 3 { .item-#{$i} { width: 2em * $i; } } is compiled to: .item-1 { width: 2em; } .item-2 { width: 4em; } .item-3 { width: 6em; } ### `@each` {#each-directive} The `@each` rule has the form `@each $var in `. `$var` can be any variable name, like `$length` or `$name`, and `` is a SassScript expression that returns a list. The `@each` rule sets `$var` to each item in the list, then outputs the styles it contains using that value of `$var`. For example: @each $animal in puma, sea-slug, egret, salamander { .#{$animal}-icon { background-image: url('/images/#{$animal}.png'); } } is compiled to: .puma-icon { background-image: url('/images/puma.png'); } .sea-slug-icon { background-image: url('/images/sea-slug.png'); } .egret-icon { background-image: url('/images/egret.png'); } .salamander-icon { background-image: url('/images/salamander.png'); } ### `@while` The `@while` directive takes a SassScript expression and repeatedly outputs the nested styles until the statement evaluates to `false`. This can be used to achieve more complex looping than the `@for` statement is capable of, although this is rarely necessary. For example: $i: 6; @while $i > 0 { .item-#{$i} { width: 2em * $i; } $i: $i - 2; } is compiled to: .item-6 { width: 12em; } .item-4 { width: 8em; } .item-2 { width: 4em; } ## Mixin Directives {#mixins} Mixins allow you to define styles that can be re-used throughout the stylesheet without needing to resort to non-semantic classes like `.float-left`. Mixins can also contain full CSS rules, and anything else allowed elsewhere in a Sass document. They can even take [arguments](#mixin-arguments) which allows you to produce a wide variety of styles with very few mixins. ### Defining a Mixin: `@mixin` {#defining_a_mixin} Mixins are defined with the `@mixin` directive. It's followed by the name of the mixin and optionally the [arguments](#mixin-arguments), and a block containing the contents of the mixin. For example, the `large-text` mixin is defined as follows: @mixin large-text { font: { family: Arial; size: 20px; weight: bold; } color: #ff0000; } Mixins may also contain selectors, possibly mixed with properties. The selectors can even contain [parent references](#referencing_parent_selectors_). For example: @mixin clearfix { display: inline-block; &:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } * html & { height: 1px } } ### Including a Mixin: `@include` {#including_a_mixin} Mixins are included in the document with the `@include` directive. This takes the name of a mixin and optionally [arguments to pass to it](#mixin-arguments), and includes the styles defined by that mixin into the current rule. For example: .page-title { @include large-text; padding: 4px; margin-top: 10px; } is compiled to: .page-title { font-family: Arial; font-size: 20px; font-weight: bold; color: #ff0000; padding: 4px; margin-top: 10px; } Mixins may also be included outside of any rule (that is, at the root of the document) as long as they don't directly define any properties or use any parent references. For example: @mixin silly-links { a { color: blue; background-color: red; } } @include silly-links; is compiled to: a { color: blue; background-color: red; } Mixin definitions can also include other mixins. For example: @mixin compound { @include highlighted-background; @include header-text; } @mixin highlighted-background { background-color: #fc0; } @mixin header-text { font-size: 20px; } Mixins that only define descendent selectors, can be safely mixed into the top most level of a document. ### Arguments {#mixin-arguments} Mixins can take arguments SassScript values as arguments, which are given when the mixin is included and made available within the mixin as variables. When defining a mixin, the arguments are written as variable names separated by commas, all in parentheses after the name. Then when including the mixin, values can be passed in in the same manner. For example: @mixin sexy-border($color, $width) { border: { color: $color; width: $width; style: dashed; } } p { @include sexy-border(blue, 1in); } is compiled to: p { border-color: blue; border-width: 1in; border-style: dashed; } Mixins can also specify default values for their arguments using the normal variable-setting syntax. Then when the mixin is included, if it doesn't pass in that argument, the default value will be used instead. For example: @mixin sexy-border($color, $width: 1in) { border: { color: $color; width: $width; style: dashed; } } p { @include sexy-border(blue); } h1 { @include sexy-border(blue, 2in); } is compiled to: p { border-color: blue; border-width: 1in; border-style: dashed; } h1 { border-color: blue; border-width: 2in; border-style: dashed; } #### Keyword Arguments Mixins can also be included using explicit keyword arguments. For instance, we the above example could be written as: p { @include sexy-border($color: blue); } h1 { @include sexy-border($color: blue, $width: 2in); } While this is less concise, it can make the stylesheet easier to read. It also allows functions to present more flexible interfaces, providing many arguments without becoming difficult to call. Named arguments can be passed in any order, and arguments with default values can be omitted. Since the named arguments are variable names, underscores and dashes can be used interchangeably. ## Function Directives {#functions} It is possible to define your own functions in sass and use them in any value or script context. For example: $grid-width: 40px; $gutter-width: 10px; @function grid-width($n) { @return $n * $grid-width + ($n - 1) * $gutter-width; } #sidebar { width: grid-width(5); } Becomes: #sidebar { width: 240px; } As you can see functions can access any globally defined variables as well as accept arguments just like a mixin. A function may have several statements contained within it, and you must call `@return` to set the return value of the function. As with mixins, you can call Sass-defined functions using keyword arguments. In the above example we could have called the function like this: #sidebar { width: grid-width($n: 5); } It is recommended that you prefix your functions to avoid naming conflicts and so that readers of your stylesheets know they are not part of Sass or CSS. For example, if you work for ACME Corp, you might have named the function above `-acme-grid-width`. ## Output Style Although the default CSS style that Sass outputs is very nice and reflects the structure of the document, tastes and needs vary and so Sass supports several other styles. Sass allows you to choose between four different output styles by setting the [`:style` option](#style-option) or using the `--style` command-line flag. ### `:nested` Nested style is the default Sass style, because it reflects the structure of the CSS styles and the HTML document they're styling. Each property has its own line, but the indentation isn't constant. Each rule is indented based on how deeply it's nested. For example: #main { color: #fff; background-color: #000; } #main p { width: 10em; } .huge { font-size: 10em; font-weight: bold; text-decoration: underline; } Nested style is very useful when looking at large CSS files: it allows you to easily grasp the structure of the file without actually reading anything. ### `:expanded` Expanded is a more typical human-made CSS style, with each property and rule taking up one line. Properties are indented within the rules, but the rules aren't indented in any special way. For example: #main { color: #fff; background-color: #000; } #main p { width: 10em; } .huge { font-size: 10em; font-weight: bold; text-decoration: underline; } ### `:compact` Compact style takes up less space than Nested or Expanded. It also draws the focus more to the selectors than to their properties. Each CSS rule takes up only one line, with every property defined on that line. Nested rules are placed next to each other with no newline, while separate groups of rules have newlines between them. For example: #main { color: #fff; background-color: #000; } #main p { width: 10em; } .huge { font-size: 10em; font-weight: bold; text-decoration: underline; } ### `:compressed` Compressed style takes up the minimum amount of space possible, having no whitespace except that necessary to separate selectors and a newline at the end of the file. It also includes some other minor compressions, such as choosing the smallest representation for colors. It's not meant to be human-readable. For example: #main{color:#fff;background-color:#000}#main p{width:10em}.huge{font-size:10em;font-weight:bold;text-decoration:underline} ## Extending Sass Sass provides a number of advanced customizations for users with unique requirements. Using these features requires a strong understanding of Ruby. ### Defining Custom Sass Functions Users can define their own Sass functions using the Ruby API. For more information, see the [source documentation](Sass/Script/Functions.html#adding_custom_functions). ### Cache Stores Sass caches parsed documents so that they can be reused without parsing them again unless they have changed. By default, Sass will write these cache files to a location on the filesystem indicated by [`:cache_location`](#cache_location-option). If you cannot write to the filesystem or need to share cache across ruby processes or machines, then you can define your own cache store and set the[`:cache_store` option](#cache_store-option). For details on creating your own cache store, please see the {Sass::CacheStores::Base source documentation}. ### Custom Importers Sass importers are in charge of taking paths passed to `@import` and finding the appropriate Sass code for those paths. By default, this code is loaded from the {Sass::Importers::Filesystem filesystem}, but importers could be added to load from a database, over HTTP, or use a different file naming scheme than what Sass expects. Each importer is in charge of a single load path (or whatever the corresponding notion is for the backend). Importers can be placed in the {file:SASS_REFERENCE.md#load_paths-option `:load_paths` array} alongside normal filesystem paths. When resolving an `@import`, Sass will go through the load paths looking for an importer that successfully imports the path. Once one is found, the imported file is used. User-created importers must inherit from {Sass::Importers::Base}. stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/0000775000175000017500000000000012414640747030663 5ustar ebourgebourg././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/test_helper.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/test_help0000664000175000017500000000316112414640747032576 0ustar ebourgebourglib_dir = File.dirname(__FILE__) + '/../lib' require 'test/unit' require 'fileutils' $:.unshift lib_dir unless $:.include?(lib_dir) require 'sass' Sass::RAILS_LOADED = true unless defined?(Sass::RAILS_LOADED) module Sass::Script::Functions def option(name) Sass::Script::String.new(@options[name.value.to_sym].to_s) end end class Test::Unit::TestCase def munge_filename(opts = {}) return if opts.has_key?(:filename) opts[:filename] = filename_for_test(opts[:syntax] || :sass) end def filename_for_test(syntax = :sass) test_name = caller. map {|c| Sass::Util.caller_info(c)[2]}. compact. map {|c| c.sub(/^(block|rescue) in /, '')}. find {|c| c =~ /^test_/} "#{test_name}_inline.#{syntax}" end def clean_up_sassc path = File.dirname(__FILE__) + "/../.sass-cache" FileUtils.rm_r(path) if File.exist?(path) end def assert_warning(message) the_real_stderr, $stderr = $stderr, StringIO.new yield if message.is_a?(Regexp) assert_match message, $stderr.string.strip else assert_equal message.strip, $stderr.string.strip end ensure $stderr = the_real_stderr end def silence_warnings(&block) Sass::Util.silence_warnings(&block) end def assert_raise_message(klass, message) yield rescue Exception => e assert_instance_of(klass, e) assert_equal(message, e.message) else flunk "Expected exception #{klass}, none raised" end def assert_raise_line(line) yield rescue Sass::SyntaxError => e assert_equal(line, e.sass_line) else flunk "Expected exception on line #{line}, none raised" end end stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/0000775000175000017500000000000012414640747031634 5ustar ebourgebourg././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/more_results/stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/more0000775000175000017500000000000012414640747032517 5ustar ebourgebourg././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/more_results/more1.cssstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/more0000664000175000017500000000054212414640747032522 0ustar ebourgebourgbody { font: Arial; background: blue; } #page { width: 700px; height: 100; } #page #header { height: 300px; } #page #header h1 { font-size: 50px; color: blue; } #content.user.show #container.top #column.left { width: 100px; } #content.user.show #container.top #column.right { width: 600px; } #content.user.show #container.bottom { background: brown; } ././@LongLink0000644000000000000000000000017500000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/more_results/more_import.cssstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/more0000664000175000017500000000171712414640747032527 0ustar ebourgebourgimported { otherconst: hello; myconst: goodbye; pre-mixin: here; } body { font: Arial; background: blue; } #page { width: 700px; height: 100; } #page #header { height: 300px; } #page #header h1 { font-size: 50px; color: blue; } #content.user.show #container.top #column.left { width: 100px; } #content.user.show #container.top #column.right { width: 600px; } #content.user.show #container.bottom { background: brown; } midrule { inthe: middle; } body { font: Arial; background: blue; } #page { width: 700px; height: 100; } #page #header { height: 300px; } #page #header h1 { font-size: 50px; color: blue; } #content.user.show #container.top #column.left { width: 100px; } #content.user.show #container.top #column.right { width: 600px; } #content.user.show #container.bottom { background: brown; } @import url(basic.css); @import url(../results/complex.css); #foo { background-color: #bbaaff; } nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; } ././@LongLink0000644000000000000000000000021200000000000011576 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/more_results/more1_with_line_comments.cssstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/more0000664000175000017500000000127612414640747032527 0ustar ebourgebourg/* line 3, ../more_templates/more1.sass */ body { font: Arial; background: blue; } /* line 7, ../more_templates/more1.sass */ #page { width: 700px; height: 100; } /* line 10, ../more_templates/more1.sass */ #page #header { height: 300px; } /* line 12, ../more_templates/more1.sass */ #page #header h1 { font-size: 50px; color: blue; } /* line 18, ../more_templates/more1.sass */ #content.user.show #container.top #column.left { width: 100px; } /* line 20, ../more_templates/more1.sass */ #content.user.show #container.top #column.right { width: 600px; } /* line 22, ../more_templates/more1.sass */ #content.user.show #container.bottom { background: brown; } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/functions_test.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/func0000775000175000017500000013157112414640747032525 0ustar ebourgebourg#!/usr/bin/env ruby require 'test/unit' require File.dirname(__FILE__) + '/../test_helper' require 'sass/script' module Sass::Script::Functions def no_kw_args Sass::Script::String.new("no-kw-args") end def only_var_args(*args) Sass::Script::String.new("only-var-args("+args.map{|a| a.plus(Sass::Script::Number.new(1)).to_s }.join(", ")+")") end declare :only_var_args, [], :var_args => true def only_kw_args(kwargs) Sass::Script::String.new("only-kw-args(" + kwargs.keys.map {|a| a.to_s}.sort.join(", ") + ")") end declare :only_kw_args, [], :var_kwargs => true end module Sass::Script::Functions::UserFunctions def call_options_on_new_literal str = Sass::Script::String.new("foo") str.options[:foo] str end def user_defined Sass::Script::String.new("I'm a user-defined string!") end def _preceding_underscore Sass::Script::String.new("I'm another user-defined string!") end end module Sass::Script::Functions include Sass::Script::Functions::UserFunctions end class SassFunctionTest < Test::Unit::TestCase # Tests taken from: # http://www.w3.org/Style/CSS/Test/CSS3/Color/20070927/html4/t040204-hsl-h-rotating-b.htm # http://www.w3.org/Style/CSS/Test/CSS3/Color/20070927/html4/t040204-hsl-values-b.htm File.read(File.dirname(__FILE__) + "/data/hsl-rgb.txt").split("\n\n").each do |chunk| hsls, rgbs = chunk.strip.split("====") hsls.strip.split("\n").zip(rgbs.strip.split("\n")) do |hsl, rgb| hsl_method = "test_hsl: #{hsl} = #{rgb}" define_method(hsl_method) do assert_equal(evaluate(rgb), evaluate(hsl)) end rgb_to_hsl_method = "test_rgb_to_hsl: #{rgb} = #{hsl}" define_method(rgb_to_hsl_method) do rgb_color = perform(rgb) hsl_color = perform(hsl) white = hsl_color.lightness == 100 black = hsl_color.lightness == 0 grayscale = white || black || hsl_color.saturation == 0 assert_in_delta(hsl_color.hue, rgb_color.hue, 0.0001, "Hues should be equal") unless grayscale assert_in_delta(hsl_color.saturation, rgb_color.saturation, 0.0001, "Saturations should be equal") unless white || black assert_in_delta(hsl_color.lightness, rgb_color.lightness, 0.0001, "Lightnesses should be equal") end end end def test_hsl_kwargs assert_equal "#33cccc", evaluate("hsl($hue: 180, $saturation: 60%, $lightness: 50%)") end def test_hsl_checks_bounds assert_error_message("Saturation -114 must be between 0% and 100% for `hsl'", "hsl(10, -114, 12)"); assert_error_message("Lightness 256 must be between 0% and 100% for `hsl'", "hsl(10, 10, 256%)"); end def test_hsl_checks_types assert_error_message("\"foo\" is not a number for `hsl'", "hsl(\"foo\", 10, 12)"); assert_error_message("\"foo\" is not a number for `hsl'", "hsl(10, \"foo\", 12)"); assert_error_message("\"foo\" is not a number for `hsl'", "hsl(10, 10, \"foo\")"); end def test_hsla assert_equal "rgba(51, 204, 204, 0.4)", evaluate("hsla(180, 60%, 50%, 0.4)") assert_equal "#33cccc", evaluate("hsla(180, 60%, 50%, 1)") assert_equal "rgba(51, 204, 204, 0)", evaluate("hsla(180, 60%, 50%, 0)") assert_equal "rgba(51, 204, 204, 0.4)", evaluate("hsla($hue: 180, $saturation: 60%, $lightness: 50%, $alpha: 0.4)") end def test_hsla_checks_bounds assert_error_message("Saturation -114 must be between 0% and 100% for `hsla'", "hsla(10, -114, 12, 1)"); assert_error_message("Lightness 256 must be between 0% and 100% for `hsla'", "hsla(10, 10, 256%, 0)"); assert_error_message("Alpha channel -0.1 must be between 0 and 1 for `hsla'", "hsla(10, 10, 10, -0.1)"); assert_error_message("Alpha channel 1.1 must be between 0 and 1 for `hsla'", "hsla(10, 10, 10, 1.1)"); end def test_hsla_checks_types assert_error_message("\"foo\" is not a number for `hsla'", "hsla(\"foo\", 10, 12, 0.3)"); assert_error_message("\"foo\" is not a number for `hsla'", "hsla(10, \"foo\", 12, 0)"); assert_error_message("\"foo\" is not a number for `hsla'", "hsla(10, 10, \"foo\", 1)"); assert_error_message("\"foo\" is not a number for `hsla'", "hsla(10, 10, 10, \"foo\")"); end def test_percentage assert_equal("50%", evaluate("percentage(.5)")) assert_equal("100%", evaluate("percentage(1)")) assert_equal("25%", evaluate("percentage(25px / 100px)")) assert_equal("50%", evaluate("percentage($value: 0.5)")) end def test_percentage_checks_types assert_error_message("25px is not a unitless number for `percentage'", "percentage(25px)") assert_error_message("#cccccc is not a unitless number for `percentage'", "percentage(#ccc)") assert_error_message("\"string\" is not a unitless number for `percentage'", %Q{percentage("string")}) end def test_round assert_equal("5", evaluate("round(4.8)")) assert_equal("5px", evaluate("round(4.8px)")) assert_equal("5px", evaluate("round(5.49px)")) assert_equal("5px", evaluate("round($value: 5.49px)")) assert_error_message("#cccccc is not a number for `round'", "round(#ccc)") end def test_floor assert_equal("4", evaluate("floor(4.8)")) assert_equal("4px", evaluate("floor(4.8px)")) assert_equal("4px", evaluate("floor($value: 4.8px)")) assert_error_message("\"foo\" is not a number for `floor'", "floor(\"foo\")") end def test_ceil assert_equal("5", evaluate("ceil(4.1)")) assert_equal("5px", evaluate("ceil(4.8px)")) assert_equal("5px", evaluate("ceil($value: 4.8px)")) assert_error_message("\"a\" is not a number for `ceil'", "ceil(\"a\")") end def test_abs assert_equal("5", evaluate("abs(-5)")) assert_equal("5px", evaluate("abs(-5px)")) assert_equal("5", evaluate("abs(5)")) assert_equal("5px", evaluate("abs(5px)")) assert_equal("5px", evaluate("abs($value: 5px)")) assert_error_message("#aaaaaa is not a number for `abs'", "abs(#aaa)") end def test_rgb assert_equal("#123456", evaluate("rgb(18, 52, 86)")) assert_equal("#beaded", evaluate("rgb(190, 173, 237)")) assert_equal("#00ff7f", evaluate("rgb(0, 255, 127)")) assert_equal("#00ff7f", evaluate("rgb($red: 0, $green: 255, $blue: 127)")) end def test_rgb_percent assert_equal("#123456", evaluate("rgb(7.1%, 20.4%, 34%)")) assert_equal("#beaded", evaluate("rgb(74.7%, 173, 93%)")) assert_equal("#beaded", evaluate("rgb(190, 68%, 237)")) assert_equal("#00ff7f", evaluate("rgb(0%, 100%, 50%)")) end def test_rgb_tests_bounds assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'", "rgb(256, 1, 1)") assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'", "rgb(1, 256, 1)") assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'", "rgb(1, 1, 256)") assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'", "rgb(1, 256, 257)") assert_error_message("Color value -1 must be between 0 and 255 inclusive for `rgb'", "rgb(-1, 1, 1)") end def test_rgb_test_percent_bounds assert_error_message("Color value 100.1% must be between 0% and 100% inclusive for `rgb'", "rgb(100.1%, 0, 0)") assert_error_message("Color value -0.1% must be between 0% and 100% inclusive for `rgb'", "rgb(0, -0.1%, 0)") assert_error_message("Color value 101% must be between 0% and 100% inclusive for `rgb'", "rgb(0, 0, 101%)") end def test_rgb_tests_types assert_error_message("\"foo\" is not a number for `rgb'", "rgb(\"foo\", 10, 12)"); assert_error_message("\"foo\" is not a number for `rgb'", "rgb(10, \"foo\", 12)"); assert_error_message("\"foo\" is not a number for `rgb'", "rgb(10, 10, \"foo\")"); end def test_rgba assert_equal("rgba(18, 52, 86, 0.5)", evaluate("rgba(18, 52, 86, 0.5)")) assert_equal("#beaded", evaluate("rgba(190, 173, 237, 1)")) assert_equal("rgba(0, 255, 127, 0)", evaluate("rgba(0, 255, 127, 0)")) assert_equal("rgba(0, 255, 127, 0)", evaluate("rgba($red: 0, $green: 255, $blue: 127, $alpha: 0)")) end def test_rgb_tests_bounds assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'", "rgba(256, 1, 1, 0.3)") assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'", "rgba(1, 256, 1, 0.3)") assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'", "rgba(1, 1, 256, 0.3)") assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'", "rgba(1, 256, 257, 0.3)") assert_error_message("Color value -1 must be between 0 and 255 inclusive for `rgba'", "rgba(-1, 1, 1, 0.3)") assert_error_message("Alpha channel -0.2 must be between 0 and 1 inclusive for `rgba'", "rgba(1, 1, 1, -0.2)") assert_error_message("Alpha channel 1.2 must be between 0 and 1 inclusive for `rgba'", "rgba(1, 1, 1, 1.2)") end def test_rgba_tests_types assert_error_message("\"foo\" is not a number for `rgba'", "rgba(\"foo\", 10, 12, 0.2)"); assert_error_message("\"foo\" is not a number for `rgba'", "rgba(10, \"foo\", 12, 0.1)"); assert_error_message("\"foo\" is not a number for `rgba'", "rgba(10, 10, \"foo\", 0)"); assert_error_message("\"foo\" is not a number for `rgba'", "rgba(10, 10, 10, \"foo\")"); end def test_rgba_with_color assert_equal "rgba(16, 32, 48, 0.5)", evaluate("rgba(#102030, 0.5)") assert_equal "rgba(0, 0, 255, 0.5)", evaluate("rgba(blue, 0.5)") assert_equal "rgba(0, 0, 255, 0.5)", evaluate("rgba($color: blue, $alpha: 0.5)") end def test_rgba_with_color_tests_types assert_error_message("\"foo\" is not a color for `rgba'", "rgba(\"foo\", 0.2)"); assert_error_message("\"foo\" is not a number for `rgba'", "rgba(blue, \"foo\")"); end def test_rgba_tests_num_args assert_error_message("wrong number of arguments (0 for 4) for `rgba'", "rgba()"); assert_error_message("wrong number of arguments (1 for 4) for `rgba'", "rgba(blue)"); assert_error_message("wrong number of arguments (3 for 4) for `rgba'", "rgba(1, 2, 3)"); assert_error_message("wrong number of arguments (5 for 4) for `rgba'", "rgba(1, 2, 3, 0.4, 5)"); end def test_red assert_equal("18", evaluate("red(#123456)")) assert_equal("18", evaluate("red($color: #123456)")) end def test_red_exception assert_error_message("12 is not a color for `red'", "red(12)") end def test_green assert_equal("52", evaluate("green(#123456)")) assert_equal("52", evaluate("green($color: #123456)")) end def test_green_exception assert_error_message("12 is not a color for `green'", "green(12)") end def test_blue assert_equal("86", evaluate("blue(#123456)")) assert_equal("86", evaluate("blue($color: #123456)")) end def test_blue_exception assert_error_message("12 is not a color for `blue'", "blue(12)") end def test_hue assert_equal("18deg", evaluate("hue(hsl(18, 50%, 20%))")) assert_equal("18deg", evaluate("hue($color: hsl(18, 50%, 20%))")) end def test_hue_exception assert_error_message("12 is not a color for `hue'", "hue(12)") end def test_saturation assert_equal("52%", evaluate("saturation(hsl(20, 52%, 20%))")) assert_equal("52%", evaluate("saturation(hsl(20, 52, 20%))")) assert_equal("52%", evaluate("saturation($color: hsl(20, 52, 20%))")) end def test_saturation_exception assert_error_message("12 is not a color for `saturation'", "saturation(12)") end def test_lightness assert_equal("86%", evaluate("lightness(hsl(120, 50%, 86%))")) assert_equal("86%", evaluate("lightness(hsl(120, 50%, 86))")) assert_equal("86%", evaluate("lightness($color: hsl(120, 50%, 86))")) end def test_lightness_exception assert_error_message("12 is not a color for `lightness'", "lightness(12)") end def test_alpha assert_equal("1", evaluate("alpha(#123456)")) assert_equal("0.34", evaluate("alpha(rgba(0, 1, 2, 0.34))")) assert_equal("0", evaluate("alpha(hsla(0, 1, 2, 0))")) assert_equal("0", evaluate("alpha($color: hsla(0, 1, 2, 0))")) end def test_alpha_exception assert_error_message("12 is not a color for `alpha'", "alpha(12)") end def test_opacify assert_equal("rgba(0, 0, 0, 0.75)", evaluate("opacify(rgba(0, 0, 0, 0.5), 0.25)")) assert_equal("rgba(0, 0, 0, 0.3)", evaluate("opacify(rgba(0, 0, 0, 0.2), 0.1)")) assert_equal("rgba(0, 0, 0, 0.7)", evaluate("fade-in(rgba(0, 0, 0, 0.2), 0.5px)")) assert_equal("black", evaluate("fade_in(rgba(0, 0, 0, 0.2), 0.8)")) assert_equal("black", evaluate("opacify(rgba(0, 0, 0, 0.2), 1)")) assert_equal("rgba(0, 0, 0, 0.2)", evaluate("opacify(rgba(0, 0, 0, 0.2), 0%)")) assert_equal("rgba(0, 0, 0, 0.2)", evaluate("opacify($color: rgba(0, 0, 0, 0.2), $amount: 0%)")) assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-in($color: rgba(0, 0, 0, 0.2), $amount: 0%)")) end def test_opacify_tests_bounds assert_error_message("Amount -0.001 must be between 0 and 1 for `opacify'", "opacify(rgba(0, 0, 0, 0.2), -0.001)") assert_error_message("Amount 1.001 must be between 0 and 1 for `opacify'", "opacify(rgba(0, 0, 0, 0.2), 1.001)") end def test_opacify_tests_types assert_error_message("\"foo\" is not a color for `opacify'", "opacify(\"foo\", 10%)") assert_error_message("\"foo\" is not a number for `opacify'", "opacify(#fff, \"foo\")") end def test_transparentize assert_equal("rgba(0, 0, 0, 0.3)", evaluate("transparentize(rgba(0, 0, 0, 0.5), 0.2)")) assert_equal("rgba(0, 0, 0, 0.1)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 0.1)")) assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-out(rgba(0, 0, 0, 0.5), 0.3px)")) assert_equal("rgba(0, 0, 0, 0)", evaluate("fade_out(rgba(0, 0, 0, 0.2), 0.2)")) assert_equal("rgba(0, 0, 0, 0)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 1)")) assert_equal("rgba(0, 0, 0, 0.2)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 0)")) assert_equal("rgba(0, 0, 0, 0.2)", evaluate("transparentize($color: rgba(0, 0, 0, 0.2), $amount: 0)")) assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-out($color: rgba(0, 0, 0, 0.2), $amount: 0)")) end def test_transparentize_tests_bounds assert_error_message("Amount -0.001 must be between 0 and 1 for `transparentize'", "transparentize(rgba(0, 0, 0, 0.2), -0.001)") assert_error_message("Amount 1.001 must be between 0 and 1 for `transparentize'", "transparentize(rgba(0, 0, 0, 0.2), 1.001)") end def test_transparentize_tests_types assert_error_message("\"foo\" is not a color for `transparentize'", "transparentize(\"foo\", 10%)") assert_error_message("\"foo\" is not a number for `transparentize'", "transparentize(#fff, \"foo\")") end def test_lighten assert_equal("#4d4d4d", evaluate("lighten(hsl(0, 0, 0), 30%)")) assert_equal("#ee0000", evaluate("lighten(#800, 20%)")) assert_equal("white", evaluate("lighten(#fff, 20%)")) assert_equal("white", evaluate("lighten(#800, 100%)")) assert_equal("#880000", evaluate("lighten(#800, 0%)")) assert_equal("rgba(238, 0, 0, 0.5)", evaluate("lighten(rgba(136, 0, 0, 0.5), 20%)")) assert_equal("rgba(238, 0, 0, 0.5)", evaluate("lighten($color: rgba(136, 0, 0, 0.5), $amount: 20%)")) end def test_lighten_tests_bounds assert_error_message("Amount -0.001 must be between 0% and 100% for `lighten'", "lighten(#123, -0.001)") assert_error_message("Amount 100.001 must be between 0% and 100% for `lighten'", "lighten(#123, 100.001)") end def test_lighten_tests_types assert_error_message("\"foo\" is not a color for `lighten'", "lighten(\"foo\", 10%)") assert_error_message("\"foo\" is not a number for `lighten'", "lighten(#fff, \"foo\")") end def test_darken assert_equal("#ff6a00", evaluate("darken(hsl(25, 100, 80), 30%)")) assert_equal("#220000", evaluate("darken(#800, 20%)")) assert_equal("black", evaluate("darken(#000, 20%)")) assert_equal("black", evaluate("darken(#800, 100%)")) assert_equal("#880000", evaluate("darken(#800, 0%)")) assert_equal("rgba(34, 0, 0, 0.5)", evaluate("darken(rgba(136, 0, 0, 0.5), 20%)")) assert_equal("rgba(34, 0, 0, 0.5)", evaluate("darken($color: rgba(136, 0, 0, 0.5), $amount: 20%)")) end def test_darken_tests_bounds assert_error_message("Amount -0.001 must be between 0% and 100% for `darken'", "darken(#123, -0.001)") assert_error_message("Amount 100.001 must be between 0% and 100% for `darken'", "darken(#123, 100.001)") end def test_darken_tests_types assert_error_message("\"foo\" is not a color for `darken'", "darken(\"foo\", 10%)") assert_error_message("\"foo\" is not a number for `darken'", "darken(#fff, \"foo\")") end def test_saturate assert_equal("#d9f2d9", evaluate("saturate(hsl(120, 30, 90), 20%)")) assert_equal("#9e3f3f", evaluate("saturate(#855, 20%)")) assert_equal("black", evaluate("saturate(#000, 20%)")) assert_equal("white", evaluate("saturate(#fff, 20%)")) assert_equal("#33ff33", evaluate("saturate(#8a8, 100%)")) assert_equal("#88aa88", evaluate("saturate(#8a8, 0%)")) assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate(rgba(136, 85, 85, 0.5), 20%)")) assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate($color: rgba(136, 85, 85, 0.5), $amount: 20%)")) end def test_saturate_tests_bounds assert_error_message("Amount -0.001 must be between 0% and 100% for `saturate'", "saturate(#123, -0.001)") assert_error_message("Amount 100.001 must be between 0% and 100% for `saturate'", "saturate(#123, 100.001)") end def test_saturate_tests_types assert_error_message("\"foo\" is not a color for `saturate'", "saturate(\"foo\", 10%)") assert_error_message("\"foo\" is not a number for `saturate'", "saturate(#fff, \"foo\")") end def test_desaturate assert_equal("#e3e8e3", evaluate("desaturate(hsl(120, 30, 90), 20%)")) assert_equal("#726b6b", evaluate("desaturate(#855, 20%)")) assert_equal("black", evaluate("desaturate(#000, 20%)")) assert_equal("white", evaluate("desaturate(#fff, 20%)")) assert_equal("#999999", evaluate("desaturate(#8a8, 100%)")) assert_equal("#88aa88", evaluate("desaturate(#8a8, 0%)")) assert_equal("rgba(114, 107, 107, 0.5)", evaluate("desaturate(rgba(136, 85, 85, 0.5), 20%)")) assert_equal("rgba(114, 107, 107, 0.5)", evaluate("desaturate($color: rgba(136, 85, 85, 0.5), $amount: 20%)")) end def test_desaturate_tests_bounds assert_error_message("Amount -0.001 must be between 0% and 100% for `desaturate'", "desaturate(#123, -0.001)") assert_error_message("Amount 100.001 must be between 0% and 100% for `desaturate'", "desaturate(#123, 100.001)") end def test_desaturate_tests_types assert_error_message("\"foo\" is not a color for `desaturate'", "desaturate(\"foo\", 10%)") assert_error_message("\"foo\" is not a number for `desaturate'", "desaturate(#fff, \"foo\")") end def test_adjust_hue assert_equal("#deeded", evaluate("adjust-hue(hsl(120, 30, 90), 60deg)")) assert_equal("#ededde", evaluate("adjust-hue(hsl(120, 30, 90), -60deg)")) assert_equal("#886a11", evaluate("adjust-hue(#811, 45deg)")) assert_equal("black", evaluate("adjust-hue(#000, 45deg)")) assert_equal("white", evaluate("adjust-hue(#fff, 45deg)")) assert_equal("#88aa88", evaluate("adjust-hue(#8a8, 360deg)")) assert_equal("#88aa88", evaluate("adjust-hue(#8a8, 0deg)")) assert_equal("rgba(136, 106, 17, 0.5)", evaluate("adjust-hue(rgba(136, 17, 17, 0.5), 45deg)")) assert_equal("rgba(136, 106, 17, 0.5)", evaluate("adjust-hue($color: rgba(136, 17, 17, 0.5), $degrees: 45deg)")) end def test_adjust_hue_tests_types assert_error_message("\"foo\" is not a color for `adjust-hue'", "adjust-hue(\"foo\", 10%)") assert_error_message("\"foo\" is not a number for `adjust-hue'", "adjust-hue(#fff, \"foo\")") end def test_adjust_color # HSL assert_equal(evaluate("hsl(180, 30, 90)"), evaluate("adjust-color(hsl(120, 30, 90), $hue: 60deg)")) assert_equal(evaluate("hsl(120, 50, 90)"), evaluate("adjust-color(hsl(120, 30, 90), $saturation: 20%)")) assert_equal(evaluate("hsl(120, 30, 60)"), evaluate("adjust-color(hsl(120, 30, 90), $lightness: -30%)")) # RGB assert_equal(evaluate("rgb(15, 20, 30)"), evaluate("adjust-color(rgb(10, 20, 30), $red: 5)")) assert_equal(evaluate("rgb(10, 15, 30)"), evaluate("adjust-color(rgb(10, 20, 30), $green: -5)")) assert_equal(evaluate("rgb(10, 20, 40)"), evaluate("adjust-color(rgb(10, 20, 30), $blue: 10)")) # Alpha assert_equal(evaluate("hsla(120, 30, 90, 0.65)"), evaluate("adjust-color(hsl(120, 30, 90), $alpha: -0.35)")) assert_equal(evaluate("rgba(10, 20, 30, 0.9)"), evaluate("adjust-color(rgba(10, 20, 30, 0.4), $alpha: 0.5)")) # HSL composability assert_equal(evaluate("hsl(180, 20, 90)"), evaluate("adjust-color(hsl(120, 30, 90), $hue: 60deg, $saturation: -10%)")) assert_equal(evaluate("hsl(180, 20, 95)"), evaluate("adjust-color(hsl(120, 30, 90), $hue: 60deg, $saturation: -10%, $lightness: 5%)")) assert_equal(evaluate("hsla(120, 20, 95, 0.3)"), evaluate("adjust-color(hsl(120, 30, 90), $saturation: -10%, $lightness: 5%, $alpha: -0.7)")) # RGB composability assert_equal(evaluate("rgb(15, 20, 29)"), evaluate("adjust-color(rgb(10, 20, 30), $red: 5, $blue: -1)")) assert_equal(evaluate("rgb(15, 45, 29)"), evaluate("adjust-color(rgb(10, 20, 30), $red: 5, $green: 25, $blue: -1)")) assert_equal(evaluate("rgba(10, 25, 29, 0.7)"), evaluate("adjust-color(rgb(10, 20, 30), $green: 5, $blue: -1, $alpha: -0.3)")) # HSL range restriction assert_equal(evaluate("hsl(120, 30, 90)"), evaluate("adjust-color(hsl(120, 30, 90), $hue: 720deg)")) assert_equal(evaluate("hsl(120, 0, 90)"), evaluate("adjust-color(hsl(120, 30, 90), $saturation: -90%)")) assert_equal(evaluate("hsl(120, 30, 100)"), evaluate("adjust-color(hsl(120, 30, 90), $lightness: 30%)")) # RGB range restriction assert_equal(evaluate("rgb(255, 20, 30)"), evaluate("adjust-color(rgb(10, 20, 30), $red: 250)")) assert_equal(evaluate("rgb(10, 0, 30)"), evaluate("adjust-color(rgb(10, 20, 30), $green: -30)")) assert_equal(evaluate("rgb(10, 20, 0)"), evaluate("adjust-color(rgb(10, 20, 30), $blue: -40)")) end def test_adjust_color_tests_types assert_error_message("\"foo\" is not a color for `adjust-color'", "adjust-color(foo, $hue: 10)") # HSL assert_error_message("$hue: \"foo\" is not a number for `adjust-color'", "adjust-color(blue, $hue: foo)") assert_error_message("$saturation: \"foo\" is not a number for `adjust-color'", "adjust-color(blue, $saturation: foo)") assert_error_message("$lightness: \"foo\" is not a number for `adjust-color'", "adjust-color(blue, $lightness: foo)") # RGB assert_error_message("$red: \"foo\" is not a number for `adjust-color'", "adjust-color(blue, $red: foo)") assert_error_message("$green: \"foo\" is not a number for `adjust-color'", "adjust-color(blue, $green: foo)") assert_error_message("$blue: \"foo\" is not a number for `adjust-color'", "adjust-color(blue, $blue: foo)") # Alpha assert_error_message("$alpha: \"foo\" is not a number for `adjust-color'", "adjust-color(blue, $alpha: foo)") end def test_adjust_color_tests_arg_range # HSL assert_error_message("$saturation: Amount 101% must be between -100% and 100% for `adjust-color'", "adjust-color(blue, $saturation: 101%)") assert_error_message("$saturation: Amount -101% must be between -100% and 100% for `adjust-color'", "adjust-color(blue, $saturation: -101%)") assert_error_message("$lightness: Amount 101% must be between -100% and 100% for `adjust-color'", "adjust-color(blue, $lightness: 101%)") assert_error_message("$lightness: Amount -101% must be between -100% and 100% for `adjust-color'", "adjust-color(blue, $lightness: -101%)") # RGB assert_error_message("$red: Amount 256 must be between -255 and 255 for `adjust-color'", "adjust-color(blue, $red: 256)") assert_error_message("$red: Amount -256 must be between -255 and 255 for `adjust-color'", "adjust-color(blue, $red: -256)") assert_error_message("$green: Amount 256 must be between -255 and 255 for `adjust-color'", "adjust-color(blue, $green: 256)") assert_error_message("$green: Amount -256 must be between -255 and 255 for `adjust-color'", "adjust-color(blue, $green: -256)") assert_error_message("$blue: Amount 256 must be between -255 and 255 for `adjust-color'", "adjust-color(blue, $blue: 256)") assert_error_message("$blue: Amount -256 must be between -255 and 255 for `adjust-color'", "adjust-color(blue, $blue: -256)") # Alpha assert_error_message("$alpha: Amount 1.1 must be between -1 and 1 for `adjust-color'", "adjust-color(blue, $alpha: 1.1)") assert_error_message("$alpha: Amount -1.1 must be between -1 and 1 for `adjust-color'", "adjust-color(blue, $alpha: -1.1)") end def test_adjust_color_argument_errors assert_error_message("Unknown argument $hoo (260deg) for `adjust-color'", "adjust-color(blue, $hoo: 260deg)") assert_error_message("Cannot specify HSL and RGB values for a color at the same time for `adjust-color'", "adjust-color(blue, $hue: 120deg, $red: 10)"); assert_error_message("10px is not a keyword argument for `adjust_color'", "adjust-color(blue, 10px)") assert_error_message("10px is not a keyword argument for `adjust_color'", "adjust-color(blue, 10px, 20px)") assert_error_message("10px is not a keyword argument for `adjust_color'", "adjust-color(blue, 10px, $hue: 180deg)") end def test_scale_color # HSL assert_equal(evaluate("hsl(120, 51, 90)"), evaluate("scale-color(hsl(120, 30, 90), $saturation: 30%)")) assert_equal(evaluate("hsl(120, 30, 76.5)"), evaluate("scale-color(hsl(120, 30, 90), $lightness: -15%)")) # RGB assert_equal(evaluate("rgb(157, 20, 30)"), evaluate("scale-color(rgb(10, 20, 30), $red: 60%)")) assert_equal(evaluate("rgb(10, 38.8, 30)"), evaluate("scale-color(rgb(10, 20, 30), $green: 8%)")) assert_equal(evaluate("rgb(10, 20, 20)"), evaluate("scale-color(rgb(10, 20, 30), $blue: -(1/3)*100%)")) # Alpha assert_equal(evaluate("hsla(120, 30, 90, 0.86)"), evaluate("scale-color(hsl(120, 30, 90), $alpha: -14%)")) assert_equal(evaluate("rgba(10, 20, 30, 0.82)"), evaluate("scale-color(rgba(10, 20, 30, 0.8), $alpha: 10%)")) # HSL composability assert_equal(evaluate("hsl(120, 51, 76.5)"), evaluate("scale-color(hsl(120, 30, 90), $saturation: 30%, $lightness: -15%)")) assert_equal(evaluate("hsla(120, 51, 90, 0.2)"), evaluate("scale-color(hsl(120, 30, 90), $saturation: 30%, $alpha: -80%)")) # RGB composability assert_equal(evaluate("rgb(157, 38.8, 30)"), evaluate("scale-color(rgb(10, 20, 30), $red: 60%, $green: 8%)")) assert_equal(evaluate("rgb(157, 38.8, 20)"), evaluate("scale-color(rgb(10, 20, 30), $red: 60%, $green: 8%, $blue: -(1/3)*100%)")) assert_equal(evaluate("rgba(10, 38.8, 20, 0.55)"), evaluate("scale-color(rgba(10, 20, 30, 0.5), $green: 8%, $blue: -(1/3)*100%, $alpha: 10%)")) # Extremes assert_equal(evaluate("hsl(120, 100, 90)"), evaluate("scale-color(hsl(120, 30, 90), $saturation: 100%)")) assert_equal(evaluate("hsl(120, 30, 90)"), evaluate("scale-color(hsl(120, 30, 90), $saturation: 0%)")) assert_equal(evaluate("hsl(120, 0, 90)"), evaluate("scale-color(hsl(120, 30, 90), $saturation: -100%)")) end def test_scale_color_tests_types assert_error_message("\"foo\" is not a color for `scale-color'", "scale-color(foo, $red: 10%)") # HSL assert_error_message("$saturation: \"foo\" is not a number for `scale-color'", "scale-color(blue, $saturation: foo)") assert_error_message("$lightness: \"foo\" is not a number for `scale-color'", "scale-color(blue, $lightness: foo)") # RGB assert_error_message("$red: \"foo\" is not a number for `scale-color'", "scale-color(blue, $red: foo)") assert_error_message("$green: \"foo\" is not a number for `scale-color'", "scale-color(blue, $green: foo)") assert_error_message("$blue: \"foo\" is not a number for `scale-color'", "scale-color(blue, $blue: foo)") # Alpha assert_error_message("$alpha: \"foo\" is not a number for `scale-color'", "scale-color(blue, $alpha: foo)") end def test_scale_color_argument_errors # Range assert_error_message("$saturation: Amount 101% must be between -100% and 100% for `scale-color'", "scale-color(blue, $saturation: 101%)") assert_error_message("$red: Amount -101% must be between -100% and 100% for `scale-color'", "scale-color(blue, $red: -101%)") assert_error_message("$alpha: Amount -101% must be between -100% and 100% for `scale-color'", "scale-color(blue, $alpha: -101%)") # Unit assert_error_message("$saturation: Amount 80 must be a % (e.g. 80%) for `scale-color'", "scale-color(blue, $saturation: 80)") assert_error_message("$alpha: Amount 0.5 must be a % (e.g. 0.5%) for `scale-color'", "scale-color(blue, $alpha: 0.5)") # Unknown argument assert_error_message("Unknown argument $hue (80%) for `scale-color'", "scale-color(blue, $hue: 80%)") # Non-keyword arg assert_error_message("10px is not a keyword argument for `scale_color'", "scale-color(blue, 10px)") # HSL/RGB assert_error_message("Cannot specify HSL and RGB values for a color at the same time for `scale-color'", "scale-color(blue, $lightness: 10%, $red: 20%)"); end def test_change_color # HSL assert_equal(evaluate("hsl(195, 30, 90)"), evaluate("change-color(hsl(120, 30, 90), $hue: 195deg)")) assert_equal(evaluate("hsl(120, 50, 90)"), evaluate("change-color(hsl(120, 30, 90), $saturation: 50%)")) assert_equal(evaluate("hsl(120, 30, 40)"), evaluate("change-color(hsl(120, 30, 90), $lightness: 40%)")) # RGB assert_equal(evaluate("rgb(123, 20, 30)"), evaluate("change-color(rgb(10, 20, 30), $red: 123)")) assert_equal(evaluate("rgb(10, 234, 30)"), evaluate("change-color(rgb(10, 20, 30), $green: 234)")) assert_equal(evaluate("rgb(10, 20, 198)"), evaluate("change-color(rgb(10, 20, 30), $blue: 198)")) # Alpha assert_equal(evaluate("rgba(10, 20, 30, 0.76)"), evaluate("change-color(rgb(10, 20, 30), $alpha: 0.76)")) # HSL composability assert_equal(evaluate("hsl(56, 30, 47)"), evaluate("change-color(hsl(120, 30, 90), $hue: 56deg, $lightness: 47%)")) assert_equal(evaluate("hsla(56, 30, 47, 0.9)"), evaluate("change-color(hsl(120, 30, 90), $hue: 56deg, $lightness: 47%, $alpha: 0.9)")) end def test_change_color_tests_types assert_error_message("\"foo\" is not a color for `change-color'", "change-color(foo, $red: 10%)") # HSL assert_error_message("$saturation: \"foo\" is not a number for `change-color'", "change-color(blue, $saturation: foo)") assert_error_message("$lightness: \"foo\" is not a number for `change-color'", "change-color(blue, $lightness: foo)") # RGB assert_error_message("$red: \"foo\" is not a number for `change-color'", "change-color(blue, $red: foo)") assert_error_message("$green: \"foo\" is not a number for `change-color'", "change-color(blue, $green: foo)") assert_error_message("$blue: \"foo\" is not a number for `change-color'", "change-color(blue, $blue: foo)") # Alpha assert_error_message("$alpha: \"foo\" is not a number for `change-color'", "change-color(blue, $alpha: foo)") end def test_change_color_argument_errors # Range assert_error_message("Saturation must be between 0 and 100 for `change-color'", "change-color(blue, $saturation: 101%)") assert_error_message("Lightness must be between 0 and 100 for `change-color'", "change-color(blue, $lightness: 101%)") assert_error_message("Red value must be between 0 and 255 for `change-color'", "change-color(blue, $red: -1)") assert_error_message("Green value must be between 0 and 255 for `change-color'", "change-color(blue, $green: 256)") assert_error_message("Blue value must be between 0 and 255 for `change-color'", "change-color(blue, $blue: 500)") # Unknown argument assert_error_message("Unknown argument $hoo (80%) for `change-color'", "change-color(blue, $hoo: 80%)") # Non-keyword arg assert_error_message("10px is not a keyword argument for `change_color'", "change-color(blue, 10px)") # HSL/RGB assert_error_message("Cannot specify HSL and RGB values for a color at the same time for `change-color'", "change-color(blue, $lightness: 10%, $red: 120)"); end def test_mix assert_equal("#7f007f", evaluate("mix(#f00, #00f)")) assert_equal("#7f7f7f", evaluate("mix(#f00, #0ff)")) assert_equal("#7f9055", evaluate("mix(#f70, #0aa)")) assert_equal("#3f00bf", evaluate("mix(#f00, #00f, 25%)")) assert_equal("rgba(63, 0, 191, 0.75)", evaluate("mix(rgba(255, 0, 0, 0.5), #00f)")) assert_equal("red", evaluate("mix(#f00, #00f, 100%)")) assert_equal("blue", evaluate("mix(#f00, #00f, 0%)")) assert_equal("rgba(255, 0, 0, 0.5)", evaluate("mix(#f00, transparentize(#00f, 1))")) assert_equal("rgba(0, 0, 255, 0.5)", evaluate("mix(transparentize(#f00, 1), #00f)")) assert_equal("red", evaluate("mix(#f00, transparentize(#00f, 1), 100%)")) assert_equal("blue", evaluate("mix(transparentize(#f00, 1), #00f, 0%)")) assert_equal("rgba(0, 0, 255, 0)", evaluate("mix(#f00, transparentize(#00f, 1), 0%)")) assert_equal("rgba(255, 0, 0, 0)", evaluate("mix(transparentize(#f00, 1), #00f, 100%)")) assert_equal("rgba(255, 0, 0, 0)", evaluate("mix($color-1: transparentize(#f00, 1), $color-2: #00f, $weight: 100%)")) end def test_mix_tests_types assert_error_message("\"foo\" is not a color for `mix'", "mix(\"foo\", #f00, 10%)") assert_error_message("\"foo\" is not a color for `mix'", "mix(#f00, \"foo\", 10%)") assert_error_message("\"foo\" is not a number for `mix'", "mix(#f00, #baf, \"foo\")") end def test_mix_tests_bounds assert_error_message("Weight -0.001 must be between 0% and 100% for `mix'", "mix(#123, #456, -0.001)") assert_error_message("Weight 100.001 must be between 0% and 100% for `mix'", "mix(#123, #456, 100.001)") end def test_grayscale assert_equal("#bbbbbb", evaluate("grayscale(#abc)")) assert_equal("gray", evaluate("grayscale(#f00)")) assert_equal("gray", evaluate("grayscale(#00f)")) assert_equal("white", evaluate("grayscale(white)")) assert_equal("black", evaluate("grayscale(black)")) assert_equal("black", evaluate("grayscale($color: black)")) end def tets_grayscale_tests_types assert_error_message("\"foo\" is not a color for `grayscale'", "grayscale(\"foo\")") end def test_complement assert_equal("#ccbbaa", evaluate("complement(#abc)")) assert_equal("aqua", evaluate("complement(red)")) assert_equal("red", evaluate("complement(aqua)")) assert_equal("white", evaluate("complement(white)")) assert_equal("black", evaluate("complement(black)")) assert_equal("black", evaluate("complement($color: black)")) end def tets_complement_tests_types assert_error_message("\"foo\" is not a color for `complement'", "complement(\"foo\")") end def test_invert assert_equal("#112233", evaluate("invert(#edc)")) assert_equal("rgba(245, 235, 225, 0.5)", evaluate("invert(rgba(10, 20, 30, 0.5))")) end def test_invert_tests_types assert_error_message("\"foo\" is not a color for `invert'", "invert(\"foo\")") end def test_unquote assert_equal('foo', evaluate('unquote("foo")')) assert_equal('foo', evaluate('unquote(foo)')) assert_equal('foo', evaluate('unquote($string: foo)')) end def test_quote assert_equal('"foo"', evaluate('quote(foo)')) assert_equal('"foo"', evaluate('quote("foo")')) assert_equal('"foo"', evaluate('quote($string: "foo")')) end def test_quote_tests_type assert_error_message("#ff0000 is not a string for `quote'", "quote(#f00)") end def test_user_defined_function assert_equal("I'm a user-defined string!", evaluate("user_defined()")) end def test_user_defined_function_with_preceding_underscore assert_equal("I'm another user-defined string!", evaluate("_preceding_underscore()")) assert_equal("I'm another user-defined string!", evaluate("-preceding-underscore()")) end def test_options_on_new_literals_fails assert_error_message(< e assert_equal("Function rgba doesn't take an argument named $extra", e.message) end def test_keyword_args_must_have_signature evaluate("no-kw-args($fake: value)") rescue Sass::SyntaxError => e assert_equal("Function no_kw_args doesn't support keyword arguments", e.message) end def test_keyword_args_with_missing_argument evaluate("rgb($red: 255, $green: 255)") rescue Sass::SyntaxError => e assert_equal("Function rgb requires an argument named $blue", e.message) end def test_only_var_args assert_equal "only-var-args(2px, 3px, 4px)", evaluate("only-var-args(1px, 2px, 3px)") end def test_only_kw_args assert_equal "only-kw-args(a, b, c)", evaluate("only-kw-args($a: 1, $b: 2, $c: 3)") end private def evaluate(value) Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new).to_s end def perform(value) Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new) end def assert_error_message(message, value) evaluate(value) flunk("Error message expected but not raised: #{message}") rescue Sass::SyntaxError => e assert_equal(message, e.message) end end ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/util_test.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/util0000775000175000017500000001633712414640747032551 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' require 'pathname' class UtilTest < Test::Unit::TestCase include Sass::Util def test_scope assert(File.exist?(scope("Rakefile"))) end def test_to_hash assert_equal({ :foo => 1, :bar => 2, :baz => 3 }, to_hash([[:foo, 1], [:bar, 2], [:baz, 3]])) end def test_map_keys assert_equal({ "foo" => 1, "bar" => 2, "baz" => 3 }, map_keys({:foo => 1, :bar => 2, :baz => 3}) {|k| k.to_s}) end def test_map_vals assert_equal({ :foo => "1", :bar => "2", :baz => "3" }, map_vals({:foo => 1, :bar => 2, :baz => 3}) {|k| k.to_s}) end def test_map_hash assert_equal({ "foo" => "1", "bar" => "2", "baz" => "3" }, map_hash({:foo => 1, :bar => 2, :baz => 3}) {|k, v| [k.to_s, v.to_s]}) end def test_powerset return unless Set[Set[]] == Set[Set[]] # There's a bug in Ruby 1.8.6 that breaks nested set equality assert_equal([[].to_set].to_set, powerset([])) assert_equal([[].to_set, [1].to_set].to_set, powerset([1])) assert_equal([[].to_set, [1].to_set, [2].to_set, [1, 2].to_set].to_set, powerset([1, 2])) assert_equal([[].to_set, [1].to_set, [2].to_set, [3].to_set, [1, 2].to_set, [2, 3].to_set, [1, 3].to_set, [1, 2, 3].to_set].to_set, powerset([1, 2, 3])) end def test_restrict assert_equal(0.5, restrict(0.5, 0..1)) assert_equal(1, restrict(2, 0..1)) assert_equal(1.3, restrict(2, 0..1.3)) assert_equal(0, restrict(-1, 0..1)) end def test_merge_adjacent_strings assert_equal(["foo bar baz", :bang, "biz bop", 12], merge_adjacent_strings(["foo ", "bar ", "baz", :bang, "biz", " bop", 12])) str = "foo" assert_equal(["foo foo foo", :bang, "foo foo", 12], merge_adjacent_strings([str, " ", str, " ", str, :bang, str, " ", str, 12])) end def test_intersperse assert_equal(["foo", " ", "bar", " ", "baz"], intersperse(%w[foo bar baz], " ")) assert_equal([], intersperse([], " ")) end def test_substitute assert_equal(["foo", "bar", "baz", 3, 4], substitute([1, 2, 3, 4], [1, 2], ["foo", "bar", "baz"])) assert_equal([1, "foo", "bar", "baz", 4], substitute([1, 2, 3, 4], [2, 3], ["foo", "bar", "baz"])) assert_equal([1, 2, "foo", "bar", "baz"], substitute([1, 2, 3, 4], [3, 4], ["foo", "bar", "baz"])) assert_equal([1, "foo", "bar", "baz", 2, 3, 4], substitute([1, 2, 2, 2, 3, 4], [2, 2], ["foo", "bar", "baz"])) end def test_strip_string_array assert_equal(["foo ", " bar ", " baz"], strip_string_array([" foo ", " bar ", " baz "])) assert_equal([:foo, " bar ", " baz"], strip_string_array([:foo, " bar ", " baz "])) assert_equal(["foo ", " bar ", :baz], strip_string_array([" foo ", " bar ", :baz])) end def test_paths assert_equal([[1, 3, 5], [2, 3, 5], [1, 4, 5], [2, 4, 5]], paths([[1, 2], [3, 4], [5]])) assert_equal([[]], paths([])) assert_equal([[1, 2, 3]], paths([[1], [2], [3]])) end def test_lcs assert_equal([1, 2, 3], lcs([1, 2, 3], [1, 2, 3])) assert_equal([], lcs([], [1, 2, 3])) assert_equal([], lcs([1, 2, 3], [])) assert_equal([1, 2, 3], lcs([5, 1, 4, 2, 3, 17], [0, 0, 1, 2, 6, 3])) assert_equal([1], lcs([1, 2, 3, 4], [4, 3, 2, 1])) assert_equal([1, 2], lcs([1, 2, 3, 4], [3, 4, 1, 2])) end def test_lcs_with_block assert_equal(["1", "2", "3"], lcs([1, 4, 2, 5, 3], [1, 2, 3]) {|a, b| a == b && a.to_s}) assert_equal([-4, 2, 8], lcs([-5, 3, 2, 8], [-4, 1, 8]) {|a, b| (a - b).abs <= 1 && [a, b].max}) end def test_silence_warnings old_stderr, $stderr = $stderr, StringIO.new warn "Out" assert_equal("Out\n", $stderr.string) silence_warnings {warn "In"} assert_equal("Out\n", $stderr.string) ensure $stderr = old_stderr end def test_sass_warn assert_warning("Foo!") {sass_warn "Foo!"} end def test_silence_sass_warnings old_stderr, $stderr = $stderr, StringIO.new silence_sass_warnings {warn "Out"} assert_equal("Out\n", $stderr.string) silence_sass_warnings {sass_warn "In"} assert_equal("Out\n", $stderr.string) ensure $stderr = old_stderr end def test_has assert(has?(:instance_method, String, :chomp!)) assert(has?(:private_instance_method, Sass::Engine, :parse_interp)) end def test_enum_with_index assert_equal(%w[foo0 bar1 baz2], enum_with_index(%w[foo bar baz]).map {|s, i| "#{s}#{i}"}) end def test_enum_cons assert_equal(%w[foobar barbaz], enum_cons(%w[foo bar baz], 2).map {|s1, s2| "#{s1}#{s2}"}) end def test_ord assert_equal(102, ord("f")) assert_equal(98, ord("bar")) end def test_flatten assert_equal([1, 2, 3], flatten([1, 2, 3], 0)) assert_equal([1, 2, 3], flatten([1, 2, 3], 1)) assert_equal([1, 2, 3], flatten([1, 2, 3], 2)) assert_equal([[1, 2], 3], flatten([[1, 2], 3], 0)) assert_equal([1, 2, 3], flatten([[1, 2], 3], 1)) assert_equal([1, 2, 3], flatten([[1, 2], 3], 2)) assert_equal([[[1], 2], [3], 4], flatten([[[1], 2], [3], 4], 0)) assert_equal([[1], 2, 3, 4], flatten([[[1], 2], [3], 4], 1)) assert_equal([1, 2, 3, 4], flatten([[[1], 2], [3], 4], 2)) end def test_set_hash assert(set_hash(Set[1, 2, 3]) == set_hash(Set[3, 2, 1])) assert(set_hash(Set[1, 2, 3]) == set_hash(Set[1, 2, 3])) s1 = Set[] s1 << 1 s1 << 2 s1 << 3 s2 = Set[] s2 << 3 s2 << 2 s2 << 1 assert(set_hash(s1) == set_hash(s2)) end def test_set_eql assert(set_eql?(Set[1, 2, 3], Set[3, 2, 1])) assert(set_eql?(Set[1, 2, 3], Set[1, 2, 3])) s1 = Set[] s1 << 1 s1 << 2 s1 << 3 s2 = Set[] s2 << 3 s2 << 2 s2 << 1 assert(set_eql?(s1, s2)) end def test_caller_info assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle'")) assert_equal(["/tmp/foo.rb", 12, nil], caller_info("/tmp/foo.rb:12")) assert_equal(["(sass)", 12, "blah"], caller_info("(sass):12: in `blah'")) assert_equal(["", 12, "boop"], caller_info(":12: in `boop'")) assert_equal(["/tmp/foo.rb", -12, "fizzle"], caller_info("/tmp/foo.rb:-12: in `fizzle'")) assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle {}'")) end def test_version_gt assert_version_gt("2.0.0", "1.0.0") assert_version_gt("1.1.0", "1.0.0") assert_version_gt("1.0.1", "1.0.0") assert_version_gt("1.0.0", "1.0.0.rc") assert_version_gt("1.0.0.1", "1.0.0.rc") assert_version_gt("1.0.0.rc", "0.9.9") assert_version_gt("1.0.0.beta", "1.0.0.alpha") assert_version_eq("1.0.0", "1.0.0") assert_version_eq("1.0.0", "1.0.0.0") end def assert_version_gt(v1, v2) #assert(version_gt(v1, v2), "Expected #{v1} > #{v2}") assert(!version_gt(v2, v1), "Expected #{v2} < #{v1}") end def assert_version_eq(v1, v2) assert(!version_gt(v1, v2), "Expected #{v1} = #{v2}") assert(!version_gt(v2, v1), "Expected #{v2} = #{v1}") end class FooBar def foo Sass::Util.abstract(self) end end def test_abstract assert_raise_message(NotImplementedError, "UtilTest::FooBar must implement #foo") {FooBar.new.foo} end end ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/script_test.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/scri0000775000175000017500000004505212414640747032530 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' require 'sass/engine' module Sass::Script::Functions::UserFunctions def assert_options(val) val.options[:foo] Sass::Script::String.new("Options defined!") end end class SassScriptTest < Test::Unit::TestCase include Sass::Script def test_color_checks_input assert_raise_message(ArgumentError, "Blue value must be between 0 and 255") {Color.new([1, 2, -1])} assert_raise_message(ArgumentError, "Red value must be between 0 and 255") {Color.new([256, 2, 3])} end def test_color_checks_rgba_input assert_raise_message(ArgumentError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, 1.1])} assert_raise_message(ArgumentError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, -0.1])} end def test_string_escapes assert_equal "'", resolve("\"'\"") assert_equal '"', resolve("\"\\\"\"") assert_equal "\\\\", resolve("\"\\\\\"") assert_equal "\\02fa", resolve("\"\\02fa\"") assert_equal "'", resolve("'\\''") assert_equal '"', resolve("'\"'") assert_equal "\\\\", resolve("'\\\\'") assert_equal "\\02fa", resolve("'\\02fa'") end def test_string_interpolation assert_equal "foo2bar", resolve('\'foo#{1 + 1}bar\'') assert_equal "foo2bar", resolve('"foo#{1 + 1}bar"') assert_equal "foo1bar5baz4bang", resolve('\'foo#{1 + "bar#{2 + 3}baz" + 4}bang\'') end def test_color_names assert_equal "white", resolve("white") assert_equal "white", resolve("#ffffff") assert_equal "#fffffe", resolve("white - #000001") end def test_rgba_color_literals assert_equal Sass::Script::Color.new([1, 2, 3, 0.75]), eval("rgba(1, 2, 3, 0.75)") assert_equal "rgba(1, 2, 3, 0.75)", resolve("rgba(1, 2, 3, 0.75)") assert_equal Sass::Script::Color.new([1, 2, 3, 0]), eval("rgba(1, 2, 3, 0)") assert_equal "rgba(1, 2, 3, 0)", resolve("rgba(1, 2, 3, 0)") assert_equal Sass::Script::Color.new([1, 2, 3]), eval("rgba(1, 2, 3, 1)") assert_equal Sass::Script::Color.new([1, 2, 3, 1]), eval("rgba(1, 2, 3, 1)") assert_equal "#010203", resolve("rgba(1, 2, 3, 1)") assert_equal "white", resolve("rgba(255, 255, 255, 1)") end def test_rgba_color_math assert_equal "rgba(50, 50, 100, 0.35)", resolve("rgba(1, 1, 2, 0.35) * rgba(50, 50, 50, 0.35)") assert_equal "rgba(52, 52, 52, 0.25)", resolve("rgba(2, 2, 2, 0.25) + rgba(50, 50, 50, 0.25)") assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)") do resolve("rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)") end assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: #123456 * rgba(50, 50, 50, 0.75)") do resolve("#123456 * rgba(50, 50, 50, 0.75)") end assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(50, 50, 50, 0.75) / #123456") do resolve("rgba(50, 50, 50, 0.75) / #123456") end end def test_rgba_number_math assert_equal "rgba(49, 49, 49, 0.75)", resolve("rgba(50, 50, 50, 0.75) - 1") assert_equal "rgba(100, 100, 100, 0.75)", resolve("rgba(50, 50, 50, 0.75) * 2") end def test_rgba_rounding assert_equal "rgba(10, 1, 0, 0.123)", resolve("rgba(10.0, 1.23456789, 0.0, 0.1234567)") end def test_compressed_colors assert_equal "#123456", resolve("#123456", :style => :compressed) assert_equal "rgba(1,2,3,0.5)", resolve("rgba(1, 2, 3, 0.5)", :style => :compressed) assert_equal "#123", resolve("#112233", :style => :compressed) assert_equal "#000", resolve("black", :style => :compressed) assert_equal "red", resolve("#f00", :style => :compressed) assert_equal "blue", resolve("#00f", :style => :compressed) assert_equal "navy", resolve("#000080", :style => :compressed) assert_equal "navy #fff", resolve("#000080 white", :style => :compressed) assert_equal "This color is #fff", resolve('"This color is #{ white }"', :style => :compressed) end def test_compressed_comma # assert_equal "foo,bar,baz", resolve("foo, bar, baz", :style => :compressed) # assert_equal "foo,#baf,baz", resolve("foo, #baf, baz", :style => :compressed) assert_equal "foo,#baf,red", resolve("foo, #baf, #f00", :style => :compressed) end def test_implicit_strings assert_equal Sass::Script::String.new("foo"), eval("foo") assert_equal Sass::Script::String.new("foo/bar"), eval("foo/bar") end def test_basic_interpolation assert_equal "foo3bar", resolve("foo\#{1 + 2}bar") assert_equal "foo3 bar", resolve("foo\#{1 + 2} bar") assert_equal "foo 3bar", resolve("foo \#{1 + 2}bar") assert_equal "foo 3 bar", resolve("foo \#{1 + 2} bar") assert_equal "foo 35 bar", resolve("foo \#{1 + 2}\#{2 + 3} bar") assert_equal "foo 3 5 bar", resolve("foo \#{1 + 2} \#{2 + 3} bar") assert_equal "3bar", resolve("\#{1 + 2}bar") assert_equal "foo3", resolve("foo\#{1 + 2}") assert_equal "3", resolve("\#{1 + 2}") end def test_interpolation_in_function assert_equal 'flabnabbit(1foo)', resolve('flabnabbit(#{1 + "foo"})') assert_equal 'flabnabbit(foo 1foobaz)', resolve('flabnabbit(foo #{1 + "foo"}baz)') assert_equal('flabnabbit(foo 1foo2bar baz)', resolve('flabnabbit(foo #{1 + "foo"}#{2 + "bar"} baz)')) end def test_interpolation_near_operators assert_equal '3 , 7', resolve('#{1 + 2} , #{3 + 4}') assert_equal '3, 7', resolve('#{1 + 2}, #{3 + 4}') assert_equal '3 ,7', resolve('#{1 + 2} ,#{3 + 4}') assert_equal '3,7', resolve('#{1 + 2},#{3 + 4}') assert_equal '3 / 7', resolve('3 / #{3 + 4}') assert_equal '3 /7', resolve('3 /#{3 + 4}') assert_equal '3/ 7', resolve('3/ #{3 + 4}') assert_equal '3/7', resolve('3/#{3 + 4}') assert_equal '3 * 7', resolve('#{1 + 2} * 7') assert_equal '3* 7', resolve('#{1 + 2}* 7') assert_equal '3 *7', resolve('#{1 + 2} *7') assert_equal '3*7', resolve('#{1 + 2}*7') assert_equal '-3', resolve('-#{1 + 2}') assert_equal '- 3', resolve('- #{1 + 2}') assert_equal '5 + 3 * 7', resolve('5 + #{1 + 2} * #{3 + 4}') assert_equal '5 +3 * 7', resolve('5 +#{1 + 2} * #{3 + 4}') assert_equal '5+3 * 7', resolve('5+#{1 + 2} * #{3 + 4}') assert_equal '3 * 7 + 5', resolve('#{1 + 2} * #{3 + 4} + 5') assert_equal '3 * 7+ 5', resolve('#{1 + 2} * #{3 + 4}+ 5') assert_equal '3 * 7+5', resolve('#{1 + 2} * #{3 + 4}+5') assert_equal '5/3 + 7', resolve('5 / (#{1 + 2} + #{3 + 4})') assert_equal '5/3 + 7', resolve('5 /(#{1 + 2} + #{3 + 4})') assert_equal '5/3 + 7', resolve('5 /( #{1 + 2} + #{3 + 4} )') assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4}) / 5') assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4})/ 5') assert_equal '3 + 7/5', resolve('( #{1 + 2} + #{3 + 4} )/ 5') assert_equal '3 + 5', resolve('#{1 + 2} + 2 + 3') assert_equal '3 +5', resolve('#{1 + 2} +2 + 3') end def test_string_interpolation assert_equal "foo bar, baz bang", resolve('"foo #{"bar"}, #{"baz"} bang"') assert_equal "foo bar baz bang", resolve('"foo #{"#{"ba" + "r"} baz"} bang"') assert_equal 'foo #{bar baz} bang', resolve('"foo \#{#{"ba" + "r"} baz} bang"') assert_equal 'foo #{baz bang', resolve('"foo #{"\#{" + "baz"} bang"') end def test_rule_interpolation assert_equal(< 2) assert_equal "public_instance_methods()", resolve("public_instance_methods()") end def test_adding_functions_directly_to_functions_module assert !Functions.callable?('nonexistant') Functions.class_eval { def nonexistant; end } assert Functions.callable?('nonexistant') Functions.send :remove_method, :nonexistant end def test_default_functions assert_equal "url(12)", resolve("url(12)") assert_equal 'blam("foo")', resolve('blam("foo")') end def test_function_results_have_options assert_equal "Options defined!", resolve("assert_options(abs(1))") assert_equal "Options defined!", resolve("assert_options(round(1.2))") end def test_funcall_requires_no_whitespace_before_lparen assert_equal "no-repeat 15px", resolve("no-repeat (7px + 8px)") assert_equal "no-repeat(15px)", resolve("no-repeat(7px + 8px)") end def test_dynamic_url assert_equal "url(foo-bar)", resolve("url($foo)", {}, env('foo' => Sass::Script::String.new("foo-bar"))) assert_equal "url(foo-bar baz)", resolve("url($foo $bar)", {}, env('foo' => Sass::Script::String.new("foo-bar"), 'bar' => Sass::Script::String.new("baz"))) assert_equal "url(foo baz)", resolve("url(foo $bar)", {}, env('bar' => Sass::Script::String.new("baz"))) assert_equal "url(foo bar)", resolve("url(foo bar)") end def test_url_with_interpolation assert_equal "url(http://sass-lang.com/images/foo-bar)", resolve("url(http://sass-lang.com/images/\#{foo-bar})") assert_equal 'url("http://sass-lang.com/images/foo-bar")', resolve("url('http://sass-lang.com/images/\#{foo-bar}')") assert_equal 'url("http://sass-lang.com/images/foo-bar")', resolve('url("http://sass-lang.com/images/#{foo-bar}")') assert_unquoted "url(http://sass-lang.com/images/\#{foo-bar})" end def test_hyphenated_variables assert_equal("a-b", resolve("$a-b", {}, env("a-b" => Sass::Script::String.new("a-b")))) end def test_ruby_equality assert_equal eval('"foo"'), eval('"foo"') assert_equal eval('1'), eval('1.0') assert_equal eval('1 2 3.0'), eval('1 2 3') assert_equal eval('1, 2, 3.0'), eval('1, 2, 3') assert_equal eval('(1 2), (3, 4), (5 6)'), eval('(1 2), (3, 4), (5 6)') assert_not_equal eval('1, 2, 3'), eval('1 2 3') assert_not_equal eval('1'), eval('"1"') end def test_booleans assert_equal "true", resolve("true") assert_equal "false", resolve("false") end def test_boolean_ops assert_equal "true", resolve("true and true") assert_equal "true", resolve("false or true") assert_equal "true", resolve("true or false") assert_equal "true", resolve("true or true") assert_equal "false", resolve("false or false") assert_equal "false", resolve("false and true") assert_equal "false", resolve("true and false") assert_equal "false", resolve("false and false") assert_equal "true", resolve("not false") assert_equal "false", resolve("not true") assert_equal "true", resolve("not not true") assert_equal "1", resolve("false or 1") assert_equal "false", resolve("false and 1") assert_equal "2", resolve("2 or 3") assert_equal "3", resolve("2 and 3") end def test_arithmetic_ops assert_equal "2", resolve("1 + 1") assert_equal "0", resolve("1 - 1") assert_equal "8", resolve("2 * 4") assert_equal "0.5", resolve("(2 / 4)") assert_equal "2", resolve("(4 / 2)") assert_equal "-1", resolve("-1") end def test_string_ops assert_equal '"foo" "bar"', resolve('"foo" "bar"') assert_equal "true 1", resolve('true 1') assert_equal '"foo", "bar"', resolve("'foo' , 'bar'") assert_equal "true, 1", resolve('true , 1') assert_equal "foobar", resolve('"foo" + "bar"') assert_equal "true1", resolve('true + 1') assert_equal '"foo"-"bar"', resolve("'foo' - 'bar'") assert_equal "true-1", resolve('true - 1') assert_equal '"foo"/"bar"', resolve('"foo" / "bar"') assert_equal "true/1", resolve('true / 1') assert_equal '-"bar"', resolve("- 'bar'") assert_equal "-true", resolve('- true') assert_equal '/"bar"', resolve('/ "bar"') assert_equal "/true", resolve('/ true') end def test_relational_ops assert_equal "false", resolve("1 > 2") assert_equal "false", resolve("2 > 2") assert_equal "true", resolve("3 > 2") assert_equal "false", resolve("1 >= 2") assert_equal "true", resolve("2 >= 2") assert_equal "true", resolve("3 >= 2") assert_equal "true", resolve("1 < 2") assert_equal "false", resolve("2 < 2") assert_equal "false", resolve("3 < 2") assert_equal "true", resolve("1 <= 2") assert_equal "true", resolve("2 <= 2") assert_equal "false", resolve("3 <= 2") end def test_equals assert_equal("true", resolve('"foo" == $foo', {}, env("foo" => Sass::Script::String.new("foo")))) assert_equal "true", resolve("1 == 1.0") assert_equal "true", resolve("false != true") assert_equal "false", resolve("1em == 1px") assert_equal "false", resolve("12 != 12") assert_equal "true", resolve("(foo bar baz) == (foo bar baz)") assert_equal "true", resolve("(foo, bar, baz) == (foo, bar, baz)") assert_equal "true", resolve('((1 2), (3, 4), (5 6)) == ((1 2), (3, 4), (5 6))') assert_equal "true", resolve('((1 2), (3 4)) == (1 2, 3 4)') assert_equal "false", resolve('((1 2) 3) == (1 2 3)') assert_equal "false", resolve('(1 (2 3)) == (1 2 3)') assert_equal "false", resolve('((1, 2) (3, 4)) == (1, 2 3, 4)') assert_equal "false", resolve('(1 2 3) == (1, 2, 3)') end def test_operation_precedence assert_equal "false true", resolve("true and false false or true") assert_equal "true", resolve("false and true or true and true") assert_equal "true", resolve("1 == 2 or 3 == 3") assert_equal "true", resolve("1 < 2 == 3 >= 3") assert_equal "true", resolve("1 + 3 > 4 - 2") assert_equal "11", resolve("1 + 2 * 3 + 4") end def test_functions assert_equal "#80ff80", resolve("hsl(120, 100%, 75%)") assert_equal "#81ff81", resolve("hsl(120, 100%, 75%) + #010001") end def test_operator_unit_conversion assert_equal "1.1cm", resolve("1cm + 1mm") assert_equal "true", resolve("2mm < 1cm") assert_equal "true", resolve("10mm == 1cm") assert_equal "true", resolve("1 == 1cm") assert_equal "true", resolve("1.1cm == 11mm") end def test_operations_have_options assert_equal "Options defined!", resolve("assert_options(1 + 1)") assert_equal "Options defined!", resolve("assert_options('bar' + 'baz')") end def test_slash_compiles_literally_when_left_alone assert_equal "1px/2px", resolve("1px/2px") assert_equal "1px/2px/3px/4px", resolve("1px/2px/3px/4px") assert_equal "1px/2px redpx bluepx", resolve("1px/2px redpx bluepx") assert_equal "foo 1px/2px/3px bar", resolve("foo 1px/2px/3px bar") end def test_slash_divides_with_parens assert_equal "0.5", resolve("(1px/2px)") assert_equal "0.5", resolve("(1px)/2px") assert_equal "0.5", resolve("1px/(2px)") end def test_slash_divides_with_other_arithmetic assert_equal "0.5px", resolve("1px*1px/2px") assert_equal "0.5px", resolve("1px/2px*1px") assert_equal "0.5", resolve("0+1px/2px") assert_equal "0.5", resolve("1px/2px+0") end def test_slash_divides_with_variable assert_equal "0.5", resolve("$var/2px", {}, env("var" => eval("1px"))) assert_equal "0.5", resolve("1px/$var", {}, env("var" => eval("2px"))) assert_equal "0.5", resolve("$var", {}, env("var" => eval("1px/2px"))) end def test_colors_with_wrong_number_of_digits assert_raise_message(Sass::SyntaxError, "Colors must have either three or six digits: '#0'") {eval("#0")} assert_raise_message(Sass::SyntaxError, "Colors must have either three or six digits: '#12'") {eval("#12")} assert_raise_message(Sass::SyntaxError, "Colors must have either three or six digits: '#abcd'") {eval("#abcd")} assert_raise_message(Sass::SyntaxError, "Colors must have either three or six digits: '#abcdE'") {eval("#abcdE")} assert_raise_message(Sass::SyntaxError, "Colors must have either three or six digits: '#abcdEFA'") {eval("#abcdEFA")} end def test_case_insensitive_color_names assert_equal "blue", resolve("BLUE") assert_equal "red", resolve("rEd") assert_equal "#7f4000", resolve("mix(GrEeN, ReD)") end def test_empty_list assert_equal "1 2 3", resolve("1 2 () 3") assert_equal "1 2 3", resolve("1 2 3 ()") assert_equal "1 2 3", resolve("() 1 2 3") assert_raise_message(Sass::SyntaxError, "() isn't a valid CSS value.") {resolve("()")} assert_raise_message(Sass::SyntaxError, "() isn't a valid CSS value.") {resolve("nth(append((), ()), 1)")} end # Regression Tests def test_funcall_has_higher_precedence_than_color_name assert_equal "teal(12)", resolve("teal(12)") assert_equal "tealbang(12)", resolve("tealbang(12)") assert_equal "teal-bang(12)", resolve("teal-bang(12)") assert_equal "teal\\+bang(12)", resolve("teal\\+bang(12)") end def test_interpolation_after_hash assert_equal "#2", resolve('"##{1 + 1}"') end def test_misplaced_comma_in_funcall assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "foo(bar, ": expected function argument, was ")"') {eval('foo(bar, )')} end def test_color_prefixed_identifier assert_equal "tealbang", resolve("tealbang") assert_equal "teal-bang", resolve("teal-bang") end def test_op_prefixed_identifier assert_equal "notbang", resolve("notbang") assert_equal "not-bang", resolve("not-bang") assert_equal "or-bang", resolve("or-bang") assert_equal "and-bang", resolve("and-bang") end private def resolve(str, opts = {}, environment = env) munge_filename opts val = eval(str, opts, environment) val.is_a?(Sass::Script::String) ? val.value : val.to_s end def assert_unquoted(str, opts = {}, environment = env) munge_filename opts val = eval(str, opts, environment) assert_kind_of Sass::Script::String, val assert_equal :identifier, val.type end def assert_quoted(str, opts = {}, environment = env) munge_filename opts val = eval(str, opts, environment) assert_kind_of Sass::Script::String, val assert_equal :string, val.type end def eval(str, opts = {}, environment = env) munge_filename opts environment.options = opts Sass::Script.parse(str, opts.delete(:line) || 1, opts.delete(:offset) || 0, opts).perform(environment) end def render(sass, options = {}) munge_filename options Sass::Engine.new(sass, options).render end def env(hash = {}) env = Sass::Environment.new hash.each {|k, v| env.set_var(k, v)} env end def test_number_printing assert_equal "1", eval("1") assert_equal "1", eval("1.0") assert_equal "1.121", eval("1.1214") assert_equal "1.122", eval("1.1215") assert_equal "Infinity", eval("1.0/0.0") assert_equal "-Infinity", eval("-1.0/0.0") assert_equal "NaN", eval("0.0/0.0") end end ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/test_helper.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/test0000664000175000017500000000027012414640747032535 0ustar ebourgebourgtest_dir = File.dirname(__FILE__) $:.unshift test_dir unless $:.include?(test_dir) class Test::Unit::TestCase def absolutize(file) "#{File.dirname(__FILE__)}/#{file}" end end ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/plugin_test.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/plug0000775000175000017500000003434412414640747032541 0ustar ebourgebourg#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../test_helper' require File.dirname(__FILE__) + '/test_helper' require 'sass/plugin' require 'fileutils' class SassPluginTest < Test::Unit::TestCase @@templates = %w{ complex script parent_ref import scss_import alt subdir/subdir subdir/nested_subdir/nested_subdir options } @@templates += %w[import_charset import_charset_ibm866] unless Sass::Util.ruby1_8? @@templates << 'import_charset_1_8' if Sass::Util.ruby1_8? @@cache_store = Sass::CacheStores::Memory.new def setup FileUtils.mkdir_p tempfile_loc FileUtils.mkdir_p tempfile_loc(nil,"more_") set_plugin_opts check_for_updates! reset_mtimes end def teardown clean_up_sassc Sass::Plugin.reset! FileUtils.rm_r tempfile_loc FileUtils.rm_r tempfile_loc(nil,"more_") end @@templates.each do |name| define_method("test_template_renders_correctly (#{name})") do assert_renders_correctly(name) end end def test_no_update File.delete(tempfile_loc('basic')) assert_needs_update 'basic' check_for_updates! assert_stylesheet_updated 'basic' end def test_update_needed_when_modified touch 'basic' assert_needs_update 'basic' check_for_updates! assert_stylesheet_updated 'basic' end def test_update_needed_when_dependency_modified touch 'basic' assert_needs_update 'import' check_for_updates! assert_stylesheet_updated 'basic' assert_stylesheet_updated 'import' end def test_update_needed_when_scss_dependency_modified touch 'scss_importee' assert_needs_update 'import' check_for_updates! assert_stylesheet_updated 'scss_importee' assert_stylesheet_updated 'import' end def test_scss_update_needed_when_dependency_modified touch 'basic' assert_needs_update 'scss_import' check_for_updates! assert_stylesheet_updated 'basic' assert_stylesheet_updated 'scss_import' end def test_update_needed_when_nested_import_dependency_modified touch 'basic' assert_needs_update 'nested_import' check_for_updates! assert_stylesheet_updated 'basic' assert_stylesheet_updated 'scss_import' end def test_no_updates_when_always_check_and_always_update_both_false Sass::Plugin.options[:always_update] = false Sass::Plugin.options[:always_check] = false touch 'basic' assert_needs_update 'basic' check_for_updates! # Check it's still stale assert_needs_update 'basic' end def test_full_exception_handling File.delete(tempfile_loc('bork1')) check_for_updates! File.open(tempfile_loc('bork1')) do |file| assert_equal(< { template_loc => tempfile_loc, template_loc(nil,'more_') => tempfile_loc(nil,'more_') } check_for_updates! ['more1', 'more_import'].each { |name| assert_renders_correctly(name, :prefix => 'more_') } end def test_two_template_directories_with_line_annotations set_plugin_opts :line_comments => true, :style => :nested, :template_location => { template_loc => tempfile_loc, template_loc(nil,'more_') => tempfile_loc(nil,'more_') } check_for_updates! assert_renders_correctly('more1_with_line_comments', 'more1', :prefix => 'more_') end def test_doesnt_render_partials assert !File.exists?(tempfile_loc('_partial')) end def test_template_location_array assert_equal [[template_loc, tempfile_loc]], Sass::Plugin.template_location_array end def test_add_template_location Sass::Plugin.add_template_location(template_loc(nil, "more_"), tempfile_loc(nil, "more_")) assert_equal( [[template_loc, tempfile_loc], [template_loc(nil, "more_"), tempfile_loc(nil, "more_")]], Sass::Plugin.template_location_array) touch 'more1', 'more_' touch 'basic' assert_needs_update "more1", "more_" assert_needs_update "basic" check_for_updates! assert_doesnt_need_update "more1", "more_" assert_doesnt_need_update "basic" end def test_remove_template_location Sass::Plugin.add_template_location(template_loc(nil, "more_"), tempfile_loc(nil, "more_")) Sass::Plugin.remove_template_location(template_loc, tempfile_loc) assert_equal( [[template_loc(nil, "more_"), tempfile_loc(nil, "more_")]], Sass::Plugin.template_location_array) touch 'more1', 'more_' touch 'basic' assert_needs_update "more1", "more_" assert_needs_update "basic" check_for_updates! assert_doesnt_need_update "more1", "more_" assert_needs_update "basic" end # Callbacks def test_updating_stylesheets_callback # Should run even when there's nothing to update assert_callback :updating_stylesheets, [] end def test_updating_stylesheets_callback_with_individual_files files = [[template_loc("basic"), tempfile_loc("basic")]] assert_callback(:updating_stylesheets, files) {Sass::Util.silence_sass_warnings{Sass::Plugin.update_stylesheets(files)}} end def test_updating_stylesheets_callback_with_never_update Sass::Plugin.options[:never_update] = true assert_no_callback :updating_stylesheets end def test_updating_stylesheet_callback_for_updated_template Sass::Plugin.options[:always_update] = false touch 'basic' assert_no_callback :updating_stylesheet, template_loc("complex"), tempfile_loc("complex") do assert_callbacks( [:updating_stylesheet, template_loc("basic"), tempfile_loc("basic")], [:updating_stylesheet, template_loc("import"), tempfile_loc("import")]) end end def test_updating_stylesheet_callback_for_fresh_template Sass::Plugin.options[:always_update] = false assert_no_callback :updating_stylesheet end def test_updating_stylesheet_callback_for_error_template Sass::Plugin.options[:always_update] = false touch 'bork1' assert_no_callback :updating_stylesheet end def test_not_updating_stylesheet_callback_for_fresh_template Sass::Plugin.options[:always_update] = false assert_callback :not_updating_stylesheet, template_loc("basic"), tempfile_loc("basic") end def test_not_updating_stylesheet_callback_for_updated_template Sass::Plugin.options[:always_update] = false assert_callback :not_updating_stylesheet, template_loc("complex"), tempfile_loc("complex") do assert_no_callbacks( [:updating_stylesheet, template_loc("basic"), tempfile_loc("basic")], [:updating_stylesheet, template_loc("import"), tempfile_loc("import")]) end end def test_not_updating_stylesheet_callback_with_never_update Sass::Plugin.options[:never_update] = true assert_no_callback :not_updating_stylesheet end def test_not_updating_stylesheet_callback_for_partial Sass::Plugin.options[:always_update] = false assert_no_callback :not_updating_stylesheet, template_loc("_partial"), tempfile_loc("_partial") end def test_not_updating_stylesheet_callback_for_error Sass::Plugin.options[:always_update] = false touch 'bork1' assert_no_callback :not_updating_stylesheet, template_loc("bork1"), tempfile_loc("bork1") end def test_compilation_error_callback Sass::Plugin.options[:always_update] = false touch 'bork1' assert_callback(:compilation_error, lambda {|e| e.message == 'Undefined variable: "$bork".'}, template_loc("bork1"), tempfile_loc("bork1")) end def test_compilation_error_callback_for_file_access Sass::Plugin.options[:always_update] = false assert_callback(:compilation_error, lambda {|e| e.is_a?(Errno::ENOENT)}, template_loc("nonexistent"), tempfile_loc("nonexistent")) do Sass::Plugin.update_stylesheets([[template_loc("nonexistent"), tempfile_loc("nonexistent")]]) end end def test_creating_directory_callback Sass::Plugin.options[:always_update] = false dir = File.join(tempfile_loc, "subdir", "nested_subdir") FileUtils.rm_r dir assert_callback :creating_directory, dir end ## Regression def test_cached_dependencies_update FileUtils.mv(template_loc("basic"), template_loc("basic", "more_")) set_plugin_opts :load_paths => [template_loc(nil, "more_")] touch 'basic', 'more_' assert_needs_update "import" check_for_updates! assert_renders_correctly("import") ensure FileUtils.mv(template_loc("basic", "more_"), template_loc("basic")) end def test_cached_relative_import old_always_update = Sass::Plugin.options[:always_update] Sass::Plugin.options[:always_update] = true check_for_updates! assert_renders_correctly('subdir/subdir') ensure Sass::Plugin.options[:always_update] = old_always_update end def test_cached_if set_plugin_opts :cache_store => Sass::CacheStores::Filesystem.new(tempfile_loc + '/cache') check_for_updates! assert_renders_correctly 'if' check_for_updates! assert_renders_correctly 'if' ensure set_plugin_opts :cache_store => @@cache_store end private def assert_renders_correctly(*arguments) options = arguments.last.is_a?(Hash) ? arguments.pop : {} prefix = options[:prefix] result_name = arguments.shift tempfile_name = arguments.shift || result_name expected_str = File.read(result_loc(result_name, prefix)) actual_str = File.read(tempfile_loc(tempfile_name, prefix)) unless Sass::Util.ruby1_8? expected_str = expected_str.force_encoding('IBM866') if result_name == 'import_charset_ibm866' actual_str = actual_str.force_encoding('IBM866') if tempfile_name == 'import_charset_ibm866' end expected_lines = expected_str.split("\n") actual_lines = actual_str.split("\n") if actual_lines.first == "/*" && expected_lines.first != "/*" assert(false, actual_lines[0..Sass::Util.enum_with_index(actual_lines).find {|l, i| l == "*/"}.last].join("\n")) end expected_lines.zip(actual_lines).each_with_index do |pair, line| message = "template: #{result_name}\nline: #{line + 1}" assert_equal(pair.first, pair.last, message) end if expected_lines.size < actual_lines.size assert(false, "#{actual_lines.size - expected_lines.size} Trailing lines found in #{tempfile_name}.css: #{actual_lines[expected_lines.size..-1].join('\n')}") end end def assert_stylesheet_updated(name) assert_doesnt_need_update name # Make sure it isn't an exception expected_lines = File.read(result_loc(name)).split("\n") actual_lines = File.read(tempfile_loc(name)).split("\n") if actual_lines.first == "/*" && expected_lines.first != "/*" assert(false, actual_lines[0..actual_lines.enum_with_index.find {|l, i| l == "*/"}.last].join("\n")) end end def assert_callback(name, *expected_args) run = false Sass::Plugin.send("on_#{name}") do |*args| run ||= expected_args.zip(args).all? do |ea, a| ea.respond_to?(:call) ? ea.call(a) : ea == a end end if block_given? yield else check_for_updates! end assert run, "Expected #{name} callback to be run with arguments:\n #{expected_args.inspect}" end def assert_no_callback(name, *unexpected_args) Sass::Plugin.send("on_#{name}") do |*a| next unless unexpected_args.empty? || a == unexpected_args msg = "Expected #{name} callback not to be run" if !unexpected_args.empty? msg << " with arguments #{unexpected_args.inspect}" elsif !a.empty? msg << ",\n was run with arguments #{a.inspect}" end flunk msg end if block_given? yield else check_for_updates! end end def assert_callbacks(*args) return check_for_updates! if args.empty? assert_callback(*args.pop) {assert_callbacks(*args)} end def assert_no_callbacks(*args) return check_for_updates! if args.empty? assert_no_callback(*args.pop) {assert_no_callbacks(*args)} end def check_for_updates! Sass::Util.silence_sass_warnings do Sass::Plugin.check_for_updates end end def assert_needs_update(*args) assert(Sass::Plugin::StalenessChecker.stylesheet_needs_update?(tempfile_loc(*args), template_loc(*args)), "Expected #{template_loc(*args)} to need an update.") end def assert_doesnt_need_update(*args) assert(!Sass::Plugin::StalenessChecker.stylesheet_needs_update?(tempfile_loc(*args), template_loc(*args)), "Expected #{template_loc(*args)} not to need an update.") end def touch(*args) FileUtils.touch(template_loc(*args)) end def reset_mtimes Sass::Plugin::StalenessChecker.dependencies_cache = {} atime = Time.now mtime = Time.now - 5 Dir["{#{template_loc},#{tempfile_loc}}/**/*.{css,sass,scss}"].each {|f| File.utime(atime, mtime, f)} end def template_loc(name = nil, prefix = nil) if name scss = absolutize "#{prefix}templates/#{name}.scss" File.exists?(scss) ? scss : absolutize("#{prefix}templates/#{name}.sass") else absolutize "#{prefix}templates" end end def tempfile_loc(name = nil, prefix = nil) if name absolutize "#{prefix}tmp/#{name}.css" else absolutize "#{prefix}tmp" end end def result_loc(name = nil, prefix = nil) if name absolutize "#{prefix}results/#{name}.css" else absolutize "#{prefix}results" end end def set_plugin_opts(overrides = {}) Sass::Plugin.options.merge!( :template_location => template_loc, :css_location => tempfile_loc, :style => :compact, :always_update => true, :never_update => false, :full_exception => true, :cache_store => @@cache_store ) Sass::Plugin.options.merge!(overrides) end end class Sass::Engine alias_method :old_render, :render def render raise "bork bork bork!" if @template[0] == "{bork now!}" old_render end end ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/scss/stapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/scss0000775000175000017500000000000012414640747032530 5ustar ebourgebourg././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/scss/test_helper.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/scss0000664000175000017500000000205212414640747032531 0ustar ebourgebourgrequire File.dirname(__FILE__) + '/../../test_helper' require 'sass/engine' module ScssTestHelper def assert_parses(scss) assert_equal scss.rstrip, render(scss).rstrip end def assert_not_parses(expected, scss) raise "Template must include where an error is expected" unless scss.include?("") after, was = scss.split("") line = after.count("\n") + 1 after.gsub!(/\s*\n\s*$/, '') after.gsub!(/.*\n/, '') after = "..." + after[-15..-1] if after.size > 18 was.gsub!(/^\s*\n\s*/, '') was.gsub!(/\n.*/, '') was = was[0...15] + "..." if was.size > 18 to_render = scss.sub("", "") render(to_render) assert(false, "Expected syntax error for:\n#{to_render}\n") rescue Sass::SyntaxError => err assert_equal("Invalid CSS after \"#{after}\": expected #{expected}, was \"#{was}\"", err.message) assert_equal line, err.sass_line end def render(scss, options = {}) options[:syntax] ||= :scss munge_filename options Sass::Engine.new(scss, options).render end end ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/scss/css_test.rbstapler-stapler-parent-1.231/jruby/src/main/resources/gem/gems/haml-3.1.1/vendor/sass/test/sass/scss0000775000175000017500000004552012414640747032543 0ustar ebourgebourg#!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/test_helper' require 'sass/scss/css_parser' # These tests just test the parsing of CSS # (both standard and any hacks we intend to support). # Tests of SCSS-specific behavior go in scss_test.rb. class ScssCssTest < Test::Unit::TestCase include ScssTestHelper def test_basic_scss assert_parses < baz {bar: baz} SCSS end if Sass::Util.ruby1_8? def test_unicode assert_parses < F') assert_selector_parses('E + F') assert_selector_parses('E ~ F') end # Taken from http://www.w3.org/TR/css3-selectors/#selectors, # but without the element names def test_lonely_selectors assert_selector_parses('[foo]') assert_selector_parses('[foo="bar"]') assert_selector_parses('[foo~="bar"]') assert_selector_parses('[foo^="bar"]') assert_selector_parses('[foo$="bar"]') assert_selector_parses('[foo*="bar"]') assert_selector_parses('[foo|="en"]') assert_selector_parses(':root') assert_selector_parses(':nth-child(n)') assert_selector_parses(':nth-last-child(n)') assert_selector_parses(':nth-of-type(n)') assert_selector_parses(':nth-last-of-type(n)') assert_selector_parses(':first-child') assert_selector_parses(':last-child') assert_selector_parses(':first-of-type') assert_selector_parses(':last-of-type') assert_selector_parses(':only-child') assert_selector_parses(':only-of-type') assert_selector_parses(':empty') assert_selector_parses(':link') assert_selector_parses(':visited') assert_selector_parses(':active') assert_selector_parses(':hover') assert_selector_parses(':focus') assert_selector_parses(':target') assert_selector_parses(':lang(fr)') assert_selector_parses(':enabled') assert_selector_parses(':disabled') assert_selector_parses(':checked') assert_selector_parses('::first-line') assert_selector_parses('::first-letter') assert_selector_parses('::before') assert_selector_parses('::after') assert_selector_parses('.warning') assert_selector_parses('#myid') assert_selector_parses(':not(s)') end def test_attribute_selectors_with_identifiers assert_selector_parses('[foo~=bar]') assert_selector_parses('[foo^=bar]') assert_selector_parses('[foo$=bar]') assert_selector_parses('[foo*=bar]') assert_selector_parses('[foo|=en]') end def test_nth_selectors assert_selector_parses(':nth-child(-n)') assert_selector_parses(':nth-child(+n)') assert_selector_parses(':nth-child(even)') assert_selector_parses(':nth-child(odd)') assert_selector_parses(':nth-child(50)') assert_selector_parses(':nth-child(-50)') assert_selector_parses(':nth-child(+50)') assert_selector_parses(':nth-child(2n+3)') assert_selector_parses(':nth-child(2n-3)') assert_selector_parses(':nth-child(+2n-3)') assert_selector_parses(':nth-child(-2n+3)') assert_selector_parses(':nth-child(-2n+ 3)') assert_equal(< baz)') assert_selector_parses(':not(h1, h2, h3)') end def test_moz_any_selector assert_selector_parses(':-moz-any(h1, h2, h3)') assert_selector_parses(':-moz-any(.foo)') assert_selector_parses(':-moz-any(foo bar, .baz > .bang)') end def test_namespaced_selectors assert_selector_parses('foo|E') assert_selector_parses('*|E') assert_selector_parses('foo|*') assert_selector_parses('*|*') end def test_namespaced_attribute_selectors assert_selector_parses('[foo|bar=baz]') assert_selector_parses('[*|bar=baz]') assert_selector_parses('[foo|bar|=baz]') end def test_comma_selectors assert_selector_parses('E, F') assert_selector_parses('E F, G H') assert_selector_parses('E > F, G > H') end def test_selectors_with_newlines assert_selector_parses("E,\nF") assert_selector_parses("E\nF") assert_selector_parses("E, F\nG, H") end def test_expression_fallback_selectors assert_selector_parses('0%') assert_selector_parses('60%') assert_selector_parses('100%') assert_selector_parses('12px') assert_selector_parses('"foo"') end def test_functional_pseudo_selectors assert_selector_parses(':foo("bar")') assert_selector_parses(':foo(bar)') assert_selector_parses(':foo(12px)') assert_selector_parses(':foo(+)') assert_selector_parses(':foo(-)') assert_selector_parses(':foo(+"bar")') assert_selector_parses(':foo(-++--baz-"bar"12px)') end def test_selector_hacks assert_selector_parses('> E') assert_selector_parses('+ E') assert_selector_parses('~ E') assert_selector_parses('> > E') assert_equal < > E { a: b; } CSS >> E { a: b; } SCSS assert_selector_parses('E*') assert_selector_parses('E*.foo') assert_selector_parses('E*:hover') end ## Errors def test_invalid_directives assert_not_parses("identifier", '@ import "foo";') assert_not_parses("identifier", '@12 "foo";') end def test_invalid_classes assert_not_parses("class name", 'p. foo {a: b}') assert_not_parses("class name", 'p.1foo {a: b}') end def test_invalid_ids assert_not_parses("id name", 'p# foo {a: b}') end def test_no_properties_at_toplevel assert_not_parses('pseudoclass or pseudoelement', 'a: b;') end def test_no_scss_directives assert_parses('@import "foo.sass";') assert_parses <$var = 12;") assert_not_parses('"}"', "foo { !var = 12; }") end def test_no_parent_selectors assert_not_parses('"{"', "foo &.bar {a: b}") end def test_no_selector_interpolation assert_not_parses('"{"', 'foo #{"bar"}.baz {a: b}') end def test_no_prop_name_interpolation assert_not_parses('":"', 'foo {a#{"bar"}baz: b}') end def test_no_prop_val_interpolation assert_not_parses('"}"', 'foo {a: b #{"bar"} c}') end def test_no_string_interpolation assert_parses <* c}') end def test_no_nested_rules assert_not_parses('":"', 'foo {bar {a: b}}') assert_not_parses('"}"', 'foo {[bar=baz] {a: b}}') end def test_no_nested_properties assert_not_parses('expression (e.g. 1px, bold)', 'foo {bar: {a: b}}') assert_not_parses('expression (e.g. 1px, bold)', 'foo {bar: bang {a: b}}') end def test_no_nested_directives assert_not_parses('"}"', 'foo {@bar {a: b}}') end def test_error_with_windows_newlines render < e assert_equal 'Invalid CSS after "foo {bar": expected ":", was "}"', e.message assert_equal 1, e.sass_line end ## Regressions def test_closing_line_comment_end_with_compact_output assert_equal(< :compact)) /* foo */ bar { baz: bang; } CSS /* * foo */ bar {baz: bang} SCSS end private def assert_selector_parses(selector) assert_parses < e assert_equal < e assert_equal "Mixins may only be defined at the root of a document.", e.message assert_equal 2, e.sass_line end def test_rules_beneath_properties render < e assert_equal 'Illegal nesting: Only properties may be nested beneath properties.', e.message assert_equal 3, e.sass_line end def test_uses_property_exception_with_star_hack render < e assert_equal 'Invalid CSS after " *bar:baz ": expected ";", was "[fail]; }"', e.message assert_equal 2, e.sass_line end def test_uses_property_exception_with_colon_hack render < e assert_equal 'Invalid CSS after " :bar:baz ": expected ";", was "[fail]; }"', e.message assert_equal 2, e.sass_line end def test_uses_rule_exception_with_dot_hack render <; } SCSS assert(false, "Expected syntax error") rescue Sass::SyntaxError => e assert_equal 'Invalid CSS after " .bar:baz ": expected "{", was "; }"', e.message assert_equal 2, e.sass_line end def test_uses_property_exception_with_space_after_name render < e assert_equal 'Invalid CSS after " bar: baz ": expected ";", was "[fail]; }"', e.message assert_equal 2, e.sass_line end def test_uses_property_exception_with_non_identifier_after_name render < e assert_equal 'Invalid CSS after " bar:1px ": expected ";", was "[fail]; }"', e.message assert_equal 2, e.sass_line end def test_uses_property_exception_when_followed_by_open_bracket render < e assert_equal 'Invalid CSS after " bar:{baz: ": expected expression (e.g. 1px, bold), was ".fail} }"', e.message assert_equal 2, e.sass_line end def test_script_error render < e assert_equal 'Invalid CSS after " bar: "baz" * ": expected expression (e.g. 1px, bold), was "* }"', e.message assert_equal 2, e.sass_line end def test_multiline_script_syntax_error render < e assert_equal 'Invalid CSS after " "baz" * ": expected expression (e.g. 1px, bold), was "* }"', e.message assert_equal 3, e.sass_line end def test_multiline_script_runtime_error render < e assert_equal "Undefined variable: \"$bang\".", e.message assert_equal 4, e.sass_line end def test_post_multiline_script_runtime_error render < e assert_equal "Undefined variable: \"$bop\".", e.message assert_equal 5, e.sass_line end def test_multiline_property_runtime_error render < e assert_equal "Undefined variable: \"$bang\".", e.message assert_equal 4, e.sass_line end def test_post_resolution_selector_error render "\n\nfoo \#{\") bar\"} {a: b}" assert(false, "Expected syntax error") rescue Sass::SyntaxError => e assert_equal 'Invalid CSS after "foo ": expected selector, was ") bar"', e.message assert_equal 3, e.sass_line end def test_parent_in_mid_selector_error assert_raise_message(Sass::SyntaxError, <:compressed) z a,z b{display:block} CSS a, b { z & { display: block; } } SCSS end def test_if_error_line assert_raise_line(2) {render(<