The following has evaluated to null or missing:
==> .vars['reserved-article-group-id'] [in template "161555#161602#ARTICLE-PAGE---HERO" at line 14, column 20]
----
Tip: It's the final [] step that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign groupId = .vars["reserved-art... [in template "161555#161602#ARTICLE-PAGE---HERO" at line 14, column 1]
----
1<#assign namespace = randomNamespace />
2<#assign JSONFactoryUtil = staticUtil["com.liferay.portal.kernel.json.JSONFactoryUtil"] />
3<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
4<#assign containerId = randomNamespace />
5<#assign shareURL = themeDisplay.getPortalURL()+themeDisplay.getURLCurrent()/>
6
7<#-- Auto-assign ALL category to every article -->
8<#assign assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") />
9<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
10<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
11
12<#-- Get current JournalArticle -->
13<#assign articleId = .vars['reserved-article-id'].data />
14<#assign groupId = .vars['reserved-article-group-id'].data?number />
15<#assign journalArticle = journalArticleLocalService.getArticle(groupId, articleId) />
16
17<#-- Get AssetEntry for this article -->
18<#assign assetEntry = assetEntryLocalService.getEntry("com.liferay.journal.model.JournalArticle", journalArticle.getResourcePrimKey()) />
19
20<#-- Your ALL category ID -->
21<#assign allCategoryId = 4614994 />
22
23<#-- Assign ALL category if not already set -->
24<#if !assetEntry.getCategories()?seq_contains(assetCategoryLocalService.getCategory(allCategoryId))>
25 <#assign categoryIds = assetEntry.getCategoryIds() + [allCategoryId] />
26 ${assetEntryLocalService.updateEntry(
27 assetEntry.getUserId(),
28 assetEntry.getGroupId(),
29 assetEntry.getClassName(),
30 assetEntry.getClassPK(),
31 assetEntry.getUuid(),
32 assetEntry.getClassTypeId(),
33 categoryIds,
34 assetEntry.getTagNames()
35 )}
36</#if>
37
38<div class="hero jmarticle__hero-main-container">
39 <div class="container">
40 <div class="row">
41 <div class="article__cont">
42 <h1 class="article__heading">${Title.getData()}</h1>
43 <#if (SubTitle.getData())??>
44 <p class="article__para">
45 ${SubTitle.getData()}
46 </p>
47 </#if>
48
49 <#assign Date_Data=getterUtil.getString(Date.getData())>
50 <#if validator.isNotNull(Date_Data)>
51 <p class="article__date">
52 <#assign Date_DateObj=dateUtil.parseDate("yyyy-MM-dd", Date_Data, locale)>
53 ${dateUtil.getDate(Date_DateObj, "dd MMMM yyyy", locale)}
54 </p>
55 </#if>
56
57 <#if Link_Title?? && Link_Title.getData()?has_content>
58 <#list Link_Title.getSiblings() as cur_Link_Title>
59 <#if cur_Link_Title?? && cur_Link_Title.getData()?has_content>
60 <#assign linkHref="#" />
61 <#assign target="" />
62
63 <#assign rowId = containerId + cur_Link_Title?index />
64 <#if cur_Link_Title.Link_Internal?? && cur_Link_Title.Link_Internal.getFriendlyUrl()?has_content>
65 <#assign linkHref=cur_Link_Title.Link_Internal.getFriendlyUrl() />
66 <#elseif cur_Link_Title.Link_Media?? && cur_Link_Title.Link_Media.getData()?has_content>
67 <#assign linkHref=cur_Link_Title.Link_Media.getData() />
68 <#elseif cur_Link_Title.Link_Mailto?? && cur_Link_Title.Link_Mailto.getData()?has_content>
69 <#assign linkHref="mailto:" + cur_Link_Title.Link_Mailto.getData() />
70 <#elseif cur_Link_Title.Link_External?? && cur_Link_Title.Link_External.getData()?has_content>
71 <#assign linkHref=cur_Link_Title.Link_External.getData() />
72 </#if>
73 <#if (cur_Link_Title.Link_Target??) && (cur_Link_Title.Link_Target.getData())?has_content>
74 <#assign target=cur_Link_Title.Link_Target.getData() />
75 </#if>
76 <div id="blue_button_click_div" data-analytics-asset-type="custom">
77 <div class="jmarticle__hero-btn-list">
78 <a id="panel_blue_button_${rowId}" class="article__btn" href="${linkHref}" title="${cur_Link_Title.getData()}" target="${target}" data-analytics-asset-action="click" onclick="onBlueButtonClick(this)" >
79 <span class="btn__text">${cur_Link_Title.getData()}</span>
80 <span class="arrow__forward"></span>
81 </a>
82 </div>
83 </div>
84 </#if>
85 </#list>
86 </#if>
87 <div class="article-download-share">
88
89 <#if PDFTitle?? && PDFTitle.getData()?has_content>
90 <#assign title = PDFTitle.getData() />
91 <#assign pdf_link = "#" />
92 <#assign pdfrowId = containerId />
93 <#if PDFTitle.PDF?? && PDFTitle.PDF.getData()?has_content>
94 <#assign pdf_link = PDFTitle.PDF.getData() />
95 </#if>
96 <div class="article-download">
97 <div id="blue_button_click_div" data-analytics-asset-type="custom">
98 <div class="jmarticle__hero-btn-list">
99 <a id="panel_blue_button_${pdfrowId}" class="article__btn" href="${pdf_link}" title="${title}" data-analytics-asset-action="click" onclick="onBlueButtonClick(this)">
100 <span class="btn__text">${title}</span>
101 <span class="arrow__forward"></span>
102 </a>
103 <a id="panel_blue_button_${pdfrowId}" class="article__btn-mobile" href="${pdf_link}" title="${title}" data-analytics-asset-action="click" onclick="onBlueButtonClick(this)">
104 <img src="${themeDisplay.getPathThemeImages()}/new__jm__images/download-white-icon.svg" alt="twitter image"/>
105 </a>
106 </div>
107 </div>
108 </div>
109 </#if>
110
111 </div>
112
113 </div>
114 </div>
115 <#if (ImageLarge.getData())?? && ImageLarge.getData() != "">
116 <div class="row jmarticle__hero-banner" id="jmarticle__hero-${namespace}"
117 style="background-image: url(${ImageLarge.getData()})">
118 </#if>
119
120 </div>
121 </div>
122</div>
123
124<#if Author?? && Author.getData()?has_content>
125 <div class="jmarticle__author-info">
126 <div class="container">
127 <div class="hero__bar">
128 <#list Author.getSiblings() as cur_Author>
129 <#if cur_Author?? && cur_Author.getData()?has_content>
130 <#assign
131 webContentData = jsonFactoryUtil.createJSONObject(cur_Author.getData())
132 gId = groupId
133 journalArticle = journalArticleLocalService.getArticleByUrlTitle(gId, webContentData.title)
134 docXML = saxReaderUtil.read(journalArticle.getContent())
135
136 fName = docXML.valueOf("//dynamic-element[@name='FullName']/dynamic-content/text()")
137 jobTitle = docXML.valueOf("//dynamic-element[@name='JobTitle']/dynamic-content/text()")
138 role = docXML.valueOf("//dynamic-element[@name='ContactInfo']/dynamic-content/text()")
139 photoXML = docXML.valueOf("//dynamic-element[@name='Photo']/dynamic-content/text()")
140 photoSrc = JSONFactoryUtil.createJSONObject(photoXML).getString("uuid")
141 fullName = docXML.valueOf("//dynamic-element[@name='Title']/dynamic-content/text()")
142 authorImageXML = docXML.valueOf("//dynamic-element[@name='ImageLarge']/dynamic-content/text()")
143 authImageSrc = JSONFactoryUtil.createJSONObject(authorImageXML).getString("uuid")
144 summary = docXML.valueOf("//dynamic-element[@name='Summary']/dynamic-content/text()")
145 />
146
147 <div class="author">
148 <figure class="author__image">
149 <#if authImageSrc?? && authImageSrc?has_content>
150 <img src="/documents/${groupId}/${authImageSrc}" alt="${fullName}" class="author_img_class_new">
151 <#elseif photoSrc?? && photoSrc?has_content>
152 <img src="/documents/${groupId}/${photoSrc}" alt="${fName}" class="author_img_class_new">
153 </#if>
154 </figure>
155 <div class="author__details d-flex flex-column">
156 <h3 class="author__name">
157 <a rel="author">
158 <#if fullName?? && fullName?has_content>
159 ${fullName}
160 <#elseif fName?? && fName?has_content>
161 ${fName}
162 </#if>
163 </a>
164 </h3>
165 <p class="author__desc text-size-a author_job_title">
166 <#if jobTitle?? && jobTitle?has_content>
167 ${jobTitle}
168 </#if>
169 </p>
170 <span>
171 <p class="author__desc text-size-a">
172 <#if summary?? && summary?has_content>
173 ${summary}
174 </#if>
175 <#if role?? && role?has_content>
176 ${role}
177 </#if>
178 </p>
179 </span>
180 </div>
181 <div>
182 <div class="author__contact">
183 <ul class="author__contact-list">
184 </ul>
185 </div>
186 </div>
187 </div>
188 </#if>
189 </#list>
190 </div>
191 </div>
192 </div>
193</#if>
194
195
196
197<div class="container">
198 <div class="row">
199 <div class="article__intro">
200 <#if (Introduction.getData())??>
201 ${Introduction.getData()}
202 </#if>
203
204 <div class="article-download-share">
205
206 <#if PDFTitle?? && PDFTitle.getData()?has_content>
207 <#assign title = PDFTitle.getData() />
208 <#assign pdf_link = "#" />
209 <#assign pdfrowId = containerId />
210 <#if PDFTitle.PDF?? && PDFTitle.PDF.getData()?has_content>
211 <#assign pdf_link = PDFTitle.PDF.getData() />
212 </#if>
213 <div class="article-download">
214 <div id="blue_button_click_div" data-analytics-asset-type="custom">
215 <div class="jmarticle__hero-btn-list">
216 <a id="panel_blue_button_${pdfrowId}" class="article__btn" href="${pdf_link}" title="${title}" data-analytics-asset-action="click" onclick="onBlueButtonClick(this)">
217 <span class="btn__text">${title}</span>
218 <span class="arrow__forward"></span>
219 </a>
220 <a id="panel_blue_button_${pdfrowId}" class="article__btn-mobile" href="${pdf_link}" title="${title}" data-analytics-asset-action="click" onclick="onBlueButtonClick(this)">
221 <img src="${themeDisplay.getPathThemeImages()}/new__jm__images/download-white-icon.svg" alt="twitter image"/>
222 </a>
223 </div>
224 </div>
225 </div>
226 </#if>
227
228
229 <div class="article-share">
230 <a href="https://linkedin.com/shareArticle?url=${shareURL}&title=<#if (Title.getData())??>${Title.getData()}</#if>" target="_blank">
231 <img class="socialicons__img" src="${themeDisplay.getPathThemeImages()}/new__jm__images/social_icons-LinkedIN.png" alt="twitter image"/>
232 </a>
233 <a href="https://twitter.com/share?url=${shareURL}&text=<#if (Title.getData())??>${Title.getData()}</#if>" target="_blank">
234 <img class="socialicons__img" src="${themeDisplay.getPathThemeImages()}/new__jm__images/social_icons-Twitter.png" alt="twitter image"/>
235 </a>
236 </div>
237 </div>
238
239 </div>
240 </div>
241</div>
242
243<style>
244 img.author_img_class_new {
245 width: 100% !important;
246 height: 100% !important;
247 position: absolute;
248 margin: auto;
249 top: 0;
250 bottom: 0;
251 }
252
253 .article__btn:focus-visible {
254 outline: 2px solid blue !important;
255}
256
257@media (min-width: 320px) and (max-width: 650px) {
258 .article__intro li {
259 margin-left: -32px !important;
260 }
261 .journal-content-article .container .article__intro {
262 margin-top: 22px !important;
263}
264}
265@media (min-width: 540px) and (max-width: 834px) {
266 .article__intro li {
267 margin-left: -32px !important;
268 }
269 .article__intro {
270 margin: 60px 15px 0 5px !important;
271 }
272}
273
274@media (min-width: 320px) and (max-width: 539px){
275.jmarticle__author-info {
276 padding: 0px 0;
277}
278.jmarticle__author-info .author__image {
279 width: 39px;
280 height: 40px;
281}
282
283.jmarticle__author-info .author__name a {
284 line-height: 0px;
285 font-size: 18px !important;
286 margin-right: 10px;
287}
288
289.jmarticle__author-info .author__desc {
290
291 line-height: 14px;
292 font-size: 12px !important;
293 margin-bottom: 7px;
294}
295}
296
297</style>
| Underlying1 performance | 2018 | 2017 | % change | % change continuing businesses2 at constant rates3 |
|
| Sales excluding precious metals (Sales) | £million | 1,853 | 1,676 | 11 | 5 |
| Operating profit | £million | 250.3 | 236.1 | 6 | -1 |
| Profit before tax | £million | 233.1 | 219.6 | 6 | - |
| Earnings per share | pence | 99.8 | 96.4 | 4 |
Group Performance in the half year
Financial highlights
- Reported revenue up 15%, driven by higher pgm prices and a £179 million translational FX benefit
- Reported operating profit down 2%, with £18 million translational FX benefit offset by one-off charges related to our restructuring programme
- Reported EPS down 5% to 87.9 pence
- Underlying sales growth 5% at constant rates2 and full year sales growth guidance is unchanged
- Underlying operating profit down 1% at constant rates, impacted by the US post-retirement medical plan credit in the prior period. Excluding this, operating profit grew in line with sales growth. Full year outlook confirmed
- Underlying EPS up 4% to 99.8 pence
- Interim dividend up 6% to 21.75 pence reflecting confidence in medium term outlook
- Cash inflow from operating activities of £7.8 million. In September, we guided to an outflow of precious metal working capital due to higher metal prices and lower liquidity.
- This amounted to £156 million in the half and negative free cash flow was £90.4 million
- Return on invested capital (ROIC) was maintained at 17.5%
- Strong balance sheet with net debt to EBITDA of 1.4 times
Operational highlights
- Strong sales growth was sustained in Clean Air led by double digit growth of Heavy Duty Diesel catalysts in every region. Sales of Light Duty Vehicle catalysts were in line with global production
- Good sales growth in Efficient Natural Resources, ahead of the average medium term growth rates of our markets, with higher sales of refill catalysts and continued strong performance in PGM Services, although operating profit declined, primarily driven by negative sales mix in Catalyst Technologies
- Good growth in Health and continued investment in the development of our pipeline of new generic and innovator products to drive future break out growth
- Significant progress in the development of our high energy battery material, eLNOTM
Robert MacLeod, Chief Executive, commented:
"We had a strong start to the year with sales growth of 5% and guidance for the full year is unchanged. We made further investments in line with the strategy we outlined at our recent capital markets day which continues to strengthen our business.
We will grow our Clean Air business over the next ten years with growth in Europe, through share gains supported by our technology leadership, and by meeting the challenges of tighter legislation across the world, particularly in China and Europe. Our growing pipeline in Health will deliver significant growth over the medium term. We will deliver outperformance through targeted investment in Efficient Natural Resources and build our New Markets business primarily through our presence in battery materials.
We are building a stronger platform from which we will achieve our goal of attractive returns to shareholders over the medium term: mid to high single digit EPS growth, expanding ROIC to 20% and a progressive dividend."
The results in detail
Full results are available to download from our results archive.
Footnotes
1 Underlying is before amortisation of acquired intangibles, major impairment and restructuring charges, profit or loss on disposal of businesses, significant tax rate changes and, where relevant, related tax effects. For reconciliation see note 4 on page 26
2 Growth at constant rates excludes the translation impact of foreign exchange movements, with H1 2016/17 results converted at H1 2017/18 average exchange rates
3 For definitions and reconciliations of other non-GAAP measures see the full results announcement.