You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@community.apache.org by rb...@apache.org on 2015/01/14 19:23:36 UTC

svn commit: r1651762 [1/7] - in /comdev/projects.apache.org: ./ scripts/ site/ site/edit/ site/images/ site/js/ site/json/ site/json/foundation/ site/json/projects/

Author: rbowen
Date: Wed Jan 14 18:23:33 2015
New Revision: 1651762

URL: http://svn.apache.org/r1651762
Log:
Adds projects.apache.org site.

Added:
    comdev/projects.apache.org/
    comdev/projects.apache.org/scripts/
    comdev/projects.apache.org/scripts/README.txt
    comdev/projects.apache.org/scripts/age.py
    comdev/projects.apache.org/scripts/parseaccounts.py
    comdev/projects.apache.org/scripts/parsechairs.py
    comdev/projects.apache.org/scripts/parsecommittees.py
    comdev/projects.apache.org/scripts/parsecommitters.py
    comdev/projects.apache.org/scripts/parsepmcs.py
    comdev/projects.apache.org/scripts/podlings.py
    comdev/projects.apache.org/scripts/rdfparse.py
    comdev/projects.apache.org/site/
    comdev/projects.apache.org/site/contributors.html
    comdev/projects.apache.org/site/edit/
    comdev/projects.apache.org/site/edit/index.html
    comdev/projects.apache.org/site/edit/save.py
    comdev/projects.apache.org/site/images/
    comdev/projects.apache.org/site/images/bg.png   (with props)
    comdev/projects.apache.org/site/images/bycategory.png   (with props)
    comdev/projects.apache.org/site/images/bydate.png   (with props)
    comdev/projects.apache.org/site/images/bylanguage.png   (with props)
    comdev/projects.apache.org/site/images/byname.png   (with props)
    comdev/projects.apache.org/site/images/bynumber.png   (with props)
    comdev/projects.apache.org/site/images/bypmc.png   (with props)
    comdev/projects.apache.org/site/images/loader.gif   (with props)
    comdev/projects.apache.org/site/images/logo.png   (with props)
    comdev/projects.apache.org/site/images/sub.png   (with props)
    comdev/projects.apache.org/site/images/tlp.png   (with props)
    comdev/projects.apache.org/site/index.html
    comdev/projects.apache.org/site/js/
    comdev/projects.apache.org/site/js/projects.js
    comdev/projects.apache.org/site/json/
    comdev/projects.apache.org/site/json/foundation/
    comdev/projects.apache.org/site/json/foundation/chairs.json
    comdev/projects.apache.org/site/json/foundation/committees.json
    comdev/projects.apache.org/site/json/foundation/committers.json
    comdev/projects.apache.org/site/json/foundation/cycles.json
    comdev/projects.apache.org/site/json/foundation/evolution.json
    comdev/projects.apache.org/site/json/foundation/people.json
    comdev/projects.apache.org/site/json/foundation/pmcs.json
    comdev/projects.apache.org/site/json/foundation/podlings.json
    comdev/projects.apache.org/site/json/foundation/projects.json
    comdev/projects.apache.org/site/json/projects/
    comdev/projects.apache.org/site/json/projects/abdera.json
    comdev/projects.apache.org/site/json/projects/accumulo.json
    comdev/projects.apache.org/site/json/projects/ace.json
    comdev/projects.apache.org/site/json/projects/activemq.json
    comdev/projects.apache.org/site/json/projects/airavata.json
    comdev/projects.apache.org/site/json/projects/allura.json
    comdev/projects.apache.org/site/json/projects/ambari.json
    comdev/projects.apache.org/site/json/projects/ant-.net-ant-library.json
    comdev/projects.apache.org/site/json/projects/ant-antunit.json
    comdev/projects.apache.org/site/json/projects/ant-compress-ant-library.json
    comdev/projects.apache.org/site/json/projects/ant-ivy.json
    comdev/projects.apache.org/site/json/projects/ant-ivyde.json
    comdev/projects.apache.org/site/json/projects/ant-props-ant-library.json
    comdev/projects.apache.org/site/json/projects/ant-vss-ant-library.json
    comdev/projects.apache.org/site/json/projects/ant.json
    comdev/projects.apache.org/site/json/projects/any23.json
    comdev/projects.apache.org/site/json/projects/apr.json
    comdev/projects.apache.org/site/json/projects/archiva.json
    comdev/projects.apache.org/site/json/projects/aries.json
    comdev/projects.apache.org/site/json/projects/avro.json
    comdev/projects.apache.org/site/json/projects/axis-axis2.json
    comdev/projects.apache.org/site/json/projects/axis-sandesha2.json
    comdev/projects.apache.org/site/json/projects/beehive.json
    comdev/projects.apache.org/site/json/projects/bigtop.json
    comdev/projects.apache.org/site/json/projects/bloodhound.json
    comdev/projects.apache.org/site/json/projects/bookkeeper.json
    comdev/projects.apache.org/site/json/projects/buildr.json
    comdev/projects.apache.org/site/json/projects/bval.json
    comdev/projects.apache.org/site/json/projects/camel.json
    comdev/projects.apache.org/site/json/projects/cassandra.json
    comdev/projects.apache.org/site/json/projects/cayenne.json
    comdev/projects.apache.org/site/json/projects/celix.json
    comdev/projects.apache.org/site/json/projects/chemistry.json
    comdev/projects.apache.org/site/json/projects/chukwa.json
    comdev/projects.apache.org/site/json/projects/clerezza.json
    comdev/projects.apache.org/site/json/projects/climate.json
    comdev/projects.apache.org/site/json/projects/cloudstack.json
    comdev/projects.apache.org/site/json/projects/cocoon.json
    comdev/projects.apache.org/site/json/projects/commons-commons-bcel.json
    comdev/projects.apache.org/site/json/projects/commons-commons-bsf.json
    comdev/projects.apache.org/site/json/projects/commons-commons-chain.json
    comdev/projects.apache.org/site/json/projects/commons-commons-cli.json
    comdev/projects.apache.org/site/json/projects/commons-commons-codec.json
    comdev/projects.apache.org/site/json/projects/commons-commons-collections.json
    comdev/projects.apache.org/site/json/projects/commons-commons-compress.json
    comdev/projects.apache.org/site/json/projects/commons-commons-configuration.json
    comdev/projects.apache.org/site/json/projects/commons-commons-daemon.json
    comdev/projects.apache.org/site/json/projects/commons-commons-dbcp.json
    comdev/projects.apache.org/site/json/projects/commons-commons-dbutils.json
    comdev/projects.apache.org/site/json/projects/commons-commons-digester.json
    comdev/projects.apache.org/site/json/projects/commons-commons-discovery.json
    comdev/projects.apache.org/site/json/projects/commons-commons-el.json
    comdev/projects.apache.org/site/json/projects/commons-commons-email.json
    comdev/projects.apache.org/site/json/projects/commons-commons-exec.json
    comdev/projects.apache.org/site/json/projects/commons-commons-fileupload.json
    comdev/projects.apache.org/site/json/projects/commons-commons-functor.json
    comdev/projects.apache.org/site/json/projects/commons-commons-io.json
    comdev/projects.apache.org/site/json/projects/commons-commons-jci.json
    comdev/projects.apache.org/site/json/projects/commons-commons-jcs.json
    comdev/projects.apache.org/site/json/projects/commons-commons-jelly.json
    comdev/projects.apache.org/site/json/projects/commons-commons-jexl.json
    comdev/projects.apache.org/site/json/projects/commons-commons-jxpath.json
    comdev/projects.apache.org/site/json/projects/commons-commons-lang.json
    comdev/projects.apache.org/site/json/projects/commons-commons-launcher.json
    comdev/projects.apache.org/site/json/projects/commons-commons-logging.json
    comdev/projects.apache.org/site/json/projects/commons-commons-math.json
    comdev/projects.apache.org/site/json/projects/commons-commons-modeler.json
    comdev/projects.apache.org/site/json/projects/commons-commons-ognl.json
    comdev/projects.apache.org/site/json/projects/commons-commons-pool.json
    comdev/projects.apache.org/site/json/projects/commons-commons-primitives.json
    comdev/projects.apache.org/site/json/projects/commons-commons-proxy.json
    comdev/projects.apache.org/site/json/projects/commons-commons-scxml.json
    comdev/projects.apache.org/site/json/projects/commons-commons-validator.json
    comdev/projects.apache.org/site/json/projects/commons-commons-vfs.json
    comdev/projects.apache.org/site/json/projects/commons-commons-weaver.json
    comdev/projects.apache.org/site/json/projects/commons.json
    comdev/projects.apache.org/site/json/projects/continuum.json
    comdev/projects.apache.org/site/json/projects/cordova.json
    comdev/projects.apache.org/site/json/projects/couchdb.json
    comdev/projects.apache.org/site/json/projects/creadur-rat.json
    comdev/projects.apache.org/site/json/projects/creadur-tentacles.json
    comdev/projects.apache.org/site/json/projects/creadur-whisker.json
    comdev/projects.apache.org/site/json/projects/crunch.json
    comdev/projects.apache.org/site/json/projects/ctakes.json
    comdev/projects.apache.org/site/json/projects/curator.json
    comdev/projects.apache.org/site/json/projects/cxf.json
    comdev/projects.apache.org/site/json/projects/datafu.json
    comdev/projects.apache.org/site/json/projects/db-derby.json
    comdev/projects.apache.org/site/json/projects/db-torque.json
    comdev/projects.apache.org/site/json/projects/deltacloud.json
    comdev/projects.apache.org/site/json/projects/deltaspike.json
    comdev/projects.apache.org/site/json/projects/devicemap.json
    comdev/projects.apache.org/site/json/projects/directmemory.json
    comdev/projects.apache.org/site/json/projects/directory-directory-studio.json
    comdev/projects.apache.org/site/json/projects/directory-directory.json
    comdev/projects.apache.org/site/json/projects/directory.json
    comdev/projects.apache.org/site/json/projects/empire-db.json
    comdev/projects.apache.org/site/json/projects/esme.json
    comdev/projects.apache.org/site/json/projects/etch.json
    comdev/projects.apache.org/site/json/projects/excalibur.json
    comdev/projects.apache.org/site/json/projects/falcon.json
    comdev/projects.apache.org/site/json/projects/felix.json
    comdev/projects.apache.org/site/json/projects/flex.json
    comdev/projects.apache.org/site/json/projects/flume.json
    comdev/projects.apache.org/site/json/projects/geronimo.json
    comdev/projects.apache.org/site/json/projects/giraph.json
    comdev/projects.apache.org/site/json/projects/gora.json
    comdev/projects.apache.org/site/json/projects/gump.json
    comdev/projects.apache.org/site/json/projects/hadoop.json
    comdev/projects.apache.org/site/json/projects/hama.json
    comdev/projects.apache.org/site/json/projects/harmony.json
    comdev/projects.apache.org/site/json/projects/hbase.json
    comdev/projects.apache.org/site/json/projects/hc-commons-httpclient.json
    comdev/projects.apache.org/site/json/projects/hc-httpcomponents-core.json
    comdev/projects.apache.org/site/json/projects/hc.json
    comdev/projects.apache.org/site/json/projects/helix.json
    comdev/projects.apache.org/site/json/projects/hive.json
    comdev/projects.apache.org/site/json/projects/hivemind.json
    comdev/projects.apache.org/site/json/projects/httpd-mod_ftp.json
    comdev/projects.apache.org/site/json/projects/httpd.json
    comdev/projects.apache.org/site/json/projects/incubator-droids-(incubating).json
    comdev/projects.apache.org/site/json/projects/isis.json
    comdev/projects.apache.org/site/json/projects/jackrabbit.json
    comdev/projects.apache.org/site/json/projects/jakarta-ecs.json
    comdev/projects.apache.org/site/json/projects/jakarta-jakarta-cactus.json
    comdev/projects.apache.org/site/json/projects/jakarta-oro.json
    comdev/projects.apache.org/site/json/projects/jakarta-regexp.json
    comdev/projects.apache.org/site/json/projects/james.json
    comdev/projects.apache.org/site/json/projects/jclouds.json
    comdev/projects.apache.org/site/json/projects/jena.json
    comdev/projects.apache.org/site/json/projects/jmeter.json
    comdev/projects.apache.org/site/json/projects/jspwiki.json
    comdev/projects.apache.org/site/json/projects/juddi-scout.json
    comdev/projects.apache.org/site/json/projects/kafka.json
    comdev/projects.apache.org/site/json/projects/karaf.json
    comdev/projects.apache.org/site/json/projects/knox.json
    comdev/projects.apache.org/site/json/projects/lenya.json
    comdev/projects.apache.org/site/json/projects/libcloud.json
    comdev/projects.apache.org/site/json/projects/logging-log4cxx.json
    comdev/projects.apache.org/site/json/projects/logging-log4j.json
    comdev/projects.apache.org/site/json/projects/logging-log4net.json
    comdev/projects.apache.org/site/json/projects/logging-log4php.json
    comdev/projects.apache.org/site/json/projects/logging.json
    comdev/projects.apache.org/site/json/projects/lucene-lucene-core.json
    comdev/projects.apache.org/site/json/projects/lucene-solr.json
    comdev/projects.apache.org/site/json/projects/lucenenet.json
    comdev/projects.apache.org/site/json/projects/mahout.json
    comdev/projects.apache.org/site/json/projects/manifoldcf.json
    comdev/projects.apache.org/site/json/projects/marmotta.json
    comdev/projects.apache.org/site/json/projects/maven.json
    comdev/projects.apache.org/site/json/projects/mesos.json
    comdev/projects.apache.org/site/json/projects/metamodel.json
    comdev/projects.apache.org/site/json/projects/mina-ftpserver.json
    comdev/projects.apache.org/site/json/projects/mina-sshd.json
    comdev/projects.apache.org/site/json/projects/mina-vysper.json
    comdev/projects.apache.org/site/json/projects/mina.json
    comdev/projects.apache.org/site/json/projects/mrunit.json
    comdev/projects.apache.org/site/json/projects/myfaces-tobago.json
    comdev/projects.apache.org/site/json/projects/myfaces.json
    comdev/projects.apache.org/site/json/projects/nutch.json
    comdev/projects.apache.org/site/json/projects/ode.json
    comdev/projects.apache.org/site/json/projects/ofbiz.json
    comdev/projects.apache.org/site/json/projects/olingo.json
    comdev/projects.apache.org/site/json/projects/oltu.json
    comdev/projects.apache.org/site/json/projects/onami.json
    comdev/projects.apache.org/site/json/projects/oodt.json
    comdev/projects.apache.org/site/json/projects/oozie.json
    comdev/projects.apache.org/site/json/projects/openjpa.json
    comdev/projects.apache.org/site/json/projects/openmeetings.json
    comdev/projects.apache.org/site/json/projects/opennlp.json
    comdev/projects.apache.org/site/json/projects/openoffice.json
    comdev/projects.apache.org/site/json/projects/openwebbeans.json
    comdev/projects.apache.org/site/json/projects/pdfbox.json
    comdev/projects.apache.org/site/json/projects/perl.json
    comdev/projects.apache.org/site/json/projects/phoenix.json
    comdev/projects.apache.org/site/json/projects/pig.json
    comdev/projects.apache.org/site/json/projects/pivot.json
    comdev/projects.apache.org/site/json/projects/poi.json
    comdev/projects.apache.org/site/json/projects/portals.json
    comdev/projects.apache.org/site/json/projects/qpid.json
    comdev/projects.apache.org/site/json/projects/rave.json
    comdev/projects.apache.org/site/json/projects/river.json
    comdev/projects.apache.org/site/json/projects/roller.json
    comdev/projects.apache.org/site/json/projects/santuario.json
    comdev/projects.apache.org/site/json/projects/servicemix.json
    comdev/projects.apache.org/site/json/projects/shale.json
    comdev/projects.apache.org/site/json/projects/shindig.json
    comdev/projects.apache.org/site/json/projects/shiro.json
    comdev/projects.apache.org/site/json/projects/sis.json
    comdev/projects.apache.org/site/json/projects/sling.json
    comdev/projects.apache.org/site/json/projects/spamassassin.json
    comdev/projects.apache.org/site/json/projects/spark.json
    comdev/projects.apache.org/site/json/projects/sqoop.json
    comdev/projects.apache.org/site/json/projects/stanbol.json
    comdev/projects.apache.org/site/json/projects/steve.json
    comdev/projects.apache.org/site/json/projects/storm.json
    comdev/projects.apache.org/site/json/projects/stratos.json
    comdev/projects.apache.org/site/json/projects/struts.json
    comdev/projects.apache.org/site/json/projects/subversion.json
    comdev/projects.apache.org/site/json/projects/synapse.json
    comdev/projects.apache.org/site/json/projects/syncope.json
    comdev/projects.apache.org/site/json/projects/tajo.json
    comdev/projects.apache.org/site/json/projects/tapestry.json
    comdev/projects.apache.org/site/json/projects/taverna.json
    comdev/projects.apache.org/site/json/projects/tcl-rivet.json
    comdev/projects.apache.org/site/json/projects/tcl-websh.json
    comdev/projects.apache.org/site/json/projects/thrift.json
    comdev/projects.apache.org/site/json/projects/tika.json
    comdev/projects.apache.org/site/json/projects/tiles.json
    comdev/projects.apache.org/site/json/projects/tomcat-reusable-dialog-components-(rdc)-taglib.json
    comdev/projects.apache.org/site/json/projects/tomcat.json
    comdev/projects.apache.org/site/json/projects/tomee.json
    comdev/projects.apache.org/site/json/projects/trafficserver.json
    comdev/projects.apache.org/site/json/projects/turbine.json
    comdev/projects.apache.org/site/json/projects/vcl.json
    comdev/projects.apache.org/site/json/projects/velocity-anakia.json
    comdev/projects.apache.org/site/json/projects/velocity-texen.json
    comdev/projects.apache.org/site/json/projects/velocity-velocity-dvsl.json
    comdev/projects.apache.org/site/json/projects/velocity-velocity-tools.json
    comdev/projects.apache.org/site/json/projects/velocity.json
    comdev/projects.apache.org/site/json/projects/vxquery.json
    comdev/projects.apache.org/site/json/projects/whirr.json
    comdev/projects.apache.org/site/json/projects/wicket.json
    comdev/projects.apache.org/site/json/projects/wink.json
    comdev/projects.apache.org/site/json/projects/wookie.json
    comdev/projects.apache.org/site/json/projects/ws-axiom.json
    comdev/projects.apache.org/site/json/projects/ws-woden.json
    comdev/projects.apache.org/site/json/projects/xalan-xalan-for-java-xslt-processor.json
    comdev/projects.apache.org/site/json/projects/xalan.json
    comdev/projects.apache.org/site/json/projects/xerces-xerces-for-java-xml-parser.json
    comdev/projects.apache.org/site/json/projects/xerces-xerces-for-perl-xml-parser.json
    comdev/projects.apache.org/site/json/projects/xerces-xml-commons-external.json
    comdev/projects.apache.org/site/json/projects/xerces-xml-commons-resolver.json
    comdev/projects.apache.org/site/json/projects/xerces.json
    comdev/projects.apache.org/site/json/projects/xml-xindice.json
    comdev/projects.apache.org/site/json/projects/xmlbeans.json
    comdev/projects.apache.org/site/json/projects/xmlgraphics-batik.json
    comdev/projects.apache.org/site/json/projects/xmlgraphics-fop.json
    comdev/projects.apache.org/site/json/projects/xmlgraphics-xml-graphics-commons.json
    comdev/projects.apache.org/site/json/projects/zookeeper.json
    comdev/projects.apache.org/site/project.html
    comdev/projects.apache.org/site/projects.html
    comdev/projects.apache.org/site/releases.html
    comdev/projects.apache.org/site/script.js
    comdev/projects.apache.org/site/styles.css
    comdev/projects.apache.org/site/timelines.html

