Author: bdelacretaz
Date: Tue Jun 17 08:41:57 2008
New Revision: 668714

URL: http://svn.apache.org/viewvc?rev=668714&view=rev
Log:
SLING-466 - JST template engine reworked, head and body elements are now 
processed separately to generate the html rendering and the javascript 
rendering code

Added:
    
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/BodyOnlyScriptFilteredCopy.java
   (with props)
    incubator/sling/trunk/scripting/jst/src/main/resources/xslt/
    
incubator/sling/trunk/scripting/jst/src/main/resources/xslt/script-transform.xsl
   (with props)
Modified:
    incubator/sling/trunk/parent/pom.xml
    incubator/sling/trunk/scripting/jst/pom.xml
    
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/HtmlCodeGenerator.java
    
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JsCodeGenerator.java
    
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JstScriptEngine.java
    
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/ScriptFilteredCopy.java

Modified: incubator/sling/trunk/parent/pom.xml
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/parent/pom.xml?rev=668714&r1=668713&r2=668714&view=diff
==============================================================================
--- incubator/sling/trunk/parent/pom.xml (original)
+++ incubator/sling/trunk/parent/pom.xml Tue Jun 17 08:41:57 2008
@@ -692,8 +692,13 @@
                 <artifactId>pax-web-service</artifactId>
                 <version>0.2.3</version>
             </dependency>
+
+            <dependency>
+                <groupId>nekohtml</groupId>
+                <artifactId>nekohtml</artifactId>
+                <version>1.9.6.2</version>
+            </dependency>
         </dependencies>
-        
     </dependencyManagement>
 
 

Modified: incubator/sling/trunk/scripting/jst/pom.xml
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/scripting/jst/pom.xml?rev=668714&r1=668713&r2=668714&view=diff
==============================================================================
--- incubator/sling/trunk/scripting/jst/pom.xml (original)
+++ incubator/sling/trunk/scripting/jst/pom.xml Tue Jun 17 08:41:57 2008
@@ -58,17 +58,26 @@
                 <extensions>true</extensions>
                 <configuration>
                     <instructions>
+                        <!--
+                          TODO the xerces and dom dependencies should
+                          come from separate bundles
+                         -->
                         <Private-Package>
                             org.apache.sling.scripting.jst,
                             org.apache.sling.scripting.javascript.io.*,
-                            org.apache.sling.servlets.get.helpers.*
+                            org.apache.sling.servlets.get.helpers.*,
+                            org.cyberneko.html.*,
+                            org.apache.xerces.*,
+                            org.w3c.dom.*,
+                            org.apache.html.dom.*
                         </Private-Package>
                         
                         <Import-Package>
                             org.apache.bsf.*;
                             sun.misc; resolution:=optional,
-                            *
+                            javax.xml.*
                         </Import-Package>
+                        <DynamicImport-Package>*</DynamicImport-Package>
                         
                         <ScriptEngine-Name>${pom.name}</ScriptEngine-Name>
                         
<ScriptEngine-Version>${pom.version}</ScriptEngine-Version>
@@ -129,6 +138,20 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>nekohtml</groupId>
+            <artifactId>nekohtml</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>xerces</groupId>
+            <artifactId>xercesImpl</artifactId>
+            <version>2.4.0</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
             <scope>provided</scope>

Added: 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/BodyOnlyScriptFilteredCopy.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/BodyOnlyScriptFilteredCopy.java?rev=668714&view=auto
==============================================================================
--- 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/BodyOnlyScriptFilteredCopy.java
 (added)
+++ 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/BodyOnlyScriptFilteredCopy.java
 Tue Jun 17 08:41:57 2008
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.scripting.jst;
+
+import java.util.regex.Pattern;
+
+
+/** Extends ScriptFilteredCopy by copying only code that was
+ *  generated from inside the <body> tag of the template
+ */
+class BodyOnlyScriptFilteredCopy extends ScriptFilteredCopy {
+
+    private int state = 0;
+    private final Pattern bodyStart;
+    private final Pattern bodyEnd;
+    
+    BodyOnlyScriptFilteredCopy() {
+        bodyStart = Pattern.compile("^out.write\\(. *<body.*");
+        bodyEnd = Pattern.compile("^out.write\\(. *</body.*");
+    }
+    
+    protected boolean copyLine(String line) {
+        boolean result = false;
+        
+        if(state == 0) {
+            // <body> not seen yet, go to state 1 if seen
+            if(bodyStart.matcher(line).matches()) {
+                state = 1;
+            }
+            
+        } else if(state == 1) {
+            // if </body>, done copying -> state 2
+            if(bodyEnd.matcher(line).matches()) {
+                state = 2;
+            } else {
+                result = true;
+            }
+        }
+        
+        return result;
+    }
+
+}

