1VMOD_STD(3) VMOD_STD(3)
2
3
4
6 vmod_std - Varnish Standard Module
7
9 import std [as name] [from "path"]
10
11 REAL random(REAL lo, REAL hi)
12
13 REAL round(REAL r)
14
15 VOID collect(HEADER hdr, STRING sep)
16
17 STRING querysort(STRING)
18
19 STRING toupper(STRING s)
20
21 STRING tolower(STRING s)
22
23 STRING strstr(STRING s1, STRING s2)
24
25 BOOL fnmatch(STRING pattern, STRING subject, BOOL pathname, BOOL noescape, BOOL period)
26
27 STRING fileread(STRING)
28
29 BLOB blobread(STRING)
30
31 BOOL file_exists(STRING path)
32
33 BOOL healthy(BACKEND be)
34
35 INT port(IP ip)
36
37 DURATION duration([STRING s], [DURATION fallback], [REAL real], [INT integer])
38
39 BYTES bytes([STRING s], [BYTES fallback], [REAL real], [INT integer])
40
41 INT integer([STRING s], [INT fallback], [BOOL bool], [BYTES bytes], [DURATION duration], [REAL real], [TIME time])
42
43 IP ip(STRING s, [IP fallback], BOOL resolve, [STRING p])
44
45 REAL real([STRING s], [REAL fallback], [INT integer], [BOOL bool], [BYTES bytes], [DURATION duration], [TIME time])
46
47 TIME time([STRING s], [TIME fallback], [REAL real], [INT integer])
48
49 VOID log(STRING s)
50
51 VOID syslog(INT priority, STRING s)
52
53 VOID timestamp(STRING s)
54
55 BOOL syntax(REAL)
56
57 STRING getenv(STRING name)
58
59 BOOL cache_req_body(BYTES size)
60
61 VOID late_100_continue(BOOL late)
62
63 VOID set_ip_tos(INT tos)
64
65 VOID rollback(HTTP h)
66
67 BOOL ban(STRING)
68
69 STRING ban_error()
70
71 INT real2integer(REAL r, INT fallback)
72
73 TIME real2time(REAL r, TIME fallback)
74
75 INT time2integer(TIME t, INT fallback)
76
77 REAL time2real(TIME t, REAL fallback)
78
80 vmod_std contains basic functions which are part and parcel of Varnish,
81 but which for reasons of architecture fit better in a VMOD.
82
84 REAL random(REAL lo, REAL hi)
85 Returns a random real number between lo and hi.
86
87 This function uses the "testable" random generator in varnishd which
88 enables determinstic tests to be run (See m00002.vtc). This function
89 should not be used for cryptographic applications.
90
91 Example:
92
93 set beresp.http.random-number = std.random(1, 100);
94
95 REAL round(REAL r)
96 Rounds the real r to the nearest integer, but round halfway cases away
97 from zero (see round(3)).
98
100 VOID collect(HEADER hdr, STRING sep=", )
101 Collapses multiple hdr headers into one long header. The default sepa‐
102 rator sep is the standard comma separator to use when collapsing head‐
103 ers, with an additional whitespace for pretty printing.
104
105 Care should be taken when collapsing headers. In particular collapsing
106 Set-Cookie will lead to unexpected results on the browser side.
107
108 Examples:
109
110 std.collect(req.http.accept);
111 std.collect(req.http.cookie, "; ");
112
113 STRING querysort(STRING)
114 Sorts the query string for cache normalization purposes.
115
116 Example:
117
118 set req.url = std.querysort(req.url);
119
120 STRING toupper(STRING s)
121 Converts the string s to uppercase.
122
123 Example:
124
125 set beresp.http.scream = std.toupper("yes!");
126
127 STRING tolower(STRING s)
128 Converts the string s to lowercase.
129
130 Example:
131
132 set beresp.http.nice = std.tolower("VerY");
133
134 STRING strstr(STRING s1, STRING s2)
135 Returns a string beginning at the first occurrence of the string s2 in
136 the string s1, or an empty string if s2 is not found.
137
138 Note that the comparison is case sensitive.
139
140 Example:
141
142 if (std.strstr(req.url, req.http.restrict)) {
143 ...
144 }
145
146 This will check if the content of req.http.restrict occurs anywhere in
147 req.url.
148
149 BOOL fnmatch(STRING pattern, STRING subject, BOOL pathname, BOOL noescape,
150 BOOL period)
151 BOOL fnmatch(
152 STRING pattern,
153 STRING subject,
154 BOOL pathname=1,
155 BOOL noescape=0,
156 BOOL period=0
157 )
158
159 Shell-style pattern matching; returns true if subject matches pattern,
160 where pattern may contain wildcard characters such as * or ?.
161
162 The match is executed by the implementation of fnmatch(3) on your sys‐
163 tem. The rules for pattern matching on most systems include the follow‐
164 ing:
165
166 • * matches any sequence of characters
167
168 • ? matches a single character
169
170 • a bracket expression such as [abc] or [!0-9] is interpreted as a
171 character class according to the rules of basic regular expressions
172 (not pcre(3) regexen), except that ! is used for character class
173 negation instead of ^.
174
175 If pathname is true, then the forward slash character / is only matched
176 literally, and never matches *, ? or a bracket expression. Otherwise, /
177 may match one of those patterns. By default, pathname is true.
178
179 If noescape is true, then the backslash character \ is matched as an
180 ordinary character. Otherwise, \ is an escape character, and matches
181 the character that follows it in the pattern. For example, \\ matches \
182 when noescape is true, and \\ when false. By default, noescape is
183 false.
184
185 If period is true, then a leading period character . only matches lit‐
186 erally, and never matches *, ? or a bracket expression. A period is
187 leading if it is the first character in subject; if pathname is also
188 true, then a period that immediately follows a / is also leading (as in
189 /.). By default, period is false.
190
191 std.fnmatch() invokes VCL failure and returns false if either of pat‐
192 tern or subject is NULL -- for example, if an unset header is speci‐
193 fied.
194
195 Examples:
196
197 # Matches URLs such as /foo/bar and /foo/baz
198 if (std.fnmatch("/foo/\*", req.url)) { ... }
199
200 # Matches URLs such as /foo/bar/baz and /foo/baz/quux
201 if (std.fnmatch("/foo/\*/\*", bereq.url)) { ... }
202
203 # Matches /foo/bar/quux, but not /foo/bar/baz/quux
204 if (std.fnmatch("/foo/\*/quux", req.url)) { ... }
205
206 # Matches /foo/bar/quux and /foo/bar/baz/quux
207 if (std.fnmatch("/foo/\*/quux", req.url, pathname=false)) { ... }
208
209 # Matches /foo/bar, /foo/car and /foo/far
210 if (std.fnmatch("/foo/?ar", req.url)) { ... }
211
212 # Matches /foo/ followed by a non-digit
213 if (std.fnmatch("/foo/[!0-9]", req.url)) { ... }
214
216 STRING fileread(STRING)
217 Reads a text file and returns a string with the content.
218
219 The entire file is cached on the first call, and subsequent calls will
220 return this cached contents, even if the file has changed in the mean‐
221 time.
222
223 For binary files, use std.blobread() instead.
224
225 Example:
226
227 synthetic("Response was served by " + std.fileread("/etc/hostname"));
228
229 Consider that the entire contents of the file appear in the string that
230 is returned, including newlines that may result in invalid headers if
231 std.fileread() is used to form a header. In that case, you may need to
232 modify the string, for example with regsub() (see vcl(7)):
233
234 set beresp.http.served-by = regsub(std.fileread("/etc/hostname"), "\R$", "");
235
236 BLOB blobread(STRING)
237 Reads any file and returns a blob with the content.
238
239 The entire file is cached on the first call, and subsequent calls will
240 return this cached contents, even if the file has changed in the mean‐
241 time.
242
243 BOOL file_exists(STRING path)
244 Returns true if path or the file pointed to by path exists, false oth‐
245 erwise.
246
247 Example:
248
249 if (std.file_exists("/etc/return_503")) {
250 return (synth(503, "Varnish is in maintenance"));
251 }
252
254 BOOL healthy(BACKEND be)
255 Returns true if the backend be is healthy.
256
257 INT port(IP ip)
258 Returns the port number of the IP address ip. Always returns 0 for a
259 *.ip variable when the address is a Unix domain socket.
260
262 These functions all have the same form:
263
264 TYPE type([arguments], [fallback TYPE])
265
266 Precisely one of the arguments must be provided (besides the optional
267 fallback), and it will be converted to TYPE.
268
269 If conversion fails, fallback will be returned and if no fallback was
270 specified, the VCL will be failed.
271
272 DURATION duration([STRING s], [DURATION fallback], [REAL real], [INT inte‐
273 ger])
274 DURATION duration(
275 [STRING s],
276 [DURATION fallback],
277 [REAL real],
278 [INT integer]
279 )
280
281 Returns a DURATION from a STRING, REAL or INT argument.
282
283 For a STRING s argument, s must be quantified by ms (milliseconds), s
284 (seconds), m (minutes), h (hours),``d`` (days), w (weeks) or y (years)
285 units.
286
287 real and integer arguments are taken as seconds.
288
289 If the conversion of an s argument fails, fallback will be returned if
290 provided, or a VCL failure will be triggered.
291
292 Conversions from real and integer arguments never fail.
293
294 Only one of the s, real or integer arguments may be given or a VCL
295 failure will be triggered.
296
297 Examples::
298 set beresp.ttl = std.duration("1w", 3600s); set beresp.ttl =
299 std.duration(real=1.5); set beresp.ttl = std.duration(inte‐
300 ger=10);
301
302 BYTES bytes([STRING s], [BYTES fallback], [REAL real], [INT integer])
303 BYTES bytes(
304 [STRING s],
305 [BYTES fallback],
306 [REAL real],
307 [INT integer]
308 )
309
310 Returns BYTES from a STRING, REAL or INT argument.
311
312 A STRING s argument can be quantified with a multiplier (k (kilo), m
313 (mega), g (giga), t (tera) or p (peta)).
314
315 real and integer arguments are taken as bytes.
316
317 If the conversion of an s argument fails, fallback will be returned if
318 provided, or a VCL failure will be triggered.
319
320 Other conversions may fail if the argument can not be represented, be‐
321 cause it is negative, too small or too large. Again, fallback will be
322 returned if provided, or a VCL failure will be triggered.
323
324 real arguments will be rounded down.
325
326 Only one of the s, real or integer arguments may be given or a VCL
327 failure will be triggered.
328
329 Example::
330 std.cache_req_body(std.bytes(something.somewhere, 10K));
331 std.cache_req_body(std.bytes(integer=10*1024));
332 std.cache_req_body(std.bytes(real=10.0*1024));
333
334 INT integer([STRING s], [INT fallback], [BOOL bool], [BYTES bytes], [DURA‐
335 TION duration], [REAL real], [TIME time])
336 INT integer(
337 [STRING s],
338 [INT fallback],
339 [BOOL bool],
340 [BYTES bytes],
341 [DURATION duration],
342 [REAL real],
343 [TIME time]
344 )
345
346 Returns an INT from a STRING, BOOL or other quantity.
347
348 If the conversion of an s argument fails, fallback will be returned if
349 provided, or a VCL failure will be triggered.
350
351 A bool argument will be returned as 0 for false and 1 for true. This
352 conversion will never fail.
353
354 For a bytes argument, the number of bytes will be returned. This con‐
355 version will never fail.
356
357 A duration argument will be rounded down to the number of seconds and
358 returned.
359
360 A real argument will be rounded down and returned.
361
362 For a time argument, the number of seconds since the UNIX epoch
363 (1970-01-01 00:00:00 UTC) will be returned.
364
365 duration, real and time conversions may fail if the argument can not be
366 represented because it is too small or too large. If so, fallback will
367 be returned if provided, or a VCL failure will be triggered.
368
369 Only one of the s, bool, bytes, duration, real or time arguments may be
370 given or a VCL failure will be triggered.
371
372 Examples:
373
374 if (std.integer(req.http.foo, 0) > 5) {
375 ...
376 }
377
378 set resp.http.answer = std.integer(real=126.42/3);
379
380 IP ip(STRING s, [IP fallback], BOOL resolve=1, [STRING p])
381 Converts the string s to the first IP number returned by the system li‐
382 brary function getaddrinfo(3). If conversion fails, fallback will be
383 returned or VCL failure will happen.
384
385 The IP address includes a port number that can be found with std.port()
386 that defaults to 80. The default port can be set to a different value
387 with the p argument. It will be overriden if s contains both an IP ad‐
388 dress and a port number or service name.
389
390 When s contains both, the syntax is either address:port or address
391 port. If the address is a numerical IPv6 address it must be enclosed
392 between brackets, for example [::1] 80 or [::1]:http. The fallback may
393 also contain both an address and a port, but its default port is always
394 80.
395
396 If resolve is false, getaddrinfo(3) is called using AI_NUMERICHOST and
397 AI_NUMERICSERV to avoid network lookups depending on the system's
398 getaddrinfo(3) or nsswitch configuration. This makes "numerical" IP
399 strings and services cheaper to convert.
400
401 Example:
402
403 if (std.ip(req.http.X-forwarded-for, "0.0.0.0") ~ my_acl) {
404 ...
405 }
406
407 REAL real([STRING s], [REAL fallback], [INT integer], [BOOL bool], [BYTES
408 bytes], [DURATION duration], [TIME time])
409 REAL real(
410 [STRING s],
411 [REAL fallback],
412 [INT integer],
413 [BOOL bool],
414 [BYTES bytes],
415 [DURATION duration],
416 [TIME time]
417 )
418
419 Returns a REAL from a STRING, BOOL or other quantity.
420
421 If the conversion of an s argument fails, fallback will be returned if
422 provided, or a VCL failure will be triggered.
423
424 A bool argument will be returned as 0.0 for false and 1.0 for true.
425
426 For a bytes argument, the number of bytes will be returned.
427
428 For a duration argument, the number of seconds will be returned.
429
430 An integer argument will be returned as a REAL.
431
432 For a time argument, the number of seconds since the UNIX epoch
433 (1970-01-01 00:00:00 UTC) will be returned.
434
435 None of these conversions other than s will fail.
436
437 Only one of the s, integer, bool, bytes, duration or time arguments may
438 be given or a VCL failure will be triggered.
439
440 Example:
441
442 if (std.real(req.http.foo, 0.0) > 5.5) {
443 ...
444 }
445
446 TIME time([STRING s], [TIME fallback], [REAL real], [INT integer])
447 TIME time([STRING s], [TIME fallback], [REAL real], [INT integer])
448
449 Returns a TIME from a STRING, REAL or INT argument.
450
451 For a STRING s argument, the following formats are supported:
452
453 "Sun, 06 Nov 1994 08:49:37 GMT"
454 "Sunday, 06-Nov-94 08:49:37 GMT"
455 "Sun Nov 6 08:49:37 1994"
456 "1994-11-06T08:49:37"
457 "784111777.00"
458 "784111777"
459
460 real and integer arguments are taken as seconds since the epoch.
461
462 If the conversion of an s argument fails or a negative real or integer
463 argument is given, fallback will be returned if provided, or a VCL
464 failure will be triggered.
465
466 Examples:
467
468 if (std.time(resp.http.last-modified, now) < now - 1w) {
469 ...
470 }
471
472 if (std.time(int=2147483647) < now - 1w) {
473 ...
474 }
475
477 VOID log(STRING s)
478 Logs the string s to the shared memory log, using vsl(7) tag
479 SLT_VCL_Log.
480
481 Example:
482
483 std.log("Something fishy is going on with the vhost " + req.http.host);
484
485 VOID syslog(INT priority, STRING s)
486 Logs the string s to syslog tagged with priority. priority is formed by
487 ORing the facility and level values. See your system's syslog.h file
488 for possible values.
489
490 Notice: Unlike VCL and other functions in the std vmod, this function
491 will not fail VCL processing for workspace overflows: For an out of
492 workspace condition, the std.syslog() function has no effect.
493
494 Example:
495
496 std.syslog(9, "Something is wrong");
497
498 This will send a message to syslog using LOG_USER | LOG_ALERT.
499
500 VOID timestamp(STRING s)
501 Introduces a timestamp in the log with the current time, using the
502 string s as the label. This is useful to time the execution of lengthy
503 VCL subroutines, and makes the timestamps inserted automatically by
504 Varnish more accurate.
505
506 Example:
507
508 std.timestamp("curl-request");
509
511 BOOL syntax(REAL)
512 Returns true if VCL version is at least REAL.
513
514 STRING getenv(STRING name)
515 Return environment variable name or the empty string. See getenv(3).
516
517 Example:
518
519 set req.http.My-Env = std.getenv("MY_ENV");
520
521 BOOL cache_req_body(BYTES size)
522 Caches the request body if it is smaller than size. Returns true if
523 the body was cached, false otherwise.
524
525 Normally the request body can only be sent once. Caching it enables
526 retrying backend requests with a request body, as usually the case with
527 POST and PUT.
528
529 Example:
530
531 if (std.cache_req_body(1KB)) {
532 ...
533 }
534
535 VOID late_100_continue(BOOL late)
536 Controls when varnish reacts to an Expect: 100-continue client request
537 header.
538
539 Varnish always generates a 100 Continue response if requested by the
540 client trough the Expect: 100-continue header when waiting for request
541 body data.
542
543 But, by default, the 100 Continue response is already generated immedi‐
544 ately after vcl_recv returns to reduce latencies under the assumption
545 that the request body will be read eventually.
546
547 Calling std.late_100_continue(true) in vcl_recv will cause the 100 Con‐
548 tinue response to only be sent when needed. This may cause additional
549 latencies for processing request bodies, but is the correct behavior by
550 strict interpretation of RFC7231.
551
552 This function has no effect outside vcl_recv and after calling
553 std.cache_req_body() or any other function consuming the request body.
554
555 Example:
556
557 vcl_recv {
558 std.late_100_continue(true);
559
560 if (req.method == "POST") {
561 std.late_100_continue(false);
562 return (pass);
563 }
564 ...
565 }
566
567 VOID set_ip_tos(INT tos)
568 Sets the Differentiated Services Codepoint (DSCP) / IPv4 Type of Ser‐
569 vice (TOS) / IPv6 Traffic Class (TCLASS) byte for the current session
570 to tos. Silently ignored if the listen address is a Unix domain socket.
571
572 Please note that setting the traffic class affects all requests on the
573 same http1.1 / http2 TCP connection and, in particular, is not removed
574 at the end of the request.
575
576 Example:
577
578 if (req.url ~ "^/slow/") {
579 std.set_ip_tos(0);
580 }
581
582 VOID rollback(HTTP h)
583 Restores the h HTTP headers to their original state.
584
585 Example:
586
587 std.rollback(bereq);
588
589 BOOL ban(STRING)
590 Invalidates all objects in cache that match the given expression with
591 the ban mechanism. Returns true if the ban succeeded and false other‐
592 wise. Error details are available via std.ban_error().
593
594 The format of STRING is:
595
596 <field> <operator> <arg> [&& <field> <oper> <arg> ...]
597
598 • <field>:
599
600 • string fields:
601
602 • req.url: The request url
603
604 • req.http.*: Any request header
605
606 • obj.status: The cache object status
607
608 • obj.http.*: Any cache object header
609
610 obj.status is treated as a string despite the fact that it is actu‐
611 ally an integer.
612
613 • duration fields:
614
615 • obj.ttl: Remaining ttl at the time the ban is issued
616
617 • obj.age: Object age at the time the ban is issued
618
619 • obj.grace: The grace time of the object
620
621 • obj.keep: The keep time of the object
622
623 • <operator>:
624
625 • for all fields:
626
627 • ==: <field> and <arg> are equal
628
629 • !=: <field> and <arg> are unequal
630
631 strings are compared case sensitively
632
633 • for string fields:
634
635 • ~: <field> matches the regular expression <arg>
636
637 • !~:<field> does not match the regular expression <arg>
638
639 • for duration fields:
640
641 • >: <field> is greater than <arg>
642
643 • >=: <field> is greater than or equal to <arg>
644
645 • <: <field> is less than <arg>
646
647 • <=: <field> is less than or equal to <arg>
648
649 • <arg>:
650
651 • for string fields:
652
653 Either a literal string or a regular expression. Note that <arg>
654 does not use any of the string delimiters like " or {"..."} or
655 """...""" used elsewhere in varnish. To match against strings con‐
656 taining whitespace, regular expressions containing \s can be used.
657
658 • for duration fields:
659
660 A VCL duration like 10s, 5m or 1h, see vcl(7)_durations
661
662 Expressions can be chained using the and operator &&. For or semantics,
663 use several bans.
664
665 The unset <field> is not equal to any string, such that, for a non-ex‐
666 isting header, the operators == and ~ always evaluate as false, while
667 the operators != and !~ always evaluate as true, respectively, for any
668 value of <arg>.
669
670 STRING ban_error()
671 Returns a textual error description of the last std.ban() call from the
672 same task or the empty string if there either was no error or no
673 std.ban() call.
674
676 INT real2integer(REAL r, INT fallback)
677 DEPRECATED: This function will be removed in a future version of var‐
678 nish, use std.integer() with a real argument and the std.round() func‐
679 tion instead, for example:
680
681 std.integer(real=std.round(...), fallback=...)
682
683 Rounds the real r to the nearest integer, but round halfway cases away
684 from zero (see round(3)). If conversion fails, fallback will be re‐
685 turned.
686
687 Examples:
688
689 set req.http.integer = std.real2integer(1140618699.00, 0);
690 set req.http.posone = real2integer( 0.5, 0); # = 1.0
691 set req.http.negone = real2integer(-0.5, 0); # = -1.0
692
693 TIME real2time(REAL r, TIME fallback)
694 DEPRECATED: This function will be removed in a future version of var‐
695 nish, use std.time() with a real argument and the std.round() function
696 instead, for example:
697
698 std.time(real=std.round(...), fallback=...)
699
700 Rounds the real r to the nearest integer (see std.real2integer()) and
701 returns the corresponding time when interpreted as a unix epoch. If
702 conversion fails, fallback will be returned.
703
704 Example:
705
706 set req.http.time = std.real2time(1140618699.00, now);
707
708 INT time2integer(TIME t, INT fallback)
709 DEPRECATED: This function will be removed in a future version of var‐
710 nish, use std.integer() with a time argument instead, for example:
711
712 std.integer(time=..., fallback=...)
713
714 Converts the time t to a integer. If conversion fails, fallback will be
715 returned.
716
717 Example:
718
719 set req.http.int = std.time2integer(now, 0);
720
721 REAL time2real(TIME t, REAL fallback)
722 DEPRECATED: This function will be removed in a future version of var‐
723 nish, use std.real() with a time argument instead, for example:
724
725 std.real(time=..., fallback=...)
726
727 Converts the time t to a real. If conversion fails, fallback will be
728 returned.
729
730 Example:
731
732 set req.http.real = std.time2real(now, 1.0);
733
735 • varnishd(1)
736
737 • vsl(7)
738
739 • fnmatch(3)
740
742 Copyright (c) 2010-2017 Varnish Software AS
743 All rights reserved.
744
745 Author: Poul-Henning Kamp <phk@FreeBSD.org>
746
747 SPDX-License-Identifier: BSD-2-Clause
748
749 Redistribution and use in source and binary forms, with or without
750 modification, are permitted provided that the following conditions
751 are met:
752 1. Redistributions of source code must retain the above copyright
753 notice, this list of conditions and the following disclaimer.
754 2. Redistributions in binary form must reproduce the above copyright
755 notice, this list of conditions and the following disclaimer in the
756 documentation and/or other materials provided with the distribution.
757
758 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
759 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
760 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
761 ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
762 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
763 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
764 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
765 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
766 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
767 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
768 SUCH DAMAGE.
769
770
771
772
773 VMOD_STD(3)