Added: comdev/projects.apache.org/scripts/README.txt
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/README.txt?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/README.txt (added)
+++ comdev/projects.apache.org/scripts/README.txt Wed Jan 14 18:23:33 2015
@@ -0,0 +1,15 @@
+This directory contains scripts for both importing and updating data from
+various sources:
+
+- parsechairs.py: Fetches current VPs from the foundation website. To be run as
+  a cron job.
+- parsecommittees.py: Parses committee-info.txt and its TLP information
+- parsecommitters.py: Fetches and parses the committer (LDAP) list via
+  people.apache.org. To be cronned
+- parsepmcs.py: imports PMC data from the old project.apache.org site. No need
+  to run that more than once.
+- podlings.py: Reads podlings.xml from the incubator site and creates a JSON
+  with timeline data, as well as as podling project information.
+- rdfparse.py: Parses existing RDF(DOAP) files from the old projects.a.o and
+  turns them into JSON objects.
+

Added: comdev/projects.apache.org/scripts/age.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/age.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/age.py (added)
+++ comdev/projects.apache.org/scripts/age.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,46 @@
+import re
+import os, sys
+from datetime import datetime
+
+currentMonth = datetime.now().month
+currentYear = datetime.now().year
+
+months = ["January","February","March","April","May","June","July","August","September","October","November","December"]
+
+
+try:
+    with open("committee-info.txt", "rb") as f:
+        data = f.read().decode('utf-8')
+        f.close()
+except:
+    print("You will need to download committee-info.txt and place it in this folder first")
+    sys.exit(1)
+    
+x = 0
+
+js = []
+
+for pmc in sorted(re.findall(r"\* .+?\s+\(est\. [0-9/]+[^\r\n]+", data, re.UNICODE | re.IGNORECASE)):
+    
+    #print(pmc)
+    m = re.search(r"\* (.+?)\s+\(est. ([0-9]+)/([0-9]+)", pmc, re.IGNORECASE | re.UNICODE)
+    if m:
+        project = m.group(1)
+        month = m.group(2)
+        year = m.group(3)
+        project = "Apache %s" % project
+        # Only TLPs, not special committees
+        if not re.search(r"[Cc]ommit", pmc, re.IGNORECASE):
+            year = int(year)
+            month = int(month)
+            
+            age = currentYear - year - ( (currentMonth- month) / 12)
+            if age > 4:
+                age = age % 5
+                if 0 <= age < 1:
+                    js.append("%04u-%02u: %s (founded %s, %s) is scheduled for certification on %s, %u" % (currentYear, month, project, months[month-1], year, months[month-1], currentYear))
+                if 4 <= age:
+                    js.append("%04u-%02u: %s (founded %s, %s) is scheduled for certification on %s, %u" % (currentYear+1, month, project, months[month-1], year, months[month-1], currentYear+1))
+
+for el in sorted(js):
+    print(el)

