An error occurred while processing the template.
The following has evaluated to null or missing:
==> entries[entries?size - 1]  [in template "29795641980326#20120#137911" at line 2, column 22]

----
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 lastEntry = entries[entries?s...  [in template "29795641980326#20120#137911" at line 2, column 1]
----
1<#assign entries = entries?reverse /> 
2<#assign lastEntry = entries[entries?size - 1] /> 
3<#assign 
4  assetRenderer = lastEntry.getAssetRenderer() 
5  ddmFormFieldValuesMap = assetRenderer.getDDMFormValuesReader().getDDMFormValues().getDDMFormFieldValuesMap() 
6  TyGiaSo = "" 
7/> 
8<#list ddmFormFieldValuesMap["TyGiaSo"] as field> 
9  <#assign TyGiaSo = field.getValue().getString(locale) /> 
10</#list> 
11<#assign secondLastEntry = entries[entries?size - 2] /> 
12 
13<#-- Giá trị mới nhất --> 
14<#assign 
15  lastRenderer = lastEntry.getAssetRenderer() 
16  lastFields = lastRenderer.getDDMFormValuesReader().getDDMFormValues().getDDMFormFieldValuesMap() 
17  lastValue = 0 
18/> 
19<#list lastFields["TyGiaSo"] as field> 
20  <#assign lastValue = field.getValue().getString(locale)?number /> 
21</#list> 
22 
23<#-- Giá trị trước đó --> 
24<#assign 
25  secondRenderer = secondLastEntry.getAssetRenderer() 
26  secondFields = secondRenderer.getDDMFormValuesReader().getDDMFormValues().getDDMFormFieldValuesMap() 
27  prevValue = 0 
28/> 
29<#list secondFields["TyGiaSo"] as field> 
30  <#assign prevValue = field.getValue().getString(locale)?number /> 
31</#list> 
32	<#assign delta = lastValue - prevValue /> 
33<#assign percent = (delta / prevValue) * 100 /> 
34 
35<#if delta gte 0> 
36  <#assign sign = "+" /> 
37<#else> 
38  <#assign sign = "" /> 
39</#if> 
40	 
41<div class="sbv-chart custom-chart"> 
42  <div class="chart-header"> 
43    <a 
44      href="https://www.dttktt.sbv.gov.vn/TyGia/faces/TyGiaTrungTam.jspx" 
45      class="chart-title" 
46
47      tỷ giá 
48    </a> 
49    <span class="chart-value"> 
50      ${lastValue?string["#,##0.00"]} VND 
51      <span class="chart-change"> 
52        ${sign}${delta?string["#,##0.00"]} (${sign}${percent?string["0.00"]}%) 
53      </span> 
54    </span> 
55  </div> 
56  <div class="chart-canvas-wrapper"> 
57    <!-- Bar chart would be rendered here --> 
58    <canvas id="TyGiaChart" width="400" height="300"></canvas> 
59  </div> 
60  <div class="chart-footer"> 
61    <span class="chart-footer-text"> 
62      <a 
63        href="https://www.dttktt.sbv.gov.vn/TyGia/faces/TyGiaTrungTam.jspx" 
64        class="chart-link" 
65
66        Xem chi tiết <i class="fa-solid fa-caret-right"></i> 
67      </a> 
68    </span> 
69  </div> 
70</div> 
71 
72	<style> 
73	.sbv-chart .text-end a{color: #9D1B43;} 
74	.sbv-chart .text-end a:hover{color: var(--btn-link-hover-color);} 
75		 
76		/* Container Responsive Widths */ 
77.custom-chart { 
78  /* Mặc định full */ 
79  width: 100%; 
80  padding-left: 0; 
81  padding-right: 0; 
82
83 
84@media (max-width: 1170px) { 
85  .custom-chart { 
86    width: calc(50% - 12px); 
87
88
89 
90@media (max-width: 768px) { 
91  .custom-chart { 
92    width: calc(50% - 4px); 
93    padding: 0.5rem; 
94
95
96 
97@media (max-width: 650px) { 
98  .custom-chart { 
99    width: 100%; 
100    padding-left: 0; 
101    padding-right: 0; 
102
103
104 
105/* Header Section */ 
106.chart-header { 
107  display: flex; 
108  flex-direction: column; 
109  gap: 1px; 
110  margin-bottom: 0.75rem; /* mb-3 */ 
111
112 
113.chart-title { 
114  color: #000000; 
115  font-size: 20px; 
116  line-height: 1.15; 
117  font-weight: bold; 
118  text-transform: uppercase; 
119  text-decoration: none; 
120
121 
122.chart-value { 
123  color: #009953; 
124  font-size: 18px; 
125  line-height: 21px; 
126
127 
128.chart-change { 
129  display: inline-block; 
130  font-size: 14px; 
131  line-height: 1rem; /* leading-4 */ 
132  color: #000000; 
133
134 
135/* Chart Canvas Box */ 
136.chart-canvas-wrapper { 
137  width: 370px; 
138  height: 270px; 
139  background-color: white; 
140  padding: 0.25rem; 
141
142 
143@media (max-width: 1170px) { 
144  .chart-canvas-wrapper { 
145    width: 100%; 
146    height: 370px; 
147
148
149 
150/* Footer Link */ 
151.chart-footer { 
152  text-align: end; 
153  margin-top: 0.5rem; 
154
155 
156.chart-footer-text { 
157  color: #9D1B43; 
158  border-radius: 9999px; 
159  display: flex; 
160  justify-content: flex-start; 
161  align-items: center; 
162  gap: 6px; 
163
164 
165.chart-link { 
166  color: #9D1B43; 
167  display: inline-block; 
168  font-size: 14px; 
169  line-height: 1.5; 
170  text-decoration: none; 
171
172 
173</style> 
174<script> 
175const showFirstAndLastLabelPlugin = { 
176  id: 'showFirstAndLastLabel', 
177  afterBuildTicks: function(chart) { 
178    const xAxis = chart.scales.x; 
179    if (!xAxis) return; 
180 
181    const ticks = xAxis.ticks; 
182    const labels = xAxis.getLabels(); 
183 
184    if (ticks.length === 0 || labels.length === 0) return; 
185 
186    // Xác định index đang hiển thị trong viewport hiện tại 
187    const minIndex = Math.ceil(xAxis.min);  // chỉ số nhỏ nhất hiển thị 
188    const maxIndex = Math.floor(xAxis.max); // chỉ số lớn nhất hiển thị 
189 
190    // Nếu mốc đầu đang nằm trong viewport, ép lại label 
191    if (ticks[0] && minIndex === 0) { 
192      ticks[0].label = labels[0]; 
193
194 
195    // Nếu mốc cuối đang nằm trong viewport, ép lại label 
196    if (ticks[ticks.length - 1] && maxIndex === labels.length - 1) { 
197      ticks[ticks.length - 1].label = labels[labels.length - 1]; 
198
199
200}; 
201	 
202document.addEventListener("DOMContentLoaded", function() { 
203var dates = [ 
204  <#list entries as curEntry> 
205    <#assign 
206      assetRenderer = curEntry.getAssetRenderer() 
207      ddmFormFieldValuesMap = assetRenderer.getDDMFormValuesReader().getDDMFormValues().getDDMFormFieldValuesMap() 
208      NgayBatDau = "" 
209    /> 
210<#assign zoomStart = (entries?size > 10)?then(entries?size - 10, 0) /> 
211<#assign zoomEnd = entries?size - 1 /> 
212    <#list ddmFormFieldValuesMap["NgayBatDau"] as field> 
213			<#assign NgayBatDau = field.getValue().getString(locale)?date("yyyy-MM-dd") /> 
214    </#list> 
215    "${NgayBatDau?string("dd-MM-yyyy")}"<#if curEntry_has_next>,</#if> 
216  </#list> 
217]; 
218 
219  var tyGiaValues = [ 
220    <#list entries as curEntry> 
221      <#assign 
222        assetRenderer = curEntry.getAssetRenderer() 
223        ddmFormFieldValuesMap = assetRenderer.getDDMFormValuesReader().getDDMFormValues().getDDMFormFieldValuesMap() 
224        TyGiaSo = "" 
225      /> 
226      <#list ddmFormFieldValuesMap["TyGiaSo"] as field> 
227        <#assign TyGiaSo = field.getValue().getString(locale) /> 
228      </#list> 
229      ${TyGiaSo?number}<#if curEntry_has_next>,</#if> 
230    </#list> 
231  ]; 
232	const ctx = document.getElementById('TyGiaChart').getContext('2d'); 
233new Chart(ctx, { 
234  type: 'line', 
235  data: { 
236    labels: dates, 
237    datasets: [{ 
238      label: 'Tỷ giá (VND)', 
239      data: tyGiaValues, 
240      borderColor: '#A37B40', 
241      backgroundColor: '#A37B40', 
242      tension: 0.3, 
243      fill: false, 
244      pointBackgroundColor: '#A37B40' 
245    }] 
246  }, 
247  options: { 
248    scales: { 
249      y: { 
250				ticks: { 
251      color: '#000000' 
252    }, 
253        title: { 
254          display: false, 
255          text: 'Tỷ giá', 
256          font: { weight: 'bold' }, 
257					color: "#000000", 
258          align: 'end' 
259        }, 
260        beginAtZero: false 
261      }, 
262      x: { 
263				ticks: { 
264      color: '#000000' 
265    }, 
266        title: { 
267          display: false, 
268          text: 'Năm', 
269          font: { weight: 'bold' }, 
270          align: 'end', 
271					color: "#000000", 
272					min: ${zoomStart}, 
273          max: ${zoomEnd}, 
274
275
276    }, 
277    plugins: { 
278      legend: { display: false }, 
279      zoom: { 
280        zoom: { 
281          wheel: { enabled: true }, // Zoom bằng cuộn chuột 
282          pinch: { enabled: true }, // Zoom bằng cảm ứng (mobile) 
283          mode: 'x', // hoặc 'y' hoặc 'xy' 
284					onZoomComplete: ({ chart }) => chart.update('none'), 
285          // 👇 Zoom theo con trỏ chuột 
286          center: { 
287            x: 'mouse', 
288            y: 'mouse' 
289
290        }, 
291        pan: { 
292          enabled: true, 
293          mode: 'x' // cho phép kéo trục x 
294        }, 
295        limits: { 
296          x: { min: 'original', max: 'original' }, 
297          y: { min: 'original', max: 'original' } 
298
299
300
301  }, 
302  plugins: [ChartZoom, showFirstAndLastLabelPlugin] 
303}); 
304			 
305}); 
306</script>