Propchange: 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/BodyOnlyScriptFilteredCopy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/BodyOnlyScriptFilteredCopy.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/HtmlCodeGenerator.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/HtmlCodeGenerator.java?rev=668714&r1=668713&r2=668714&view=diff
==============================================================================
--- 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/HtmlCodeGenerator.java
 (original)
+++ 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/HtmlCodeGenerator.java
 Tue Jun 17 08:41:57 2008
@@ -18,12 +18,22 @@
  */
 package org.apache.sling.scripting.jst;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.LinkedList;
 import java.util.List;
 
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
+import javax.script.ScriptException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
@@ -31,8 +41,11 @@
 import org.apache.sling.commons.json.JSONException;
 import org.apache.sling.commons.json.jcr.JsonItemWriter;
 import org.apache.sling.servlets.get.helpers.HtmlRendererServlet;
+import org.cyberneko.html.parsers.DOMParser;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
 
 /** Generates HTML code for JST templates */ 
 class HtmlCodeGenerator {
@@ -55,68 +68,86 @@
         htmlRenderer = new HtmlRendererServlet();
     }
     
-    /** Generate HTML code for the given request and script path */
-    void generateHtml(SlingHttpServletRequest request, String scriptPath, 
PrintWriter output) throws RepositoryException, JSONException {
+    /** Generate HTML code for the given request and script path */ 
+    void generateHtml(SlingHttpServletRequest request, String scriptPath, 
+            InputStream scriptStream, PrintWriter output) 
+    throws RepositoryException, JSONException, ScriptException, IOException {
         
         // access our data (need a Node)
         final Resource r = request.getResource();
         final Node n = r.adaptTo(Node.class);
-
-        // output HEAD with javascript initializations
-        // TODO we should instead parse (at least minimally) the template 
file, and inject our
-        // stuff in the right places
-        output.println("<html><head><title id=\"JstPageTitle\">");
-        output.println(getTitle(r, n));
-        output.println("</title>");
-        
-        // TODO get additional head stuff from the script?
-        // something like
-        //  <!-- jst:head
-        //      <link rel="stylesheet" href="/apps/foo/foo.css"/>
-        //  -->
-
-        // library scripts
-        for(String lib : libraryScripts) {
-            final String fullScriptPath =
-                SlingRequestPaths.getContextPath(request)
-                + SlingRequestPaths.getServletPath(request)
-                + lib
-            ;
-            output.println("<script type=\"text/javascript\" src=\"" + 
fullScriptPath + "\"></script>");
+        final String pageTitle = getTitle(r, n);
+        
+        // Parse script using the NekoHTML permissive HTML parser 
+        final DOMParser parser = new DOMParser();
+        try {
+            parser.setFeature("http://xml.org/sax/features/namespaces";, 
false);  
+            
parser.setProperty("http://cyberneko.org/html/properties/names/elems";, "lower");
+            
parser.setProperty("http://cyberneko.org/html/properties/names/attrs";, "lower");
+            parser.parse(new InputSource(scriptStream));
+        } catch(Exception e) {
+            final ScriptException se = new ScriptException("Error parsing 
script " + scriptPath);
+            se.initCause(e);
+            throw se;
         }
-
-        // Node data in JSON format
-        final JsonItemWriter j = new JsonItemWriter(null);
-        final int maxRecursionLevels = 1;
-        output.println("<script language='javascript'>");
-        output.print("var currentNode=");
+        final Document template = parser.getDocument();
+        
+        // compute default rendering
+        final StringWriter defaultRendering = new StringWriter();
         if(n!=null) {
-            j.dump(n, output, maxRecursionLevels);
-        } else {
-            output.print("{}");
+            final PrintWriter pw = new PrintWriter(defaultRendering);
+            htmlRenderer.render(pw, r, n);
+            pw.flush();
         }
-        output.println(";");
-        output.println("</script>");
-
-        // default rendering, turned off automatically from the javascript that
-        // follows, if javascript is enabled
-        output.println("</head><body>");
-        output.println("<div id=\"JstDefaultRendering\">");
-        if(n!=null) {
-            htmlRenderer.render(output, r, n);
+        
+        // compute currentNode values in JSON format
+        final StringWriter jsonData = new StringWriter();
+        if(n != null) {
+            final PrintWriter pw = new PrintWriter(jsonData);
+            final JsonItemWriter j = new JsonItemWriter(null);
+            final int maxRecursionLevels = 1;
+            pw.print("var currentNode=");
+            if(n!=null) {
+                j.dump(n, pw, maxRecursionLevels);
+            } else {
+                pw.print("{}");
+            }
+            pw.print(";");
+            pw.flush();
         }
-        output.println("</div>");
-        output.println("<script language=\"javascript\">");
-        output.println("var e = 
document.getElementById(\"JstDefaultRendering\"); 
e.parentNode.removeChild(e);");
-        output.println("</script>");
-        
-        // reference to script provided by the JstCodeGeneratorServlet
-        final String scriptUrl = scriptPath + ".jst.js";
-        output.println("<script type=\"text/javascript\" src=\"" + scriptUrl + 
"\"></script>");
-
-        // all done
-        output.println("</body></html>");
         
+        // run XSLT transform on script, passing parameter
+        // for our computed values
+        final String xslt = "/xslt/script-transform.xsl";
+        InputStream xslTransform = getClass().getResourceAsStream(xslt);
+        if(xslTransform == null) {
+            throw new ScriptException("XSLT transform " + xslt + " not found");
+        }
+        try {
+            final TransformerFactory tf = TransformerFactory.newInstance();
+            final Transformer t = tf.newTransformer(new 
StreamSource(xslTransform));
+            t.setParameter("pageTitle", pageTitle);
+            t.setParameter("slingScriptPath", fullPath(request,SLING_JS_PATH));
+            t.setParameter("jstScriptPath", fullPath(request, scriptPath + 
".jst.js"));
+            t.setParameter("defaultRendering", defaultRendering.toString());
+            t.setParameter("jsonData", jsonData.toString());
+            final Result result = new StreamResult(output);
+            final DOMSource source = new DOMSource(template);
+            t.transform(source, result);
+            
+        } catch (Exception e) {
+            final ScriptException se = new ScriptException("Error in XSLT 
transform for " + scriptPath);
+            se.initCause(e);
+            throw se;
+            
+        } finally {
+            xslTransform.close();
+        }
+    }
+    
+    /** Return the full path to supplied resource */
+    static String fullPath (SlingHttpServletRequest request, String path) {
+        return SlingRequestPaths.getContextPath(request) + 
SlingRequestPaths.getServletPath(request) + path;
     }
     
     /** Return the title to use for the generated page */ 

Modified: 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JsCodeGenerator.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JsCodeGenerator.java?rev=668714&r1=668713&r2=668714&view=diff
==============================================================================
--- 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JsCodeGenerator.java
 (original)
+++ 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JsCodeGenerator.java
 Tue Jun 17 08:41:57 2008
@@ -31,12 +31,13 @@
 class JsCodeGenerator {
 
     /** Convert the script read on scriptReader to javascript code and 
-     *  write the result to output using a ScriptFilteredCopy
+     *  write the result to output using a BodyOnlyScriptFilteredCopy,
+     *  to keep only the part that's relevant for the document body
      */
     void generateCode(Reader scriptReader, PrintWriter output) throws 
IOException {
         final EspReader er = new EspReader(scriptReader);
-        output.println("// Script generated by the Sling JST engine " + 
getClass().getSimpleName());
-        er.setOutInitStatement("out=document;\n");
-        new ScriptFilteredCopy().copy(er,output);
+        er.setOutInitStatement("");
+        output.println("out=document;");
+        new BodyOnlyScriptFilteredCopy().copy(er,output);
     }
 }

Modified: 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JstScriptEngine.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JstScriptEngine.java?rev=668714&r1=668713&r2=668714&view=diff
==============================================================================
--- 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JstScriptEngine.java
 (original)
+++ 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/JstScriptEngine.java
 Tue Jun 17 08:41:57 2008
@@ -19,6 +19,7 @@
 package org.apache.sling.scripting.jst;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.Reader;
 
 import javax.jcr.RepositoryException;
@@ -31,6 +32,8 @@
 import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.commons.json.JSONException;
 import org.apache.sling.scripting.api.AbstractSlingScriptEngine;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /** JST script engine.
  *  This engine does not really execute the supplied script: it dumps a default
@@ -42,7 +45,8 @@
 public class JstScriptEngine extends AbstractSlingScriptEngine {
 
     private final HtmlCodeGenerator htmlGenerator;
-    
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
     JstScriptEngine(ScriptEngineFactory scriptEngineFactory) {
         super(scriptEngineFactory);
         htmlGenerator = new HtmlCodeGenerator();
@@ -53,10 +57,12 @@
 
         final Bindings props = context.getBindings(ScriptContext.ENGINE_SCOPE);
         final SlingScriptHelper helper = (SlingScriptHelper) 
props.get(SlingBindings.SLING);
+        final InputStream scriptStream = 
helper.getScript().getScriptResource().adaptTo(InputStream.class);
         
         try {
             htmlGenerator.generateHtml(helper.getRequest(), 
-                    helper.getScript().getScriptResource().getPath(), 
helper.getResponse().getWriter());
+                    helper.getScript().getScriptResource().getPath(), 
scriptStream,
+                    helper.getResponse().getWriter());
                     
         } catch (IOException ioe) {
             throw new ScriptException(ioe);
@@ -66,9 +72,18 @@
             
         } catch(JSONException je) {
             throw new ScriptException(je);
+            
+        } finally {
+            if(scriptStream != null) {
+                try { 
+                    scriptStream.close();
+                } catch(IOException ioe) {
+                    log.warn("IOException while closing scriptStream",ioe);
+                }
+            }
         }
 
         return null;
     }
     
-}
+}
\ No newline at end of file

Modified: 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/ScriptFilteredCopy.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/ScriptFilteredCopy.java?rev=668714&r1=668713&r2=668714&view=diff
==============================================================================
--- 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/ScriptFilteredCopy.java
 (original)
+++ 
incubator/sling/trunk/scripting/jst/src/main/java/org/apache/sling/scripting/jst/ScriptFilteredCopy.java
 Tue Jun 17 08:41:57 2008
@@ -37,11 +37,17 @@
         final BufferedReader br = new BufferedReader(r);
         String line = null;
         while( (line = br.readLine()) != null) {
-            final String toWrite = processLine(line);
-            w.write(toWrite, 0, toWrite.length());
-            w.write('\n');
+            if(copyLine(line)) {
+                final String toWrite = processLine(line);
+                w.write(toWrite, 0, toWrite.length());
+                w.write('\n');
+            }
         }
     }
+    
+    protected boolean copyLine(String line) {
+        return true;
+    }
 
     /** Transform lines that look like
      *  <pre>

Added: 
incubator/sling/trunk/scripting/jst/src/main/resources/xslt/script-transform.xsl
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/scripting/jst/src/main/resources/xslt/script-transform.xsl?rev=668714&view=auto
==============================================================================
--- 
incubator/sling/trunk/scripting/jst/src/main/resources/xslt/script-transform.xsl
 (added)
+++ 
incubator/sling/trunk/scripting/jst/src/main/resources/xslt/script-transform.xsl
 Tue Jun 17 08:41:57 2008
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+    
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+
+<!-- 
+  Transform JST scripts (after they've been parsed by nekoHTML) to 
+  their HTML rendering, by adding some values passed via xsl:param 
+  to the head element, and replacing the body with the default 
+  rendering and a reference to the script that does the actual 
+  client-side rendering. 
+ -->
+<xsl:transform 
+  version="1.0" 
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+>
+
+  <!-- parameters provided by the HtmlCodeGenerator class -->
+  <xsl:param name="pageTitle"/>
+  <xsl:param name="jstScriptPath"/>
+  <xsl:param name="slingScriptPath"/>
+  <xsl:param name="defaultRendering"/>
+  <xsl:param name="jsonData"/>
+  
+  <!-- 
+    NekoHTML should provide lowercase element names but
+    that doesn't seem to work
+   -->
+  <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
+  <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
+  
+  <!-- lowercase element names and call mode=inner templates -->
+  <xsl:template match="*">
+    <xsl:element name="{translate(local-name(),$upper,$lower)}">
+      <xsl:apply-templates select="@*"/>
+      <xsl:apply-templates mode="inner" select="."/>
+    </xsl:element>
+  </xsl:template>
+  
+  <!-- copy attributes, lowercasing element names -->
+  <xsl:template match="@*">
+    <xsl:attribute name="{translate(local-name(),$upper,$lower)}">
+      <xsl:value-of select="."/>
+    </xsl:attribute>
+  </xsl:template>
+  
+  <!-- by default, nothing special in mode=inner for  -->
+  <xsl:template match="*" mode="inner">
+    <xsl:apply-templates/>
+  </xsl:template>
+  
+  <!-- replace body with default rendering + script reference -->
+  <xsl:template match="body|BODY" mode="inner">
+    <div id="JstDefaultRendering">
+     <xsl:value-of select="$defaultRendering" disable-output-escaping="yes" />
+    </div>
+    <script language="javascript">
+      var e = document.getElementById("JstDefaultRendering"); 
+      e.parentNode.removeChild(e);
+    </script>
+    <script src="{$jstScriptPath}"/>
+  </xsl:template>
+  
+  <!-- add reference to sling.js in head, and currentNode data -->
+  <xsl:template match="head|HEAD" mode="inner">
+    <xsl:apply-templates/>
+    <script src="{$slingScriptPath}"/>
+    <script language="javascript">
+      <xsl:value-of select="$jsonData"/>
+    </script>
+  </xsl:template>
+  
+  <!-- For title, set value computed from node properties -->
+  <xsl:template match="head/title|HEAD/TITLE">
+    <title>
+      <xsl:value-of select="$pageTitle"/>
+    </title>
+  </xsl:template>
+  
+</xsl:transform>
\ No newline at end of file

Propchange: 
incubator/sling/trunk/scripting/jst/src/main/resources/xslt/script-transform.xsl
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to