Added: comdev/projects.apache.org/scripts/parseaccounts.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/parseaccounts.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/parseaccounts.py (added)
+++ comdev/projects.apache.org/scripts/parseaccounts.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,24 @@
+import os, sys, subprocess, re, time, json
+from datetime import datetime
+
+logs = subprocess.check_output("svn log -r 868931:HEAD new-account-reqs.txt").decode('utf-8')
+js = {}
+for year in range(2012, 2016):
+    for month in range(1,13):
+        js["%04u-%02u" % (year, month)] = 0
+        
+
+for m in re.finditer(r"r\d+.+?(\d\d\d\d-\d\d)-\d\d.+?[\r\n]+New accounts:[\r\n]+([\S\s]+?)------------", logs, re.MULTILINE | re.UNICODE):
+    date = m.group(1)
+    cc = m.group(2).strip().split("\n")
+    js[date] += len(cc)
+    
+for date in js:
+    print(date, js[date])
+    
+with open("./newaccounts.json", "w") as jsout:
+    jsout.write(json.dumps(js))
+    jsout.close
+    
+print("Done!")
+

Added: comdev/projects.apache.org/scripts/parsechairs.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/parsechairs.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/parsechairs.py (added)
+++ comdev/projects.apache.org/scripts/parsechairs.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,23 @@
+import re, urllib.request
+import csv
+import json
+import os
+
+chairs = {}
+
+data = urllib.request.urlopen("http://www.apache.org/foundation/").read().decode('utf-8')
+x = 0
+
+for committer in re.findall(r"<tr>[\s\S]+?V\.P\., Apache [\s\S]+?</tr>", data, re.MULTILINE | re.UNICODE):
+    x += 1
+    #print(committer)
+    m = re.search(r"<td>V.P., (Apache [\s\S]+?)</td>[\s\S]*?<td>([\s\S]+?)</td>", committer, re.MULTILINE | re.UNICODE)
+    if m:
+        project = m.group(1)
+        person = m.group(2)
+        chairs[project] = person
+        
+
+with open("../site/json/foundation/chairs.json", "w") as f:
+    f.write(json.dumps(chairs))
+    f.close()

Added: comdev/projects.apache.org/scripts/parsecommittees.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/parsecommittees.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/parsecommittees.py (added)
+++ comdev/projects.apache.org/scripts/parsecommittees.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,51 @@
+import re, urllib.request
+import csv
+import json
+import os
+
+chairs = json.load(open("../site/json/foundation/chairs.json"))
+data = None
+committees = {}
+psize = {}
+c = {}
+
+try:
+    with open("committee-info.txt", "rb") as f:
+        data = f.read().decode('utf-8')
+        f.close()
+except:
+    print("You will need to download committee-info.txt and place it in this folder first")
+    os.exit(1)
+    
+x = 0
+
+for year in range(1995,2015):
+    for month in range(1,13):
+        committees["%04u-%02u" % (year, month)] = []
+
+for pmc in re.findall(r"\* .+?\s+\(est\. [0-9/]+[^\r\n]+", data, re.UNICODE | re.IGNORECASE):
+    
+    #print(pmc)
+    m = re.search(r"\* (.+?)\s+\(est. ([0-9]+)/([0-9]+)", pmc, re.IGNORECASE | re.UNICODE)
+    if m:
+        project = m.group(1)
+        month = m.group(2)
+        year = m.group(3)
+        project = "Apache %s" % project
+        if not re.search(r"[Cc]ommit", pmc, re.IGNORECASE):
+            #print(project)
+            x += 1
+            committees["%s-%s" % (year, month)].append(project)
+        else:
+            print("%s was found but is not an STLP" % project)
+        c[project] = True
+
+with open("../site/json/foundation/committees.json", "w") as f:
+    f.write(json.dumps(committees))
+    f.close()
+
+for chair in chairs:
+    if not chair in c:
+        print("%s is not in committee-info!" % chair)
+
+print(x)
\ No newline at end of file

Added: comdev/projects.apache.org/scripts/parsecommitters.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/parsecommitters.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/parsecommitters.py (added)
+++ comdev/projects.apache.org/scripts/parsecommitters.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,42 @@
+from xml.dom import minidom
+import xml.etree.ElementTree as ET
+import re, urllib.request
+import csv
+import json
+import os
+
+people = {}
+pmcs = {}
+data = urllib.request.urlopen("http://people.apache.org/committer-index.html").read().decode('utf-8')
+x = 0
+for committer in re.findall(r"<tr>([\S\s]+?)</tr>", data, re.MULTILINE | re.UNICODE):
+    x += 1
+##    print(committer)
+    m = re.search(r"<a id='(.+?)'>[\s\S]+?<td.+?>(.+?)</td>[\s\S]+?>(.+)</td>", committer, re.MULTILINE | re.UNICODE)
+    if m:
+        cid = m.group(1)
+        cname = re.sub(r"<.+?>", "", m.group(2), 4)
+        cproj = m.group(3)
+        projects = []
+        isMember = False
+        if re.search(r"<b", committer, re.MULTILINE | re.UNICODE):
+            isMember = True
+        for project in re.findall(r"#([-a-z0-9._]+)", cproj):
+            projects.append(project)
+            pmcs[project] = pmcs[project] if project in pmcs else []
+            pmcs[project].append(cid)
+        people[cid] = {
+            'name':  cname,
+            'member': isMember,
+            'projects': projects
+        }
+        
+
+with open("../site/json/foundation/people.json", "w") as f:
+    f.write(json.dumps(people))
+    f.close()
+    
+with open("../site/json/foundation/committers.json", "w") as f:
+    f.write(json.dumps(pmcs))
+    f.close()
+    
\ No newline at end of file

Added: comdev/projects.apache.org/scripts/parsepmcs.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/parsepmcs.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/parsepmcs.py (added)
+++ comdev/projects.apache.org/scripts/parsepmcs.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,63 @@
+from xml.dom import minidom
+import xml.etree.ElementTree as ET
+import re, urllib.request
+import csv
+import json
+import os
+
+data = urllib.request.urlopen("https://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/data_files/").read().decode('utf-8')
+itemlist = re.findall(r">([a-z0-9]+)\.rdf<", data)
+
+projects = {}
+
+def handleChild(el):
+    retval = None
+    hasKids = False
+    for child in list(el):
+        hasKids = True
+    attribs = {}
+    for key in el.attrib:
+        xkey = re.sub(r"\{.+\}", "", key)
+        attribs[xkey] = el.attrib[key]
+    tag = re.sub(r"\{.+\}", "", el.tag)
+    value = attribs['resource'] if 'resource' in attribs else el.text
+    if not hasKids:
+        retval = value
+    else:
+        retval = {}
+        for child in list(el):
+            k, v = handleChild(child)
+            retval[k] = v
+    return tag, retval
+
+for s in itemlist :
+    url = "https://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/data_files/%s.rdf" % s
+    print(url)
+    try:
+        rdf = urllib.request.urlopen(url).read()
+        rdfxml = ET.fromstring(rdf)
+        project = rdfxml[0]
+        pjson = {
+            
+        }
+        prname = None
+        for el in project:
+            k, v = handleChild(el)
+            if k in pjson:
+                if type(pjson[k]) is str:
+                    pjson[k] = "%s, %s" % (pjson[k], v)
+                else:
+                    for xk in v:
+                        pjson[k][xk] = v[xk]
+            else:
+                pjson[k] = v
+        projects[s] = pjson
+
+    except Exception as err:
+        print(err)
+        
+with open ("../site/json/foundation/pmcs.json", "w") as f:
+    f.write(json.dumps(projects))
+    f.close()
+print("Done!")
+    
\ No newline at end of file

