From 62f6c6df9e08d469a044e97e7450058146e07de1 Mon Sep 17 00:00:00 2001 From: "David A. Madore" Date: Fri, 3 Oct 2014 15:53:02 +0200 Subject: Remove all templates from damlengine; introduce config variables instead. Location of template files should now be specified by the DAMLENGINE_TEMPLATE_PATH environment variable. --- org/madore/damlengine/DamlEngine.java | 44 +++- org/madore/damlengine/TodoDamlElement.java | 5 +- .../damlengine/WeblogDatabaseConnection.java | 36 +++- org/madore/damlengine/WeblogIndexSelect.java | 3 +- org/madore/damlengine/WeblogSelect.java | 3 +- org/madore/damlengine/included.css | 115 ---------- org/madore/damlengine/included.js | 109 ---------- org/madore/damlengine/weblog-cat-template.daml | 66 ------ org/madore/damlengine/weblog-index-template.daml | 60 ------ org/madore/damlengine/weblog-month-template.daml | 231 --------------------- org/madore/damlengine/weblog-recent-template.daml | 84 -------- org/madore/damlengine/weblog-single-template.daml | 50 ----- 12 files changed, 79 insertions(+), 727 deletions(-) delete mode 100644 org/madore/damlengine/included.css delete mode 100644 org/madore/damlengine/included.js delete mode 100644 org/madore/damlengine/weblog-cat-template.daml delete mode 100644 org/madore/damlengine/weblog-index-template.daml delete mode 100644 org/madore/damlengine/weblog-month-template.daml delete mode 100644 org/madore/damlengine/weblog-recent-template.daml delete mode 100644 org/madore/damlengine/weblog-single-template.daml (limited to 'org') diff --git a/org/madore/damlengine/DamlEngine.java b/org/madore/damlengine/DamlEngine.java index 77fbf7f..f708d81 100644 --- a/org/madore/damlengine/DamlEngine.java +++ b/org/madore/damlengine/DamlEngine.java @@ -3,6 +3,7 @@ package org.madore.damlengine; import java.util.MissingResourceException; import java.util.regex.Pattern; import java.util.regex.Matcher; +import java.util.Properties; import java.io.InputStream; import java.io.FileInputStream; import java.io.InputStreamReader; @@ -11,6 +12,7 @@ import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.io.BufferedReader; import java.io.PrintStream; +import java.io.FileNotFoundException; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import org.w3c.dom.*; @@ -148,9 +150,47 @@ public final class DamlEngine { fullProcess(in, out, null); } + public static Properties appProps; + public static String basePath; + public static String templatePath; + public static void main(String[] args) throws Exception { + appProps = new Properties(); + String appPropsFile = null; + if ( System.getenv("DAMLENGINE_PROPERTIES_PATH") != null ) + appPropsFile = System.getenv("DAMLENGINE_PROPERTIES_PATH"); + if ( appPropsFile == null ) { + if ( System.getProperty("user.home") != null ) + appPropsFile = System.getProperty("user.home") + "/damlengine.properties"; + else + appPropsFile = "damlengine.properties"; + } + try { + appProps.load(new FileInputStream(appPropsFile)); + } catch (FileNotFoundException e) { } + + basePath = null; + if ( System.getenv("DAMLENGINE_BASE_PATH") != null ) + basePath = System.getenv("DAMLENGINE_BASE_PATH"); + if ( basePath == null ) + basePath = appProps.getProperty("base_path"); + if ( basePath == null ) { + basePath = "."; + System.err.println("warning: using working directory as base path"); + } + + templatePath = null; + if ( System.getenv("DAMLENGINE_TEMPLATE_PATH") != null ) + templatePath = System.getenv("DAMLENGINE_TEMPLATE_PATH"); + if ( templatePath == null ) + templatePath = appProps.getProperty("template_path"); + if ( templatePath == null ) { + templatePath = basePath + "/templates"; + System.err.println("warning: using "+templatePath+" as template path"); + } + BufferedReader buf = new BufferedReader(new InputStreamReader(System.in, "UTF-8")); String line; Matcher matcher; @@ -162,7 +202,7 @@ public final class DamlEngine { if ( (matcher=Pattern.compile("process\\s+(\\S+)(?:\\s+\\>\\s*(\\S+))?\\s*").matcher(line)).matches() ) { String inf = matcher.group(1); String outf = matcher.group(2); - InputStream in = new FileInputStream(inf); + InputStream in = new FileInputStream((inf.charAt(0)=='/'?"":basePath+"/")+inf); OutputStream out = (outf != null) ? new FileOutputStream(outf) : System.out; @@ -226,7 +266,7 @@ public final class DamlEngine { out.close(); } else if ( (matcher=Pattern.compile("populate-weblog\\s+(\\S+)\\s*").matcher(line)).matches() ) { String inf = matcher.group(1); - InputStream in = new FileInputStream(inf); + InputStream in = new FileInputStream((inf.charAt(0)=='/'?"":basePath+"/")+inf); WeblogPopulate.populate(in); } else if ( (matcher=Pattern.compile("echo\\s+(\\S+)(?:\\s+\\>\\s*(\\S+))?\\s*").matcher(line)).matches() ) { String str = matcher.group(1); diff --git a/org/madore/damlengine/TodoDamlElement.java b/org/madore/damlengine/TodoDamlElement.java index 599e49a..9de2714 100644 --- a/org/madore/damlengine/TodoDamlElement.java +++ b/org/madore/damlengine/TodoDamlElement.java @@ -2,6 +2,7 @@ package org.madore.damlengine; import java.util.ArrayList; import java.util.regex.Pattern; +import java.io.FileInputStream; import java.io.Reader; import java.io.InputStreamReader; import java.io.BufferedReader; @@ -61,7 +62,7 @@ public final class TodoDamlElement extends TodoDefaultElement { ctx.gc.styleContent = new StringBuffer(); try { - Reader rd = new BufferedReader(new InputStreamReader(DamlEngine.class.getResourceAsStream("included.css"), "UTF-8")); + Reader rd = new BufferedReader(new InputStreamReader(new FileInputStream(DamlEngine.templatePath+"/included.css"), "UTF-8")); int ch; while ((ch = rd.read()) > -1) ctx.gc.styleContent.append((char)ch); @@ -71,7 +72,7 @@ public final class TodoDamlElement extends TodoDefaultElement { } ctx.gc.scriptContent = new StringBuffer(); try { - Reader rd = new BufferedReader(new InputStreamReader(DamlEngine.class.getResourceAsStream("included.js"), "UTF-8")); + Reader rd = new BufferedReader(new InputStreamReader(new FileInputStream(DamlEngine.templatePath+"/included.js"), "UTF-8")); int ch; while ((ch = rd.read()) > -1) ctx.gc.scriptContent.append((char)ch); diff --git a/org/madore/damlengine/WeblogDatabaseConnection.java b/org/madore/damlengine/WeblogDatabaseConnection.java index 9347406..900f3a0 100644 --- a/org/madore/damlengine/WeblogDatabaseConnection.java +++ b/org/madore/damlengine/WeblogDatabaseConnection.java @@ -20,24 +20,48 @@ public final class WeblogDatabaseConnection { public static Connection getConnection() throws SQLException { if ( conn == null ) { - String dbHost = System.getenv("PGHOST"); + String dbHost = System.getenv("DAMLENGINE_PGHOST"); + if ( dbHost == null ) + dbHost = DamlEngine.appProps.getProperty("pghost"); + if ( dbHost == null ) + dbHost = System.getenv("PGHOST"); if ( dbHost == null ) dbHost = "localhost"; - String dbPort = System.getenv("PGPORT"); + String dbPort = System.getenv("DAMLENGINE_PGPORT"); + if ( dbPort == null ) + dbPort = DamlEngine.appProps.getProperty("pgport"); + if ( dbPort == null ) + dbPort = System.getenv("PGPORT"); if ( dbPort == null ) dbPort = "5432"; - String dbName = "weblog"; - String dbUser = System.getenv("PGUSER"); + String dbName = System.getenv("DAMLENGINE_DBNAME"); + if ( dbName == null ) + dbName = DamlEngine.appProps.getProperty("dbname"); + if ( dbName == null ) + dbName = "weblog"; + String dbUser = System.getenv("DAMLENGINE_PGUSER"); + if ( dbUser == null ) + dbUser = DamlEngine.appProps.getProperty("pguser"); + if ( dbUser == null ) + dbUser = System.getenv("PGUSER"); if ( dbUser == null ) dbUser = System.getenv("USER"); if ( dbUser == null ) dbUser = System.getProperty("user.name"); if ( dbUser == null ) dbUser = dbName; - String dbPass = System.getenv("PGPASSWORD"); + String dbPass = System.getenv("DAMLENGINE_PGPASSWORD"); + if ( dbPass == null ) + dbPass = DamlEngine.appProps.getProperty("pgpassword"); + if ( dbPass == null ) + dbPass = System.getenv("PGPASSWORD"); if ( dbPass == null ) try { - String dbPassFile = System.getenv("PGPASSFILE"); + String dbPassFile = System.getenv("DAMLENGINE_PGPASSFILE"); + if ( dbPassFile == null ) + dbPassFile = DamlEngine.appProps.getProperty("pgpassfile"); + if ( dbPassFile == null ) + dbPassFile = System.getenv("PGPASSFILE"); if ( dbPassFile == null ) dbPassFile = System.getProperty("user.home") + "/.pgpass"; diff --git a/org/madore/damlengine/WeblogIndexSelect.java b/org/madore/damlengine/WeblogIndexSelect.java index 83c5461..0361177 100644 --- a/org/madore/damlengine/WeblogIndexSelect.java +++ b/org/madore/damlengine/WeblogIndexSelect.java @@ -1,5 +1,6 @@ package org.madore.damlengine; +import java.io.FileInputStream; import java.io.OutputStream; public final class WeblogIndexSelect { @@ -11,7 +12,7 @@ public final class WeblogIndexSelect { public static void fullProcess(OutputStream out) throws Exception { - DamlEngine.fullProcess(DamlEngine.class.getResourceAsStream("weblog-index-template.daml"), + DamlEngine.fullProcess(new FileInputStream(DamlEngine.templatePath+"/weblog-index-template.daml"), out, null); } diff --git a/org/madore/damlengine/WeblogSelect.java b/org/madore/damlengine/WeblogSelect.java index 8ebdaf4..075cab1 100644 --- a/org/madore/damlengine/WeblogSelect.java +++ b/org/madore/damlengine/WeblogSelect.java @@ -2,6 +2,7 @@ package org.madore.damlengine; import java.util.TreeSet; import java.util.ArrayList; +import java.io.FileInputStream; import java.io.OutputStream; import java.sql.Connection; import java.sql.PreparedStatement; @@ -50,7 +51,7 @@ public final class WeblogSelect { wsc.xmlData.add(content); } - DamlEngine.fullProcess(DamlEngine.class.getResourceAsStream(templateResourceName), + DamlEngine.fullProcess(new FileInputStream(DamlEngine.templatePath+"/"+templateResourceName), out, wsc); } diff --git a/org/madore/damlengine/included.css b/org/madore/damlengine/included.css deleted file mode 100644 index 4ad2a4d..0000000 --- a/org/madore/damlengine/included.css +++ /dev/null @@ -1,115 +0,0 @@ -body { - color: black; - font-family: Optima, "Zapf Humanist", Palatino, "Palatino Linotype", serif; -} -h1,h2,h3,h4,h5,h6 { - font-family: Futura, "Century Gothic", "Avant Garde", "Avant Garde Gothic", Helvetica, Arial, sans-serif; -} -h1 { color: rgb(0,128,0); } -h2 { color: rgb(96,96,0); } -h3 { color: rgb(96,64,0); } -.title { text-align: center; } -.subtitle { - font-size: 1.5em; text-align: center; - font-family: Futura, "Century Gothic", "Avant Garde", "Avant Garde Gothic", Helvetica, Arial, sans-serif; - color: rgb(24,96,0); -} -article { display: block; } -.navbar { - display: block; - font-size: .83em; - font-family: "Times Roman", Times, "Times New Roman", serif; -} -.ffii-call { - clear: both; - color: red; - font-size: 1.7em; - font-family: Helvetica, Arial, sans-serif; - text-align: center; - border: outset; -} -.important { font-weight: bold; border: solid; padding: 1em; } -.outset { border: outset; padding-left: 0.5em; padding-right: 0.5em; } -.sidenote { font-size: .83em; } -.weblog-entry-headlink { color: rgb(128,64,0); } -.weblog-entry-headlink > a { color: inherit; } -.weblog-entry-title { - color: black; - font-size: 1.17em; - font-weight: bold; - font-family: Futura, "Avant Garde", Helvetica, Arial, sans-serif; -} -.talkback-link { - color: rgb(128,64,0); font-size: 0.83em; text-align: right; - font-family: Futura, "Avant Garde", Helvetica, Arial, sans-serif; - margin-bottom: 0pt; -} -.talkback-link > a { color: inherit; } -.categories-list { - color: rgb(128,64,0); font-size: 0.83em; text-align: right; - font-family: Futura, "Avant Garde", Helvetica, Arial, sans-serif; - margin-bottom: 0pt; -} -.categories-list > a { color: inherit; } -.cut-link { - font-family: Futura, "Avant Garde", Helvetica, Arial, sans-serif; -} -.sitemap-note { - font-style: italic; - color: rgb(96,0,0); -} -.idlist > dt { color: rgb(96,64,0); } -.numtable td { text-align: right; } -.noparskip p { margin-top: 0; margin-bottom: 0; } -.cleared { clear: both; } -.cleared-left { clear: left; } -.cleared-right { clear: right; } -.pic { float: left; margin-right: 1em; margin-bottom: 1em; } -.pic-right { float: right; margin-left: 1em; margin-bottom: 1em; } -.pic-embed { float: left; margin-right: 1em; margin-bottom: 1em; margin-top: 1em; } -.pic-embed-right { float: right; margin-left: 1em; margin-bottom: 1em; margin-top: 1em; } -.smiley { vertical-align: middle; } -.separated { margin-top: 2.33em; } -a { text-decoration: none; } -:lang(en) > q { quotes: "\201C" "\201D" "\2018" "\2019"; } -:lang(fr) > q { quotes: "\AB\A0" "\A0\BB" "\201C" "\201D"; } -:lang(de) > q { quotes: "\201E" "\201C" "\201A" "\2018"; } -q:before { content: open-quote; } -q:after { content: close-quote; } -li { -moz-float-edge: content-box; } /* Undo Mozilla buggy bugware! */ -/* For despammed email addresses */ -@media all { /* Hide from various buggy browsers! */ - .subreplace-full-stop:before { content: "."; } - .subreplace-full-stop > img { display: none; } - .subreplace-commercial-at:before { content: "@"; } - .subreplace-commercial-at > img { display: none; } -} -/* Screen-specific rules */ -@media screen { - body { background: rgb(192,208,224); } - .navbar { - background: rgb(224,192,192); - border: solid; border-color: rgb(224,0,0); - padding: 1em; - float: right; margin-left: 1.33em; - } - .important { - background: rgb(208,208,208); - border-color: rgb(255,0,0); - } - .weblog-entry { - background: rgb(224,224,192); - border: solid; border-color: rgb(128,64,0); - padding: 1em; margin-bottom: 1em; - overflow: hidden; - } - .outset { background: rgb(192,224,208); } - .ffii-call { background: rgb(192,224,208); } - :link { color: rgb(0,0,192); } - :visited { color: rgb(96,0,192); } - .weblog-internal-link:link,.weblog-internal-link:visited { color: rgb(0,64,192); } - :link:hover,:visited:hover { text-decoration: underline; } -} -@media print { - .navbar { display: none; } -} diff --git a/org/madore/damlengine/included.js b/org/madore/damlengine/included.js deleted file mode 100644 index 1bf6db7..0000000 --- a/org/madore/damlengine/included.js +++ /dev/null @@ -1,109 +0,0 @@ -"use strict"; - -var textNodeType; - -function textContent(n) { - if ( n.nodeType == textNodeType ) { - return n.data; - } else { - var children = n.childNodes; - var t = ""; - for ( var i=0 ; i elements having class="despammed-address". - elts = document.getElementsByTagName("a"); - for ( var i=0 ; i - - - %HTMLlat1; - - %HTMLspecial; - - %HTMLsymbol; - - - david+wwwmadoreorg"> -]> - - - -David Madore's WebLog: - -David Alexander Madore's WebLog / Diary - -David Alexander Madore, WebLog, diary - - - - - -

This WebLog is bilingual, some entries are in English and others -are in French. A few of them have a version in either language. -Other than that, the French entries are not translations of -the English ones or vice versa. Of course, if you understand only -English, the English entries ought to be quite understandable without -reading the French ones.

- -

Ce WebLog est bilingue, certaines entrées sont en -anglais et d'autres sont en français. Quelques-unes ont une version -dans chaque langue. À part ça, les entrées en français ne -sont pas des traductions de celles en anglais ou vice versa. -Bien sûr, si vous ne comprenez que le français, les entrées en -français devraient être assez compréhensibles sans lire celles en -anglais.

- -

Note that the first entry -comes last! -/ Notez que la première entrée vient -en dernier !

- -

Index of all entries / -Index de toutes les entréesXML (RSS 1.0) • Recent -comments / Commentaires -récents

- -
- -

Entries with category -/ Entrées de la -catégorie :

- - - - - - diff --git a/org/madore/damlengine/weblog-index-template.daml b/org/madore/damlengine/weblog-index-template.daml deleted file mode 100644 index 1c9f0ed..0000000 --- a/org/madore/damlengine/weblog-index-template.daml +++ /dev/null @@ -1,60 +0,0 @@ - - - - %HTMLlat1; - - %HTMLspecial; - - %HTMLsymbol; - - - david+wwwmadoreorg"> -]> - - - -David Madore's WebLog: index - -David Alexander Madore's WebLog / Diary - -David Alexander Madore, WebLog, diary - - - - - -

This WebLog is bilingual, some entries are in English and others -are in French. A few of them have a version in either language. -Other than that, the French entries are not translations of -the English ones or vice versa. Of course, if you understand only -English, the English entries ought to be quite understandable without -reading the French ones.

- -

Ce WebLog est bilingue, certaines entrées sont en -anglais et d'autres sont en français. Quelques-unes ont une version -dans chaque langue. À part ça, les entrées en français ne -sont pas des traductions de celles en anglais ou vice versa. -Bien sûr, si vous ne comprenez que le français, les entrées en -français devraient être assez compréhensibles sans lire celles en -anglais.

- -

Note that the first entry -comes last! -/ Notez que la première entrée vient -en dernier !

- -

Index of all entries / -Index de toutes les entréesXML (RSS 1.0) • Recent -comments / Commentaires -récents

- - - -
- -
diff --git a/org/madore/damlengine/weblog-month-template.daml b/org/madore/damlengine/weblog-month-template.daml deleted file mode 100644 index 0ba3c17..0000000 --- a/org/madore/damlengine/weblog-month-template.daml +++ /dev/null @@ -1,231 +0,0 @@ - - - - %HTMLlat1; - - %HTMLspecial; - - %HTMLsymbol; - - - david+wwwmadoreorg"> -]> - - - -David Madore's WebLog: - - -David Alexander Madore's WebLog / Diary - -David Alexander Madore, WebLog, diary - - - - - -

This WebLog is bilingual, some entries are in English and others -are in French. A few of them have a version in either language. -Other than that, the French entries are not translations of -the English ones or vice versa. Of course, if you understand only -English, the English entries ought to be quite understandable without -reading the French ones.

- -

Ce WebLog est bilingue, certaines entrées sont en -anglais et d'autres sont en français. Quelques-unes ont une version -dans chaque langue. À part ça, les entrées en français ne -sont pas des traductions de celles en anglais ou vice versa. -Bien sûr, si vous ne comprenez que le français, les entrées en -français devraient être assez compréhensibles sans lire celles en -anglais.

- -

Note that the first entry -comes last! -/ Notez que la première entrée vient -en dernier !

- -

Index of all entries / -Index de toutes les entréesXML (RSS 1.0) • Recent -comments / Commentaires -récents

- -
- -

Entries of month -- -/ Entrées du mois --:

- - - -

Continue to older -entries. -/ Continuer -à lire les entrées plus anciennes.

- -
- -

Entries by month / Entrées par mois:

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
2014Jan 2014Feb 2014Mar 2014Apr 2014May 2014Jun 2014Jul 2014Aug 2014Sep 2014Oct 2014
2013Jan 2013Feb 2013Mar 2013Apr 2013May 2013Jun 2013Jul 2013Aug 2013Sep 2013Oct 2013Nov 2013Dec 2013
2012Jan 2012Feb 2012Mar 2012Apr 2012May 2012Jun 2012Jul 2012Aug 2012Sep 2012Oct 2012Nov 2012Dec 2012
2011Jan 2011Feb 2011Mar 2011Apr 2011May 2011Jun 2011Jul 2011Aug 2011Sep 2011Oct 2011Nov 2011Dec 2011
2010Jan 2010Feb 2010Mar 2010Apr 2010May 2010Jun 2010Jul 2010Aug 2010Sep 2010Oct 2010Nov 2010Dec 2010
2009Jan 2009Feb 2009Mar 2009Apr 2009May 2009Jun 2009Jul 2009Aug 2009Sep 2009Oct 2009Nov 2009Dec 2009
2008Jan 2008Feb 2008Mar 2008Apr 2008May 2008Jun 2008Jul 2008Aug 2008Sep 2008Oct 2008Nov 2008Dec 2008
2007Jan 2007Feb 2007Mar 2007Apr 2007May 2007Jun 2007Jul 2007Aug 2007Sep 2007Oct 2007Nov 2007Dec 2007
2006Jan 2006Feb 2006Mar 2006Apr 2006May 2006Jun 2006Jul 2006Aug 2006Sep 2006Oct 2006Nov 2006Dec 2006
2005Jan 2005Feb 2005Mar 2005Apr 2005May 2005Jun 2005Jul 2005Aug 2005Sep 2005Oct 2005Nov 2005Dec 2005
2004Jan 2004Feb 2004Mar 2004Apr 2004May 2004Jun 2004Jul 2004Aug 2004Sep 2004Oct 2004Nov 2004Dec 2004
2003May 2003Jun 2003Jul 2003Aug 2003Sep 2003Oct 2003Nov 2003Dec 2003
- - - - diff --git a/org/madore/damlengine/weblog-recent-template.daml b/org/madore/damlengine/weblog-recent-template.daml deleted file mode 100644 index 05d986a..0000000 --- a/org/madore/damlengine/weblog-recent-template.daml +++ /dev/null @@ -1,84 +0,0 @@ - - - - %HTMLlat1; - - %HTMLspecial; - - %HTMLsymbol; - - - david+wwwmadoreorg"> -]> - - - -David Madore's WebLog - -David Alexander Madore's WebLog / Diary - -David Alexander Madore, WebLog, diary - - - - -// - - - - -

This WebLog is bilingual, some entries are in English and others -are in French. A few of them have a version in either language. -Other than that, the French entries are not translations of -the English ones or vice versa. Of course, if you understand only -English, the English entries ought to be quite understandable without -reading the French ones.

- -

Ce WebLog est bilingue, certaines entrées sont en -anglais et d'autres sont en français. Quelques-unes ont une version -dans chaque langue. À part ça, les entrées en français ne -sont pas des traductions de celles en anglais ou vice versa. -Bien sûr, si vous ne comprenez que le français, les entrées en -français devraient être assez compréhensibles sans lire celles en -anglais.

- -

Note that the first entry comes last! Notez que la -première entrée vient en dernier !

- -

Index of all entries / -Index de toutes les entréesXML (RSS 1.0) • Recent -comments / Commentaires -récents

- -
- - - -

Only the most recent entries -were included above. Continue -to older entries.

- -

Seules les plus -récentes entrées ont été incluses -ici. Continuer à lire les -entrées plus anciennes.

- - - - diff --git a/org/madore/damlengine/weblog-single-template.daml b/org/madore/damlengine/weblog-single-template.daml deleted file mode 100644 index 7ee2d80..0000000 --- a/org/madore/damlengine/weblog-single-template.daml +++ /dev/null @@ -1,50 +0,0 @@ - - - - %HTMLlat1; - - %HTMLspecial; - - %HTMLsymbol; - - - david+wwwmadoreorg"> -]> - - - -David Madore's WebLog: - -David Alexander Madore's WebLog / Diary - -David Alexander Madore, WebLog, diary - - - - - -

Index of all entries / -Index de toutes les entréesXML (RSS 1.0) • Recent -comments / Commentaires -récents

- -
- -

Entry # -/ Entrée #:

- - - -

Recent entries / Entrées -récentesIndex of all -entries / -Index de toutes les entrées

- - - - -- cgit v1.2.3