Author: buildbot
Date: Fri Aug  3 15:22:07 2012
New Revision: 827830

Log:
Staging update by buildbot for vcl

Added:
    websites/staging/vcl/trunk/content/downloads/
    websites/staging/vcl/trunk/content/downloads/.htaccess
    websites/staging/vcl/trunk/content/downloads/download.cgi
    websites/staging/vcl/trunk/content/downloads/download.html
    websites/staging/vcl/trunk/content/downloads/ezt.py
    websites/staging/vcl/trunk/content/downloads/mirrors.cgi
Modified:
    websites/staging/vcl/trunk/content/   (props changed)

Propchange: websites/staging/vcl/trunk/content/
------------------------------------------------------------------------------
--- cms:source-revision (original)
+++ cms:source-revision Fri Aug  3 15:22:07 2012
@@ -1 +1 @@
-1367718
+1369024

Added: websites/staging/vcl/trunk/content/downloads/.htaccess
==============================================================================
--- websites/staging/vcl/trunk/content/downloads/.htaccess (added)
+++ websites/staging/vcl/trunk/content/downloads/.htaccess Fri Aug  3 15:22:07 
2012
@@ -0,0 +1 @@
+Options +ExecCGI
\ No newline at end of file

Added: websites/staging/vcl/trunk/content/downloads/download.cgi
==============================================================================
--- websites/staging/vcl/trunk/content/downloads/download.cgi (added)
+++ websites/staging/vcl/trunk/content/downloads/download.cgi Fri Aug  3 
15:22:07 2012
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Wrapper script around mirrors.cgi script
+# (we must change to that directory in order for python to pick up the
+#  python includes correctly)
+cd /www/vcl.apache.org/content/downloads
+/www/vcl.apache.org/content/downloads/mirrors.cgi $*
\ No newline at end of file

Added: websites/staging/vcl/trunk/content/downloads/download.html
==============================================================================
--- websites/staging/vcl/trunk/content/downloads/download.html (added)
+++ websites/staging/vcl/trunk/content/downloads/download.html Fri Aug  3 
15:22:07 2012
@@ -0,0 +1,207 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd";>
+<html>
+<head>
+<!--
+
+    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.
+-->
+
+  <link href="/css/vcl.css" rel="stylesheet" type="text/css">
+  <link href="/css/code.css" rel="stylesheet" type="text/css">
+  <title>Apache VCL - Downloads</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+</head>
+
+<body>
+  <div id="sitetitle">
+    <table width="100%" border="0" cellspacing="0" cellpadding="5">
+      <tr>
+                 <td><a href="/index.html">Apache VCL</a></td>
+        <td><img src="/img/vcllogo.png" width="63" height="52" 
align="right"></td>
+      </tr>
+    </table>
+  </div>
+
+  <div id="navigation"> 
+  <ul>
+<li>Information<ul>
+<li><a href="/info/about.html">What is VCL?</a></li>
+<li><a href="/info/features.html">Features</a></li>
+<li><a href="/info/architecture.html">Architecture</a></li>
+<li><a href="/info/use-cases.html">Use Cases</a></li>
+<li><a href="/download.cgi">Download</a></li>
+<li><a href="/info/license.html">License</a></li>
+<li><a href="/info/faq.html">FAQ</a></li>
+</ul>
+</li>
+<li><a href="/docs/index.html">Documentation</a><ul>
+<li><a href="/docs/using-vcl.html">Using VCL</a></li>
+<li><a href="/docs/image-creation.html">Image Creation</a></li>
+<li><a href="/docs/administration.html">Administration</a></li>
+<li><a href="/docs/installation.html">Installation</a></li>
+<li><a href="/docs/deployment-planning.html">Deployment Planning</a></li>
+</ul>
+</li>
+<li><a href="/comm/index.html">Community</a><ul>
+<li><a href="/comm/index.html#getInvolved">Getting Involved</a></li>
+<li><a href="/comm/index.html#mail-list">Mailing Lists</a></li>
+<li><a href="/comm/index.html#how-do-i-join-the-project">How can I 
Join</a></li>
+<li><a href="/comm/wiki.html">Wiki</a></li>
+<li><a href="/dev/index.html">Development</a><ul>
+<li><a href="/dev/jira.html">Issue Tracking</a></li>
+<li><a href="/dev/code-documentation.html">Code Documentation</a></li>
+<li><a href="/dev/roadmap.html">Roadmap</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><a href="http://www.apache.org";>Apache Software Foundation</a><ul>
+<li><a href="http://www.apache.org/foundation/thanks.html";>Thanks</a></li>
+<li><a href="http://www.apache.org/foundation/sponsorship.html";>Become a 
Sponsor</a></li>
+</ul>
+</li>
+</ul>
+  </div>
+  
+  <div id="content">
+    <h1 class="title">Downloads</h1>
+    <h2 id="download-links">Download Links</h2>
+<p>Use the links below to download Apache VCL from one of our mirrors. You 
<strong>must</strong>
+<a href="download.cgi#verify">verify the integrity</a> of the downloaded files 
using 
+signatures downloaded from our main distribution directory, 
<strong>not</strong> from 
+a mirror.</p>
+<p>Only current recommended releases are available on the main distribution 
site and
+its mirrors. Older releases are available from the archive download site.</p>
+<p>Stable Release - Latest Version:</p>
+<ul>
+<li><a 
href="[location]?Preferred=[preferred]&action=download&filename=%2Fvcl%2Fapache-VCL-2.3.tar.bz2">apache-VCL-2.3.tar.bz2</a>
+[ <a href="http://www.apache.org/dist/vcl/apache-VCL-2.3.tar.bz2.asc";>GPG</a> ]
+[ <a 
href="http://www.apache.org/dist/vcl/apache-VCL-2.3.tar.bz2.sha1";>SHA1</a> ]
+[ <a href="http://www.apache.org/dist/vcl/apache-VCL-2.3.tar.bz2.md5";>MD5</a> ]
+(released 2012-07-20)</li>
+</ul>
+<p>Previous Releases:</p>
+<ul>
+<li><a 
href="[location]?Preferred=http://archive.apache.org/dist/&action=download&filename=%2Fincubator%2Fvcl%2Fapache-VCL-2.2.1-incubating.tar.bz2";>apache-VCL-2.2.1-incubating.tar.bz2</a>
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2.1-incubating.tar.bz2.asc";>GPG</a>
 ]
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2.1-incubating.tar.bz2.sha1";>SHA1</a>
 ]
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2.1-incubating.tar.bz2.md5";>MD5</a>
 ]