Added: comdev/projects.apache.org/scripts/podlings.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/podlings.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/podlings.py (added)
+++ comdev/projects.apache.org/scripts/podlings.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,112 @@
+from xml.dom import minidom
+import re, urllib.request
+import csv
+import json
+from datetime import datetime
+
+data = urllib.request.urlopen("http://incubator.apache.org/podlings.xml").read()
+xmldoc = minidom.parseString(data)
+itemlist = xmldoc.getElementsByTagName('podling') 
+
+new = {}
+grads = {}
+ret = {}
+current  = 0
+cpods = {}
+
+fieldnames = ['month', 'new', 'graduated', 'retired']
+for year in range(2003,2016):
+    for month in range(1,13):
+        m = "%u-%02u" % (year, month)
+        grads[m] = 0
+        new[m] = 0
+        ret[m] = 0
+        
+for s in itemlist :
+        name = s.attributes['name'].value
+        uname = s.attributes['resource'].value
+        status = s.attributes['status'].value
+        sd = s.attributes['startdate'].value
+        ed = s.attributes['enddate'].value if 'enddate' in s.attributes else None
+        desc = "No description"
+        for c in s.childNodes:
+            if c.__class__.__name__ != 'Text' and c.tagName == 'description':
+                desc = c.childNodes[0].data
+                break
+        #print(name, status, sd, ed)
+        if sd and re.match(r"(\d{4}-\d+)", sd):
+            sd = re.match(r"(\d{4}-\d+)", sd).group(1)
+        if ed and re.match(r"(\d{4}-\d+)", ed):
+            ed = re.match(r"(\d{4}-\d+)", ed).group(1)
+        
+        new[sd] += 1
+        if status == "graduated":
+            if not ed:
+                ed = sd
+                print("%s did not specify a graduation date, assuming %s!" % (name,ed))
+            grads[ed] += 1
+        elif status == "retired":
+            if not ed:
+                ed = sd
+                print("%s did not specify a retirement date, assuming %s!" % (name,ed))
+            ret[ed] += 1
+        elif status == "current":
+            current += 1
+            cpods[uname] = {
+                'started': sd,
+                'name': "Apache %s (Incubating)" % name,
+                'description': desc,
+                'homepage': "http://%s.incubator.apache.org/" % uname,
+                'podling': True
+            }
+    
+
+with open('podlings.csv', 'w') as csvfile:
+    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
+    writer.writeheader()
+    for year in range(2003,2015):
+        for month in range(1,13):
+            m = "%u-%02u" % (year, month)
+            writer.writerow({
+                'month': m,
+                'new': new[m],
+                'graduated': grads[m],
+                'retired': ret[m]
+            })
+    csvfile.close()
+    
+currentMonth = datetime.now().month
+currentYear = datetime.now().year
+
+js = []
+for year in range(2003,2016):
+    for month in range(1,13):
+        m = "%u-%02u" % (year, month)
+        mjs = {
+            'month': m,
+            'new': new[m],
+            'graduated': grads[m],
+            'retired': ret[m],
+            'current': 0
+        }
+        if currentYear > year or (currentYear == year and currentMonth >= month):
+            js.append(mjs)
+        
+js.reverse()
+
+for i in js:
+    i['current'] = current
+    current -= i['new']
+    current += i['graduated']
+    current += i['retired']
+    
+with open('../site/json/foundation/evolution.json', 'w') as f:
+    f.write(json.dumps(js))
+    f.close()
+    
+with open('../site/json/foundation/podlings.json', 'w') as f:
+    f.write(json.dumps(cpods))
+    f.close()
+    
+print("Done!")
+    
\ No newline at end of file

Added: comdev/projects.apache.org/scripts/rdfparse.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/scripts/rdfparse.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/scripts/rdfparse.py (added)
+++ comdev/projects.apache.org/scripts/rdfparse.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,91 @@
+from xml.dom import minidom
+import xml.etree.ElementTree as ET
+import re, urllib.request
+import csv
+import json
+import os
+
+data = urllib.request.urlopen("https://svn.apache.org/repos/asf/infrastructure/site-tools/trunk/projects/files.xml").read()
+xmldoc = minidom.parseString(data)
+itemlist = xmldoc.getElementsByTagName('location') 
+
+projects = {}
+
+def handleChild(el):
+    retval = None
+    hasKids = False
+    for child in list(el):
+        hasKids = True
+    attribs = {}
+    for key in el.attrib:
+        xkey = re.sub(r"\{.+\}", "", key)
+        attribs[xkey] = el.attrib[key]
+    tag = re.sub(r"\{.+\}", "", el.tag)
+    value = attribs['resource'] if 'resource' in attribs else el.text
+    if not hasKids:
+        retval = value
+    else:
+        retval = {}
+        for child in list(el):
+            k, v = handleChild(child)
+            retval[k] = v
+            if k == "location":
+                retval = v
+                break
+    return tag, retval
+
+for s in itemlist :
+    url = s.childNodes[0].data
+    try:
+        rdf = urllib.request.urlopen(url).read()
+        rdfxml = ET.fromstring(rdf)
+        project = rdfxml[0]
+        pjson = {
+            'doap': url
+        }
+        prname = None
+        for el in project:
+            k, v = handleChild(el)
+            if k in pjson and not k in ['name','homepage']:
+                if type(pjson[k]) is str:
+                    pjson[k] = "%s, %s" % (pjson[k], v)
+                else:
+                    for xk in v:
+                        pjson[k][xk] = v[xk]
+            else:
+                pjson[k] = v
+        
+        if pjson['homepage']:
+            m = re.match(r"https?://([^.]+)\.", pjson['homepage'], re.IGNORECASE)
+            if m:
+                prname = m.group(1)
+        nn = pjson['name'].replace("Apache ", "").replace(" ", "-").lower()
+        m = re.search(r"http://([-a-z0-9]+)\.", pjson['pmc'])
+        if m:
+            pjson['pmc'] = m.group(1)
+        if re.search(r"/[a-z0-9+A-Z]+/?$", pjson['homepage']) or os.path.isfile("../site/json/projects/%s.json" % prname):
+            prname = "%s-%s" % (prname, nn)
+        if prname:
+            add = {}
+            for k in pjson:
+                if type(pjson[k]) is not str:
+                    for e in pjson[k]:
+                        add[e] = pjson[k][e]
+                    pjson[k] = None
+                    
+            for e in add:
+                pjson[e] = add[e]
+            if not os.path.isfile("../site/json/projects/%s.json" % prname):
+                projects[prname] = pjson
+                print("Writing %s.json..." % prname)
+                with open ("../site/json/projects/%s.json" % prname, "w") as f:
+                    f.write(json.dumps(pjson))
+                    f.close()
+    except Exception as err:
+        print("Error: %s" % err)
+        
+with open ("../site/json/foundation/projects.json", "w") as f:
+    f.write(json.dumps(projects))
+    f.close()
+print("Done!")
+    
\ No newline at end of file

Added: comdev/projects.apache.org/site/contributors.html
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/contributors.html?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/site/contributors.html (added)
+++ comdev/projects.apache.org/site/contributors.html Wed Jan 14 18:23:33 2015
@@ -0,0 +1,38 @@
+<!doctype html>
+<html lang=''>
+<head>
+   <meta charset='utf-8'>
+   <meta http-equiv="X-UA-Compatible" content="IE=edge">
+   <meta name="viewport" content="width=device-width, initial-scale=1">
+   <link rel="stylesheet" href="styles.css">
+   <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
+   <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+   <script src="script.js"></script>
+   <script src="js/projects.js"></script>
+   
+   <title>Apache Projects Directory</title>
+</head>
+<body>
+
+<div id="logo"></div>
+<div id='cssmenu'>
+<ul>
+   <li><a href='/'><span>Home</span></a></li>
+   <li><a href='/projects.html'><span>Projects</span></a></li>
+   <li><a href='/releases.html'><span>Releases</span></a></li>
+   <li class='active'><a href='/contributors.html'><span>Contributors</span></a></li>
+   <li class='last'><a href='/timelines.html'><span>Timelines</span></a></li>
+   <li style="background: none !important"><input type="text" style="margin-top: 20px;" onkeypress="checkKeyPress(event, this);" placeholder="Search..."/></li>
+</ul>
+</div>
+
+<div id="contents">
+   Coming soon..!
+</div>
+<div id="footer">
+   Copyright&copy; 2015, the Apache Software Foundation. Licensed under the Apache License v/2.0<br/>
+   For inquiries, contact <a href="mailto:dev@community.apache.org">dev@community.apache.org</a>.
+</div>
+
+</body>
+<html>

Added: comdev/projects.apache.org/site/edit/index.html
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/edit/index.html?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/site/edit/index.html (added)
+++ comdev/projects.apache.org/site/edit/index.html Wed Jan 14 18:23:33 2015
@@ -0,0 +1,40 @@
+<!doctype html>
+<html lang=''>
+<head>
+   <meta charset='utf-8'>
+   <meta http-equiv="X-UA-Compatible" content="IE=edge">
+   <meta name="viewport" content="width=device-width, initial-scale=1">
+   <link rel="stylesheet" href="/styles.css">
+   <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
+   <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+   <script src="/script.js"></script>
+   <script src="/js/projects.js"></script>
+   
+   <title>Apache Projects Directory</title>
+</head>
+<body>
+
+<div id="logo"></div>
+<div id='cssmenu'>
+<ul>
+   <li class='active'><a href='/'><span>Home</span></a></li>
+   <li><a href='/projects.html'><span>Projects</span></a></li>
+   <li><a href='/releases.html'><span>Releases</span></a></li>
+   <li><a href='/contributors.html'><span>Contributors</span></a></li>
+   <li class='last'><a href='/timelines.html'><span>Timelines</span></a></li>
+   <li style="background: none !important"><input type="text" style="margin-top: 20px;" onkeypress="checkKeyPress(event, this);" placeholder="Search..."/></li>
+</ul>
+</div>
+
+<div id="contents">
+   
+</div>
+<div id="footer">
+   Copyright&copy; 2015, the Apache Software Foundation. Licensed under the Apache License v/2.0<br/>
+   For inquiries, contact <a href="mailto:dev@community.apache.org">dev@community.apache.org</a>.
+</div>
+<script type="text/javascript">
+   preloadEverything(function() { buildEditor('rbowen')});
+</script>
+</body>
+<html>

Added: comdev/projects.apache.org/site/edit/save.py
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/edit/save.py?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/site/edit/save.py (added)
+++ comdev/projects.apache.org/site/edit/save.py Wed Jan 14 18:23:33 2015
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+import os
+import cgi;
+import json;
+import smtplib;
+import re
+from email.mime.text import MIMEText
+from subprocess import Popen, PIPE
+
+print ("Content-Type: text/html\r\n\r\n")
+print ("Received!")
+
+try:
+    form = cgi.FieldStorage();
+    user = os.environ['REMOTE_USER'] if 'REMOTE_USER' in os.environ else "nobody"
+    f = form['file'].value if 'file' in form else None
+
+
+    if f and not re.search(r"([^-.a-zA-Z0-9])", f):
+        project = f
+        f = "%s.json" % f
+        js = {}
+        for k in form:
+            js[k] = form[k].value
+        with open("../json/projects/%s" % f, "w") as out:
+            out.write(json.dumps(js))
+            out.close()
+
+        with open("../json/foundation/projects.json", "r") as g:
+            gjson = json.loads(g.read())
+            g.close()
+
+            gjson[project] = js
+            with open("../json/foundation/projects.json", "w") as og:
+                og.write(json.dumps(gjson))
+                og.close()
+
+
+        text = """
+    Hello,
+
+    The following new base data was set for %s by %s:
+
+%s
+
+    With regards,
+    projects.apache.org
+    """ % (project, user, json.dumps(js, indent=4))
+
+        msg = MIMEText(text)
+        msg["From"] = "no-reply@projects.apache.org"
+        msg["To"] = "humbedooh@humbedooh.com"
+        msg["Subject"] = "Project base data change for project '%s'" % project
+        p = Popen(["/usr/sbin/sendmail", "-t"], stdin=PIPE)
+        p.communicate(msg.as_string())
+        print("And saved!")
+    else:
+        print("But no valid JSON was present!")
+except Exception as err:
+    print("Exception: %s" % err)

