Fast and Memory-Efficient Regular Expression Matching For Deep Packet Inspection
Fast and Memory-Efficient Regular Expression Matching For Deep Packet Inspection
Fast and Memory-Efficient Regular Expression Matching For Deep Packet Inspection
Fang Yu
Zhifeng Chen
Yanlei Diao
T.V. Lakshman
Randy H. Katz
Permission to make digital or hard copies of all or part of this work for
personal or classroom use is granted without fee provided that copies are
not made or distributed for profit or commercial advantage and that copies
bear this notice and the full citation on the first page. To copy otherwise, to
republish, to post on servers or to redistribute to lists, requires prior specific
permission.
Fast and Memory-Efficient Regular Expression
Matching for Deep Packet Inspection
Fang Yu, Member, IEEE Zhifeng Chen, Member, IEEE Yanlei Diao, Member, IEEE
T. V. Lakshman , Fellow, IEEE Randy H. Katz, Fellow, IEEE
Abstract—Packet content scanning at high speed has become As regular expressions gain widespread adoption for
extremely important due to its applications in network security, packet content scanning, it is imperative that regular
network monitoring, HTTP load balancing, etc. In content expression matching over the packet payload keep up with
scanning, the packet payload is compared against a set of the line-speed packet header processing. Unfortunately, this
patterns specified as regular expressions. In this paper, we first
show that memory requirements using traditional methods are
requirement cannot be met in many existing payload
prohibitively high for many patterns used in packet scanning scanning implementations. For example, when all 70
applications. We then propose regular expression rewrite protocol filters are enabled in the Linux L7-filter [1], we
techniques that can effectively reduce memory usage. Further, found that the system throughput drops to less than 10Mbps,
we develop a grouping scheme that can strategically compile a which is well below current LAN speeds. Moreover, over
set of regular expressions into several engines, resulting in 90% of the CPU time is spent in regular expression
remarkable improvement of regular expression matching speed matching, leaving little time for other intrusion detection or
without much increase in memory usage. We implement a new monitoring functions. On the other hand, although many
DFA-based packet scanner using the above techniques. Our schemes for fast string matching [4-11] have been developed
experimental results using real-world traffic and patterns show
that our implementation achieves a factor of 12 to 42
recently in intrusion detection systems, they focus on explicit
performance improvement over a commonly used DFA-based string patterns only and can not be easily extended to fast
scanner. Compared to the state-of-art NFA-based regular expression matching.
implementation, our DFA-based packet scanner achieves 50 to The inefficiency in regular expression matching is largely
700 times speedup. due to the fact that the current solutions are not optimized for
the following three unique complex features of regular
I. INTRODUCTION expressions used in network packet scanning applications.
Packet content scanning (also known as Layer-7 filtering or • First, many such patterns use multiple wildcard
payload scanning) is crucial to network security and network metacharacters (e.g., ‘.’, ‘*’). For example, the pattern
monitoring applications. In these applications, the payload of for identifying the Internet radio protocol,
packets in a traffic stream is matched against a given set of “membername.*session.*player”, has two wildcard
patterns to identify specific classes of applications, viruses, fragments “.*”. Some patterns even contain over ten
protocol definitions, etc. such wildcard fragments. As regular expressions are
converted into state machines for pattern matching, large
Currently, regular expressions are replacing explicit
numbers of wildcards can cause the corresponding
string patterns as the pattern matching language of choice in
Deterministic Finite Automaton (DFA) to grow
packet scanning applications. Their widespread use is due to
exponentially.
their expressive power and flexibility for describing useful
patterns. For example, in the Linux Application Protocol • Second, a majority of the wildcards are used with length
Classifier (L7-filter) [1], all protocol identifiers are expressed restrictions (‘?’, ‘+’). As we shall show later in the
as regular expressions. Similarly, the Snort [2] intrusion paper, such length restrictions can increase the resource
detection system has evolved from no regular expressions in needs for expression matching.
its ruleset in April 2003 to 1131 out of 4867 rules using • Third, groups of characters are also commonly used: for
regular expressions as of February 2006. Another intrusion example, the pattern for matching the ftp protocol,
detection system, Bro [3], also uses regular expressions as its “^220[\x09-\x0d -~]*ftp”, contains a class (inside the
pattern language. brackets) that includes all the printing characters and
space characters. The class of characters may intersect
F. Yu, Department of EECS, University of California Berkeley, Berkeley, with other classes or wildcards. Such interaction can
CA 94720 (phone: 510-642-8284; email: fyu@eecs.berkeley.edu).
Z. Chen, Google Inc., 1600 Amphitheathre Pkwy, Mountain View, CA result in a highly complex state machine.
94043 (email: zhifengc@google.com) To the best of our knowledge, there has not been any
Y. Diao, Department of Computer Science, University of Massachusetts detailed study of optimizations for these kinds of regular
Amherst, Amherst, MA 01003 (email: yanlei@cs.umass.edu).
T.V. Lakshman, Bell Laboratories, Lucent Technologies, 101 Crawfords
expressions as they are so specific to network packet
Corner Road, Holmdel, NJ 07733 (email: lakshman@research.bell-labs.com). scanning applications. In this paper, we address this gap by
Randy H. Katz, Department of EECS, University of California Berkeley, analyzing these regular expressions and developing memory-
Berkeley, CA 94720 (email: randy@eecs.berkeley.edu).
1
efficient DFA-based solutions for high speed processing. then a letter l, w or t, and some arbitrary characters, and
Specifically, we make the following contributions: finally the ASCII letters c0 and 80 in the hexadecimal form.
• We analyze the computational and storage cost of Table 2 compares the regular expressions used in two
building individual DFAs for matching regular networking applications, Snort and the Linux L7-filter,
expressions, and identify the structural characteristics of against those used in emerging Extensible Markup Language
the regular expressions in networking applications that (XML) filtering applications [12, 13] where regular
lead to exponential growth of DFAs, as presented in expressions are matched over text documents encoded in
Section 3.2. XML. We notice three main differences: (1) While both
• Based on the above analysis, we propose two rewrite types of applications use wildcards (‘.’, ‘?’, ‘+’, ‘*’), the
rules for specific regular expressions in Section 3.3. The patterns for packet scanning applications contain larger
rewritten rules can dramatically reduce the size of numbers of them in each pattern; (2) classes of characters
resulting DFAs, making them small enough to fit in (“[]”) are used only in packet scanning applications; (3) a
memory. We prove that the patterns after rewriting are high percentage of patterns in packet payload scanning
equivalent to the original ones for detecting non- applications have length restrictions on some of the classes or
overlapping patterns. While we do not claim to handle wildcards, while such length restrictions usually do not occur
all possible cases of dramatic DFA growth (in fact the in XML filtering. This shows that compared to the XML
worse case cannot be improved), our rewrite rules do filtering applications, network packet scanning applications
cover those patterns present in common payload face additional challenges These challenges lead to a
scanning rulesets like Snort and Bro, thus making fast significant increase in the complexity of regular expression
DFA-based pattern matching feasible for today’s matching, as we shall show later in this paper.
payload scanning applications. Table 1. Features of Regular Expressions
Syntax Meaning Example
• We further develop techniques to intelligently combine ^ Pattern to be matched ^AB means the input starts with AB.
multiple DFAs into a small number of groups to improve at the start of the input A pattern without ‘^’, e.g., AB, can
the matching speed in Section IV, while avoiding the be matched anywhere in the input.
| OR relationship A|B denotes A or B.
exponential growth in the number of states in memory.
. A single character
We demonstrate the effectiveness of our rewriting and wildcard
grouping solutions through a detailed performance analysis ? A quantifier denoting A? denotes A or an empty string.
one or less
using real-world payload scanning pattern sets. As the results
* A quantifier denoting A* means an arbitrary number of As.
show, our DFA-based implementation can increase the zero or more
regular expression matching speed on the order of 50 to 700 {} Repeat A{100} denotes 100 As.
times over the NFA-based implementation used in the Linux [] A class of characters [lwt] denotes a letter l, w, or t.
L7-filter and Snort system. It can also achieve 12-42 times [^] Anything but [^\n] denotes any character except \n.
speedup over a commonly used DFA-based parser. The Table 2. Comparison of regular expressions in networking
pattern matching speed can achieve gigabit rates for certain applications against those in XML filtering
pattern sets. This is significant for implementing fast regular Snort L7-filter XML filtering
# of regular expressions analyzed 1555 70 1,000-100,000
expression matching of the packet payload using network
% of patterns starting with “^” 74.4% 72.8% ≥80%
processors or general-purpose processors, as the ability to % of patterns with wildcards “., +, 74.9% 75.7% 50% -
more quickly and efficiently classify enables many new ?, *” 100%
technologies like real-time worm detection, content lookup in Average # of wildcards per pattern 4.65 7.03 1-2
overlay networks, fine-grained load balancing, etc. % of patterns with class “[ ]” 31.6% 52.8% 0
Average # of classes per pattern 7.97 4.78 0
% of patterns with length 56.3% 21.4% ≈0
II.PROBLEM STATEMENT restrictions on classes or wildcards
In this section, we first discuss regular expressions used in 2.2 Solution Space for Regular Expression Matching
packet payload scanning applications, then present the
Finite automata are a natural formalism for regular
possible solutions for regular expression matching, and
expressions. There are two main categories: Deterministic
finally define the specific problem that we address in this
Finite Automaton (DFA) and Nondeterministic Finite
paper.
Automaton (NFA). In this section, we survey existing
2.1 Regular Expression Patterns solutions using these two types of automata.
A regular expression describes a set of strings without A DFA consists of a finite set of input symbols, denoted
enumerating them explicitly. Table 1 lists the common as ∑, a finite set of states, and a transition function δ [14]. In
features of regular expression patterns used in packet payload networking applications, ∑ contains the 28 symbols from the
scanning. For example, consider a regular expression from extended ASCII code. Among the states, there is a single
the Linux L7-filter [1] for detecting Yahoo traffic: start state q0 and a set of accepting states. The transition
“^(ymsg|ypns|yhoo).?.?.?.?.?.?.?[lwt].*\xc0\x80”. This pattern function δ takes a state and an input symbol as arguments
matches any packet payload that starts with ymsg, ypns, or and returns a state. A key feature of DFA is that at any time
yhoo, followed by seven or fewer arbitrary characters, and there is only one active state in the DFA. An NFA works
similarly to a DFA except that the δ function maps from a
2
state and a symbol to a set of new states. Therefore, multiple such situations, a network processor or general-purpose
states can be active simultaneously in an NFA. CPU-based implementation may be more desirable.
A theoretical worst case study [14] shows that a single 2.3 Problem statement
regular expression of length n can be expressed as an NFA In this paper, we seek a fast and memory-efficient solution to
with O(n) states. When the NFA is converted into a DFA, it
regular expression matching for packet payload scanning.
may generate O(∑n) states. The processing complexity for We define the scope of the problem as follows:
each character in the input is O(1) in a DFA, but is O(n2) for
• We consider DFA-based approaches in this paper, as
an NFA when all n states are active at the same time.
NFA-based approaches are inefficient on serial
To handle m regular expressions, two choices are processors or processors with limited parallelism (e.g.,
possible: processing them individually in m automata, or multi-core CPUs in comparison to FPGAs). Our goal is
compiling them into a single automaton. The former is used to achieve O(1) computation cost for each incoming
in Snort [2] and Linux L7-filer [1]. The latter is proposed in character, which cannot be accomplished by any existing
recent studies [12, 13] so that the single composite NFA can DFA-based solutions due to their excessive memory
support shared matching of common prefixes of those usage. Thus, the focus of the study is to reduce memory
expressions. Despite the demonstrated performance gains overhead of DFA while approaching the optimal
over using m separate NFAs, in practice this approach processing speed of O(1) per character.
experiences large numbers of active states. This has the same
worst case complexity as the sum of m separate NFAs. • We focus on general-purpose processor-based
Therefore, this approach on a serial processor can be slow, as architectures and explore the limits of regular
given any input character, each active state must be serially expression matching in this environment. Wherever
examined to obtain new states. appropriate, we leverage the trend of multi-core
processors that are becoming prevalent in those
In DFA-based systems, compiling m regular expressions
architectures. Nevertheless, our results can be used in
into a composite DFA provides guaranteed performance
FPGA-based and ASIC-based approaches as well [20].
benefit over running m individual DFA. Specifically, a
composite DFA reduces processing cost from O(m) (O(1) for It is worth noting that there are two sources of memory
each automaton) to O(1), i.e., a single lookup to obtain the usage in DFAs: states and transitions. The number of
next state for any given character. However, the number of transitions is linear with respect to the number of states
because for each state there can be at most 28 (for all ASCII
states in the composite automaton grows to O(∑mn) in the
characters) links to next states. Therefore, we consider the
theoretical worst case. In fact, we will show in Section 4 that
number of states (in minimized DFA) as the primary factor
typical patterns in packet payload scanning applications
for determining the memory usage in the rest of the paper.
indeed interact with each other and can cause the creation of
Also, due to the need for high performance, we do not
an exponential number of states in the composite DFA.
consider DFAs that use any table compression techniques.
Table 3. Worst case comparisons of DFA and NFA
One regular expression of m regular expressions
length n compiled together III.MATCHING OF INDIVIDUAL PATTERNS
Processing Storage Processing Storage In this section, we present our solution to matching
complexity cost complexity cost individual regular expression patterns. The main technical
NFA O(n2) O(n) O(n2m) O(nm)
challenge is to create DFAs that can fit in memory, thus
DFA O(1) O(∑n) O(1) O(∑nm) making a fast DFA-based approach feasible. We first define
There is a middle ground between DFA and NFA called a few concepts key to DFA construction in the context of
lazy DFA. Lazy DFA are designed to reduce memory packet payload scanning in Section 3.1. We then analyze the
consumption of conventional DFA [12, 15]: a lazy DFA size of DFAs for typical payload scanning patterns in Section
keeps a subset of the DFA that matches the most common 3.2. Although theoretical analyses [12, 14] have shown that
strings in memory; for uncommon strings, it extends the DFAs are subject to exponential blow-up, here, we identify
subset from the corresponding NFA at runtime. As such, a specific structures that can lead to exponential growth of
lazy DFA is usually much smaller than the corresponding DFAs. Based on the insights from this analysis, in Section
fully-compiled DFA and provides good performance for 3.3, we propose pattern rewrite techniques that explore the
common input strings. Bro intrusion detection systems [3] possibility of trading off exhaustive pattern matching (which
adopt this approach. However, malicious senders can easily real-world applications often allow) for memory efficiency.
construct packets that keep the system busy and slow down Finally, we offer guidelines to pattern writers on how to write
the matching process. patterns amenable to efficient implementation in Section 3.4.
Field Programmable Gate Arrays (FPGAs) provide a
high degree of parallelism and thus can be used to speed up 3.1 Design Considerations
the regular expression matching process. There are existing Although regular expressions and automata theory can be
FPGA solutions that build circuits based on DFA [16] or directly applied to packet payload scanning, there is a
NFA [17-19]. These approaches are promising if the extra noticeable difference in between. Most existing studies on
FPGA hardware can be embedded in the packet processors. regular expressions focus on a specific type of evaluation,
FPGAs, however, are not available in many applications; in that is, checking if a fixed length string belongs to the
language that a regular expression defines. More specifically,
3
a fixed length string is said to be in the language of a regular search starts from the beginning of the input, reading
expression, if the string is matched from start to end by a characters until (1) it has reported all matches (if exhaustive
DFA corresponding to that regular expression. In contrast, in matching is used) or one match (if non-overlapping matching
packet payload scanning, a regular expression pattern can be is used), or (2) it has reached the end of the input. In the
matched by the entire input or specific substrings of the input. former case, the new search will start from the next character
Without a priori knowledge of the starting and ending in input (if exhaustive matching is used) or from the
positions of those substrings, DFAs created for recognizing character after the reported match (if non-overlapping
all substring matches can be highly complex. matching is used). In the latter case, a new search is initiated
For a better understanding, we next present a few from the next character in input. This style of repeated
concepts pertaining to the completeness of matching results scanning using DFA is commonly used in language parsers.
and the DFA execution model for substring matching. However, it is inefficient for packet payload scanning where
Completeness of matching results the chance of the packet payload matching a particular
Given a regular expression pattern and an input string, a pattern is low (such inefficiency is verified in Section 5.3.3).
complete set of results contains all substrings of the input One-pass search. In the second approach, “.*” is pre-
that the pattern can possibly match. For example, given a pended to each pattern without ‘^’, which explicitly states
pattern ab* and an input abbb, three possible matches can be that the pattern can be matched anywhere in the input. Then a
reported, ab, abb, and abbb. We call this style of matching DFA is created for the extended pattern. As the input is
Exhaustive Matching. It is formally defined as below: scanned from start to end, the DFA can recognize all
substring matches that may start at different positions of the
Exhaustive Matching: Consider the matching process M as a
function from a pattern P and a string S to a power set of input. Using one pass search, this approach can truly achieve
S, such that, M(P, S) = {substring S' of S| S' is accepted O(1) computation cost per character, thus suitable for
networking applications. To achieve high scanning rate, we
by the DFA of P}.
adopt this approach in the rest of the study.
In practice, it is expensive and often unnecessary to
report all matching substrings, as most applications can be 3.2 DFA Analysis for Individual Regular Expressions
satisfied by a subset of those matches. Therefore, we propose Next, we study the complexity of DFA for typical patterns
a new concept, Non-overlapping Matching, that relaxes the used in real-world packet payload scanning applications such
requirements of exhaustive matching. as Linux L7-filter, Snort, and Bro. The study is based on the
Non-overlapping Matching: Consider the matching process use of exhaustive matching and one-pass search. Table 4
M as a function from a pattern P and a string S to a set of summarizes the results.
strings, specifically, M(P, S) = {substring Si of S| ∀ Si, Sj • Explicit strings generate DFAs of length linear to the
accepted by the DFA of P, Si ∩ Sj = φ }. number of characters in the pattern.
If a pattern appears in multiple locations of the input, this • If a pattern starts with ‘^’, it creates a DFA of polynomial
matching process reports all non-overlapping substrings that complexity with respect to the pattern length k and the
match the pattern. Revisit our example above. For the pattern length restriction j. Our observation from the existing
ab* and the input abbb, the three matches overlap by sharing payload scanning rule sets is that the pattern length k is
the prefix ab. For this example, non-overlapping matching usually limited but the length restriction j can reach
will report one match instead of three. hundreds or even thousands. Therefore, Case 4 can result
For most payload scanning applications, we expect that in a large DFA because it has a factor quadratic in j.
non-overlapping matching would suffice, as those • Patterns starting with “.*” and having length restrictions
applications are mostly interested in knowing if certain (Case 5) cause the creation of DFA of exponential size.
attacks or application layer patterns appear in a packet. In Table 4. Analysis of patterns with k characters
fact, most existing scanning tools like grep and flex and Pattern features Example # of states
systems like Snort [2] and Bro [3] implement special cases of 1. Explicit strings with k characters ^ABCD k+1
non-overlapping matching such as left-most longest .*ABCD
matching or left-most shortest matching. As we shall show 2. Wildcards ^AB.*CD k+1
.*AB.*CD
later this section, non-overlapping matching can be exploited
3. Patterns with ^, a wildcard, and a ^AB.{j+}CD O(k*j)
to construct more memory-efficient DFAs. length restriction j ^AB.{0, j}CD
DFA execution model for substring matching ^AB.{j}CD
In the following discussion, we focus on patterns without ‘^’ 4. Patterns with ^, a class of characters
^A+[A-Z]{j}D O(k+j2)
attached at the beginning. Recall that for such patterns, there overlaps with the prefix, and a length
restriction j
is no prior knowledge of whether/where a matching substring
5. Patterns with a length restriction j, .*AB.{j}CD O(k+2j)
may appear. To handle these patterns, two types of DFAs can where a wildcard or a class of .*A[A-Z]{j+}D
be created with different execution models: characters overlaps with the prefix
Repeated searches. A DFA can be created directly from a Next, we explain the two cases of large DFA sizes,
pattern using standard DFA construction techniques [14]. To namely, Case 4 and Case 5 of Table 4, in more detail.
find the set of matching substrings (using either exhaustive or Case 4: DFA of Quadratic Size
non-overlapping matching), the DFA execution needs to be A common misconception is that patterns starting with ‘^’
augmented with repeated searches of the input: An initial create simple DFAs. However, we discover that even with
4
‘^’, classes of characters that overlap with the prefix pattern post processing after identifying the prefix “SEARCH”. This
can still yield a complex DFA. Consider the pattern approach does not solve the problem because every packet
^B+[^\n]{3}D, where the class of character [^\n] denotes any (even normal traffic) with the prefix will incur the counting
character but the return character (\n). Its corresponding DFA process. In addition, intruders can easily construct packets
has a quadratic number of states, as shown in Figure 1. The with multiple (different) prefixes to invoke many requests for
quadratic complexity comes from the fact that the letter B such post processing.
overlaps with the class of character [^\n] and, hence, there is Case 5: DFA of Exponential Size
inherent ambiguity in the pattern: A second B letter can be Many payload scanning patterns contain an exact distance
matched either as part of B+, or as part of [^\n]{3}. requirement. Figure 2 shows the DFA for an example pattern
Therefore, if an input contains multiple Bs, the DFA needs to “.*A..CD”. An exponential number of states (22+1) are needed
remember the number of Bs it has seen and their locations in to represent these two wildcard characters. This is because
order to make a correct decision with the next input we need to remember all possible effects of the preceding As
character. If the class of characters has length restriction of j as they may yield different results when combined with
bytes, DFA needs O(j2) states to remember the combination subsequent inputs. For example, an input AAB is different
of distance to the first B and the distance to the last B. from ABA because a subsequent input BCD forms a valid
pattern with AAB (AABBCD), but not so with ABA
(ABABCD). In general, if a pattern matches exactly j
arbitrary characters, O(2j) states are needed to handle the
exact j requirement. This result is also reported in [12].
Similar results apply to the case where the class of characters
overlaps with the prefix, e.g., “.*A[A-Z]{j}D”.
7
leading to the individual DFA, a new accepting state, and
two ε edges from the DFA accepting states to the new
accepting state, as shown in Figure 9. Then we run the NFA
to DFA conversion algorithm and the DFA minimization
algorithm to obtain the composite DFA.
ε ε
ε ε
Figure 7. A DFA for pattern .*AB.*CD and .*EF.*GH
Figure 9. Composite NFA for two DFAs
4.2 Interactions of Real-world Regular Expressions We use the information on pairwise interaction to group a
We study the pattern interactions of the Linux L7-filter [1] in set of m regular expressions. The intuition is that if there is
this section. If 70 patterns are compiled separately into 70 no interaction between any pair selected from R1, R2, and R3,
DFAs, each DFA has tens to hundreds of states. The total the composite DFA of R1, R2, R3 is not likely to exceed the
number of states is 3533. When we start to group multiple sum of individual ones. We validate this point using
patterns into a composite DFA (we select patterns with a empirical results in Section 5.3.1.
random order), the processing complexity decreases. We devise grouping algorithms both for multi-core
However, the total number of DFA states (i.e., the sum of the processor architecture, where groups of patterns can be
composite DFA and those ungroup ones) grows over 136,786 processed in parallel among different processing units, and
with just 40 patterns, as illustrated by the increasing dotted for general processor architecture, where the DFA for one
line in Figure 8. We could not add more patterns into the group corresponds to one process or thread. Next, we present
composite DFA because it exceeded the memory limit in the the algorithm for the former architecture first and then the
test machine that we used (1.5 GB). However, not all patterns algorithm for the latter.
cause significant DFA growth. Only some patterns (e.g., In multi-core architecture, there are multiple parallel
pattern 12, 37, and 38 as shown in Figure 8) lead to processing units. Their number is usually limited, e.g., 16 in
significant growth of the DFA. These patterns all contain Intel IXP2800 NPU, which is much smaller than the number
large numbers of wildcards, and sometimes have classes of of patterns. Hence, one DFA per pattern per processing unit
characters. For example, pattern 12 contains a fixed length is infeasible. Our goal is to design an algorithm that divides
(20) of wildcards, pattern 37 contains three unrestricted regular expressions into several groups, so that one
wildcards (“.*”), and pattern 38 contains 19 classes of processing unit can run one or several composite DFAs. In
characters, 4 unrestricted wildcards, and 8 length restricted addition, the size of local memory of each processing unit is
wildcards. quite limited. For example, the newly architected IBM cell
60000
processor has 8 synergistic processor elements, each with
128KB local memory [23]. Hence, we need to keep grouping
Total Num ber of States
50000
40000 patterns until they meet the local memory limit. The pseudo-
30000
code of the algorithm is provided below.
In this algorithm, we first compute the pairwise
20000
interaction of regular expressions. With this pairwise
10000
information, we construct a graph with each pattern as a
0 vertex and an edge between patterns Ri and Rj if they interact
with each other. Using this graph, we can start with a pattern
1 6 11 16 21 26 31
13