|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r70959 - in branches/quickbook-dev/tools/quickbook: src test/include
From: dnljms_at_[hidden]
Date: 2011-04-03 15:18:42
Author: danieljames
Date: 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
New Revision: 70959
URL: http://svn.boost.org/trac/boost/changeset/70959
Log:
Quickbook: Import templates+macros from quickbook file in 1.6
Added:
branches/quickbook-dev/tools/quickbook/test/include/macros-1.5.gold (contents, props changed)
branches/quickbook-dev/tools/quickbook/test/include/macros-1.5.quickbook (contents, props changed)
branches/quickbook-dev/tools/quickbook/test/include/macros-1.6.gold (contents, props changed)
branches/quickbook-dev/tools/quickbook/test/include/macros-1.6.quickbook (contents, props changed)
branches/quickbook-dev/tools/quickbook/test/include/macros-inc1.quickbook (contents, props changed)
Text files modified:
branches/quickbook-dev/tools/quickbook/src/actions.cpp | 97 ++++++++++++++++++++++++---------------
branches/quickbook-dev/tools/quickbook/src/actions.hpp | 14 +++++
branches/quickbook-dev/tools/quickbook/src/actions_class.cpp | 5 +
branches/quickbook-dev/tools/quickbook/src/actions_class.hpp | 13 ++++
branches/quickbook-dev/tools/quickbook/src/block_element_grammar.cpp | 3
branches/quickbook-dev/tools/quickbook/test/include/Jamfile.v2 | 2
branches/quickbook-dev/tools/quickbook/test/include/templates-1.6.gold | 3 +
branches/quickbook-dev/tools/quickbook/test/include/templates-1.6.quickbook | 4 +
8 files changed, 100 insertions(+), 41 deletions(-)
Modified: branches/quickbook-dev/tools/quickbook/src/actions.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions.cpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/actions.cpp 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -177,7 +177,7 @@
// Handles line-breaks (DEPRECATED!!!)
void break_action::operator()(iterator first, iterator) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, phrase);
file_position const pos = first.get_position();
@@ -226,7 +226,7 @@
void block_action(quickbook::actions& actions, value block)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
detail::markup markup = detail::get_markup(block.get_tag());
@@ -238,7 +238,7 @@
void block_empty_action(quickbook::actions& actions, value block)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
detail::markup markup = detail::get_markup(block.get_tag());
@@ -247,7 +247,7 @@
void phrase_action(quickbook::actions& actions, value phrase)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.phrase);
detail::markup markup = detail::get_markup(phrase.get_tag());
@@ -259,7 +259,7 @@
void raw_phrase_action(quickbook::actions& actions, value phrase)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.phrase);
detail::markup markup = detail::get_markup(phrase.get_tag());
@@ -268,7 +268,7 @@
void paragraph_action::operator()() const
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_output)) return;
std::string str;
actions.phrase.swap(str);
@@ -303,7 +303,7 @@
void header_action(quickbook::actions& actions, value heading_list)
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_output)) return;
value_consumer values = heading_list;
@@ -360,7 +360,7 @@
void simple_phrase_action::operator()(char mark) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, out);
int tag =
@@ -391,20 +391,22 @@
bool cond_phrase_push::start()
{
- saved_suppress = actions.suppress;
+ saved_process_state = actions.process_state;
value_consumer values = actions.values.release();
bool condition = find(actions.macro,
values.consume().get_quickbook().c_str());
-
- actions.suppress = actions.suppress || !condition;
+
+ if (!condition)
+ actions.process_state = actions.process_none;
return true;
}
void cond_phrase_push::cleanup()
{
- actions.suppress = saved_suppress;
+ actions.process_state =
+ static_cast<quickbook::actions::process_flags>(saved_process_state);
}
namespace {
@@ -428,7 +430,7 @@
void list_action(quickbook::actions& actions, value list)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
typedef std::pair<char, int> mark_type;
@@ -502,7 +504,7 @@
void explicit_list_action(quickbook::actions& actions, value list)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
detail::markup markup = detail::get_markup(list.get_tag());
@@ -547,7 +549,7 @@
void anchor_action(quickbook::actions& actions, value anchor)
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_output)) return;
value_consumer values = anchor;
actions.anchors.push_back(values.consume().get_quickbook());
@@ -556,7 +558,7 @@
void do_macro_action::operator()(std::string const& str) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, phrase);
if (str == quickbook_get_date)
@@ -607,7 +609,7 @@
void code_action::operator()(iterator first, iterator last) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, out);
// preprocess the code section to remove the initial indentation
@@ -640,7 +642,7 @@
void inline_code_action::operator()(iterator first, iterator last) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, out);
std::string save;
@@ -658,7 +660,7 @@
void raw_char_action::operator()(char ch) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, phrase);
phrase << ch;
@@ -666,7 +668,7 @@
void raw_char_action::operator()(iterator first, iterator /*last*/) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, phrase);
phrase << *first;
@@ -674,7 +676,7 @@
void plain_char_action::operator()(char ch) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, phrase);
detail::print_char(ch, phrase.get());
@@ -682,7 +684,7 @@
void plain_char_action::operator()(iterator first, iterator /*last*/) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, phrase);
detail::print_char(*first, phrase.get());
@@ -690,7 +692,7 @@
void escape_unicode_action::operator()(iterator first, iterator last) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, phrase);
while(first != last && *first == '0') ++first;
@@ -712,7 +714,7 @@
void image_action(quickbook::actions& actions, value image)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.phrase);
typedef std::map<std::string, value> attribute_map;
@@ -890,7 +892,7 @@
void macro_definition_action(quickbook::actions& actions, quickbook::value macro_definition)
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_macros)) return;
value_consumer values = macro_definition;
std::string macro_id = values.consume().get_quickbook();
@@ -905,7 +907,7 @@
void template_body_action(quickbook::actions& actions, quickbook::value template_definition)
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_templates)) return;
value_consumer values = template_definition;
std::string identifier = values.consume().get_quickbook();
@@ -1133,7 +1135,7 @@
void do_template_action(quickbook::actions& actions, value template_list,
file_position pos)
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_output)) return;
// Get the arguments
value_consumer values = template_list;
@@ -1332,7 +1334,7 @@
void link_action(quickbook::actions& actions, value link)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.phrase);
detail::markup markup = detail::get_markup(link.get_tag());
@@ -1356,7 +1358,7 @@
void variable_list_action(quickbook::actions& actions, value variable_list)
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
value_consumer values = variable_list;
@@ -1393,7 +1395,7 @@
void table_action(quickbook::actions& actions, value table)
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
value_consumer values = table;
@@ -1486,7 +1488,7 @@
void begin_section_action(quickbook::actions& actions, value begin_section_list)
{
- if(actions.suppress) return;
+ if(!(actions.process_state & actions.process_output)) return;
value_consumer values = begin_section_list;
@@ -1539,7 +1541,7 @@
void end_section_action(quickbook::actions& actions, value end_section, file_position pos)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
if (actions.section_level <= actions.min_section_level)
@@ -1685,7 +1687,7 @@
void xinclude_action(quickbook::actions& actions, value xinclude)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
value_consumer values = xinclude;
@@ -1749,7 +1751,7 @@
{
assert(load_type == block_tags::include ||
load_type == block_tags::import);
-
+
{
file_state state(actions,
load_type == block_tags::import ? file_state::scope_none :
@@ -1759,6 +1761,11 @@
actions.filename = paths.filename;
actions.filename_relative = paths.filename_relative;
+ if (load_type == block_tags::import)
+ actions.process_state =
+ static_cast<quickbook::actions::process_flags>(
+ actions.process_macros | actions.process_templates);
+
// remain bug compatible with old versions of quickbook
if(qbk_version_n < 106) actions.doc_id.clear();
@@ -1820,7 +1827,7 @@
void include_action(quickbook::actions& actions, value include)
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.out);
value_consumer values = include;
@@ -1832,6 +1839,7 @@
if (qbk_version_n >= 106)
{
std::string ext = paths.filename.extension().generic_string();
+
if (ext == ".qbk" || ext == ".quickbook")
{
load_quickbook(actions, paths, include.get_tag(), include_doc_id);
@@ -1857,7 +1865,7 @@
void phrase_to_docinfo_action_impl::operator()(iterator first, iterator last,
value::tag_type tag) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, actions.phrase);
std::string encoded;
@@ -1873,7 +1881,7 @@
void collector_to_value_action::operator()(iterator, iterator) const
{
- if (actions.suppress) return;
+ if (!(actions.process_state & actions.process_output)) return;
write_anchors(actions, output);
std::string value;
@@ -1922,4 +1930,19 @@
{
actions_.context = saved_context_;
}
+
+ bool activate_processing_impl::start()
+ {
+ saved_process_state = actions.process_state;
+ actions.process_state = actions.process_normal;
+
+ return true;
+ }
+
+ void activate_processing_impl::cleanup()
+ {
+ actions.process_state =
+ static_cast<quickbook::actions::process_flags>(saved_process_state);
+ }
+
}
Modified: branches/quickbook-dev/tools/quickbook/src/actions.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions.hpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/actions.hpp 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -144,7 +144,7 @@
void cleanup();
quickbook::actions& actions;
- bool saved_suppress;
+ int saved_process_state;
};
struct span
@@ -402,6 +402,18 @@
quickbook::actions& actions_;
int saved_context_;
};
+
+ struct activate_processing_impl : scoped_action_base
+ {
+ activate_processing_impl(quickbook::actions& x)
+ : actions(x) {}
+
+ bool start();
+ void cleanup();
+
+ quickbook::actions& actions;
+ int saved_process_state;
+ };
}
#endif // BOOST_SPIRIT_QUICKBOOK_ACTIONS_HPP
Modified: branches/quickbook-dev/tools/quickbook/src/actions_class.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions_class.cpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/actions_class.cpp 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -31,10 +31,10 @@
, error_count(0)
, anchors()
, no_eols(true)
- , suppress(false)
, warned_about_breaks(false)
, context(0)
+ , process_state(process_normal)
, macro()
, source_mode("c++")
, doc_id()
@@ -59,6 +59,7 @@
, scoped_output(*this)
, scoped_no_eols(*this)
, scoped_context(*this)
+ , scoped_activate_processing(*this)
, element(*this)
, error(*this)
@@ -101,6 +102,7 @@
, filename(a.filename)
, filename_relative(a.filename_relative)
, source_mode(a.source_mode)
+ , process_state(a.process_state)
, macro()
{
if (scope & scope_macros) macro = a.macro;
@@ -115,6 +117,7 @@
boost::swap(a.filename, filename);
boost::swap(a.filename_relative, filename_relative);
boost::swap(a.source_mode, source_mode);
+ boost::swap(a.process_state, process_state);
if (scope & scope_templates) a.templates.pop();
if (scope & scope_macros) a.macro = macro;
}
Modified: branches/quickbook-dev/tools/quickbook/src/actions_class.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions_class.hpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/actions_class.hpp 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -36,6 +36,14 @@
typedef std::vector<std::string> string_list;
static int const max_template_depth = 100;
+
+ enum process_flags {
+ process_none = 0,
+ process_macros = 1,
+ process_templates = 2,
+ process_output = 4,
+ process_normal = 7
+ };
// global state
std::string doc_type; // For the whole document, not
@@ -47,11 +55,11 @@
int error_count;
string_list anchors;
bool no_eols;
- bool suppress;
bool warned_about_breaks;
int context;
// state saved for files and templates.
+ process_flags process_state;
string_symbols macro;
std::string source_mode;
std::string doc_id;
@@ -89,6 +97,8 @@
scoped_no_eols;
scoped_parser<scoped_context_impl>
scoped_context;
+ scoped_parser<activate_processing_impl>
+ scoped_activate_processing;
element_action element;
error_action error;
@@ -130,6 +140,7 @@
fs::path filename;
fs::path filename_relative;
std::string source_mode;
+ actions::process_flags process_state;
string_symbols macro;
private:
file_state(file_state const&);
Modified: branches/quickbook-dev/tools/quickbook/src/block_element_grammar.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/block_element_grammar.cpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/block_element_grammar.cpp 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -126,7 +126,8 @@
space
>> macro_identifier [actions.values.entry(ph::arg1, ph::arg2)]
>> blank
- >> local.inner_phrase
+ >> actions.scoped_activate_processing()
+ [ local.inner_phrase ]
;
local.identifier =
Modified: branches/quickbook-dev/tools/quickbook/test/include/Jamfile.v2
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/include/Jamfile.v2 (original)
+++ branches/quickbook-dev/tools/quickbook/test/include/Jamfile.v2 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -22,6 +22,8 @@
[ quickbook-test section-unclosed ]
[ quickbook-test templates-1.5 ]
[ quickbook-test templates-1.6 ]
+ [ quickbook-test macros-1.5 ]
+ [ quickbook-test macros-1.6 ]
[ quickbook-error-test section-fail1 ]
[ quickbook-error-test section-fail2 ]
;
Added: branches/quickbook-dev/tools/quickbook/test/include/macros-1.5.gold
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/test/include/macros-1.5.gold 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<article id="macros_test_1_5" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Macros Test 1.5</title>
+ <para>
+ Foo:macros-inc1.quickbook
+ </para>
+ <para>
+ Defined conditional phrase.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ <emphasis role="underline">_foo_</emphasis>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ Defined template:macros-1.5.quickbook
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ <emphasis role="underline">_defined_macro_</emphasis>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ [not_defined_template]
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ <emphasis role="underline">_not_defined_macro__</emphasis>
+ </simpara>
+ </listitem>
+ </itemizedlist>
+</article>
Added: branches/quickbook-dev/tools/quickbook/test/include/macros-1.5.quickbook
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/test/include/macros-1.5.quickbook 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -0,0 +1,13 @@
+[article Macros Test 1.5
+[quickbook 1.5]
+]
+
+[def __defined__]
+
+[include macros-inc1.quickbook]
+
+* __foo__
+* [defined_template]
+* __defined_macro__
+* [not_defined_template]
+* [__not_defined_macro__]
Added: branches/quickbook-dev/tools/quickbook/test/include/macros-1.6.gold
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/test/include/macros-1.6.gold 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE article PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN" "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+<article id="macros_test_1_6" last-revision="DEBUG MODE Date: 2000/12/20 12:00:00 $"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+ <title>Macros Test 1.6</title>
+ <para>
+ Foo:macros-inc1.quickbook
+ </para>
+ <para>
+ Defined conditional phrase.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ <emphasis role="underline">_foo_</emphasis>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ [defined_template]
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ <emphasis role="underline">_defined_macro_</emphasis>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ [not_defined_template]
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ <emphasis role="underline">_not_defined_macro__</emphasis>
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ Foo:macros-inc1.quickbook
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ Defined template:macros-1.6.quickbook
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ Defined macro:macros-inc1.quickbook
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ [not_defined_template]
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ <emphasis role="underline">_not_defined_macro__</emphasis>
+ </simpara>
+ </listitem>
+ </itemizedlist>
+</article>
Added: branches/quickbook-dev/tools/quickbook/test/include/macros-1.6.quickbook
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/test/include/macros-1.6.quickbook 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -0,0 +1,21 @@
+[article Macros Test 1.6
+[quickbook 1.6]
+]
+
+[def __defined__]
+
+[include macros-inc1.quickbook]
+
+* __foo__
+* [defined_template]
+* __defined_macro__
+* [not_defined_template]
+* [__not_defined_macro__]
+
+[import macros-inc1.quickbook]
+
+* __foo__
+* [defined_template]
+* __defined_macro__
+* [not_defined_template]
+* [__not_defined_macro__]
Added: branches/quickbook-dev/tools/quickbook/test/include/macros-inc1.quickbook
==============================================================================
--- (empty file)
+++ branches/quickbook-dev/tools/quickbook/test/include/macros-inc1.quickbook 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -0,0 +1,15 @@
+[def __foo__ Foo:__FILENAME__]
+
+__foo__
+
+[?__defined__
+Defined conditional phrase.
+[template defined_template Defined template:__FILENAME__]
+[def __defined_macro__ Defined macro:__FILENAME__]
+]
+
+[?__not_defined__
+Not defined conditional phrase.
+[template not_defined_template Not defined template:__FILENAME__]
+[def __not_defined_macro__ Not defined macro:__FILENAME__]
+]
\ No newline at end of file
Modified: branches/quickbook-dev/tools/quickbook/test/include/templates-1.6.gold
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/include/templates-1.6.gold (original)
+++ branches/quickbook-dev/tools/quickbook/test/include/templates-1.6.gold 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -9,4 +9,7 @@
<para>
[foo]
</para>
+ <para>
+ Foo:templates-1.6.quickbook
+ </para>
</article>
Modified: branches/quickbook-dev/tools/quickbook/test/include/templates-1.6.quickbook
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/include/templates-1.6.quickbook (original)
+++ branches/quickbook-dev/tools/quickbook/test/include/templates-1.6.quickbook 2011-04-03 15:18:38 EDT (Sun, 03 Apr 2011)
@@ -5,3 +5,7 @@
[include templates-inc1.quickbook]
[foo]
+
+[import templates-inc1.quickbook]
+
+[foo]
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk