change to more python / ezt style syntax for metadata expansion in asfreader
diff --git a/content/foundation/index.ezmd b/content/foundation/index.ezmd
index 96c100f..63155cb 100644
--- a/content/foundation/index.ezmd
+++ b/content/foundation/index.ezmd
@@ -82,9 +82,9 @@
 
 |  |  |  |
 |-----------|-----------|-------------|
-| {{ board(0).name }} | {{ board(1).name }} | {{ board(2).name }} |
-| {{ board(3).name }} | {{ board(4).name }} | {{ board(5).name }} | 
-| {{ board(6).name }} | {{ board(7).name }} | {{ board(8).name }} |
+| [{ board[0].name }] | [{ board[1].name }] | [{ board[2].name }] |
+| [{ board[3].name }] | [{ board[4].name }] | [{ board[5].name }] | 
+| [{ board[6].name }] | [{ board[7].name }] | [{ board[8].name }] |
 
 #### Officers ####
 
@@ -92,38 +92,38 @@
 
 | Office    | Individual  |
 |-----------|-------------|
-| Board Chair |  {{ ci.boardchair.roster }} |
-| Vice Chair |  {{ ci.vicechair.roster }} |
-| President |  {{ ci.president.roster }} |
-| Exec. V.P |  {{ ci.execvp.roster }} |
-| [[]Treasurer](https://treasurer.apache.org/) |  {{ ci.treasurer.roster }} |
-| Assistant Treasurer |  {{ ci.assistanttreasurer.roster }} |
-| Secretary |  {{ ci.secretary.roster }} |
-| Assistant Secretary |  {{ ci.assistantsecretary.roster }} |
-| V.P., [[]Legal Affairs](/legal/) |  {{ ci.legal.chair }} |
-| Assistant V.P., [[]Legal Affairs](/legal/) |  {{ ci.assistantvplegalaffairs.roster }} |
-| V.P., [[]Security](/security/) |  {{ ci.security.chair }} |
-| V.P., [[]Data Privacy](https://privacy.apache.org/) |  {{ ci.dataprivacy.chair }} |
-| V.P., [[]W3C Relations](https://whimsy.apache.org/board/minutes/W3C_Relations.html) |  {{ ci.w3crelations.roster }} |
+| Board Chair |  [{ ci[boardchair][roster] }] |
+| Vice Chair |  [{ ci[vicechair][roster] }] |
+| President |  [{ ci[president][roster] }] |
+| Exec. V.P |  [{ ci[execvp][roster] }] |
+| [[]Treasurer](https://treasurer.apache.org/) |  [{ ci[treasurer][roster] }] |
+| Assistant Treasurer |  [{ ci[assistanttreasurer][roster] }] |
+| Secretary |  [{ ci[secretary][roster] }] |
+| Assistant Secretary |  [{ ci[assistantsecretary][roster] }] |
+| V.P., [[]Legal Affairs](/legal/) |  [{ ci[legal][chair] }] |
+| Assistant V.P., [[]Legal Affairs](/legal/) |  [{ ci[assistantvplegalaffairs][roster] }] |
+| V.P., [[]Security](/security/) |  [{ ci[security][chair] }] |
+| V.P., [[]Data Privacy](https://privacy.apache.org/) |  [{ ci[dataprivacy][chair] }] |
+| V.P., [[]W3C Relations](https://whimsy.apache.org/board/minutes/W3C_Relations.html) |  [{ ci[w3crelations][roster] }] |
 
 The President has appointed the following corporate officers of the ASF:
 
 | Office    | Individual  |
 |-----------|-------------|
-| V.P., [[]Brand Management](marks/) |  {{ ci.brand.chair }} |
-| V.P., [[]Conferences](https://events.apache.org/) |  {{ ci.concom.chair }} |
-| V.P., [[]Diversity and Inclusion](http://diversity.apache.org/) |  {{ ci.diversity.chair }} |
-| V.P., Fundraising |  {{ ci.fundraising.chair }} |
-| V.P., [[]Infrastructure](/dev/) |  {{ ci.infrastructure.roster }} |
-| V.P., [[]Marketing and Publicity](/press/) |  {{ ci.marketingandpublicity.chair }} |
-| V.P., [[]Travel Assistance](/travel/) |  {{ ci.tac.chair }} |
-| [[]Infrastructure Administrator](/dev/) |  {{ ci.infrastructureadministrator.roster }} |
+| V.P., [[]Brand Management](marks/) |  [{ ci[brand][chair] }] |
+| V.P., [[]Conferences](https://events.apache.org/) |  [{ ci[concom][chair] }] |
+| V.P., [[]Diversity and Inclusion](http://diversity.apache.org/) |  [{ ci[diversity][chair] }] |
+| V.P., Fundraising |  [{ ci[fundraising][chair] }] |
+| V.P., [[]Infrastructure](/dev/) |  [{ ci[infrastructure][roster] }] |
+| V.P., [[]Marketing and Publicity](/press/) |  [{ ci[marketingandpublicity][chair] }] |
+| V.P., [[]Travel Assistance](/travel/) |  [{ ci[tac][chair] }] |
+| [[]Infrastructure Administrator](/dev/) |  [{ ci[infrastructureadministrator][roster] }] |
 
 VP, Fundraising has appointed the following corporate officers of the ASF:
 
 | Office    | Individual  |
 |-----------|-------------|
-| V.P., Sponsor Relations |  {{ ci.sponsorrelations.roster }} |
+| V.P., Sponsor Relations |  [{ ci[sponsorrelations][roster] }] |
 
 #### PMC chairs ####
 
diff --git a/content/index.ezmd b/content/index.ezmd
index e0fcd59..b8eec92 100644
--- a/content/index.ezmd
+++ b/content/index.ezmd
@@ -10,24 +10,24 @@
 <div class="col-sm-4 col-sm-offset-2">
 
 - All volunteer community
-- {{ code_lines }}+ lines of code in&nbsp;stewardship
-- {{ code_changed }}+ lines of code&nbsp;changed
-- {{ code_commits }}+ code commits
-- {{ asf_members }} individual ASF&nbsp;Members
-- {{ asf_committers }}+ Apache Committers
-- {{ asf_contributors }}+ code contributors
-- {{ asf_people }}+ people involved in our&nbsp;communities
+- [{ code_lines }]+ lines of code in&nbsp;stewardship
+- [{ code_changed }]+ lines of code&nbsp;changed
+- [{ code_commits }]+ code commits
+- [{ asf_members }] individual ASF&nbsp;Members
+- [{ asf_committers }]+ Apache Committers
+- [{ asf_contributors }]+ code contributors
+- [{ asf_people }]+ people involved in our&nbsp;communities
 
 </div>
 <div class="col-sm-4">
 
-- {{ com_initiatives }}+ Projects and Initiatives
-- {{ com_projects }}+ Top-Level Projects
-- {{ com_podlings }} podlings in the Apache&nbsp;Incubator
-- {{ com_downloads }} source code downloads from Apache&nbsp;mirrors
-- {{ com_emails }}+ emails across {{ com_mailinglists }}+ mailing&nbsp;lists
+- [{ com_initiatives }]+ Projects and Initiatives
+- [{ com_projects }]+ Top-Level Projects
+- [{ com_podlings }] podlings in the Apache&nbsp;Incubator
+- [{ com_downloads }] source code downloads from Apache&nbsp;mirrors
+- [{ com_emails }]+ emails across [{ com_mailinglists }]+ mailing&nbsp;lists
 - Web requests received from every Internet-connected country on the&nbsp;planet
-- {{ com_pageviews }}+ weekly page views across [[]apache.org](/)
+- [{ com_pageviews }]+ weekly page views across [[]apache.org](/)
 
 </div>
 <div class="col-sm-8 col-sm-offset-2 text-center">
@@ -218,7 +218,7 @@
 
 The ASF develops, shepherds, and incubates hundreds of freely-available, enterprise-grade projects that serve as the
 backbone for some of the most visible and widely used applications in computing today. Through the ASF's merit-based
-process known as [[]"The Apache Way,"](/theapacheway) more than [[]{{ asf_members_rounded }} individual volunteer Members and {{ asf_committers }}+ code
+process known as [[]"The Apache Way,"](/theapacheway) more than [[][{ asf_members_rounded }] individual volunteer Members and [{ asf_committers }]+ code
 Committers](http://community.zones.apache.org/map.html) across six continents successfully collaborate on innovations
 in Artificial Intelligence and Deep Learning, Big Data, Build Management, Cloud Computing, Content Management, DevOps,
 IoT and Edge Computing, Mobile, Servers, and Web Frameworks, [[]among other categories](https://projects.apache.org/projects.html?category).
diff --git a/theme/plugins/asfgenid.py b/theme/plugins/asfgenid.py
index 178ac74..399a0e1 100644
--- a/theme/plugins/asfgenid.py
+++ b/theme/plugins/asfgenid.py
@@ -41,11 +41,7 @@
 ELEMENTID_RE = re.compile(r'(?:[ \t]*[{\[][ \t]*(?P<type>[#.])(?P<id>[-._:a-zA-Z0-9 ]+)[}\]])(\n|$)')
 
 # Find {{ metadata }}
-METADATA_RE = re.compile(r'{{\s*(?P<meta>[-._:a-zA-Z0-9\(\)\[\]]+)\s*}}')
-FIXUP_METADATA = [
-    (re.compile(r'\('),'['),
-    (re.compile(r'\)'),']')
-]
+METADATA_RE = re.compile(r'{{\s*(?P<meta>[-_:a-zA-Z0-9]+)\s*}}')
 
 # Find table tags
 TABLE_RE = re.compile(r'^table')
@@ -184,22 +180,9 @@
         m = METADATA_RE.search(this_string)
         if m:
             this_data = m.group(1).strip()
-            for regex, replace in FIXUP_METADATA:
-                n = regex.search(this_data)
-                if n:
-                    this_data = re.sub(regex, replace, this_data)
             format_string = '{{{0}}}'.format(this_data)
-            parts = this_data.split('.')
-            subs = parts[0].split('[')
             try:
-                # should refactor this to be more general
-                if len(subs) == 1 and isinstance(metadata[parts[0]], dict):
-                    ref = metadata
-                    for part in parts:
-                        ref = ref[part]
-                    new_string = ref
-                else:
-                    new_string = format_string.format(**metadata)
+                new_string = format_string.format(**metadata)
                 print(f'{{{{{m.group(1)}}}}} -> {new_string}')
             except Exception:
                 # the data expression was not found
diff --git a/theme/plugins/asfreader.py b/theme/plugins/asfreader.py
index c17ad47..750a2cc 100644
--- a/theme/plugins/asfreader.py
+++ b/theme/plugins/asfreader.py
@@ -25,6 +25,7 @@
 import os
 import traceback
 
+import re
 import ezt
 
 import pelican.plugins.signals
@@ -33,6 +34,7 @@
 
 GFMReader = sys.modules['pelican-gfm.gfm'].GFMReader
 
+METADATA_RE = re.compile(r'\[{\s*(?P<meta>[-._:a-zA-Z0-9\[\]]+)\s*}\]')
 
 class ASFTemplateReader(ezt.Reader):
     """Enables inserts relative to the template we loaded."""
@@ -53,12 +55,29 @@
     generation prior to processing the GFM
     """
 
-    def add_data(self, metadata):
+    def add_data(self, text, metadata):
         "Mix in ASF data as metadata"
 
         asf_metadata = self.settings.get('ASF_DATA', { }).get('metadata')
         if asf_metadata:
             metadata.update(asf_metadata)
+            # insert any direct references
+            m = 1
+            while m:
+                m = METADATA_RE.search(text)
+                if m:
+                    this_data = m.group(1).strip()
+                    format_string = '{{{0}}}'.format(this_data)
+                    try:
+                        new_string = format_string.format(**metadata)
+                        print(f'{{{{{m.group(1)}}}}} -> {new_string}')
+                    except Exception:
+                        # the data expression was not found
+                        new_string = format_string
+                        print(f'{{{{{m.group(1)}}}}} is not found')
+                    text = re.sub(METADATA_RE, new_string, text, count=1)
+        return text, metadata
+
 
     def read(self, source_path):
         "Read metadata and content, process content as ezt template, then render into HTML."
@@ -68,7 +87,7 @@
             assert text
             assert metadata
             # supplement metadata with ASFData if available
-            self.add_data(metadata)
+            text, metadata = self.add_data(text, metadata)
             # prepare text as an ezt template
             # compress_whitespace=0 is required as blank lines and indentation have meaning in markdown.
             template = ezt.Template(compress_whitespace=0)