Content uploaded by Tahir Ahmad
Author content
All content in this area was uploaded by Tahir Ahmad on Jul 03, 2018
Content may be subject to copyright.
Content uploaded by Tahir Ahmad
Author content
All content in this area was uploaded by Tahir Ahmad on Jun 21, 2018
Content may be subject to copyright.
Performance Analysis of Non-cryptographic Hash Functions for real-time storage
and lookup of URLs
Tahir Ahmad, Usman Younis
School of Electrical Engineering and Computer Science (SEECS),
National University of Sciences and Technology (NUST),
Islamabad, Pakistan.
Email: {11msccstahmad,usman.younis}@seecs.edu.pk
Abstract—In this work, the performance of various non-
cryptographic hash functions has been investigated to identify
their random nature when employed in the implementation
of hash tables for real-time storage and lookup of uniform re-
source locators. The performance analysis is performed mainly
using statistical studies on the sequences generated using five
widely used non-cryptographic hash functions: 1) CRC, 2)
Adler, 3) FNV, 4) DJBX33A, and 5) Murmur. The comparative
analysis of tested non-cryptographic hash functions shows
that the Adler hash function is not suitable for hash table
implementation, whereas, the rest of non-cryptographic hash
functions exhibit similar and better randomizing features which
make them an attractive choice for hash table implementation.
The results of these statistical studies have been verified by the
implementation of hash table using these non-cryptographic
hash functions. The implementation results show that the
average number of probes for Adler based hash table varies
between 1.25 and 2.75 for different load factors and hash table
sizes; whereas, for the rest of non-cryptographic hash functions
the average number of probes in a hash table is ∼1, which
is highly desirable for real-time network applications. Thus
proving that 1) CRC, 2) FNV, 3) DJBX33A, and 4) Murmur
non-cryptographic hash functions are good choices for hash
table based implementation for real-time storage and lookup
of uniform resource locators.
Keywords-Non-cryptographic Hash Functions; Randomiza-
tion Functions; Hash Table; Real-time Network Applications;
I. INTRODUCTION
Non-cryptographic hash functions (NCHFs), due to their
computational efficiency, are widely used in many comput-
ing applications [3], [4], [8], [11], [17], [20]. This includes
hash table implementation in which NCHFs make it possible
to perform lookup operation in O (1) time irrespective of the
table size [9], [10], [15]. Additionally, the performance of
a hash table depends upon the random output of the hash
function which is employed in its implementation. Random-
izing functions are generally good NCHFs, but not the vice
versa. Therefore, the performance of NCHFs as randomizing
functions have been investigated in this work. Exhaustive
test runs, identified in National Institute of Standards and
Technology (NIST) statistical suite, have been executed on
five NCHFs used in hash table implementation. Important
features which determine the quality of a NCHF are collision
resistance, distribution of output, avalanche effect, and speed
[1], [6], [7], [8], [12]. Additionally, all of these features are
data-dependent [19]. It is required of a NCHF to produce
the output which follows a uniform distribution [8], [12].
The function must generate each possible output value with
equal probability, and it must be independent of the input
distribution [12].
The focus of this work is to evaluate the randomness and
uniform distribution of mapping done by NCHFs for input
uniform resource locators (URLs). In our proposed hash
table based approach for URL storage and lookup, the entries
are stored as a key-value pair. We are setting URL as a key,
and the hash of a key provides the address of a slot where
entries are required to be stored. An associated problem with
the hash functions is the collision which occurs when the
calculated hash of two distinct keys map to a same slot.
This is resolved by finding an alternate slot for the storage of
collided entry, called probing. The strength of our proposed
URL storage and lookup lies in the random outcome of
a hash function. A suitable hash function provides unique
hashes which minimizes the probing, and this ensures O (1)
average time for URL storage and lookup.
A hash function used in real-time network applications
can be categorized as Checksum, cyclic redundancy check
(CRC), and NCHF. We have analyzed following 32-bit hash
functions in this work:
1) CRC-32 hash function (CRC hash function) [5], [13],
[8].
2) Adler-32 hash function (Checksum hash function) [5],
[16].
3) DJBX33A Hash function (non-cryptographic hash
function) [4].
4) Fowler-Noll-Vo (FNV) hash function (non-
cryptographic hash function) [2], [4].
5) and, Murmur hash function (non-cryptographic hash
function) [1], [4].
In our case, input to a hash function is a list containing
unique URLs. A total of 2744529 URLs are captured at the
squid proxy server of the School of Electrical Engineering
978-1-4799-2293-2/13 $31.00 2013 IEEE
DOI 10.1109/FIT.2013.21 72
2013 11th International Conference on Frontiers of Information Technology
and Computer Science (SEECS), at various times, and saved
in six different files.
The list of unique URLs is given as an input to each
hash function, and the hashed outputs are stored in ASCII
format. Each output file is further divided in fifteen sub files,
containing 106bytes, in order to repeat the statistical tests
fifteen times using distinct datasets.
II. STATI ST ICA L TESTS
In order to assess the randomness of a hash function,
a set of statistical tests are proposed by National Institute
for Standards and Technology (NIST) [14], [18]. The NIST
statistical framework is based upon the null hypothesis H0,
i.e., the sequence under test is random. On the other hand,
the alternate hypothesis H𝑎is that the sequence being tested
is not random. Type-I error occurs for a random data if the
alternative hypothesis is true, i.e., for a random sequence,
H0is rejected, and H𝑎is accepted.
A statistical test, which is performed in order to assess
the randomness of a hash function, results in P-values. Each
P-value is a probability that the sequence under test is more
random than the sequence which would have been generated
by a prefect random number generator. A P-value of 1
means that the sequence under test is completely random;
however, a P-value of 0 means that the sequence under test
is not random at all. A significance level 𝛼is defined as
the probability of concluding that a random sequence under
observation is not random, i.e., the probability of Type-I
error [18]. For a fixed significance level, a certain percentage
of P-values are expected to indicate failure. In our case, we
have fixed the significance level to 0.01, which means that
there is about 1% chance that the sequences under test might
fail. A sequence passes a statistical test whenever the P-value
≥𝛼, and fails otherwise.
III. EMPIRICAL RESULTS
The NIST suite is developed to test the randomness of a
binary sequence produced by a random number generator,
which in our case is the hash function. The NIST test suite
focuses on various types of non-random behaviors that can
exist in a binary sequence. The required and the used length
of an input bit sequence for each test is given in Table I.
In our case, each of the five tests has been executed on
one thousand distinct m-bit sequences, which have been
individually obtained from fifteen ASCII files of the size
106bytes containing hashed output.
The number of samples produced by a specific hash
function is termed as the sample size. It is required to use a
sample size as per NIST recommendations for the evaluation
based upon P-value proportions. In our case, as shown in
Table I, we have used the sample size of one thousand bits,
i.e., m = 1000. If for a given test, P-value is greater than or
equal to 0.01, the test will be successful and sequence under
test should be considered as random.
In order to interpret the outcome of a statistical test,
following two approaches as per NIST standard have been
employed [18]:
1) Proportion of sequences passing a test
Given the statistical results of a test performed, com-
pute the proportion of sequences that have passed. The
resultant P-value of a specific test is compared with a
statistical threshold value (T-value), defined as:
T-va lue =(1−𝛼)−3√𝛼(1 −𝛼)
𝑚(1)
If P-value is greater than or equal to the threshold
value, test is considered to be successful. For the
significance level 𝛼= 0.01, and m = 1000, the obtained
T-value is 0.9805607. If at least 980 sequences out of
1000 sequences pass the test, the test is considered as
successful. However, if the the test results are below
the threshold levels, relative comparison among the
output of hash functions are performed.
2) Uniform distribution of P-values
The second approach proposed by NIST provides
further in-depth analysis of the performed statistical
tests. Uniformity of the hash functions is ensured by
a uniform distribution of P-values. This can be visually
illustrated using a histogram, in which the interval
between zero and one is divided into ten sub-intervals,
and the P-values that lie within each sub-interval are
counted and displayed.
A. The Frequency (Monobit) Test
This test focuses on the frequency of zeros and ones in the
entire binary sequence [18]. The total number of zeros and
ones in a sequence must be equally distributed for a truly
random sequence. The P-value in this test is calculated using
the cumulative value S𝑛, which is the sum of the bits in an
input bit sequence. It can have both positive and negative
values. A large positive value of S𝑛indicates more number
of ones in the input bit sequence, and a large negative value
of S𝑛indicates more number of zeros.
It can be seen in Table II that the proportion of sequences
passing the frequency test is almost below the threshold
value, i.e., T-value = 0.9805607, calculated using equation 1.
This shows that the frequency of zeros and ones in the entire
bit sequence, under test, are not uniform. Additionally, the
relative comparison of different hash functions shows that
the percentage of sequences passing the frequency test lie
between 96-98% for CRC, DJBX33A, FNV, and Murmur.
However, Adler hash function has not been able to achieve
this performance.
Fig. 1 shows the histogram of P-values for the frequency
test of all the hash functions. It is observed from the
histogram that the distribution of zeros and ones is not
uniform. In sub-interval 8, we have no frequency count for
all the hash functions. The standard deviation of all the hash
73
Tab le I
LENGTHS OF THE BIT SEQUENCES WHICH HAVE BEEN EMPLOYED IN VARIOUS STATISTICAL TESTS.
Statistical tests Required length of
input bit sequences
(n) (bits)
Used length of input
bit sequences (bits)
Recommended sam-
ple size (m) (bits)
Used Sample size
(bits)
Frequency test n≥100 100 m≥100 1000
Runs test n≥100 100 m≥100 1000
Cusums test n≥100 100 m≥100 1000
Longest run test n≥128/6272/750000 128 m≥100 1000
Spectral test n≥1000 1000 m≥100 1000
Tab le I I
EMPIRICAL RESULTS FOR PROPORTION OF SEQUENCES PASSING VARIOUS STATISTICAL TESTS.
Hash functions Frequency test Runs test Cusums test Longest run test Spectral test
CRC 0.9663 0.9894 0.9794 0.9812 0.9824
Adler 0.9597 0.9824 0.9741 0.9599 0.9759
DJBX33A 0.9697 0.9902 0.9808 0.9801 0.9835
FNV 0.9703 0.9913 0.9818 0.9800 0.9838
Murmur 0.9690 0.9916 0.9812 0.9811 0.9834
functions for the frequency test is on a higher side, i.e., it
is ranging between 43 and 46.
CRC DJBX33A Adler FNV Murmur
0
20
40
60
80
100
120
140
160
180
Frequency Counts
Probability Components of Hash Functions
0.0- 0.1
0.1- 0.2
0.2- 0.3
0.3- 0.4
0.4- 0.5
0.5- 0.6
0.6- 0.7
0.7- 0.8
0.8- 0.9
0.9- 1.0
Figure 1. Histogram of P-values for the Frequency (Monobit) test.
B. The Runs Test
This test identifies the runs of zeros and ones of various
lengths across a random sequence [18]. A “run” is defined
as an uninterrupted sequence of identical bits. The rate of
oscillations between zeros and ones is monitored in order to
determine the nature of randomness. The reference distribu-
tion for this test statistic is a “chi-squared” 𝜒2distribution.
An input bit-stream with a high degree of oscillations
results in a higher P-value, and vice versa. Table II shows
that the Adler hash function has a lower oscillations rate,
and hence, the passing proportion lies below the threshold
limit in some tests. The rest of the hash functions, i.e., CRC,
DJBX33A, FNV, and Murmur, have a fast variation between
zeros and ones, which results in a higher P-value. Therefore,
the percentage of sequences passing the runs test for these
hash functions lies above the threshold value.
Similar to frequency test, the histogram of P-values for
the runs test performed using the output of all the hash
functions. It is observed that the distribution between zeros
and ones is quite uniform. The standard deviation of all the
hash functions for the runs test ranges between 8 and 14.
CRC hash function has the least standard deviation, which is
8.170, and the Adler hash function has the highest standard
deviation, which is 13.428.
C. Test for the Longest-Run-of-Ones in a block
In this test, an input bit sequence is initially divided into
M-bit blocks, and then for each block, the test is executed
[18]. The purpose of this test is to determine whether the
length of the longest-run-of-ones, within the test sequence,
is consistent with the length of the longest-run-of-ones
which is expected of a true random sequence. The reference
distribution for this test is a “chi-squared” 𝜒2distribution.
The P-value, which is calculated using the value of 𝜒2(obs),
determines how well the length of a longest run matches the
expected value. A high value of 𝜒2(obs) indicates that the
tested sequence contains large clusters of ones, which results
in a low P-value.
It can be seen in Table II that the Adler hash function has a
less proportions of sequences passing this test. This indicates
that the output of Adler hash function contains large clusters
of ones. The performance of other hash functions, i.e.,
CRC, DJBX33A, FNV, and Murmur, is observed to be quite
similar.
Similar to the previous tests, the histogram of P-values
for the longest-run-of-ones in a M-bit block test has been
computed. It is observed that the distribution of zeros and
74
ones is not uniform for all the hash functions. The standard
deviation of all the hash functions ranges between 24 and 54.
FNV hash function has the least standard deviation, which
is 24.406, and the Adler hash function has the most standard
deviation, which is 53.935.
D. The Discrete Fourier Transform (Spectral) Test
The purpose of this test is to identify periodic features
in a test sequence that would indicate a deviation from the
randomness [18]. The reference distribution for this test is
a normal distribution. Additionally, the P-value in this test
is calculated using the normalized difference 𝑑between the
observed and the expected number of frequency components.
A small value of the normalized difference 𝑑is desirable,
which means that there is an acceptable number of peaks
above the threshold value.
It can be seen in Table II that the proportion of sequences
passing this test are less in the case of Adler hash function
as compared to other non-cryptographic hash functions. This
is caused by a large number of peaks below the threshold,
resulting in a higher normalized difference 𝑑. The rest of the
hash functions have similar periodic features.
The histogram of P-values for the Discrete Fourier Trans-
form test of all the hash functions has been computed.It is
observed that the standard deviation of all the hash functions
is on a higher side, ranging between 76 and 80.
E. The Cumulative Sums (Cusums) Test
This test looks for a large number of zeros and ones oc-
curring at the start and the end of an input binary sequence.
Additionally, it identifies the intermixing of zeros and ones
across the entire bit sequence [18]. The reference distribution
for this test is a normal distribution. This test is performed
in forward (Mode 0), and backward (Mode 1), directions in
order to determine the number of zeros and ones at the start,
and at the end, of an input bit sequence, respectively.
It can be seen in Table II that the proportion of se-
quences generated by Adler hash function have not been
able to achieve the required threshold of passing this test
as compared to other non-cryptographic hash functions.
Additionally, the rest of the hash functions, i.e., CRC,
DJBX33A, FNV, and Murmur, have a similar test statistics.
It is observed in the histogram of P-values for the
Cumulative Sums test of all the hash functions that the
distribution between zeros and ones is not uniform. The
standard deviation of all the hash functions for Cumulative
Sums test ranges between 30 and 36.
IV. ANALYSIS OF THE EMPIRICAL RESULTS
A. Success rate based upon P-values
Success rate of the tests are based upon the empirical
results calculated in previous section. Table III shows the
success rate of the tests performed for all hash functions.
Adler hash function is found to be a non-uniformly dis-
tributed hash function, whereas, for the rest of hash functions
(CRC, DJBX33A, FNV, and Murmur) the outcomes are
quite close, but inconclusive. Further in-depth analysis is
required to decide a hash function with better randomizing
features. For each hash function the percentage of passing a
specific test is calculated as:
Success Rate =Number of successful tests
Total number of tests ×100 (2)
B. Uniform distribution of P-values
The standard deviation of the distribution of P-values
in sub-intervals can be used as a metric to analyze the
uniformity in the output of a hash function. The lesser the
standard deviation, the more uniformly distributed is the
output of a hash function.
Fig. 2 shows the standard deviation of the distribution
of P-values for all the hash functions. It is evident that
outputs of Adler hash function are less uniformly distributed,
however, the distribution of P-values for the rest of the
hash functions (CRC, DJBX33A, FNV and Murmur) is quite
similar.
Runs F requency Longest Run Cusums S pectral
0
10
20
30
40
50
60
70
80
Standard Deviation of the P-values D istribution
Statistical Tests
CRC
DJBX33A
Adler
FNV
Murmur
Figure 2. Uniform distribution of P-values.
V. V ERIFICATION OF STATISTICAL RESULTS
The results of statistical tests are verified by the imple-
mentation of hash table using respective non-cryptographic
hash functions. The hash table is populated with URL
entries. The number of probes for each entry in hash table
is computed. Various tests are performed for computing the
average number of probes by varying the hash table size and
load factor. The load factor is computed as:
Load factor =Number of URL entries in Hash Table
Total size of Hash Table (3)
To avoid wastage of valuable storage, the hash table is
initialized with 8 slots. When the load factor reaches 0.666,
75
Table III
SUCCESS RATE OF HASH FUNCTIONS.
Hash functions Frequency test Cusums test Runs test Longest run
test
Spectral test Mean success
rate
CRC 0.00% 40.00% 100.00% 73.33% 73.33% 57.33%
Adler 0.00% 33.33% 73.33% 0.06% 13.33% 24.01%
DJBX33A 0.00% 60.00% 100.00% 53.33% 80.00% 58.67%
FNV 0.06% 66.66% 100.00% 33.33% 80.00% 56.01%
Murmur 0.06% 53.33% 100.00% 53.33% 80.00% 57.34%
it resizes. To keep the resize operation memory efficient, it
follows the following conditions:
If URL entries <50K; Then hash table size ×4
If URL entries >50K; Then hash table size ×2
URL storage in our hash table is performed by initially
computing the hash of a URL entry, the computed hash is
then truncated to get the index of a slot depending upon
the current size of hash table. If the slot is vacant the entry
is stored in it, in case it is occupied, a backup recursive
algorithm is executed by utilizing the unused upper bits to
find a secondary storage location. The process repeats until
a vacant slot is found. If the first slot calculated is vacant the
number of probes required to retrieve it will be 1, whereas,
the number of probes will vary depending upon the number
of times the recursive function is called.
The performance of hash Table is dependent upon the
load factor. The greater the load factor the greater will be
number of probes for each URL entry. In Fig. 3, where
the load factor is 0.20, the average number of probes is
∼1.15 for hash table size up to 2048 entries. As the size of
hash table increase, the performance of Adler Hash function
falls and its average number of probes reaches 2.112. The
performance of the rest of hash functions (CRC, FNV,
Murmur and DJBX33A) remains unchanged.
Adler CRC DJBX33A F NV MURMUR
0.0
0.5
1.0
1.5
2.0
2.5
3.0
3.5
4.0
4.5
5.
0
Average No. of Probes
Hash Functions
512
2048
8192
32768
131072
Figure 3. Average Number of Probes for 0.20 Load Factor.
Fig. 4 shows the average number of probes taken by
each hash function at load factor of 0.40. It can be seen
that average number of probes for all the hash functions
are around 1.25 up to hash table size of 2048 entries. The
performance for all the hash functions remains the same
except Adler Hash Function as the average number of probes
rises to 2.75 with increasing the hash table size.
Adler CRC DJBX33A F NV MURMUR
0.0
0.5
1.0
1.5
2.0
2.5
3.0
3.5
4.0
4.5
5.
0
Average No. of Probes
Hash Functions
512
2048
8192
32768
131072
Figure 4. Average Number of Probes for 0.40 Load Factor.
Fig. 5 shows the average number of probes taken by
each hash function at the load factor of 0.60. It is observed
that the variations in average number of probes for Adler
hash function are quite large. The average number of probes
for the rest of hash functions (CRC, FNV, Murmur and
DJBX33A) are quite similar. The average number of probes
for hash table size 32768 is 1.5, but it gets better as the
table resizes itself as the number of truncated bits are raised
from 15 to 17 which adds more randomness and the average
number of probes falls to 1.0.
VI. CONCLUSION
The empirical results of statistical studies of non-
cryptographic hash functions and their hash table based
implementation reveal that Adler hash function is a weak
randomizing function and has poor performance in hash
table based implementations. Whereas, the rest of NCHFs
(CRC, DJBX33A, FNV, and Murmur) exhibit similar and
better statistical properties, and they can be used in hash
table based implementations for real-time storage and lookup
of URLs.
76
Adler CRC D JBX33A FNV MUR MUR
0.0
0.5
1.0
1.5
2.0
2.5
3.0
3.5
4.0
4.5
5.
0
Average No. of Probes
Hash Functions
512
2048
8192
32768
131072
Figure 5. Average Number of Probes for 0.60 Load Factor.
ACKNOWLEDGMENT
The authors would like to thank Information Technology
Services (ITS) staff of SEECS, NUST, Islamabad specif-
ically Mr. Ajmal Farooq (System Administrator) and Mr.
Abdel Wahab Khan (Network Administrator) for helping in
data capturing at SEECS edge router and providing access
logs of SEECS squid proxy server.
REFERENCES
[1] A. Appleby, “Murmurhash 2.0,” 2013. [Online]. Available:
http://code.google.com/p/smhasher/
[2] D. Eastlake, G. Fowler, K.-P. Vo, and L. Noll, “The fnv non-
cryptographic hash algorithm,” 2012. [Online]. Available:
http://tools.ietf.org/html/draft-eastlake-fnv-03
[3] C. Estbanez, J. C. Hernndez-Castro, A. Ribagorda, and
P. Isa s i , Finding state-of-the-art non-cryptographic hashes
with genetic programming. Springer, 2006, pp. 818–827.
[4] C. Estbanez, Y. Saez, G. Recio, and P. Isasi, “Performance of
the most common non-cryptographic hash functions,” Journal
of Software: Practice and Experience (2013), 2013.
[5] J.-l. Gailly and M. Adler, “Zlib compression library,” 2013.
[Online]. Available: www.zlib.net
[6] M. T. Goodrich and R. Tamassia, Algorithm Design: Founda-
tion, Analysis and Internet Examples. John Wiley & Sons,
2006.
[7] C. Henke, C. Schmoll, and T. Zseby, “Empirical evaluation
of hash functions for multipoint measurements,” ACM SIG-
COMM Computer Communication Review, vol. 38, no. 3, pp.
39–50, 2008.
[8] N. Hua, E. Norige, S. Kumar, and B. Lynch, “Non-crypto
hardware hash functions for high performance networking
asics,” in Proceedings of the 2011 ACM/IEEE Seventh Sym-
posium on Architectures for Networking and Communications
Systems. IEEE Computer Society, pp. 156–166.
[9] K. Huang, G. Xie, R. Li, and S. Xiong, “Fast and determin-
istic hash table lookup using discriminative bloom filters,”
Journal of Network and Computer Applications, vol. 36,
no. 2, pp. 657 – 666, 2013.
[10] B. Jenkins, “A hash function for hash table lookup,”
Dr. Dobbs Journal (1997), 1997. [Online]. Available:
http://burtleburtle.net/bob/hash/doobs.html
[11] J. Karasek, R. Burget, and O. Morsky, “Towards an automatic
design of non-cryptographic hash function,” in Telecommuni-
cations and Signal Processing (TSP), 2011 34th International
Conference on. IEEE, pp. 19–23.
[12] D. E. Knuth, “Sorting and searching (the art of computer
programming volume 3),” 1973.
[13] P. Koopman, “32-bit cyclic redundancy codes for internet
applications,” in Dependable Systems and Networks, 2002.
DSN 2002. Proceedings. International Conference on. IEEE,
pp. 459–468.
[14] W. ling Chang, B. Fang, X. chun Yun, S. Wang, and
X.-Z. Yu, “Randomness testing of compressed data,”
CoRR, vol. abs/1001.3485, 2010. [Online]. Available:
http://arxiv.org/abs/1001.3485
[15] W. D. Maurer and T. G. Lewis, “Hash table methods,” ACM
Computing Surveys (CSUR), vol. 7, no. 1, pp. 5–19, 1975.
[16] T. Maxino, “Revisiting fletcher and adler checksums,” 2006.
[Online]. Available: http://repository.cmu.edu/isr/690/
[17] B. J. McKenzie, R. Harries, and T. Bell, “Selecting a hashing
algorithm,” Journal of Software: Practice and Experience,
vol. 20, no. 2, pp. 209–224, 1990.
[18] A. Rukhin, J. Soto, J. Nechvatal, M. Smid, and E. Barker, “A
statistical test suite for random and pseudorandom number
generators for cryptographic applications,” DTIC Document,
Tech. Rep., 2010.
[19] J. K. M. S. U. Zaman and R. Ghosh, “A review
study of nist statistical test suite: Development of an
indigenous computer package,” CoRR, vol. abs/1208.5740,
2012. [Online]. Available: http://arxiv.org/abs/1208.5740
[20] M. R. J. Zobel, “Performance in practice of string hashing
functions,” in Database Systems for Advanced Applications’
97: Proceedings of the 5th International Conference on
Database Systems for Advanced Applications Melbourne,
Australia April 1-4, 1997, vol. 6. World Scientific Publishing
Company Incorporated, p. 215.
77