+(released 2011-04-08)</li>
+<li><a 
href="[location]?Preferred=http://archive.apache.org/dist/&action=download&filename=%2Fincubator%2Fvcl%2Fapache-VCL-2.2-incubating.tar.bz2";>apache-VCL-2.2-incubating.tar.bz2</a>
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2-incubating.tar.bz2.asc";>GPG</a>
 ]
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2-incubating.tar.bz2.sha1";>SHA1</a>
 ]
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.2-incubating.tar.bz2.md5";>MD5</a>
 ]
+(released 2010-10-05)</li>
+<li><a 
href="[location]?Preferred=http://archive.apache.org/dist/&action=download&filename=%2Fincubator%2Fvcl%2Fapache-VCL-2.1-incubating.tar.bz2";>apache-VCL-2.1-incubating.tar.bz2</a>
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.1-incubating.tar.bz2.asc";>GPG</a>
 ]
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.1-incubating.tar.bz2.sha1";>SHA1</a>
 ]
+[ <a 
href="http://archive.apache.org/dist/incubator/vcl/apache-VCL-2.1-incubating.tar.bz2.md5";>MD5</a>
 ]
+(released 2009-12-04)</li>
+</ul>
+<h2 id="mirror">Mirror</h2>
+<p>The currently selected mirror is <strong>[preferred]</strong>. If you 
encounter a problem with this 
+mirror, please select another mirror. If all mirrors are failing, there are 
backup 
+mirrors (at the end of the mirrors list) that should be available.</p>
+<form name="setmirror" method="get" action="[location]">
+Other mirrors: 
+<select name="Preferred">
+[if-any http]
+  [for http]
+    <option value="[http]">[http]</option>
+  [end]
+[end]
+[if-any ftp]
+  [for ftp]
+    <option value="[ftp]">[ftp]</option>
+  [end]
+[end]
+[if-any backup]
+  [for backup]
+    <option value="[backup]">[backup] (backup)</option>
+  [end]
+[end]
+</select>
+<input type="submit" value="Change"></input>
+</form>
+
+<p>You may also consult the <a href="http://www.apache.org/mirrors/";>complete 
list of mirrors</a>.</p>
+<p><a name="verify"></a></p>
+<h2 id="verifying-the-integrity-of-the-files">Verifying the integrity of the 
files</h2>
+<p>It is essential that you verify the integrity of the downloaded files using 
the PGP or 
+MD5 signatures. Security of the mirrors cannot be guaranteed, which means 
malicious code 
+could be added to the downloads from the mirrors. By verifying the integrity 
of 
+downloaded release files, you ensure they have not been tainted.</p>
+<p>Run the following command to verify the MD5 sum. It should give output 
similar to 
+"apache-VCL-2.3.tar.bz2: OK":</p>
+<pre>
+md5sum &#45;c apache-VCL-2.3.tar.bz2.md5
+</pre>
+
+<p>Similarly, run the following command to verify the SHA1 sum. You should get 
output 
+similar to "apache-VCL-2.3.tar.bz2: OK":</p>
+<pre>
+sha1sum &#45;c apache-VCL-2.3.tar.bz2.sha1
+</pre></p>
+<p>To verify the GPG signature (you'll need to have 
+<a href="http://www.gnupg.org/";>GnuPG</a> installed):</p>
+<ol>
+<li>download and import the VCL KEYS file (if you've imported the KEYS file 
for previously releases, you do not need to import it again):<br>
+gpg &#45;-import KEYS</li>
+<li>download the GPG Signature to the same location as the release file</li>
+<li>from the directory containing both the release file and the GPG signature, 
run<br>
+gpg &#45;-verify apache-VCL-2.3.tar.bz2.asc</li>
+</ol>
+<h2 id="installation">Installation</h2>
+<p>For new installs, visit the on-line installation guide:</p>
+<p>Latest Version:</p>
+<ul>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/VCL+2.3+Installation";>Apache
 VCL 2.3 Installation Guide</a></li>
+</ul>
+<p>Previous Versions:</p>
+<ul>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/VCL+2.3+Installation";>Apache
 VCL 2.2.1 Installation Guide</a></li>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/VCL+2.3+Installation";>Apache
 VCL 2.2 Installation Guide</a></li>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/VCL+2.3+Installation";>Apache
 VCL 2.1 Installation Guide</a></li>
+</ul>
+<h2 id="upgrading">Upgrading</h2>
+<p>For upgrades, visit the on-line upgrade guide:</p>
+<p>Upgrade to latest version:</p>
+<ul>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.2.1+to+2.3%29";>upgrade
 2.2.1 to 2.3</a></li>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.2+to+2.3%29";>upgrade
 2.2 to 2.3</a></li>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.1+to+2.3%29";>upgrade
 2.1 to 2.3</a></li>