Added: comdev/projects.apache.org/site/images/bg.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/bg.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/bg.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/bycategory.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/bycategory.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/bycategory.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/bydate.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/bydate.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/bydate.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/bylanguage.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/bylanguage.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/bylanguage.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/byname.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/byname.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/byname.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/bynumber.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/bynumber.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/bynumber.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/bypmc.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/bypmc.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/bypmc.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/loader.gif
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/loader.gif?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/loader.gif
------------------------------------------------------------------------------
    svn:mime-type = image/gif

Added: comdev/projects.apache.org/site/images/logo.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/logo.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/logo.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/sub.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/sub.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/sub.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/images/tlp.png
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/images/tlp.png?rev=1651762&view=auto
==============================================================================
Binary file - no diff available.

Propchange: comdev/projects.apache.org/site/images/tlp.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: comdev/projects.apache.org/site/index.html
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/index.html?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/site/index.html (added)
+++ comdev/projects.apache.org/site/index.html Wed Jan 14 18:23:33 2015
@@ -0,0 +1,51 @@
+<!doctype html>
+<html lang=''>
+<head>
+   <meta charset='utf-8'>
+   <meta http-equiv="X-UA-Compatible" content="IE=edge">
+   <meta name="viewport" content="width=device-width, initial-scale=1">
+   <link rel="stylesheet" href="styles.css">
+   <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
+   <script type="text/javascript" src="https://www.google.com/jsapi"></script>
+   <script src="script.js"></script>
+   <script src="js/projects.js"></script>
+   
+   <title>Apache Projects Directory</title>
+</head>
+<body>
+
+<div id="logo"></div>
+<div id='cssmenu'>
+<ul>
+   <li class='active'><a href='/'><span>Home</span></a></li>
+   <li><a href='/projects.html'><span>Projects</span></a></li>
+   <li><a href='/releases.html'><span>Releases</span></a></li>
+   <li><a href='/contributors.html'><span>Contributors</span></a></li>
+   <li class='last'><a href='/timelines.html'><span>Timelines</span></a></li>
+   <li style="background: none !important"><input type="text" style="margin-top: 20px;" onkeypress="checkKeyPress(event, this);" placeholder="Search..."/></li>
+</ul>
+</div>
+
+<div id="contents">
+   <p style="text-align: center;">
+      Loading data, please wait...<br/>
+      <img src="/images/loader.gif"/>
+   </p>
+   <noscript>
+      <h2>Notice!</h2>
+      <p>
+         This site relies heavily on JavaScript.
+         Please enable it or get a browser that supports it.
+      </p>
+   </noscript>
+</div>
+<div id="footer">
+   Copyright&copy; 2015, the Apache Software Foundation. Licensed under the Apache License v/2.0<br/>
+   For inquiries, contact <a href="mailto:dev@community.apache.org">dev@community.apache.org</a>.
+</div>
+<script type="text/javascript">
+   google.load("visualization", "1", {packages:["corechart"]});
+   google.setOnLoadCallback(function() { preloadEverything(buildFrontPage)});
+</script>
+</body>
+<html>

