テンプレート処理中にエラーが発生しました。
Java method "template.custom.services.TemplateCustomService.getArticleViewURL(String, com.liferay.portal.kernel.model.Group, long, com.liferay.portal.kernel.theme.ThemeDisplay, long)" threw an exception when invoked on template.custom.services.TemplateCustomService object "template.custom.services.TemplateCustomService@3fd4b93c"; see cause exception in the Java stack trace.

----
FTL stack trace ("~" means nesting-related):
	- Failed at: #assign viewURL = TemplateCustomServi...  [in template "20116#20152#511008" at line 117, column 33]
----
1<#-- 
2Application display templates can be used to modify the look of a 
3specific application. 
4 
5Please use the left panel to quickly add commonly used variables. 
6Autocomplete is also available and can be invoked by typing "${". 
7--> 
8 
9<#assign JournalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService")> 
10<#assign LayoutLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.LayoutLocalService")> 
11<#assign PortletPreferencesLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.PortletPreferencesLocalService")/> 
12<#assign PropertyFactoryUtil = serviceLocator.findService("com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil") /> 
13<#assign DynamicQueryFactoryUtil = serviceLocator.findService("com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil") /> 
14 
15<#assign GroupLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.GroupLocalService")> 
16<#assign virtualHostLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.VirtualHostLocalService") /> 
17 
18<#assign portletId = themeDisplay.getPortletDisplay().getId()> 
19<#assign PortletPreferencesLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.PortletPreferencesLocalService")/> 
20 
21<#-- 
227.4 Upgrade start - portlet perferences would not be stored as xml, see https://github.com/liferay/liferay-portal/blob/master/readme/BREAKING_CHANGES.markdown#what-changed-11 
23<#assign portletPreferencesXML = saxReaderUtil.read((PortletPreferencesLocalService.getPortletPreferences(themeDisplay.getPlid(), portletId)?first).getPreferences())> 
24--> 
25<#assign plid = themeDisplay.getPlid()> 
26 
27<#assign portletPreferences = PortletPreferencesLocalService.getPortletPreferences(plid, portletId)?first /> 
28 
29<#assign preferences = PortletPreferencesLocalService.fetchPreferences(portletPreferences.getCompanyId(), portletPreferences.getOwnerId(), portletPreferences.getOwnerType(), plid, portletId) /> 
30<#-- 
317.4 Upgrade end 
32--> 
33<#assign TemplateCustomService = serviceLocator.findService("template.custom.services.TemplateCustomService") /> 
34 
35<#assign iconCommonPath = "/o/atk-dot-com-theme/images/common/" /> 
36<#assign iconExtension = ".svg" /> 
37<#assign iconImagePath = GroupLocalService.getGroup(themeDisplay.getScopeGroupId()).getExpandoBridge().getAttribute("Icon-Image-Path")!"" /> 
38<#if iconImagePath?starts_with("/documents/")> 
39	<#assign iconPath = iconImagePath /> 
40	<#assign iconCommonPath = iconPath /> 
41	<#assign iconExtension = "" /> 
42</#if> 
43 
44<#-- Macro used to get specific field text from an Asset Entry --> 
45<#macro entryNode article field> 
46	<#assign document = saxReaderUtil.read(article.getContent())> 
47	<#if document.selectSingleNode("/root/dynamic-element[@name='"+field+"']/dynamic-content")??> 
48    "${document.selectSingleNode("/root/dynamic-element[@name='"+field+"']/dynamic-content").getText()?js_string}" 
49	<#else> 
50    "" 
51	</#if> 
52</#macro> 
53 
54<#-- Macro used to get repeatable field text from an Asset Entry --> 
55<#macro entryNodes article field childField> 
56	<#assign document = saxReaderUtil.read(article.getContent())> 
57	<#if document.selectNodes("/root/dynamic-element[@name='"+field+"']/dynamic-content")??> 
58
59		<#list document.selectNodes("/root/dynamic-element[@name='"+field+"']/dynamic-content") as curField> 
60
61		${field}: '${curField.getText()}', 
62		${childField}: '${curField.selectSingleNode("../dynamic-element[@name='"+childField+"']/dynamic-content").getText()}' 
63
64		</#list> 
65
66	<#else> 
67    [] 
68	</#if> 
69</#macro> 
70 
71<#-- Macro used to get specific portlet preference --> 
72<#macro preference prefKey defaultValue> 
73    <#assign preferenceValue = preferences.getValue(prefKey, defaultValue)?js_string> 
74 
75    "${preferenceValue}"<#return> 
76</#macro> 
77 
78<div id="bioGrid_${portletId}"></div> 
79 
80<script> 
81 
82	<#assign gridPagingBehavior> 
83		<@preference prefKey="gridPagingBehavior" defaultValue="Vertical Stack"/> 
84	</#assign> 
85	 
86	<!-- update name here if change asset library name --> 
87	<#assign assetLibGroup = GroupLocalService.getGroup(themeDisplay.getCompanyId(), "Kearney Global Asset Library") /> 
88 
89    var parsedBios = [ 
90	<#if entries?has_content> 
91		<#list entries as curEntry> 
92 
93            <#assign usePositionOverTitle = preferences.getValue("usePositionOverTitle", "false")> 
94 
95            <#if usePositionOverTitle == "true"> 
96                <#assign title = "Position" /> 
97            <#else> 
98                <#assign title = "Title" /> 
99            </#if> 
100 
101			<#assign jArt = JournalArticleLocalService.getLatestArticle(curEntry.getClassPK())> 
102			<#assign articleGroup = GroupLocalService.getGroup(jArt.getGroupId()) 
103				guestGroup = GroupLocalService.getFriendlyURLGroup(articleGroup.getCompanyId(), "/guest") /> 
104			<#assign document = saxReaderUtil.read(jArt.getContentByLocale(themeDisplay.getLocale()))> 
105
106                "urlTitle": encodeURIComponent(<@entryNode article=jArt field="FullName"/>), 
107                "fullName": <@entryNode article=jArt field="FullName"/>, 
108                "preferredFirstName": <@entryNode article=jArt field="PreferredFirstName"/>, 
109                "position": <@entryNode article=jArt field="Positon"/>, 
110                "title": <@entryNode article=jArt field=title />, 
111                "description": <@entryNode article=jArt field="Description"/>, 
112                "quote": <@entryNode article=jArt field="Quote"/>, 
113                "linkedInURL": <@entryNode article=jArt field="LinkedInURL"/>, 
114                "additionalLinks": <@entryNodes article=jArt field="AdditionalLink" childField="AdditionalLinkURL"/>, 
115                "headshot": '${TemplateCustomService.getDocumentURL(document,"CutoutHeadshot",themeDisplay)}', 
116 
117				<#assign viewURL = TemplateCustomService.getArticleViewURL(jArt.getArticleId(),assetLibGroup,jArt.getGroupId(),themeDisplay,guestGroup.getGroupId())/> 
118				 "bioURL": '${viewURL}' 
119            }, 
120		</#list> 
121	</#if> 
122    ]; 
123 
124    var ensureFieldNotEmpty = function (bio, field) { 
125        var value = bio[field]; 
126        return value !== undefined && value !== null && value !== ""; 
127    }; 
128 
129    var bios = _.filter(parsedBios, function (bio) { 
130        return ensureFieldNotEmpty(bio, "title") && ensureFieldNotEmpty(bio, "fullName") && ensureFieldNotEmpty(bio, "headshot"); 
131    }); 
132 
133    console.log("Filtered out " + (parsedBios.length - bios.length) + " bios with incomplete content"); 
134 
135	<#if (gridPagingBehavior?contains("Carousel")) && (entries?has_content) && (entries?size > 0)> 
136 
137    //Create the carousel navigation arrows and carousel root element 
138    $("#bioGrid_${portletId}").append("<div id='carouselPrev_${portletId}' class='carousel-arrow arrow-prev noselect'></div>"); 
139    $("#carouselPrev_${portletId}").append("<img src='${iconCommonPath}Rotator-Arrow-Left-Mobile${iconExtension}' />"); 
140    $("#bioGrid_${portletId}").append("<div id='carouselNext_${portletId}' class='carousel-arrow arrow-next noselect'></div>"); 
141    $("#carouselNext_${portletId}").append("<img src='${iconCommonPath}Rotator-Arrow-Right-Mobile${iconExtension}' />"); 
142    $("#bioGrid_${portletId}").append("<div id='carousel_${portletId}' class='owl-carousel owl-theme'></div>"); 
143 
144    var wrapperCache = []; 
145 
146    for (var i = 0; i < bios.length;) { 
147 
148        var groupIndex = _.floor(i / 4); 
149 
150        $("#carousel_${portletId}").append("<div class='atk-container'><div class='atk-row' id='bio_group_" 
151                + groupIndex + "' style='margin: 0px'></div></div>"); 
152 
153        for (var j = 0; j < 4 && i < bios.length; j++, i++) { 
154 
155            var marginBottomClasses = j > 1 ? ' after-0-px' : ' after-60-px'; 
156 
157            if (j !== 3) { 
158                marginBottomClasses += ' after-30-px-mobile'; 
159
160 
161            var nrpClasses = j === 1 ? 'd-nrp t-nrp p-nrp' : ''; 
162            var thisContributorURL = ATK.ContributorsURL + "?contributor=" + bios[i].fullName; 
163 
164            var wrapperDiv = $("<div class='d-6-col t-4-col p-6-col normalize-partial-width " + nrpClasses + marginBottomClasses 
165				+ "' id='bio_" + i + "_${portletId}'></div>"); 
166 
167			wrapperCache.push(wrapperDiv); 
168 
169            $("#bio_group_" + groupIndex).append(wrapperDiv); 
170 
171            ATK.React.Component.SquarePerson("bio_" + i + "_${portletId}", bios[i].headshot, bios[i].fullName, bios[i].title, thisContributorURL); 
172
173
174 
175    ATK.Utility.sennaDomReady(function () { 
176        var carousel = jQuery('#carousel_${portletId}'); 
177 
178        var setDotWidth = function() { 
179            setTimeout(function() { 
180                var width = $(window).width(); 
181                var padding = 0; 
182 
183                if(width <= 767) { 
184                    padding = 20; 
185                } else if(width <= 1024) { 
186                    padding = 60; 
187                } else if(width > 1000) { 
188                    width = 1000; 
189
190 
191                $('.atk-container .owl-dots').width(width - padding*2); 
192            }, 200); 
193        }; 
194 
195        carousel.on('initialized.owl.carousel', setDotWidth); 
196        carousel.on('refreshed.owl.carousel', setDotWidth); 
197 
198        carousel.owlCarousel({ 
199            loop: true, 
200            dots: true, 
201            items: 1 
202        }); 
203 
204        $('#carouselNext_${portletId}').click(function() { 
205            carousel.trigger('next.owl.carousel'); 
206        }); 
207        // Go to the previous item 
208        $('#carouselPrev_${portletId}').click(function() { 
209            carousel.trigger('prev.owl.carousel'); 
210        }); 
211 
212        //handle case where left bio in top row is taller than right bio in top row. Without this, bios do not appear in correct order 
213		for (var i = 0; i < bios.length; i = i + 4){ 
214 
215			var firstSlide = wrapperCache[i]; 
216			var secondSlide = wrapperCache[i+1]; 
217 
218			if (firstSlide.height() > secondSlide.height()){ 
219				secondSlide.css('height', firstSlide.css('height')); 
220
221
222 
223    }); 
224	<#else> 
225    ATK.React.App.ExpandingTopToBottomGrid("bioGrid_${portletId}", 2, "bio", "bio", parsedBios); 
226	</#if> 
227 
228</script> 

Our Roles

Analyst

Together with experienced consultants, analysts work on a broad range of consulting projects involving data gathering and analysis, and apply sophisticated modeling to real-life business problems. For undergraduates, the analyst program is an outstanding introduction to the discipline of consulting and the advanced, collaborative, and innovative solutions delivered on client engagements. Analysts often travel while on assignments that combine strategic business consulting skills with advanced analytical methodologies.

Sourcing Analyst

For undergraduates interested in supply chain management, the sourcing analyst program is a great entry-level consulting opportunity. Sourcing analysts work with clients and sourcing teams to develop and execute the overall strategic sourcing process. A rotational program is in place, providing training and working experience in a number of different roles to enhance your knowledge and potential. Sourcing analysts often work at the client site and apply data analytics techniques as well as category sourcing strategies.

Senior Analyst

For individuals with either an advanced degree other than an MBA or an undergraduate degree plus several years of full-time relevant work experience, the Kearney Solutions senior analyst position is an important bridge between analyst and analytics associate. This position is designed to develop the talents of individuals who may not have received an MBA but possess relevant experience and a desire to learn and deliver advanced analytical, collaborative, and innovative solutions on client engagements.

Senior Sourcing Analyst

Alongside experienced sourcing consultants, senior sourcing analysts apply their academic, internship, and training experience to various client projects. This role is for individuals with an interest in learning and delivering data analytics techniques and category sourcing strategies on various client engagements. Senior sourcing analysts typically have an advanced degree with a supply management concentration or an undergraduate degree plus several years of relevant work experience.

Summer Associate

Summer associates gain invaluable experience collaborating with clients as they help them achieve lasting, transformational changes, while developing a deeper skillset in procurement or advanced analytic solutions. Over the eight to 10 week summer consultant program, we will nurture your entrepreneurial spirit with hands-on experience that will positively influence the rest of your career. Kearney Solutions summer associates travel while on assignment to work side by side with our clients. We require enrollment in a competitive MBA program with a supply management concentration or quantitative discipline such as statistics, operations research, or econometrics.

Analytics Associate

As an Kearney Solutions analytics associate, you will be able to combine your MBA degree and our sophisticated analytics training, and apply those skills to a broad range of management consulting engagements. Analytics associates provide analytical solutions and statistical expertise to market-facing business problems. You will also have the opportunity to participate in internal firm-building activities and represent Kearney Solutions’ broad capabilities to clients.

Sourcing Associate

Sourcing associates apply their MBA degree and our in-depth strategic sourcing training to various client engagements. Our goal is to help you be very successful throughout your career life cycle. Sourcing associates routinely work at the client site to coach category sourcing teams from the development stage through execution and post follow-up. You will also be able to participate in various internal firm building activities and represent Kearney Solutions’ broad capabilities to clients.

Analytics Manager

As an analytics manager, you will be involved in various phases of a consulting engagement, from pre-proposal research through final implementation. Almost immediately, you will join a project team, where you will work at a client location sharing your ideas and delivering sophisticated analytical techniques across a broad range of management consulting engagements. Our goal is to involve you in various phases of the consulting process, helping you hone your professional skills. Analytics managers also participate in marketing activities and the preparation of proposals for new engagement opportunities.

Sourcing Manager

Sourcing managers lead client category sourcing teams through the strategic sourcing process. They often work at the client site and are involved in various phases of a consulting engagement. We want to involve you in all phases of the consulting process, helping you hone your professional skills. A sourcing manager is also responsible for project marketing and training communications with client stakeholders and suppliers. Leadership opportunities in client management and staff development increase as you progress into a senior sourcing manager role.

Director

Directors have project oversight on engagements. They are responsible for assigning specific tasks to client team members and making sure that the deliverables are scheduled and presented on time. Directors have opportunities for professional development and mentoring to help guide their career path and develop expertise in specific industry of service practices.

Vice President

Vice presidents are expected to manage large, complex engagements, build client relationships, and contribute to business development. Vice presidents with Kearney Solutions take on a leadership role and are elected to their position.

Partner

Partners are involved in senior client relationship development and management. They collaborate with CEOs to create long-term strategies and develop enduring relationships. Partners take an active role in the leadership of Kearney Solutions, developing future leaders and executing the business strategy for the firm. Partners at Kearney are elected to their position.