+</ul>
+<p>Upgrade really old versions to older versions:</p>
+<ul>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.2+to+2.2.1%29";>upgrade
 2.2 to 2.2.1</a></li>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version+%282.1+to+2.2.1%29";>upgrade
 2.1 to 2.2.1</a></li>
+<li><a 
href="http://cwiki.apache.org/confluence/display/VCL/Upgrade+From+Previous+Version";>upgrade
 2.1 to 2.2</a></li>
+</ul>
+  </div>
+  
+  <div id="footer">
+    <div class="copyright">
+      <p>
+        Copyright &copy; 2012 The Apache Software Foundation, Licensed under 
+        the <a href="http://www.apache.org/licenses/LICENSE-2.0";>Apache 
License, Version 2.0</a>.
+        <br />
+        Apache and the Apache feather logo are trademarks of The Apache 
Software Foundation.
+      </p>
+    </div>
+  </div>
+  
+</body>
+</html>

Added: websites/staging/vcl/trunk/content/downloads/ezt.py
==============================================================================
--- websites/staging/vcl/trunk/content/downloads/ezt.py (added)
+++ websites/staging/vcl/trunk/content/downloads/ezt.py Fri Aug  3 15:22:07 2012
@@ -0,0 +1,653 @@
+#!/usr/bin/env python
+"""ezt.py -- EaZy Templating
+
+For documentation, please see: http://code.google.com/p/ezt/wiki/Syntax
+"""
+#
+# Copyright (C) 2001-2011 Greg Stein. 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 REGENTS 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.
+#
+#
+# This software is maintained by Greg and is available at:
+#    http://code.google.com/p/ezt/
+#
+
+__author__ = 'Greg Stein'
+__version__ = '1.0'
+__license__ = 'BSD'
+
+import re
+from types import StringType, IntType, FloatType, LongType
+import os
+import urllib
+try:
+  import cStringIO
+except ImportError:
+  import StringIO
+  cStringIO = StringIO
+
+#
+# Formatting types
+#
+FORMAT_RAW = 'raw'
+FORMAT_HTML = 'html'
+FORMAT_XML = 'xml'
+FORMAT_JS = 'js'
+FORMAT_URL = 'url'
+
+#
+# This regular expression matches three alternatives:
+#   expr: NEWLINE | DIRECTIVE | BRACKET | COMMENT
+#   DIRECTIVE: '[' ITEM (whitespace ITEM)* ']
+#   ITEM: STRING | NAME
+#   STRING: '"' (not-slash-or-dquote | '\' anychar)* '"'
+#   NAME: (alphanum | '_' | '-' | '.')+
+#   BRACKET: '[[]'
+#   COMMENT: '[#' not-rbracket* ']'
+#
+# When used with the split() method, the return value will be composed of
+# non-matching text and the three paren groups (NEWLINE, DIRECTIVE and
+# BRACKET). Since the COMMENT matches are not placed into a group, they are
+# considered a "splitting" value and simply dropped.
+#
+_item = r'(?:"(?:[^\\"]|\\.)*"|[-\w.]+)'
+_re_parse = re.compile(r'(\r?\n)|\[(%s(?: +%s)*)\]|(\[\[\])|\[#[^\]]*\]' %
+                       (_item, _item))
+
+_re_args = re.compile(r'"(?:[^\\"]|\\.)*"|[-\w.]+')
+
+# block commands and their argument counts
+_block_cmd_specs = { 'if-index':2, 'for':1, 'is':2, 'define':1, 'format':1 }
+_block_cmds = _block_cmd_specs.keys()
+
+# two regular expressions for compressing whitespace. the first is used to
+# compress any whitespace including a newline into a single newline. the
+# second regex is used to compress runs of whitespace into a single space.
+_re_newline = re.compile('[ \t\r\f\v]*\n\\s*')
+_re_whitespace = re.compile(r'\s\s+')
+
+# this regex is used to substitute arguments into a value. we split the value,
+# replace the relevant pieces, and then put it all back together. splitting
+# will produce a list of: TEXT ( splitter TEXT )*. splitter will be '%' or
+# an integer.
+_re_subst = re.compile('%(%|[0-9]+)')
+
+class Template:
+
+  def __init__(self, fname=None, compress_whitespace=1,
+               base_format=FORMAT_RAW):
+    self.compress_whitespace = compress_whitespace
+    if fname:
+      self.parse_file(fname, base_format)
+
+  def parse_file(self, fname, base_format=FORMAT_RAW):
+    "fname -> a string object with pathname of file containg an EZT template."
+
+    self.parse(_FileReader(fname), base_format)
+
+  def parse(self, text_or_reader, base_format=FORMAT_RAW):
+    """Parse the template specified by text_or_reader.
+
+    The argument should be a string containing the template, or it should
+    specify a subclass of ezt.Reader which can read templates. The base
+    format for printing values is given by base_format.
+    """
+    if not isinstance(text_or_reader, Reader):
+      # assume the argument is a plain text string
+      text_or_reader = _TextReader(text_or_reader)
+
+    self.program = self._parse(text_or_reader,
+                               base_printer=_parse_format(base_format))
+
+  def generate(self, fp, data):
+    if hasattr(data, '__getitem__') or callable(getattr(data, 'keys', None)):
+      # a dictionary-like object was passed. convert it to an
+      # attribute-based object.
+      class _data_ob:
+        def __init__(self, d):
+          vars(self).update(d)
+      data = _data_ob(data)
+
+    ctx = _context()
+    ctx.data = data
+    ctx.for_index = { }
+    ctx.defines = { }
+    self._execute(self.program, fp, ctx)
+
+  def _parse(self, reader, for_names=None, file_args=(), base_printer=None):
+    """text -> string object containing the template.
+
+    This is a private helper function doing the real work for method parse.
+    It returns the parsed template as a 'program'.  This program is a sequence
+    made out of strings or (function, argument) 2-tuples.
+
+    Note: comment directives [# ...] are automatically dropped by _re_parse.
+    """
+
+    filename = reader.filename()
+    # parse the template program into: (TEXT NEWLINE DIRECTIVE BRACKET)* TEXT
+    parts = _re_parse.split(reader.text)
+
+    program = [ ]
+    stack = [ ]
+    if not for_names:
+      for_names = [ ]
+
+    if base_printer is None:
+      base_printer = ()
+    printers = [ base_printer ]
+
+    one_newline_copied = False
+    line_number = 1
+    for i in range(len(parts)):
+      piece = parts[i]
+      which = i % 4  # discriminate between: TEXT NEWLINE DIRECTIVE BRACKET
+      if which == 0:
+        # TEXT. append if non-empty.
+        if piece:
+          if self.compress_whitespace:
+            piece = _re_whitespace.sub(' ', piece)
+          program.append(piece)
+          one_newline_copied = False
+      elif which == 1:
+        # NEWLINE. append unless compress_whitespace requested
+        if piece:
+          line_number += 1
+          if self.compress_whitespace:
+            if not one_newline_copied:
+              program.append('\n')
+              one_newline_copied = True
+          else:
+            program.append(piece)
+      elif which == 3:
+        # BRACKET directive. append '[' if present.
+        if piece:
+          program.append('[')
+          one_newline_copied = False
+      elif piece:
+        # DIRECTIVE is present.
+        one_newline_copied = False
+        args = _re_args.findall(piece)
+        cmd = args[0]
+        if cmd == 'else':
+          if len(args) > 1:
+            raise ArgCountSyntaxError(str(args[1:]), filename, line_number)
+          ### check: don't allow for 'for' cmd
+          idx = stack[-1][1]
+          true_section = program[idx:]
+          del program[idx:]
+          stack[-1][3] = true_section
+        elif cmd == 'end':
+          if len(args) > 1:
+            raise ArgCountSyntaxError(str(args[1:]), filename, line_number)
+          # note: true-section may be None
+          try:
+            cmd, idx, args, true_section, start_line_number = stack.pop()
+          except IndexError:
+            raise UnmatchedEndError(None, filename, line_number)
+          else_section = program[idx:]
+          if cmd == 'format':
+            printers.pop()
+          else:
+            func = getattr(self, '_cmd_' + re.sub('-', '_', cmd))
+            program[idx:] = [ (func, (args, true_section, else_section),
+                               filename, line_number) ]
+            if cmd == 'for':
+              for_names.pop()
+        elif cmd in _block_cmds:
+          if len(args) > _block_cmd_specs[cmd] + 1:
+            raise ArgCountSyntaxError(str(args[1:]), filename, line_number)
+          ### this assumes arg1 is always a ref unless cmd is 'define'
+          if cmd != 'define':
+            args[1] = _prepare_ref(args[1], for_names, file_args)
+
+          # handle arg2 for the 'is' command
+          if cmd == 'is':
+            args[2] = _prepare_ref(args[2], for_names, file_args)
+          elif cmd == 'for':
+            for_names.append(args[1][0])  # append the refname
+          elif cmd == 'format':
+            if args[1][0]:
+              raise BadFormatConstantError(str(args[1:]), filename, 
line_number)
+            printers.append(_parse_format(args[1][1]))
+
+          # remember the cmd, current pos, args, and a section placeholder
+          stack.append([cmd, len(program), args[1:], None, line_number])
+        elif cmd == 'include' or cmd == 'insertfile':
+          is_insertfile = (cmd == 'insertfile')
+          # extra arguments are meaningless when using insertfile
+          if is_insertfile and len(args) != 2:
+            raise ArgCountSyntaxError(str(args), filename, line_number)
+          if args[1][0] == '"':
+            include_filename = args[1][1:-1]
+            if is_insertfile:
+              program.append(reader.read_other(include_filename).text)
+            else:
+              f_args = [ ]
+              for arg in args[2:]:
+                f_args.append(_prepare_ref(arg, for_names, file_args))
+              program.extend(self._parse(reader.read_other(include_filename),
+                                         for_names, f_args, printers[-1]))
+          else:
+            if len(args) != 2:
+              raise ArgCountSyntaxError(str(args), filename, line_number)
+            if is_insertfile:
+              cmd = self._cmd_insertfile
+            else:
+              cmd = self._cmd_include
+            program.append((cmd,
+                            (_prepare_ref(args[1], for_names, file_args),
+                             reader, printers[-1]), filename, line_number))
+        elif cmd == 'if-any':
+          f_args = [ ]
+          for arg in args[1:]:
+            f_args.append(_prepare_ref(arg, for_names, file_args))
+          stack.append(['if-any', len(program), f_args, None, line_number])
+        else:
+          # implied PRINT command
+          if len(args) > 1:
+            f_args = [ ]
+            for arg in args:
+              f_args.append(_prepare_ref(arg, for_names, file_args))
+            program.append((self._cmd_subst,
+                            (printers[-1], f_args[0], f_args[1:]),
+                            filename, line_number))
+          else:
+            valref = _prepare_ref(args[0], for_names, file_args)
+            program.append((self._cmd_print, (printers[-1], valref),
+                            filename, line_number))
+
+    if stack:
+      raise UnclosedBlocksError('Block opened at line %s' % stack[-1][4],
+                                filename=filename)
+    return program
+
+  def _execute(self, program, fp, ctx):
+    """This private helper function takes a 'program' sequence as created
+    by the method '_parse' and executes it step by step.  strings are written
+    to the file object 'fp' and functions are called.
+    """
+    for step in program:
+      if isinstance(step, StringType):
+        fp.write(step)
+      else:
+        method, method_args, filename, line_number = step
+        method(method_args, fp, ctx, filename, line_number)
+
+  def _cmd_print(self, (transforms, valref), fp, ctx, filename, line_number):
+    value = _get_value(valref, ctx, filename, line_number)
+    # if the value has a 'read' attribute, then it is a stream: copy it
+    if hasattr(value, 'read'):
+      while 1:
+        chunk = value.read(16384)
+        if not chunk:
+          break
+        for t in transforms:
+          chunk = t(chunk)
+        fp.write(chunk)
+    else:
+      for t in transforms:
+        value = t(value)
+      fp.write(value)
+
+  def _cmd_subst(self, (transforms, valref, args), fp, ctx, filename,
+                 line_number):
+    fmt = _get_value(valref, ctx, filename, line_number)
+    parts = _re_subst.split(fmt)
+    for i in range(len(parts)):
+      piece = parts[i]
+      if i%2 == 1 and piece != '%':
+        idx = int(piece)
+        if idx < len(args):
+          piece = _get_value(args[idx], ctx, filename, line_number)
+        else:
+          piece = '<undef>'
+      for t in transforms:
+        piece = t(piece)
+      fp.write(piece)
+
+  def _cmd_include(self, (valref, reader, printer), fp, ctx, filename,
+                   line_number):
+    fname = _get_value(valref, ctx, filename, line_number)
+    ### note: we don't have the set of for_names to pass into this parse.
+    ### I don't think there is anything to do but document it
+    self._execute(self._parse(reader.read_other(fname), base_printer=printer),
+                  fp, ctx)
+
+  def _cmd_insertfile(self, (valref, reader, printer), fp, ctx, filename,
+                      line_number):
+    fname = _get_value(valref, ctx, filename, line_number)
+    fp.write(reader.read_other(fname).text)
+
+  def _cmd_if_any(self, args, fp, ctx, filename, line_number):
+    "If any value is a non-empty string or non-empty list, then T else F."
+    (valrefs, t_section, f_section) = args
+    value = 0
+    for valref in valrefs:
+      if _get_value(valref, ctx, filename, line_number):
+        value = 1
+        break
+    self._do_if(value, t_section, f_section, fp, ctx)
+
+  def _cmd_if_index(self, args, fp, ctx, filename, line_number):
+    ((valref, value), t_section, f_section) = args
+    list, idx = ctx.for_index[valref[0]]
+    if value == 'even':
+      value = idx % 2 == 0
+    elif value == 'odd':
+      value = idx % 2 == 1
+    elif value == 'first':
+      value = idx == 0
+    elif value == 'last':
+      value = idx == len(list)-1
+    else:
+      value = idx == int(value)
+    self._do_if(value, t_section, f_section, fp, ctx)
+
+  def _cmd_is(self, args, fp, ctx, filename, line_number):
+    ((left_ref, right_ref), t_section, f_section) = args
+    right_value = _get_value(right_ref, ctx, filename, line_number)
+    left_value = _get_value(left_ref, ctx, filename, line_number)
+    value = left_value.lower() == right_value.lower()
+    self._do_if(value, t_section, f_section, fp, ctx)
+
+  def _do_if(self, value, t_section, f_section, fp, ctx):
+    if t_section is None:
+      t_section = f_section
+      f_section = None
+    if value:
+      section = t_section
+    else:
+      section = f_section
+    if section is not None:
+      self._execute(section, fp, ctx)
+
+  def _cmd_for(self, args, fp, ctx, filename, line_number):
+    ((valref,), unused, section) = args
+    list = _get_value(valref, ctx, filename, line_number)
+    refname = valref[0]
+    if isinstance(list, StringType):
+      raise NeedSequenceError(refname, filename, line_number)
+    ctx.for_index[refname] = idx = [ list, 0 ]
+    for item in list:
+      self._execute(section, fp, ctx)
+      idx[1] = idx[1] + 1
+    del ctx.for_index[refname]
+
+  def _cmd_define(self, args, fp, ctx, filename, line_number):
+    ((name,), unused, section) = args
+    valfp = cStringIO.StringIO()
+    if section is not None:
+      self._execute(section, valfp, ctx)
+    ctx.defines[name] = valfp.getvalue()
+
+def boolean(value):
+  "Return a value suitable for [if-any bool_var] usage in a template."
+  if value:
+    return 'yes'
+  return None
+
+
+def _prepare_ref(refname, for_names, file_args):
+  """refname -> a string containing a dotted identifier. example:"foo.bar.bang"
+  for_names -> a list of active for sequences.
+
+  Returns a `value reference', a 3-tuple made out of (refname, start, rest),
+  for fast access later.
+  """
+  # is the reference a string constant?
+  if refname[0] == '"':
+    return None, refname[1:-1], None
+
+  parts = refname.split('.')
+  start = parts[0]
+  rest = parts[1:]
+
+  # if this is an include-argument, then just return the prepared ref
+  if start[:3] == 'arg':
+    try:
+      idx = int(start[3:])
+    except ValueError:
+      pass
+    else:
+      if idx < len(file_args):
+        orig_refname, start, more_rest = file_args[idx]
+        if more_rest is None:
+          # the include-argument was a string constant
+          return None, start, None
+
+        # prepend the argument's "rest" for our further processing
+        rest[:0] = more_rest
+
+        # rewrite the refname to ensure that any potential 'for' processing
+        # has the correct name
+        ### this can make it hard for debugging include files since we lose
+        ### the 'argNNN' names
+        if not rest:
+          return start, start, [ ]
+        refname = start + '.' + '.'.join(rest)
+
+  if for_names:
+    # From last to first part, check if this reference is part of a for loop
+    for i in range(len(parts), 0, -1):
+      name = '.'.join(parts[:i])
+      if name in for_names:
+        return refname, name, parts[i:]
+
+  return refname, start, rest
+
+def _get_value((refname, start, rest), ctx, filename, line_number):
+  """(refname, start, rest) -> a prepared `value reference' (see above).
+  ctx -> an execution context instance.
+
+  Does a name space lookup within the template name space.  Active
+  for blocks take precedence over data dictionary members with the
+  same name.
+  """
+  if rest is None:
+    # it was a string constant
+    return start
+
+  # get the starting object
+  if ctx.for_index.has_key(start):
+    list, idx = ctx.for_index[start]
+    ob = list[idx]
+  elif ctx.defines.has_key(start):
+    ob = ctx.defines[start]
+  elif hasattr(ctx.data, start):
+    ob = getattr(ctx.data, start)
+  else:
+    raise UnknownReference(refname, filename, line_number)
+
+  # walk the rest of the dotted reference
+  for attr in rest:
+    try:
+      ob = getattr(ob, attr)
+    except AttributeError:
+      raise UnknownReference(refname, filename, line_number)
+
+  # make sure we return a string instead of some various Python types
+  if isinstance(ob, (IntType, FloatType, LongType)):
+    return str(ob)
+  if ob is None:
+    return ''
+
+  # string or a sequence
+  return ob
+
+def _replace(s, replace_map):
+  for orig, repl in replace_map:
+    s = s.replace(orig, repl)
+  return s
+
+REPLACE_JS_MAP = (
+  ('\\', r'\\'), ('\t', r'\t'), ('\n', r'\n'), ('\r', r'\r'),
+  ('"', r'\x22'), ('\'', r'\x27'), ('&', r'\x26'),
+  ('<', r'\x3c'), ('>', r'\x3e'), ('=', r'\x3d'),
+)
+
+# Various unicode whitespace
+REPLACE_JS_UNICODE_MAP = (
+  (u'\u0085', r'\u0085'), (u'\u2028', r'\u2028'), (u'\u2029', r'\u2029'),
+)
+
+# Why not cgi.escape? It doesn't do single quotes which are occasionally
+# used to contain HTML attributes and event handler definitions (unfortunately)
+REPLACE_HTML_MAP = (
+  ('&', '&amp;'), ('<', '&lt;'), ('>', '&gt;'),
+  ('"', '&quot;'), ('\'', '&#39;'),
+)
+
+def _js_escape(s):
+  s = _replace(s, REPLACE_JS_MAP)
+  ### perhaps attempt to coerce the string to unicode and then replace?
+  if isinstance(s, unicode):
+    s = _replace(s, REPLACE_JS_UNICODE_MAP)
+  return s
+
+def _html_escape(s):
+  return _replace(s, REPLACE_HTML_MAP)
+
+def _url_escape(s):
+  ### quote_plus barfs on non-ASCII characters. According to
+  ### http://www.w3.org/International/O-URL-code.html URIs should be
+  ### UTF-8 encoded first.
+  if isinstance(s, unicode):
+    s = s.encode('utf8')
+  return urllib.quote_plus(s)
+
+FORMATTERS = {
+  FORMAT_RAW: None,
+  FORMAT_HTML: _html_escape,
+  FORMAT_XML: _html_escape,   ### use the same quoting as HTML for now
+  FORMAT_JS: _js_escape,
+  FORMAT_URL: _url_escape,
+}
+
+def _parse_format(format_string=FORMAT_RAW):
+  format_funcs = []
+  try:
+    for fspec in format_string.split(','):
+      format_func = FORMATTERS[fspec]
+      if format_func is not None:
+        format_funcs.append(format_func)
+  except KeyError:
+    raise UnknownFormatConstantError(format_string)
+  return format_funcs
+
+class _context:
+  """A container for the execution context"""
+
+
+class Reader:
+  """Abstract class which allows EZT to detect Reader objects."""
+  def filename(self):
+    return '(%s does not provide filename() method)' % repr(self)
+
+class _FileReader(Reader):
+  """Reads templates from the filesystem."""
+  def __init__(self, fname):
+    self.text = open(fname, 'rb').read()
+    self._dir = os.path.dirname(fname)
+    self.fname = fname
+  def read_other(self, relative):
+    return _FileReader(os.path.join(self._dir, relative))
+  def filename(self):
+    return self.fname
+
+class _TextReader(Reader):
+  """'Reads' a template from provided text."""
+  def __init__(self, text):
+    self.text = text
+  def read_other(self, relative):
+    raise BaseUnavailableError()
+  def filename(self):
+    return '(text)'
+
+
+class EZTException(Exception):
+  """Parent class of all EZT exceptions."""
+  def __init__(self, message=None, filename=None, line_number=None):
+    self.message = message
+    self.filename = filename
+    self.line_number = line_number
+  def __str__(self):
+    ret = []
+    if self.message is not None:
+      ret.append(self.message)
+    if self.filename is not None:
+      ret.append('in file ' + str(self.filename))
+    if self.line_number is not None:
+      ret.append('at line ' + str(self.line_number))
+    return ' '.join(ret)
+
+class ArgCountSyntaxError(EZTException):
+  """A bracket directive got the wrong number of arguments."""
+
+class UnknownReference(EZTException):
+  """The template references an object not contained in the data dictionary."""
+
+class NeedSequenceError(EZTException):
+  """The object dereferenced by the template is no sequence (tuple or list)."""
+
+class UnclosedBlocksError(EZTException):
+  """This error may be simply a missing [end]."""
+
+class UnmatchedEndError(EZTException):
+  """This error may be caused by a misspelled if directive."""
+
+class BaseUnavailableError(EZTException):
+  """Base location is unavailable, which disables includes."""
+
+class BadFormatConstantError(EZTException):
+  """Format specifiers must be string constants."""
+
+class UnknownFormatConstantError(EZTException):
+  """The format specifier is an unknown value."""
+
+
+# --- standard test environment ---
+def test_parse():
+  assert _re_parse.split('[a]') == ['', '[a]', None, '']
+  assert _re_parse.split('[a] [b]') == \
+         ['', '[a]', None, ' ', '[b]', None, '']
+  assert _re_parse.split('[a c] [b]') == \
+         ['', '[a c]', None, ' ', '[b]', None, '']
+  assert _re_parse.split('x [a] y [b] z') == \
+         ['x ', '[a]', None, ' y ', '[b]', None, ' z']
+  assert _re_parse.split('[a "b" c "d"]') == \
+         ['', '[a "b" c "d"]', None, '']
+  assert _re_parse.split(r'["a \"b[foo]" c.d f]') == \
+         ['', '["a \\"b[foo]" c.d f]', None, '']
+
+def _test(argv):
+  import doctest, ezt
+  verbose = "-v" in argv
+  return doctest.testmod(ezt, verbose=verbose)
+
+if __name__ == "__main__":
+  # invoke unit test for this module:
+  import sys
+  sys.exit(_test(sys.argv)[0])