Added: comdev/projects.apache.org/site/js/projects.js
URL: http://svn.apache.org/viewvc/comdev/projects.apache.org/site/js/projects.js?rev=1651762&view=auto
==============================================================================
--- comdev/projects.apache.org/site/js/projects.js (added)
+++ comdev/projects.apache.org/site/js/projects.js Wed Jan 14 18:23:33 2015
@@ -0,0 +1,1124 @@
+/*
+   Copyright 2015, the Apache Software Foundation.
+
+   Licensed 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.
+   
+*/
+
+// ----- Global hashes used throughout the script ------ \\
+
+var people = {} // committer -> name lookups
+var unixgroups = {} // unix (ldap) groups (project -> committers lookup)
+var chairs = {} // chair-people of various TLPs
+var cycles = {} // Reporting cycles
+var projects = {} // Projects (sub + tlp)
+var committees = {} // TLP committees for TLP evolution charts et al
+var committees_raw = {} // TLP committees, sorted by date founded
+var pmcs = {} // pmc -> project name lookups
+var evolution = {} // Podling evolution
+
+
+// --------- Global helpers ----------- \\
+
+// Function for async fetching of a single JSON file with JS callback
+function GetAsyncJSON(theUrl, xstate, callback) {
+    var xmlHttp = null;
+    if (window.XMLHttpRequest) {
+	xmlHttp = new XMLHttpRequest();
+    } else {
+	xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+    }
+    xmlHttp.open("GET", theUrl, true);
+    xmlHttp.send(null);
+    xmlHttp.onreadystatechange = function(state) {
+	if (xmlHttp.readyState == 4 && xmlHttp.status == 200 || xmlHttp.status == 404) {
+	    if (callback) {
+		if (xmlHttp.status == 404) {
+		    callback({}, xstate);
+		} else {
+		    callback(JSON.parse(xmlHttp.responseText), xstate);
+		}
+	    }
+	}
+    }
+}
+
+// Fetch an array of URLs, each with their own callback plus a final callback
+// Used to fetch everything before rendering a page that relies on multiple JSON sources.
+function GetAsyncJSONArray(urls, finalCallback) {
+    if (urls.length > 0) {
+	var a = urls.shift();
+	var URL = a[0]
+	var cb = a[1]
+	var xmlHttp = null;
+	if (window.XMLHttpRequest) {
+	    xmlHttp = new XMLHttpRequest();
+	} else {
+	    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+	}
+	xmlHttp.open("GET", URL, true);
+	xmlHttp.send(null);
+	xmlHttp.onreadystatechange = function(state) {
+	    if (xmlHttp.readyState == 4 && xmlHttp.status == 200 || xmlHttp.status == 404) {
+		if (cb) {
+		    if (xmlHttp.status == 404) {
+			cb({});
+		    } else {
+			cb(JSON.parse(xmlHttp.responseText));
+		    }
+		}
+		GetAsyncJSONArray(urls, finalCallback);
+	    }
+	}
+    }
+    else {
+	finalCallback();
+    }
+}
+
+
+// ------------ form data functions for project editor ------------\\
+
+function addKeyVal(key, val) {
+    var div = document.createElement('div')
+    var left = document.createElement('div')
+    var right = document.createElement('div')
+    div.style = "width: 1020px; margin: 10px; overflow: auto;"
+    left.style = "float: left; width: 300px; font-weight: bold"
+    right.style = "float: left; width: 700px;"
+    left.appendChild(document.createTextNode(key + ": "))
+    right.appendChild(val)
+    div.appendChild(left);
+    div.appendChild(right)
+    return div
+}
+
+function input(type, name, value) {
+    var t = document.createElement('input');
+    t.setAttribute("type", type)
+    t.setAttribute("name", name)
+    t.setAttribute("value", value)
+    t.style.minWidth = "380px"
+    return t;
+}
+
+function makeSelect(name, arr, sarr) {
+    var sel = document.createElement('select');
+    sel.setAttribute("name", name)
+    for (i in arr) {
+	var val = arr[i];
+	var opt = document.createElement('option')
+	opt.setAttribute("value", val)
+	opt.innerHTML = val
+	sel.appendChild(opt);
+    }
+    return sel
+}
+
+function postREST(json, oform) {
+    var form = new FormData(oform)
+    var xmlHttp = null;
+    if (window.XMLHttpRequest) {
+	xmlHttp = new XMLHttpRequest();
+    } else {
+	xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+    }
+    for (i in json) {
+	form.append(i, json[i])
+    }
+    xmlHttp.open("POST", "/edit/save.py", false);
+    xmlHttp.send(form);
+}
+
+function editProject(json, project) {
+    var obj = document.getElementById('contents');
+    obj.innerHTML = "<a href='/edit/'>Back to front page</a><br/><h1>Project editor:</h1><p>Editing " + project + ".json:</p>"
+    if (!json || !json.name) {
+	json = projects[project] ? projects[project] : {}
+    }
+    if (json.category) {
+	json.category = json.category.replace(/http:\/\/projects.apache.org\/category\//gi, "")
+    }
+    var form = document.createElement('form')
+    form.appendChild(input("hidden", "file", project))
+    var keys = ['name','pmc','homepage','shortdesc','description','category','programming-language','mailing-list', 'download-page','bug-database','SVNRepository','GitRepository']
+    for (i in keys) {
+	k = keys[i]
+	if (k == 'description') {
+	    var txt = document.createElement('textarea');
+	    txt.setAttribute("name", "description")
+	    txt.style.width = "600px"
+	    txt.style.height = "140px"
+	    txt.innerHTML =  json[k] ? json[k] : "";
+	    form.appendChild(addKeyVal(k, txt))
+	}
+	else {
+	    form.appendChild(addKeyVal(k, input("text", k, json[k] ? json[k] : "")))
+	}
+    } 
+    var but = input("button", "submit", "Save changes")
+    but.setAttribute("onclick", "postREST({}, this.form); alert('Changes saved!');")
+    form.appendChild(but)
+    obj.appendChild(form)
+}
+
+function editProjectPreload(project) {
+    GetAsyncJSON("/json/projects/" + project + ".json?" + Math.random(), project, editProject);
+}
+function buildEditor(uid) {
+    var obj = document.getElementById('contents');
+    obj.innerHTML = "<h1>Project editor:</h1><h3>Select a project to edit:</h3><p>Only projects where you are in the sponsoring PMC can be edited</p>"
+    for (i in projects) {
+	var p = i.split("-")[0];
+	if (projects[i].name.match(/incubating/i)) {
+	    p = 'incubator'
+	}
+	if (unixgroups[p+"-pmc"] && unixgroups[p+"-pmc"].indexOf(uid) >= 0) {
+	    obj.innerHTML += "<a href='javascript:void(0);' onclick='editProjectPreload(\"" + i + "\");'>" + projects[i].name + "</a><br/>"
+	}
+	
+    }
+    obj.innerHTML += "<hr/><h3>Or create a new project:</h3>"
+    var form = document.createElement('form')
+    var groups = []
+    for (i in unixgroups) {
+	for (x in unixgroups[i]) { 
+	    if (unixgroups[i][x] == uid && i.match(/.+-pmc$/i)) {
+		groups.push(i.replace("-pmc",""))
+		break
+	    }
+	}
+    }
+    form.appendChild(addKeyVal("PMC", makeSelect("pmc", groups, [])));
+    form.appendChild(addKeyVal("Sub-project (if any) (a-z,0-9 only)", input("text", "sub", "")))
+    var but = input("button", "submit", "Create project data file")
+    but.setAttribute("onclick", "newProject(this.form);")
+    form.appendChild(but)
+    obj.appendChild(form)
+}
+
+function newProject(form) {
+    filename = form.pmc.value
+    if (form.sub.value.length > 0) {
+	filename += "-" + form.sub.value.toLowerCase().replace(/[^-a-z0-9]/g, "")
+    }
+    editProject({}, filename);
+}
+
+
+
+// ------------ Project information page ------------\\
+
+function renderProjectPage(json, state) {
+    
+    var obj = document.getElementById('contents');
+    var isTLP = false
+    if ((!json || !json.name) && projects[state]) {
+	json = projects[state];
+    }
+    if (json && json.name) {
+	// Start by splitting the name, thus fetching the root name of the project, and not the sub-project.
+	
+	if (!json.description) {
+	    json.description = "No description available"
+	}
+	
+	// Title + description
+	pt = "Top Level Project"
+	if ((!committees[json.name] && pmcs[json.pmc]) || json.name.match("Incubating", "i")) {
+	    pt = "Sub-project"
+	} else {
+	    isTLP = true
+	}
+	obj.innerHTML = "<h1>" + json.name + " (" + pt + "):</h1>"
+	
+	// Rerig the unix name and pmc
+	state = state.split("-")[0];
+	if (json.name.match("incubating", "i")) {
+	    json.pmc = 'incubator'
+	}
+	
+	var p = document.createElement('p');
+	p.style.fontFamily = '"Times New Roman", Times, serif';
+	p.innerHTML = json.description.replace(/([^\r\n]+)\r?\n\r?\n/g,function(a) { return "<p>"+a+"</p>"});
+	obj.appendChild(p);
+	
+	
+	// Base data
+	var p = document.createElement('h4');
+	p.innerHTML = "Project base data:"
+	obj.appendChild(p);	
+	var ul = document.createElement('ul');
+	
+	// Website
+	if (json.homepage) {
+	    var li = document.createElement('li');
+	    li.innerHTML = "<b>Website:</b> <a href='" + json.homepage + "' target='_blank'>" + json.homepage + "</a>"
+	    ul.appendChild(li)
+	}
+	var li = document.createElement('li');
+	if (unixgroups[state]) {
+	    li.innerHTML = "<b>Project status:</b> <span class='pactive'>Active</span>";
+	} else {
+	    li.innerHTML = "<b>Project status:</b> <span class='pretired'>Retired(?)</span>";
+	}
+	if (json.podling) {
+	    li.innerHTML = "<b>Project status:</b> <span class='ppodling'>Incubating</span>";
+	}
+	
+	ul.appendChild(li)
+	if (committees[json.name]) {
+	    var li = document.createElement('li');
+	    li.innerHTML = "<b>Project founded:</b> " + committees[json.name]
+	    ul.appendChild(li)
+	}
+	
+	// TLP Owner?
+	if (json.pmc) {
+	    if (json.pmc.match(/http:\/\/([a-z0-9]+)/i)) {
+		json.pmc = json.pmc.match(/http:\/\/([a-z0-9]+)/i)[1];
+	    }	    
+	} else {
+	    json.pmc = state
+	}
+	if (!committees[json.name] && pmcs[json.pmc]) {
+	    var li = document.createElement('li');
+	    li.innerHTML = "<b>Sub-project of:</b> <a href='/project.html?" + json.pmc + "'>" + pmcs[json.pmc].name + "</a>"
+	    ul.appendChild(li)
+	}
+	
+	if (isTLP) {
+		
+	    // VP
+	    if (chairs[json.name]) {
+		var li = document.createElement('li');
+		li.innerHTML = "<b>PMC Chair:</b> " + chairs[json.name];
+		ul.appendChild(li)
+	    }
+	    
+	    // Reporting cycle
+	    if (cycles[json.name]) {
+		var li = document.createElement('li');
+		li.innerHTML = "<b>Reporting cycle:</b> " + cycles[json.name]
+		ul.appendChild(li)
+	    }
+	    
+	    // PMC
+	    if (unixgroups[state+"-pmc"]) {
+		pmcl = []
+		for (i in unixgroups[state+"-pmc"]) {
+		    cid = unixgroups[state+"-pmc"][i]
+		    fullname = "Anonymous"
+		    cl = "committer"
+		    if (people[cid]) {
+			fullname = people[cid].name;
+			if (people[cid].member) {
+			    cl = "member"
+			} else {
+			    cl = "committer"
+			}
+		    }
+		    pmcl.push("<a class='" + cl + "' title='" + cid + "' href='http://people.apache.org/committer-index.html#" + cid + "' target='_blank'>" + fullname + "</a>")
+		}
+		pmc = pmcl.join(", &nbsp;")
+		var li = document.createElement('li');
+		li.innerHTML = "<b>PMC Members (" + unixgroups[state+"-pmc"].length + "):</b> <blockquote>" + pmc + "</blockqoute>"
+		ul.appendChild(li)
+	    }
+	}
+	
+	// Committers
+	if (unixgroups[state]) {
+	    pmcl = []
+	    for (i in unixgroups[state]) {
+		cid = unixgroups[state][i]
+		fullname = "Anonymous"
+		cl = "committer"
+		if (people[cid]) {
+		    fullname = people[cid].name;
+		    if (people[cid].member) {
+			cl = "member"
+		    } else {
+			cl = "committer"
+		    }
+		}
+		pmcl.push("<a class='" + cl + "' title='" + cid + "' href='http://people.apache.org/committer-index.html#" + cid + "' target='_blank'>" + fullname + "</a>")
+	    }
+	    pmc = pmcl.join(", &nbsp;")
+	    var li = document.createElement('li');
+	    li.innerHTML = "<b>Committers (" + unixgroups[state].length + "):</b> <blockquote>" + pmc + "</blockqoute>"
+	    ul.appendChild(li)
+	}
+	
+	// maintainer
+	if (json.maintainer && json.maintainer.Person && json.maintainer.Person.mbox) {
+	    var li = document.createElement('li');
+	    mt = json.maintainer.Person.mbox
+	    li.innerHTML = "<b>Project data maintainer:</b> <a href='" + mt + "'>" + mt.substr(mt.indexOf(":") + 1) + "</a>"
+	    ul.appendChild(li)
+	}
+	// doap/rdf
+	if (json.doap) {
+	    var li = document.createElement('li');
+	    li.innerHTML = "<b>Project data file:</b> <a href='" + json.doap + "' target='_blank'>RDF Source</a>"
+	    ul.appendChild(li)
+	}
+	    
+	obj.appendChild(ul);
+	
+	// Code data	
+	var p = document.createElement('h4');
+	p.innerHTML = "Development:"
+	obj.appendChild(p);	
+	var ul = document.createElement('ul');
+	
+	if (json['programming-language']) {
+	    var li = document.createElement('li');
+	    pl = json['programming-language']
+	    var arr = pl.split(/,\s*/)
+	    pls = "";
+	    for (i in arr) {
+		pls += "<a href='/projects.html?language#" + arr[i] + "'>" + arr[i] + "</a> &nbsp; "
+	    }
+	    li.innerHTML = "<b>Programming language:</b> " + pls
+	    ul.appendChild(li)
+	}
+	
+	if (json['bug-database']) {
+	    var li = document.createElement('li');
+	    bd = json['bug-database']
+	    li.innerHTML = "<b>Bug-tracking:</b> <a href='" + bd + "'>" + bd + "</a>"
+	    ul.appendChild(li)
+	}
+	
+	if (json['mailing-list']) {
+	    var li = document.createElement('li');
+	    bd = json['mailing-list']
+	    li.innerHTML = "<b>Mailing list(s):</b> <a href='" + bd + "'>" + bd + "</a>"
+	    ul.appendChild(li)
+	}
+	
+	obj.appendChild(ul);
+    
+	// repositories
+	var p = document.createElement('h4');
+	p.innerHTML = "Repositories:"
+	obj.appendChild(p);	
+	var ul = document.createElement('ul');
+	if (json.SVNRepository) {
+	    var li = document.createElement('li');
+	    li.innerHTML = "<b>Subversion:</b> <a target=*_blank' href='" + json.SVNRepository + "'>" + json.SVNRepository + "</a>"
+	    ul.appendChild(li);
+	}
+	if (json.GitRepository) {
+	    var li = document.createElement('li');
+	    li.innerHTML = "<b>Git:</b> <a target=*_blank' href='" + json.GitRepository + "'>" + json.GitRepository + "</a>"
+	    ul.appendChild(li);
+	}
+	obj.appendChild(ul);
+    } else {
+	obj.innerHTML = "<h2>Sorry, I don't have any information available about this project</h2>"
+    }
+    
+}
+
+
+function buildProjectPage() {
+    var project = document.location.search.substr(1);
+    GetAsyncJSON("/json/projects/" + project + ".json?" + Math.random(), project, renderProjectPage)
+}
+
+
+function setChairs(json, state) {
+    chairs = json
+}
+
+function setCycles(json, state) {
+    cycles = json
+}
+
+
+
+// ------------ Projects listing ------------\\
+
+function renderProjectsList(cat) {
+
+    var obj = document.getElementById('contents');
+    
+    if (cat == "name") {
+	// Title + description
+	obj.innerHTML = "<h1>Projects by name:</h1>"
+
+	// Project list
+	var ul = document.createElement('ul');
+	var arr = []
+	for (i in projects) {
+	    arr.push(i);
+	}
+	arr.sort();
+	for (i in arr) {
+	    project = arr[i]
+	    var li = document.createElement('li');
+	    li.innerHTML = "<a href='/project.html?" + project + "'>" + projects[project].name + "</a>";
+	    if (isTLP(projects[project].name)) {
+		li.innerHTML += "<img src='/images/tlp.png' title='Top Level Project' style='vertical-align: middle; padding: 2px;'/>"
+	    } else {
+		li.innerHTML += "<img src='/images/sub.png' title='Sub-project' style='vertical-align: middle; padding: 2px;'/>"
+	    }
+	    ul.appendChild(li)
+	}
+	obj.appendChild(ul);
+    }
+    
+    // By language
+    if (cat == "language") {
+	// Title + description
+	obj.innerHTML = "<h1>Projects by language:</h1>"
+    
+	// Compile Language array
+	var lingos = []
+	var lcount = {}
+	for (i in projects) {
+	    if (projects[i]['programming-language']) {
+		var a = projects[i]['programming-language'].split(/,\s*/)
+		for (x in a) {
+		    if (lingos.indexOf(a[x]) < 0) {
+			lingos.push(a[x])
+			lcount[a[x]] = 0;
+		    }
+		    lcount[a[x]]++;
+		}
+	    }
+	}
+	
+	// Construct language list
+	lingos.sort()
+	var ul = document.createElement('ul');
+	
+	for (l in lingos) {
+	    var lang = lingos[l]
+	    var li = document.createElement('li');
+	    li.innerHTML = "<h3><a id='" + lang + "'>" + lang + " (" + lcount[lang] + ")</a>:</h3>"
+	    var cul = document.createElement('ul');
+	    for (i in projects) {
+		if (projects[i]['programming-language']) {
+		    var a = projects[i]['programming-language'].split(/,\s*/)
+		    for (x in a) {
+			if (a[x] == lang) {
+			    var cli = document.createElement('li');
+			    cli.innerHTML = "<a href='/project.html?" + i + "'>" + projects[i].name + "</a>";
+			    if (isTLP(projects[i].name)) {
+				cli.innerHTML += "<img src='/images/tlp.png' title='Top Level Project' style='vertical-align: middle; padding: 2px;'/>"
+			    } else {
+				cli.innerHTML += "<img src='/images/sub.png' title='Sub-project' style='vertical-align: middle; padding: 2px;'/>"
+			    }
+			    cul.appendChild(cli)
+			}
+		    }
+		}
+	    }
+	    li.appendChild(cul);
+	    ul.appendChild(li);
+	}
+	
+	obj.appendChild(ul);
+    }
+    // By category
+    if (cat == "category") {
+	// Title + description
+	obj.innerHTML = "<h1>Projects by category:</h1>"
+    
+	var cats = []
+	var ccount = {}
+	for (i in projects) {
+	    if (projects[i].category) {
+		var a = projects[i].category.split(/,\s*/)
+		for (x in a) {
+		    a[x] = a[x].replace("http://projects.apache.org/category/", "").toLowerCase();
+		}
+		for (x in a) {
+		    if (cats.indexOf(a[x]) < 0) {
+			cats.push(a[x])
+			ccount[a[x]] = 0;
+		    }
+		    ccount[a[x]]++;
+		}
+	    }
+	    
+	}
+	cats.sort()
+	
+	// Construct category list
+	var ul = document.createElement('ul');
+	
+	for (l in cats) {
+	    var lang = cats[l]
+	    var li = document.createElement('li');
+	    li.innerHTML = "<h3><a id='" + lang + "'>" + lang + " (" + ccount[lang] + ")</a>:</h3>"
+	    var cul = document.createElement('ul');
+	    for (i in projects) {
+		if (projects[i].category) {
+		    var a = projects[i]['category'].split(/,\s*/)
+		    for (x in a) {
+			a[x] = a[x].replace("http://projects.apache.org/category/", "").toLowerCase();
+			if (a[x] == lang) {
+			    var cli = document.createElement('li');
+			    cli.innerHTML = "<a href='/project.html?" + i + "'>" + projects[i].name + "</a>";
+			    if (isTLP(projects[i].name)) {
+				cli.innerHTML += "<img src='/images/tlp.png' title='Top Level Project' style='vertical-align: middle; padding: 2px;'/>"
+			    } else {
+				cli.innerHTML += "<img src='/images/sub.png' title='Sub-project' style='vertical-align: middle; padding: 2px;'/>"
+			    }
+			    cul.appendChild(cli)
+			}
+		    }
+		}
+	    }
+	    li.appendChild(cul);
+	    ul.appendChild(li);
+	}
+	
+	obj.appendChild(ul);
+    }
+    
+    // By date founded
+    if (cat == "date") {
+	// Title + description
+	obj.innerHTML = "<h1>Projects by founding date (TLPs only):</h1>"
+    
+	var dates = []
+	var dcount = {}
+	for (i in projects) {
+	    if (committees[projects[i].name]) {
+		var date = committees[projects[i].name]
+	    
+		if (dates.indexOf(date) < 0) {
+		    dates.push(date)
+		    dcount[date] = 0;
+		}
+		dcount[date]++;
+	    }
+	    
+	}
+	dates.sort()
+	
+	// Construct date list
+	var ul = document.createElement('ul');
+	
+	for (l in dates) {
+	    var date = dates[l]
+	    var li = document.createElement('li');
+	    li.innerHTML = "<h3><a id='" + date + "'>" + date + " (" + dcount[date] + ")</a>:</h3>"
+	    var cul = document.createElement('ul');
+	    for (i in projects) {
+		 if (committees[projects[i].name]) {
+		    xdate = committees[projects[i].name]
+		    if (xdate == date) {
+			var cli = document.createElement('li');
+			cli.innerHTML = "<a href='/project.html?" + i + "'>" + projects[i].name + "</a>";
+			if (isTLP(projects[i].name)) {
+			    cli.innerHTML += "<img src='/images/tlp.png' title='Top Level Project' style='vertical-align: middle; padding: 2px;'/>"
+			} else {
+			    cli.innerHTML += "<img src='/images/sub.png' title='Sub-project' style='vertical-align: middle; padding: 2px;'/>"
+			}
+			cul.appendChild(cli)
+		    }
+		 }
+	    }
+	    li.appendChild(cul);
+	    ul.appendChild(li);
+	}
+	
+	obj.appendChild(ul);
+    }
+    
+    
+    // By number of committers
+    if (cat == "number") {
+	// Title + description
+	obj.innerHTML = "<h1>Projects by number of committers:</h1>"
+    
+	var lens = []
+	var lcount = {}
+	for (i in projects) {
+	    if (unixgroups[i] && i != 'incubator') {
+		var len = unixgroups[i].length;
+		if (lens.indexOf(len) < 0) {
+		    lens.push(len)
+		    lcount[len] = 0;
+		}
+		lcount[len]++;
+	    }
+	}
+	lens.sort(function(a,b) { return b - a })
+	
+	// Construct date list
+	var ul = document.createElement('ul');
+	
+	for (l in lens) {
+	    var len = lens[l]
+	    for (i in projects) {
+		if (unixgroups[i]) {
+		    var xlen = unixgroups[i].length
+		    if (xlen == len) {
+			var cli = document.createElement('li');
+			cli.innerHTML = "<a href='/project.html?" + i + "'>" + projects[i].name + "</a>: " + len + " committers";
+			if (unixgroups[i+'-pmc']) {
+			    cli.innerHTML += ", " + unixgroups[i+'-pmc'].length + " PMC members";
+			    if (isTLP(projects[i].name)) {
+				cli.innerHTML += "<img src='/images/tlp.png' title='Top Level Project' style='vertical-align: middle; padding: 2px;'/>"
+			    } else {
+				cli.innerHTML += "<img src='/images/sub.png' title='Sub-project' style='vertical-align: middle; padding: 2px;'/>"
+			    }
+			}
+			ul.appendChild(cli)
+		    }
+		 }
+	    }
+	}
+	
+	obj.appendChild(ul);
+    }
+    
+    // By PMC
+    if (cat == "pmc") {
+	// Title + description
+	obj.innerHTML = "<h1>Projects by PMC:</h1>"
+    
+	var lpmcs = []
+	var dcount = {}
+	for (i in projects) {
+	    // Fix Incubating projects
+	    if (projects[i].name.match("incubating", "i")) {
+		projects[i].pmc = 'incubator'
+	    }
+	    if (pmcs[projects[i].pmc]) {
+		var lpmc = projects[i].pmc
+	    
+		if (lpmcs.indexOf(lpmc) < 0) {
+		    lpmcs.push(lpmc)
+		    dcount[lpmc] = 0;
+		}
+		dcount[lpmc]++;
+	    }
+	    
+	}
+	lpmcs.sort()
+	
+	// Construct pmc list
+	var ul = document.createElement('ul');
+	
+	for (l in lpmcs) {
+	    var lpmc = lpmcs[l]
+	    var li = document.createElement('li');
+	    li.innerHTML = "<h3><a id='" + lpmc + "'>" + pmcs[lpmc].name + " (" + dcount[lpmc] + ")</a>:</h3>"
+	    var cul = document.createElement('ul');
+	    for (i in projects) {
+		// Fix Incubating projects
+		if (projects[i].name.match("incubating", "i")) {
+		    projects[i].pmc = 'incubator'
+		}
+		 if (pmcs[projects[i].pmc]) {
+		    xlpmc = projects[i].pmc
+		    if (xlpmc == lpmc) {
+			var cli = document.createElement('li');
+			cli.innerHTML = "<a href='/project.html?" + i + "'>" + projects[i].name + "</a>";
+			if (isTLP(projects[i].name)) {
+			    cli.innerHTML += "<img src='/images/tlp.png' title='Top Level Project' style='vertical-align: middle; padding: 2px;'/>"
+			} else {
+			    cli.innerHTML += "<img src='/images/sub.png' title='Sub-project' style='vertical-align: middle; padding: 2px;'/>"
+			}
+			cul.appendChild(cli)
+		    }
+		 }
+	    }
+	    li.appendChild(cul);
+	    ul.appendChild(li);
+	}
+	
+	obj.appendChild(ul);
+    }
+    
+    if (location.hash.length > 1) {
+	location.href = location.href;
+    }
+}
+
+function buildProjectList(json) {
+    setCommittees(json, null);
+    var cat = document.location.search.substr(1);
+    if (cat.length == 0) {
+	cat = "name";
+    }
+    renderProjectsList(cat);
+}
+
+
+function isTLP(project) {
+    if (committees[project]) {
+	return true;
+    }
+    return false
+}
+
+// ------------ Front page rendering ------------\\
+
+function renderFrontPage() {
+    numchairs = 0;
+    for (i in committees) numchairs++;
+    cur = evolution[0].current;
+    var nsubs = 0;
+    
+    for (i in projects) {
+	if (!projects[i].name.match(/incubating/i)) {
+	    initiatives++;
+	}
+	if (!isTLP(projects[i].name) && !projects[i].name.match(/incubating/i)) {
+	    nsubs++;
+	}
+    }
+    var initiatives = cur + numchairs + nsubs + 5; // podlings + tlps + sub-projects + specials
+    initiatives -= initiatives % 100; // round down
+    var obj = document.getElementById('contents');
+    obj.innerHTML = "<h2>Welcome to the Apache Projects Directory</h2>"
+    obj.innerHTML += "<p>This site is a catalog of Apache Software Foundation projects. It is designed to help you find specific projects that meet your interests and to gain a broader understanding of the wide variety of work currently underway in the Apache community.</p>"
+    var p = document.createElement('p');
+    p.innerHTML = "<h3 style='text-align: center;'>There are currently <span style='color: #269;'>" + initiatives + "+</span> open source initatives at the ASF:</h3>"
+    p.innerHTML += "<ul style='width: 300px; margin: 0 auto; font-size: 18px; color: #269; font-weight: bold;'><li>" + numchairs + " top level software projects</li><li>" + nsubs + " sub-projects</li><li>5 special committees*</li><li>" + cur + " incubating podlings</li></ul><p><small>*Infrastructure, Travel Assistance, Security Team, Legal Affairs and Brand Management</small></p>"
+    obj.appendChild(p);
+    
+    var parr = [];
+    var cur = 0;
+    var karr = []
+    for (i in committees_raw) {
+	karr.push(i);
+    }
+    karr.sort();
+    
+    for (j in karr) {
+	var i = karr[j]
+	cur += committees_raw[i].length;
+	parr.push([i, committees_raw[i].length, cur, (committees_raw[i].length == 0) ? i + " (" + cur + "): No new projects" : i + " (" + cur + "): " + committees_raw[i].join(", ")]);
+    }
+    //narr.sort(function(a,b) { return (b[1] - a[1]) });
+    var data1 = new google.visualization.DataTable();
+    data1.addColumn('string', 'Month');
+    data1.addColumn('number', "New projects");
+    data1.addColumn('number', 'Current projects');
+    data1.addColumn({type: 'string', role: 'tooltip'});
+    
+    data1.addRows(parr);
+    
+    coptions = {
+	title: "TLP evolution",
+	isStacked: true,
+	height: 320,
+	width: 1160,
+	seriesType: "bars",
+	backgroundColor: 'transparent',
+	series: {1: {type: "line", targetAxisIndex: 1}},
+	vAxes:[
+              {title: 'Change in states'},
+              {title: 'Current number of projects'},
+              ]
+    };
+    var div = document.createElement('div');
+    obj.appendChild(div);
+    chart = new google.visualization.ComboChart(div);
+    chart.draw(data1, coptions);
+    
+    
+    var earr = [];
+    for (i in evolution) {
+	if (i > 260) {
+	    break
+	}
+	earr.push([evolution[i].month, evolution[i].new, evolution[i].graduated, evolution[i].retired, evolution[i].current]);
+    }
+    //narr.sort(function(a,b) { return (b[1] - a[1]) });
+    var data = new google.visualization.DataTable();
+    data.addColumn('string', 'Month');
+    data.addColumn('number', "New podlings");
+    data.addColumn('number', "Graduated podlings");
+    data.addColumn('number', "Retired podlings");
+    data.addColumn('number', 'Current podlings');
+    data.addRows(earr.reverse());
+    
+    coptions = {
+	title: "Podling evolution",
+	isStacked: true,
+	height: 320,
+	width: 1160,
+	seriesType: "bars",
+	backgroundColor: 'transparent',
+	series: {3: {type: "line", targetAxisIndex: 1}},
+	vAxes:[
+              {title: 'Change in states'},
+              {title: 'Current number of podlings'},
+              ]
+    };
+    var div = document.createElement('div');
+    obj.appendChild(div);
+    chart = new google.visualization.ComboChart(div);
+    chart.draw(data, coptions);
+    
+    renderLanguageChart();
+}
+
+
+// ------------ Chart functions ------------\\
+
+
+function renderLanguageChart() {
+    var obj = document.getElementById('contents');
+    var chartDiv = document.createElement('div');
+    
+    
+    // Languages
+    var lingos = []
+    var lcount = {}
+    for (i in projects) {
+	if (projects[i]['programming-language']) {
+	    var a = projects[i]['programming-language'].split(", ")
+	    for (x in a) {
+		if (lingos.indexOf(a[x]) < 0) {
+		    lingos.push(a[x])
+		    lcount[a[x]] = 0;
+		}
+		lcount[a[x]]++;
+	    }
+	}
+    }
+    
+    
+    narr = []
+    for (i in lingos) {
+	var lang = lingos[i]
+	narr.push([lang, lcount[lang], 'Click here to view all projects using ' + lang])
+    }
+    narr.sort(function(a,b) { return (b[1] - a[1]) });
+    
+    var data = new google.visualization.DataTable();
+        data.addColumn('string', 'Language');
+        data.addColumn('number', "Projects using it");
+	data.addColumn({type: 'string', role: 'tooltip'});
+        data.addRows(narr);
+
+    var options = {
+      title: 'Language distribution (click on a language to view all projects using it)',
+      height: 400,
+      backgroundColor: 'transparent'
+    };
+
+    var chart = new google.visualization.PieChart(chartDiv);
+    obj.appendChild(chartDiv)
+    
+    function selectHandlerLanguage() {
+	var selectedItem = chart.getSelection()[0];
+	if (selectedItem) {
+	  var value = data.getValue(selectedItem.row, 0);
+	  location.href = "/projects.html?language#" + value;
+	}
+    }
+    google.visualization.events.addListener(chart, 'select', selectHandlerLanguage);
+    chart.draw(data, options);
+    
+    
+    // Categories    
+    var cats = []
+    var ccount = {}
+    for (i in projects) {
+	if (projects[i].category) {
+	    var a = projects[i].category.split(", ")
+	    for (x in a) {
+		a[x] = a[x].replace("http://projects.apache.org/category/", "");
+	    }
+	    for (x in a) {
+		if (cats.indexOf(a[x]) < 0) {
+		    cats.push(a[x])
+		    ccount[a[x]] = 0;
+		}
+		ccount[a[x]]++;
+	    }
+	}
+    }
+    
+    
+    carr = []
+    for (i in cats) {
+	var cat = cats[i]
+	carr.push([cat, ccount[cat], 'Click here to view all projects in the ' + cat + ' category'])
+    }
+    carr.sort(function(a,b) { return (b[1] - a[1]) });
+    
+    
+    var data2 = new google.visualization.DataTable();
+        data2.addColumn('string', 'Category');
+        data2.addColumn('number', "Projects");
+	data2.addColumn({type: 'string', role: 'tooltip'});
+        data2.addRows(carr);
+
+    var options = {
+      title: 'Categories (click on a category to view projects within it)',
+      height: 400,
+      backgroundColor: 'transparent'
+    };
+
+    var chartDiv = document.createElement('div');
+    var chart2 = new google.visualization.PieChart(chartDiv);
+    obj.appendChild(chartDiv)
+    
+    
+    function selectHandlerCategory() {
+	var selectedItem = chart2.getSelection()[0];
+	if (selectedItem) {
+	  var value = data2.getValue(selectedItem.row, 0);
+	  location.href = "/projects.html?category#" + value;
+	}
+    }
+    google.visualization.events.addListener(chart2, 'select', selectHandlerCategory);
+    chart2.draw(data2, options);
+    
+
+}
+
+function buildFrontPage() {
+    GetAsyncJSON("/json/foundation/evolution.json?" + Math.random(), null, renderFrontPage)
+}
+
+
+
+// ------------ Search feature for the site ------------\\
+
+function searchProjects(str) {
+    var obj = document.getElementById('contents');
+    
+    str = str.toLowerCase()
+    hits = {}
+    hitssorted = []
+    
+    // Search TLPs
+    for (p in projects) {
+	var project = projects[p];
+	for (key in project) {
+	    if (typeof project[key] == "string") {
+	        val = project[key].toLowerCase()
+		if (val.indexOf(str) >= 0 && val.substr(0,1) != "{") {
+		    if (!hits[p]) {
+			hits[p] = [];
+		    }
+		    estr = new RegExp(str, "i");
+		    hits[p].push({
+			'key': key,
+			'val': project[key].replace(estr, function(a) { return "<u style='color: #963;'>"+a+"</u>"}, "img")
+		    })
+		    if (hitssorted.indexOf(p) < 0) {
+			hitssorted.push(p);
+		    }
+		} 
+	    }
+	}
+    }
+    
+    obj.innerHTML = "<h2>Search results for '" + str + "' (" + hitssorted.length + "):</h2>"
+    hitssorted.sort(function(a,b) { return hits[b].length - hits[a].length })
+    var ul = document.createElement('ul');
+	
+    for (h in hitssorted) {
+	var project = hits[hitssorted[h]]
+	var li = document.createElement('li');
+	li.innerHTML = "<h4><a href='/project.html?" + hitssorted[h] + "'>" + projects[hitssorted[h]].name + "</a> (" + project.length + " hit(s)):</h4>"
+	for (x in project) {
+	    li.innerHTML += "<blockquote><b>" + project[x].key + ":</b> " +  project[x].val + "</blockquote>"
+	}
+	ul.appendChild(li);
+    }
+    if (hitssorted.length == 0) {
+	obj.innerHTML += "No search results found"
+    }
+    obj.appendChild(ul);
+}
+
+
+
+// Key press monitoring for search field
+function checkKeyPress(e, txt) {
+    if (!e) e = window.event;
+    var keyCode = e.keyCode || e.which;
+    if (keyCode == '13'){
+	searchProjects(txt.value);
+    }
+}
+
+
+// ------------ Weave functions ------------\\
+
+// Add projects if they aren't in the hash already
+function weaveInProjects(json) {
+    for (p in json) {
+	if (!projects[p]) {
+	    projects[p] = json[p];
+	}
+    }
+}
+
+// Add committer IDs+names to project hashes
+function weaveInCommitters(json) {
+    unixgroups = json
+    for (p in json) {
+	if (projects[p] && p != 'incubator') {
+	    fn = []
+	    for (i in json[p]) {
+		if (people[json[p][i]]) {
+		    fn.push(people[json[p][i]].name)
+		}
+	    }
+	    projects[p].committers = json[p].join(", ")
+	    projects[p].committers_fullname = fn.join(", ")
+	}
+    }
+}
+
+
+function setCommittees(json, state) {
+    committees_raw = json
+    for (i in json) {
+	for (j in json[i]) {
+	    committees[json[i][j]] = i;
+	}
+    }
+    if (state) {
+	state();
+    }
+}
+
+
+// ------------ Async data fetching ------------\\
+// This function is the starter of every page, and preloads the needed files
+// before running the final page renderer. This is roughly 1 mb of JSON, but as
+// it gets cached after first run, it's not really a major issue.
+
+function preloadEverything(callback) {
+    GetAsyncJSONArray([
+	    ["/json/foundation/pmcs.json", function(json) { pmcs = json; }],
+	    ["/json/foundation/people.json", function(json) { people = json; }],
+	    ["/json/foundation/cycles.json", function(json) { cycles = json; }],
+	    ["/json/foundation/chairs.json", function(json) { chairs = json; }],
+	    ["/json/foundation/evolution.json", function(json) { evolution = json; }],
+	    ["/json/foundation/committees.json", setCommittees],
+	    ["/json/foundation/projects.json", weaveInProjects],
+	    ["/json/foundation/podlings.json", weaveInProjects],
+	    ["/json/foundation/committers.json", weaveInCommitters],
+        ],
+	callback);
+}