Added: websites/staging/vcl/trunk/content/downloads/mirrors.cgi
==============================================================================
--- websites/staging/vcl/trunk/content/downloads/mirrors.cgi (added)
+++ websites/staging/vcl/trunk/content/downloads/mirrors.cgi Fri Aug  3 
15:22:07 2012
@@ -0,0 +1,274 @@
+#!/usr/local/bin/python2.7
+# -*- python -*-
+#
+# 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.
+#
+#
+# This is a Python CGI script that uses EZT to produce templated
+# mirror content and GeoIP to choose the appropriate mirror
+#
+
+import sys
+import os
+import cgi
+import stat
+import random
+import time
+import traceback
+import cStringIO
+
+# Should be installed in the main system library
+import GeoIP
+
+# Insert this directory into PATH so that we can import ezt
+this_dir = os.path.dirname(__file__) or '.'
+sys.path.insert(0, this_dir)
+
+import ezt
+
+
+# Configurable stuff
+MIRRORS_LIST = "/x1/www/www.apache.org/mirrors/mirrors.list"
+DEFAULT_REGION = "us"
+DEFAULT_TEMPLATE = "/x1/www/www.apache.org/dyn/closer.html"
+DEFAULT_LOCATION = "http://www.apache.org/dyn/closer.cgi";
+
+
+def get_region(environ):
+  """Use GeoIP to find the client's country, falling back to
+     DEFAULT_REGION on failure."""
+  try:
+    remote_ip = environ['REMOTE_ADDR'];
+    gi = GeoIP.new(GeoIP.GEOIP_STANDARD)
+    region = gi.country_code_by_addr(remote_ip).lower().strip()
+    if region == 'gb':
+      return 'uk'
+    else:
+      return region
+  except:
+    ### should we log an error here? absorbing without reporting is
+    ### generally bad form.
+    return DEFAULT_REGION
+
+
+def parse_mirrors(filename, country, preferred, mingood):
+  """Parse the mirror database to find the best mirrors for a client.
+
+  The Format of the mirror database is (last two fields are optional):
+  ftp au  ftp://ftp.planetmirror.com/pub/apache/dist/ 1117724635 
http://example.com/logo.gif http://example.com/ """
+
+  output = { 'http'   : [ ],
+             'ftp'    : [ ],
+             'backup' : [ ],
+             'preferred' : None,
+             'logo' : None,
+             'link' : None,
+             }
+
+  # Read the mirror database and put it in a list of lists
+  # skip empty lines and comment
+  mirrors = [line.split() for line in open(filename).readlines()
+             if line.strip() and not line.startswith('#')]
+
+  mirrors.append(['http', 'us', 'http://archive.apache.org/dist/', 
'9999999999'])
+
+  # Add trailing slashes where missing.  Otherwise,
+  # strcat("http://www.mirror.org";, pathinfo=".foo.evil") would link to
+  # http://www.mirror.org.foo.evil
+  for mir in mirrors:
+    if not mir[2].endswith('/'):
+      mir[2] += '/'
+
+  # grab the backup mirrors
+  backupmirrors = [mir for mir in mirrors if mir[1] == 'Backup']
+
+  # Grab the mirrors for the requested country or, failing that,
+  # from the default region (us)
+  for region in (country, DEFAULT_REGION):
+    countrymirrors = [mir for mir in mirrors if mir[1] == region]
+    random.shuffle(countrymirrors)
+    goodmirror = None
+    for mir in countrymirrors:
+      if mir[0] == 'http' and int(mir[3]) > mingood:
+        goodmirror = mir
+        break
+    if goodmirror:
+      break
+
+  # Check if the requested Preferred mirror is in the list
+  # Note the user-requested mirror doesn't have a trailing-slash
+  prefmir = None
+  if preferred:
+    for mir in mirrors:
+      if mir[2] == preferred:
+        prefmir = mir
+        break
+  # Otherwise pick a preferred mirror from our country
+  if not prefmir and goodmirror:
+    prefmir = goodmirror
+  if not prefmir:  # In the worst case, choose a backup
+    prefmir = random.choice(backupmirrors)
+
+  # Record the preferred mirror and, if available, its logo and link
+  # Keep the trailing-slash on the URL (it is later joined to the path_info)
+  output['preferred'] = prefmir[2]
+  if len(prefmir) > 5:
+    output['logo'] = prefmir[4]
+    output['link'] = prefmir[5]
+
+  # Now assemble a list of all the other mirrors.
+  # Keep the trailing-slash on the URL (it is later joined to the path_info)
+  output['http'] = [mir[2] for mir in countrymirrors if mir[0] == 'http']
+  output['ftp'] = [mir[2] for mir in countrymirrors if mir[0] == 'ftp']
+  output['backup'] = [mir[2] for mir in backupmirrors]
+
+  return output
+
+
+def mirrorwrap(environ, start_response):
+  try:
+    return mirrorsapp(environ, start_response)
+  except:
+    status = "500 Oops"
+    response_headers = [("content-type","text/plain")]
+    start_response(status, response_headers, sys.exc_info())
+    return ["Problem running mirror.cgi, contact <[email protected]> "
+            "if it persists.\n\n"
+            + traceback.format_exc() ]
+
+
+def locate_template(environ):
+  # Determine the correct template by noting our filesystem location
+  if environ.has_key('ASF_MIRROR_FILENAME'):
+    template_file = environ['ASF_MIRROR_FILENAME'].replace(".cgi", ".html")
+  elif environ.has_key('SCRIPT_FILENAME'):
+    template_file = environ['SCRIPT_FILENAME'].replace(".cgi", ".html")
+  else:
+    template_file = sys.argv[0].replace(".cgi", ".html")
+
+  if not os.path.isfile(template_file):
+    # look in docroot instead if this is in a cgi-bin dir
+    template_file = template_file.replace("/cgi-bin/", "/content/")
+    if not os.path.isfile(template_file):
+      template_file = DEFAULT_TEMPLATE
+
+  return template_file
+
+
+def locate_mirrors(environ):
+  # Allow the MIRRORS_LIST environment variable to override the default
+  mirrors = environ.get('MIRRORS_LIST')
+  if mirrors and os.path.isfile(mirrors):
+    return mirrors
+  return MIRRORS_LIST  # the default
+
+
+def mirrorsapp(environ, start_response):
+  headers = [ ]
+  resp_code = '200 OK'
+
+  # Where is the client coming from
+  region = get_region(environ)
+
+  # Was there a preferred mirror or update requirement?
+  form = cgi.FieldStorage(fp=environ['wsgi.input'],
+                          environ=environ,
+                          keep_blank_values=True)
+  preferred = form.getfirst("Preferred", "")
+  update = form.getfirst("update", "")
+
+  # Get the last update time of the mirror database
+  mirrors = locate_mirrors(environ)
+  base_time = os.path.getmtime(mirrors)
+
+  # convert from YYYYMMDDhhmm to time-since-unix-epoch
+  try:
+    mingood = time.mktime(time.strptime(update, "%Y%m%d%H%M"))
+    # Never use a mirror more than a week old
+    mingood = max(mingood, base_time - 7*24*60*60)
+  except:
+    # if we didn't get a time, or we can't convert it, then
+    # use the time the mirror database was last updated minus 24 hours
+    mingood = base_time - 24*60*60
+
+  # Load the mirrors file and parse it out
+  data = parse_mirrors(mirrors, region, preferred, mingood)
+
+  # ======== new download tracking code ==========
+  action = form.getfirst("action", "")
+  filename = form.getfirst("filename", "")
+  if action == 'download' and filename != '':
+    url = "%s%s" % (data['preferred'][:-1], filename)
+    headers.append(('Location', url))
+    start_response(resp_code, headers)
+    #log_download(url, data['preferred'], environ, region)
+    return ''
+  # ====== end new download tracking code ========
+
+  # Note location to self
+  data['location'] = environ.get('SCRIPT_NAME', DEFAULT_LOCATION)
+
+  path_param = form.getfirst("path", None)
+  if path_param:
+    path_info = cgi.escape(path_param, 1)
+  else:
+    # Note any PATH_INFO
+    if environ.has_key('PATH_INFO'):
+      path_info = cgi.escape(environ['PATH_INFO'], 1)
+      if environ.has_key('SCRIPT_NAME'):
+        if environ['PATH_INFO'] == environ['SCRIPT_NAME']:
+          path_info = ''
+    else:
+      path_info = ''
+  # The mirror URL already has a trailing slash. Avoid doubling it up.
+  if path_info.startswith('/'):
+    path_info = path_info[1:]
+  data['path_info'] = path_info
+
+  template_file = locate_template(environ)
+
+  # Print out the CGI header component
+  # using xml if the filename ends with the magic '--xml' string
+  if template_file.endswith('--xml.html'):
+    headers.append(('Content-type', 'text/xml'))
+  else:
+    headers.append(('Content-type', 'text/html'))
+
+  start_response(resp_code, headers)
+
+  output = cStringIO.StringIO()
+  template = ezt.Template(template_file)
+  template.generate(output, data)
+  return [ output.getvalue() ]
+
+# ======== new download tracking code ==========
+def log_download(url, preferred, environ, region):
+  timestamp = int(time.time())
+  # format: timestamp,url,mirror,IP,region,"useragent"
+  try:
+    fh = open('/home/jfthomps/debug', 'a')
+    fh.write('%s,%s,%s,%s,%s,"%s"\n' % (timestamp, url, preferred, 
environ['REMOTE_ADDR'], region, environ['HTTP_USER_AGENT']))
+    fh.close
+  except:
+    pass
+# ====== end new download tracking code ========
+
+if __name__ == '__main__':
+  #from flup.server.fcgi import WSGIServer
+  from flup.server.cgi import WSGIServer
+  WSGIServer(mirrorwrap).run()


Reply via email to