Hi,
  here it is; implemented, documented, unit-tested, build-tested.
Permission to merge (as soon as the build farm confirms portability) ?

On Mon, Jul 27, 2015 at 1:50 AM, Amos Jeffries <[email protected]> wrote:

> On 27/07/2015 8:47 a.m., Kinkie wrote:
> > On Sun, Jul 26, 2015 at 10:23 PM, Amos Jeffries <[email protected]>
> > wrote:
> >
> >> On 27/07/2015 4:48 a.m., Kinkie wrote:
> >>> HI,
> >>>   the low-hanging fruits from Coverity's analysis have been picked, now
> >>> working on somewhat more complex fixes.
> >>> The attached patch takes a hint from two benign coverity defects to:
> >>
> >>> - refactor Digest auth's field lookup table to use a std::map instead
> of
> >>> abusing httpHeaderFieldsInfo; this improves readability and size of the
> >>> code, and has the added small bonus of lowering the lookup cost from
> >> linear
> >>> to logarithmic
> >>>
> >>> the Digest code has been run-tested. I'd like feedback on its style, as
> >>> httpHeaderFieldsInfo is abused similarly elswehere and I'm considering
> to
> >>> apply it elsewhere as well; it can then be further refined to get O(1)
> >> via
> >>> a carefully-chosen hash (via std::unsorted_map)
> >>>
> >>
> >> My thoughts: (sorry if its a bit rambling)
> >>
> >> I dont like spawning lots of new classes for basic things. I know its
> >> essentially the C++ way. But applying pattern theory can go too far
> >> sometimes. And this patterns usage is one case where I can see exactly
> >> that happening.
> >>
> >> You have a struct, a class, an enum and array. Thats a lot of custom
> >> infrastructure just to represent a simple set of name:id. We could as
> >> easily have std::map<const char*, enum> holding that directly and avoid
> >> all the local types except enum.
> >>
> >> There are already 5 headers currently in Squid that need these same
> >> operations applied, and at least as many more that should but dont even
> >> use the current HttpHeaderFieldAttrs related types yet.
> >>
> >>
> >>
> >> struct HttpDigestFieldAttrs should be a template class so we dont have
> >> to re-implement a new little struct for each enum.
> >>
> >> BUT, notice that generalizing that same structure is also where the enum
> >> casting hack for HttpHeaderFieldAttrs comes from in the first place.
> >>  The probkem was template style breaks with C++03 compilers thinking all
> >> enums are of "int" type. Enter lots of repeated-instantiation complaints
> >> from dumb compilers.
> >>  I've not tried it with current C++11 compilers which are quite a bit
> >> smarter. It may work now (or not).
> >>
> >> If *that* can be solved then refactoring HttpHeaderFieldAttrs to a
> >> template is better way forward. Maybe followed by replacing or
> >> refactoring the HttpHeaderFieldInfo bits to avoid the performance
> >> problem you identified.
> >>
> >
> > Hi,
> >   no rambling, it's ok.
> > Actually, the performance improvement is just a nice byproduct, that's
> not
> > the objective at all, as I tried explaining in the merge proposal.
> > The actual problem I was addressing is the multiple C casts used to try
> and
> > coerce anything resembling a map<const char *, int> into an http/1 header
> > table, simply because there is code in squid which implements that map
> as a
> > header table (and rather naively, at that - linear scan is SO fifties ;)
> ).
> >
> > In fact, I argue that the proposed version is actually simpler than the
> > previous code; it can maybe even be simplified further but not much
> > further, let's go over it a bit toghether if you want.
>
> It looks that way for a single case. But multiply the number of
> type-specific little class and structs by 5, 10, 20 and the moving
> pieces get to be so many that we can't be sure all the manualy crafted
> bits actually all are doing the same thing.
> So when the compilers let that template simplfication happen we may
> discover multiple little hacks all over needing to fix.
>
> >
> > struct HttpDigestFieldAttrs is there simply to have a convenient
> > representation of the header table DigestAttrs. It makes no attempt to be
> > anything different. Can it be turned into
> > GenericInitializerFromStringTo<enum foo> ? Yes. Is it worth it for 3 LOC?
> > not so sure.
> >
> > DigestFieldslookupTable_t is probably what you are lashing out at, I bet.
>
> Its itching. :-)
>
> > Yes, it could be made generic and templatized to represent a
> > SBuf-to-anything with a static table initializer. I haven't tried that as
> > that may be PMO and it may preclude turning the index from a map to an
> > unordered_map with a table-specific hasher (gperf-generated or
> > hand-written, it's rather trivial to do it in this and in many other
> cases
> > we care about).
>
> I don't think that would be a problem. Since we dont need to change the
> stored node types under the maps feet. The type / header name is always
> pre-known, even when generating them dynamically as part of message
> parsing.
>
>
> Try these ...
>
> src/base/LookupTable.h:
>
> /**
>  * SBuf -> enum lookup table.
>  */
> template<class EnumType>
> class LookupTable {
> public:
>     typedef struct Record_ {
>         const char *name;
>         EnumType id;
>     } Record;
>
>     LookupTable(const EnumType theInvalid, const Record data[]) :
>         invalidValue(theInvalid)
>     {
>         for (auto i = 0; data[i].name != nullptr; ++i) {
>             lookupTable[SBuf(data[i].name)] = data[i].id;
>         }
>     }
>
>     EnumType lookup(const SBuf &key) const {
>         auto r = lookupTable.find(key);
>         if (r == lookupTable.end())
>             return invalidValue;
>         return r->second;
>     }
>
> private:
>     typedef std::map<const SBuf, EnumType> lookupTable_t;
>     lookupTable_t lookupTable;
>     EnumType invalidValue;
> };
>
>
>
>
> in src/auth/digest/Config.cc (or wherever else needs a table):
>
> static const LookupTable<http_digest_attr_type>::Record
>   DigestAttrs_Exp[] = {
>     {"username", DIGEST_USERNAME},
>     {"realm", DIGEST_REALM},
>     {"qop", DIGEST_QOP},
>     {"algorithm", DIGEST_ALGORITHM},
>     {"uri", DIGEST_URI},
>     {"nonce", DIGEST_NONCE},
>     {"nc", DIGEST_NC},
>     {"cnonce", DIGEST_CNONCE},
>     {"response", DIGEST_RESPONSE},
>     {nullptr, DIGEST_ENUM_END}
> };
>
> LookupTable<http_digest_attr_type>
> DigestFieldsLookupTable(DIGEST_ENUM_END, DigestAttrs_Exp);
>
>
>
> NOTE: range based for loops require begin/end operators. The default
> definitions dont work for templated things apparently.
> The constructor for loop is explicit now only because I could not be
> bothered creating new ones for the LookupTable<DataType>::Record type.
>
> Or we could be a bit fancy and use a while loop instead. Then magically
> derive the invalidValue from whatever array entry has the nullptr for
> its name.
>
>
> >
> > The patch has been build-tested successfully on all platforms we care
> > about, and run-tested (refactoring went in two phases: add new code,
> > assert() that it behaves like the old code and run-test, rip old code
> out).
> >
> > IMVHO HttpHeaderFieldAttrs is poor legacy, and deserves a thankful and
> > merciful eviction from our code-base :)
>
> Look closer. Its doing the exact same job as your HttpDigestFieldAttrs
> but for a different enum name. That job wont change so long as that
> other enum exists in Squid. And in your design we have a struct per enum
> either way.
>
> So applying this patch goes from x1 to x2 custom and slightly different
> instances of the pattern. They you get to the S-C header that needs its
> own version, now its got x3 instances. And so on.
>
> The code re-use is not a future need. Its already got somewhere between
> 4 and 10 use cases existing in Squid that need to be updated. Then
> theres the headers we have not implemented specific code for yet.
>
>
> With my above template the pattern remains the same. Even uses almost
> all your code. But we only define the custom enum + name array, and
> instantiate a LookupTable from those.
>
> PS. You can probably even remove HttpHeaderFieldAttrs,
> HttpHeaderFieldInfo and friends entirely in favour of LookupTable<>.
> Though I saw some stats gathering also going on when I looked at those.
> Which is just another reason for it all to be kept identical/consistent
> - counting digest field value sightings is an (un)important as cache
> control ones.
>
> Amos
>
>


-- 
    Francesco
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [email protected]
# target_branch: file:///home/kinkie/squid/workspace/trunk/
# testament_sha1: a22d9ee4ac41a348ffd9d4749118985db7b8112d
# timestamp: 2015-07-27 18:32:19 +0200
# base_revision_id: [email protected]\
#   laysak37yrb6qzdu
# 
# Begin patch
=== modified file 'src/Makefile.am'
--- src/Makefile.am	2015-07-21 13:56:20 +0000
+++ src/Makefile.am	2015-07-27 16:25:09 +0000
@@ -917,7 +917,8 @@
 	tests/testSBuf \
 	tests/testSBufList \
 	tests/testConfigParser \
-	tests/testStatHist
+	tests/testStatHist \
+	tests/testLookupTable
 
 if HAVE_FS_ROCK
 check_PROGRAMS += tests/testRock
@@ -3655,6 +3656,24 @@
 	$(COMPAT_LIB)
 tests_testStatHist_DEPENDENCIES = $(SQUID_CPPUNIT_LA)
 
+tests_testLookupTable_SOURCES = \
+	tests/testLookupTable.h \
+	tests/testLookupTable.cc \
+	tests/stub_debug.cc \
+	tests/stub_libmem.cc \
+	tests/stub_SBufDetailedStats.cc \
+	base/LookupTable.h \
+	String.cc \
+	$(SBUF_SOURCE)
+nodist_tests_testLookupTable_SOURCES = $(TESTSOURCES)
+tests_testLookupTable_LDFLAGS = $(LIBADD_DL)
+tests_testLookupTable_LDADD = \
+	base/libbase.la \
+	$(SQUID_CPPUNIT_LIBS) \
+	$(COMPAT_LIB) \
+	$(XTRA_LIBS)
+tests_testLookupTable_DEPENDENCIES = $(SQUID_CPPUNIT_LA)
+
 TESTS += testHeaders
 
 ## Special Universal .h dependency test script

=== modified file 'src/auth/digest/Config.cc'
--- src/auth/digest/Config.cc	2015-06-05 05:56:36 +0000
+++ src/auth/digest/Config.cc	2015-07-27 16:31:57 +0000
@@ -19,6 +19,7 @@
 #include "auth/digest/UserRequest.h"
 #include "auth/Gadgets.h"
 #include "auth/State.h"
+#include "base/LookupTable.h"
 #include "base64.h"
 #include "cache_cf.h"
 #include "event.h"
@@ -60,23 +61,25 @@
     DIGEST_NC,
     DIGEST_CNONCE,
     DIGEST_RESPONSE,
-    DIGEST_ENUM_END
-};
-
-static const HttpHeaderFieldAttrs DigestAttrs[DIGEST_ENUM_END] = {
-    HttpHeaderFieldAttrs("username",  (http_hdr_type)DIGEST_USERNAME),
-    HttpHeaderFieldAttrs("realm", (http_hdr_type)DIGEST_REALM),
-    HttpHeaderFieldAttrs("qop", (http_hdr_type)DIGEST_QOP),
-    HttpHeaderFieldAttrs("algorithm", (http_hdr_type)DIGEST_ALGORITHM),
-    HttpHeaderFieldAttrs("uri", (http_hdr_type)DIGEST_URI),
-    HttpHeaderFieldAttrs("nonce", (http_hdr_type)DIGEST_NONCE),
-    HttpHeaderFieldAttrs("nc", (http_hdr_type)DIGEST_NC),
-    HttpHeaderFieldAttrs("cnonce", (http_hdr_type)DIGEST_CNONCE),
-    HttpHeaderFieldAttrs("response", (http_hdr_type)DIGEST_RESPONSE),
-};
-
-class HttpHeaderFieldInfo;
-static HttpHeaderFieldInfo *DigestFieldsInfo = NULL;
+    DIGEST_INVALID_ATTR
+};
+
+static const LookupTable<http_digest_attr_type>::Record
+  DigestAttrs[] = {
+    {"username", DIGEST_USERNAME},
+    {"realm", DIGEST_REALM},
+    {"qop", DIGEST_QOP},
+    {"algorithm", DIGEST_ALGORITHM},
+    {"uri", DIGEST_URI},
+    {"nonce", DIGEST_NONCE},
+    {"nc", DIGEST_NC},
+    {"cnonce", DIGEST_CNONCE},
+    {"response", DIGEST_RESPONSE},
+    {nullptr, DIGEST_INVALID_ATTR}
+};
+
+LookupTable<http_digest_attr_type>
+DigestFieldsLookupTable(DIGEST_INVALID_ATTR, DigestAttrs);
 
 /*
  *
@@ -545,7 +548,6 @@
 Auth::Digest::Config::init(Auth::Config *)
 {
     if (authenticateProgram) {
-        DigestFieldsInfo = httpHeaderBuildFieldsInfo(DigestAttrs, DIGEST_ENUM_END);
         authenticateDigestNonceSetup();
         authdigest_initialised = 1;
 
@@ -581,11 +583,6 @@
     if (digestauthenticators)
         helperShutdown(digestauthenticators);
 
-    if (DigestFieldsInfo) {
-        httpHeaderDestroyFieldsInfo(DigestFieldsInfo, DIGEST_ENUM_END);
-        DigestFieldsInfo = NULL;
-    }
-
     if (!shutting_down)
         return;
 
@@ -815,7 +812,7 @@
         }
 
         /* find type */
-        http_digest_attr_type t = (http_digest_attr_type)httpHeaderIdByName(item, nlen, DigestFieldsInfo, DIGEST_ENUM_END);
+        const http_digest_attr_type t = DigestFieldsLookupTable.lookup(keyName);
 
         switch (t) {
         case DIGEST_USERNAME:

=== added file 'src/base/LookupTable.h'
--- src/base/LookupTable.h	1970-01-01 00:00:00 +0000
+++ src/base/LookupTable.h	2015-07-27 16:25:09 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_LOOKUPTABLE_H_
+#define SQUID_LOOKUPTABLE_H_
+
+#include "SBuf.h"
+
+#include <map>
+
+/**
+ * SBuf -> enum lookup table
+ *
+ * How to use:
+ * enum enum_type { ... };
+ * static const LookupTable<enum_type>::Record initializerTable[] {
+ *   {"key1", ENUM_1}, {"key2", ENUM_2}, ... {nullptr, ENUM_INVALID_VALUE}
+ * };
+ * LookupTable<enum_type> lookupTableInstance(ENUM_INVALID_VALUE, initializerTable);
+ *
+ * then in the code:
+ * SBuf s(string_to_lookup);
+ * enum_type item = lookupTableInstance.lookup(s);
+ * if (item != ENUM_INVALID_VALUE) { // do stuff }
+ *
+ */
+template<typename EnumType>
+class LookupTable
+{
+public:
+    /// element of the lookup table initialization list
+    typedef struct {
+        const char *name;
+        EnumType id;
+    } Record;
+
+    LookupTable(const EnumType theInvalid, const Record data[]) :
+        invalidValue(theInvalid)
+    {
+        for (auto i = 0; data[i].name != nullptr; ++i) {
+            lookupTable[SBuf(data[i].name)] = data[i].id;
+        }
+    }
+    EnumType lookup(const SBuf &key) const {
+        auto r = lookupTable.find(key);
+        if (r == lookupTable.end())
+            return invalidValue;
+        return r->second;
+    }
+
+private:
+    typedef std::map<const SBuf, EnumType> lookupTable_t;
+    lookupTable_t lookupTable;
+    EnumType invalidValue;
+};
+
+#endif /* SQUID_LOOKUPTABLE_H_ */

=== modified file 'src/base/Makefile.am'
--- src/base/Makefile.am	2015-03-03 09:45:37 +0000
+++ src/base/Makefile.am	2015-07-27 09:30:32 +0000
@@ -25,6 +25,7 @@
 	CharacterSet.cc \
 	InstanceId.h \
 	Lock.h \
+	LookupTable.h \
 	LruMap.h \
 	Packable.h \
 	RunnersRegistry.cc \

=== added file 'src/tests/testLookupTable.cc'
--- src/tests/testLookupTable.cc	1970-01-01 00:00:00 +0000
+++ src/tests/testLookupTable.cc	2015-07-27 16:25:09 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#include "squid.h"
+#include "base/LookupTable.h"
+#include "testLookupTable.h"
+#include "unitTestMain.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION( testLookupTable );
+
+enum EnumData {
+    ENUM_1,
+    ENUM_2,
+    ENUM_3,
+    ENUM_4,
+    ENUM_5,
+    ENUM_6,
+    ENUM_7,
+    ENUM_INVALID
+};
+
+static const LookupTable<EnumData>::Record tableData[] = {
+                {"one", ENUM_1},
+                {"two", ENUM_2},
+                {"three", ENUM_3},
+                {"four", ENUM_4},
+                {"five", ENUM_5},
+                {"six", ENUM_6},
+                {"seven", ENUM_7},
+                {nullptr, ENUM_INVALID}
+};
+
+void
+testLookupTable::testLookupTableLookup()
+{
+    LookupTable<EnumData> lt(ENUM_INVALID, tableData);
+    // element found
+    CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("one")), ENUM_1);
+    CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("two")), ENUM_2);
+    CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("three")), ENUM_3);
+    CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("four")), ENUM_4);
+    CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("five")), ENUM_5);
+    CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("six")), ENUM_6);
+    CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("seven")), ENUM_7);
+
+    // element not found
+    CPPUNIT_ASSERT_EQUAL(lt.lookup(SBuf("eleventy")), ENUM_INVALID);
+}

=== added file 'src/tests/testLookupTable.h'
--- src/tests/testLookupTable.h	1970-01-01 00:00:00 +0000
+++ src/tests/testLookupTable.h	2015-07-27 16:25:09 +0000
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_TESTLOOKUPTABLE_H_
+#define SQUID_TESTLOOKUPTABLE_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class testLookupTable : public CPPUNIT_NS::TestFixture
+{
+    CPPUNIT_TEST_SUITE( testLookupTable );
+    CPPUNIT_TEST( testLookupTableLookup );
+    CPPUNIT_TEST_SUITE_END();
+public:
+    void testLookupTableLookup();
+};
+
+#endif /* SQUID_TESTLOOKUPTABLE_H_ */

# Begin bundle
IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWd8Pqn4AGfxfgER0ff///3/v
/26////6YCPe7Xr2m30O46NR71GzHz4YXijZigJAAAEmnoB0APob6vh9t0bG7c73de7u93tt5Z3u
49z3N72e7773tnn2jcbhKRXmaSRCXoYE4tezuBqq2XhJITSZNJjKbQTRPDU0yap+k9Ke0UeoaAeo
zKNHqND1NAkkAAggQU02inpoIm1BoA0NGagGgDQBiEE1MptBE0NDygNGg0AAAAADQAJNSQFNMI00
mNBBlI/UTaj1GZTan6UHqaeFB6gGmjQRSQEYmjUYBJiZDTAmVP0yEMKe0kA0AB6gikECGp6AQ1PQ
aAKjynqbSMamIAZAAA0pETggVGlX8g1Qhr1cfLnpmfuQ0fOIwmqnoieetOPr2NUuVrTRjgSLJmwT
g8CAbFf6SZJLK7vLGM9xBNForTFyzfm6VeeCnV8Sk/TC3mRZm/kd6EnvP6IW/gfqM8hN9xZlxnO+
1GbUojU2ZTkLpTnRaNu2SF1VxYw+kBMOpthb0SXZ0Ba1srGhxbXzOOCFCaNF+T5dHkQ14AGQKz2y
IJAyJg3smyiBWUO7vhUSDomAZPqPZENW+n9ipP2D4PZZfll+yafJQrNHzOTsxrupHa8vKc1jAkv7
aCZWobuKjnayTozvcLXXYWOakhtuO+YRSSZlZkFKuQF2T8uT/NxphKm1fS8UhD63CrnJnDrX3wRG
fEi0CeItFQIUTiWJWANwYOouupYRNmVbPKGhBBstIAqgyCkAcdlcxV+YakpG1807Hnzmu/jt81ZG
tN9fDwq57wIRbwAThaSOenhgFRhgfne0ND57ORQY2SAmlqyPxaZAPGX/9sVODjmYad9FqfIAf5Cd
UgqSRGEUBVFgoioiQUw9cg/ftWfcSQ293Jndq4C0mAxKYLBtmBjfezy0ZZdt4eZ6/JWHblLAwTFl
plRenAPdi4FoZYX2LkfNOV3lH1Yd+JSAriEny77OUmJsi7PYpfBHDpTikWeQeToNg8ymCnCCoKGF
W9qi5NQhUCKrUWmHlZ2dWsmmjZQJNAiz2DCdYMgrkpsXowpVpqINbVkkUsBZbiAwAQTh0AUPiXc8
DFsRpr0lBqSOyQ3zaevbLyc7z+8HxekePGQJ4Ebyvdchw7G+IIAdDNF8okHOUxkmbNNiBEYKSFRN
y+6j0XCZkLa3ZmzFyx1HTkq2++RGzuqD83eozxLnErAPCZrgAt66BLoSLmmGBGdhUyL+x8sX8/ZW
y++p6/9/RBX+8b1lwAeyay897+8F2IrlVLPrt9OqAemcJxogUGK0X5H23Ll5uYcirM3lL7ECAgyF
geZcyoHt+0AZlmdV9sLZXidQC5LbDxbmxV9j959QS+JBVgt98Elea/RFx7AYrEszq3ACay+9YYq6
Pt0X4XUS0tvPYFhvZHHubT3FHIZhO+b7w+ina+qp8hg9QtvVy9b22b2c/e2863ClCMi3vn5mPkQO
Zz8oxFciqoJz8d1V5XJt6qta7LPJ0UXujVp14aNh4uZudvjnzvOsqTlfTLQnpy7Exit0voaiiQ4F
ooDSkBy/p5tRt59++27k4JDrevWUQsMLWKAKRpbCWgBahSxVUVQooq1YWFrLaqFKJ6ZJ7KVVncfL
4/4u+c0xFiCcLj9A9h67/DIP0z96/Naz4lAGB05sTYT4qdyCkQR+sCUEEQTgM0kJZ5H+Onntnrob
Lx/RBsnYuy0+5fh63Pt2vLMohimcGvAzk13JIfD5gP4pj9nm4ZrwGKnL3ZHVwy1dbx/Vw7OHbLbx
OU5+HRvursTsurKR2bMd7caU4fCP2MAoYiCxYsJrjPZNFuPbnt3eID0gR6znCWooBIjIHk42+woq
qqtx+Oxzc/Jyt+J04hcYHSUYrOokUhAT3cAmdd3vf+wyleVhHB9wezatJ0EwPUPiaSxnHKE5tfKx
hEYYWZgT3jCoQWElTLiW615hKDePINZ4HUgIdj2mt1A9QMgdGZWwQxQmJIOUGoGCrMbgeZWa2hAm
5m9KNraF4m7eBH1BrLbtuaeedKRF5cPMO7Nz0mtGUAwSkOTNeGuW2BbvL2wTuASVLeBLQCB3wO+H
qm4T31TRaqQDPgxDfxGvwbTwrqy49q51VVVVVVS1VVKpaKqgqqmXfiuiSjl3k5q7C3RUZ2ccCdSQ
6m5OJgKBkihSTJil6SXoZpJ2MCzwZ54ZEwEHjMi1G8Sg1nOc5KQJdAJ/7vkZ4EwIQcwsGHApZFUQ
PEDDt760Ni5RISCPI2kpm7lmAIqJ22qiJIH6i7/4RSQ224Bgp8dyvZS0VmOEyQ79VSbxWiXhDa7g
RawKmwUrppkhYXmDKyuZCZbMUcIVUhdRHlnLjXBYLU2kaOsElsrzE4UHDkA7ZxBjRo3nYEVYEZQL
sihKds7GB0HGWGuXOKBogowf+m8J7AtgWiuMkbl6mjXDKB/qgPQuclYI0PEQxooywrazGqFCGqMv
thZwtLAuN12Eucgd0T+2FjUtiNl1gxeSH2g6Rv2wEhCDLHgM6CEH0aZnOcQHf5A7bsoyieEt8aui
CWe2sNAoWBXBOOo+9L737RuQKiPMnYQ8o9qwGlF+fS0pWaUMbS5tXOiUoy6gmKmSRLUGZtTil3oQ
k+T2Qh8H0FWJungI04AwYiB3BQ1lCgYaWYBL1B4g7AbXHa3NsAKHVeJM1RnAuYAbOOphC8tg8GJT
EMaGtFK+HpLqwEzwIKKK1u+rRJqeC8kp3evC7QstHe0x7R6OJBZd3hNtpur4/Hl1cJVnuWEYKDox
4fh4/eAyevV9jkBdQDgcdmMGxLxtSO+xTkiQmNDo3RdO/ftmtB25OPo0CMfeI25GeF7uvrhGfkI9
UloDwlcovpPOPUl4T+2ZJN5sDsgUgM903BACfLPPj3fSmiA+D3pk9xExT2fr8SaqWBF0k5ae9g0b
XL7ZEmKWiQrcDaISUULBLA44SLovwnE28ILaSKR0E2RZqMy8TUVuSIkJItwbJ19kt7Gmd+MQ6kZC
ogHMJKjw47hwOKcIJCMjmcve4R6T5eN9SSwUiqC+h6S7EYbyCMn83yYqtMI91HCOa8K13diF2aYC
BkSbhx8ktcEKzmU38mscUMcWCVKs/nxMwlbj4WE9Ah4x4OhZ5rnncxIxMj9wON/QlRgucXHltXts
9h9dWLWwI/J8w/rFER9SXvK758Fndnhw21mJumxHmJHd0rlnCeE5FLpK04zS6Yn0ORif1qtbuGNi
4iSy7y6g4RwBpnCNvHu9298KvKSaojfkaeDy6zQ+oM4OnQ6Axgx6mozylPCtEioqsc9kvozKb6iD
IXWELkfNggFjg+zuYK2r2uRg5zZucBydPRCtGkHuv2KocQTlwN9gTnGAXHCuMiowmOD8F4zRq0CB
axW3mr+RcFNwtDQOhIyP3JwHkCCxLM2mPkWpG5Y6fNQNoipMlA2hdxAeDxGV3wI8vcksCD6xHsHv
21TuP7bbKWpzi6Ep9+9YNJ07FiFqrmd0vesIOpX5MQKAI4PFkr6z5H05BbV1Iv6d3AEhHGBSYWdx
RCR0a7RZGwMyZmA5YOfiCv6CGhi0o4bnvDa8hGlRqVNECxfk2WHoUpDhzJ8DXS+w+MXCNh6u2QnD
THuED75bmmLGh5vIL7YW1w0EFgtMfqT6QEV1jtg0VfZUsKoKe7gFkAB6uCWpSJ/DQ7nRqu/gRIrm
RHB9oichsmiQ9WxmGHfqSvyRzSXYl4EevSvsc6vUPbeuZ9bjA6648SVrJ4SN5IqBupKylIN+JOdI
a0nuw6Io0FMAhtmMHPhLphEQoAeJnk4hwT2LIWiIjVJAjYl63p53AvO5Uik9VoUZcBOfT2V1nRTr
ffHBvHM0KDKRLJKBPXovIZhWo1TqjORBQUFBYoLBYqG6n3M9PNdKhm+dzjU7WqtmAmFlQI73Iy5O
tqwLUkat09+p/LxEuZq7Az2+IukXlenQoJdl44gYOOktVkhPQV1W7gT8V2M88kRzsuxMI2KC1XQG
NKX05muL6w9n2f6t5S7cSdGFGtZU7YKKpgRMR1rhoEWJdYwGwrhfNIetiMosRS2ek5O7+HkPGzxD
sIHwAKM8cbl4AVmOKMIKT39LEnzO4UW8lA9eZGGVDfRY5wtVIPvvQmxOcp5qUmepsUrzba3srWW9
LYKF7nYmVIbU4HFoo9wLuhLvc73gZzStxzmHGRwg1LsbFOhfFQs8g9apkji4vsPhuHwFZC+77vo6
26evahw3Lov6NEIUnNo0fSEppxUgQAmwQ8oVdr0ESVkImPOToEnQ6kgS8Mkjm3FSV9xKqRwBoKOc
gAG2FrjTUQ4h51nbWt9Q2Jrzgl191dc3Buo5w5Fo0TX3wlOOmfgvR5vchQcnt1a7Kq9QWgEQfEK1
MkUKNSMoP6EWeUyQGYoRdPqV6Sz8wkyw617QW+tU+oRH3gbGlNMHkl0D6zhO4D04e0ilL7neDnVc
+BHqzEXSjKPwQzUH/aXT51iwsnr2xAVM59B4WCfk6PlwTd7yOrOTkuW2HH11kWyGCVK+pRjc3Goq
kRxJzPKnqXr8gmr0ZnYIj2CBbRxuvktyVB/p7+u1tVTTcc1GKk5RUWXepfv060rk6dLl8LlsNWej
RaRsWMUI+xJ0k3egKHsC3BUInPM8koVOZ7HA4hjuX4UjNZmSxh3nCY4aOR5W+XSSf7EJ3KnFIo2m
k5McXqhlnSc60SwBuQLAgQTAIaz2Wm4ERPGE4cIeUcUJFLb1wito1N7vOTrsWK32eksMVHDiKelK
EE+xfLvHecY+AHHIxbvWWXEToDc6CJzK0qHLiZn7VcOpKxXUOtzaBTRlbb2HhE7nFTch28gFqYxD
R03oWlJu9ryKrv3tTTjMWatFKmY2TJVDvE9ivDyE9RN3i6BluiDoJEN+igGShZ834y3grz4A15pY
Y9zsqatdM1KaQYWwGwGQF4NoMTBQsS4GYLUGQCQDUDQygFvGiEEqqrBkD42xdHeEolj9xSJLm4YF
9mpNheXWG6oDaWsF6JfVNr6fVf35WZuhLy9+ktR+gAbmgliSmQ+Se4QiMppheEuk5ASLEZB4SCRg
VGUPUqqisRFBRksIXwvwzPKQ+vFhJx2OedQMrGtMOzgoFiskAEGYX3fiKvpH+gHc/VT4sPxdFalA
HzOOQfWVGwXOpH68ycIIxQYMCLEQlZa/tJY+lmWxgT9l0kNHtdOMEMBKMzCEqDYBQlJ0SB39Q8Zt
xoNkilTYE2FaLYE4RPwdNiiQ++Bhmf8EzSaNFQO3Xu5ChCvTww0qztAORoVafPxWNXD2e/set323
zW8nKSdaa9TFiiiii0Sq4lS+4DNgThJAcV9zY3p+irDA1kuAY6S39D+mUmCo3EiWOzQbSCeqnSq2
vODzutEO7U1eqqGietkPLCgaVI6d+AQxpg7wgMgICelEPuYQzqaNZ0XODkr2m0OaOoKncO0DLHH/
l8oQh6hsleNKkNTK4lWpl9AppDm4Gc9e+dFXFz8qK74xQzRiszQAgLlVWvGXVXUCCya4YwmJiVY1
W4ewSRAHaDmVyKdkEEWDOwELFN/2pFqFIxO5hwZm4f/SYLhOJ3PGHiFnov1VNLjV3huVraVMHyO0
JzO2AYwMnHRIhCCwKViTaUYTYQSFokMHm0Isx13TGeand5soCB5xx9Go6WwDixBYurFRcgPDzZAi
SedOjMpIOPn347xzYBnhkmark4svu0s51CGwCENIEBKaJDEAwEDSdSnnhUIhA4ANebB7F4QOx4SA
zOSIbFfuHrDaNoVUknO7+Bc+HoMVWPbQQHDM8pEn942iLI9oGsXQkjMkSBmcnFmyg1IURKXzQRLq
cxTUwYGp4Gd8GkmRph+3VSTBQwhDBxnCr5FXuB0q0IVjSJDD7wZJKCCEEmpZ/HgTB032gBaJ61rC
61p2oCrH4nSfDAsHtaiH2cXrE1e3G89xNgCPwYApwmI0/KSnQeWe6w91BnkT9R+GVEvMkTExDwMM
SOs8i5IXiBb4pro6kXT73IoO/he8Z30wfXnzYIyMERJEBkiMCaveHE7s4BA+P2XXfenNSD4Zua6L
z7x8+AOfgC9kCNxDw4aAOMwaca8EdSOs41mXgvIVoDgJkzCC4C5ZejlaBgAyR9PM5gNKkzq1jxCg
VWPpBpOYPsXtDYjk6Abgv1GIpBpWh9UoYn1K5HyHaOc8ssofPXC/p2LVusJegxbJCZ4Nglk1uNu0
cW3SHMpYFFw3GcE5xJmC5+SmIjz6QffLuJM/VkKNTeRQc9/Bf7Fu48gd6f0vG/sNrm1vx6I6ubcd
TxKRvCGISNyJhrw3Vuwu3Yzp5+kPulrlVVX4Ym/j4ho3+L2B/WSUgpxDDpyfEDgj0A+b2WlqG5kf
YKpM1IyGEX8e5dpySAt4mJKbLujPk0S3GGllml2rSVDVz5TR7hjb6xFhHrv8tzccDYVeBzGKYsQp
xsUcR2gpmS/3JVLHkiUzMdtsfNAIPX7j3bsFG6F3Bv2PNCTeMGYP2PoA+HimDtD39g8/hTUsHksA
qFDmlZspBq0hvICGYQiYHi5IKKQexdz+oHSNWsnnB6CnjAw+eYl6TSiFUgsBs8h1CZeAdJcE3sfJ
w7m9cjy3SYbzxgnxnJrQJMpEmCss1LFCP2iEIHV3CmRsK4q7jp6AleN7cLWnwPiUL/Gd4Y3IzNCd
Q8uoj6pfrTpgvlNuFJuyEsET1NI57AIhd5Kx1Kgt10jEwyrTiR9geXCuxEAp0K+wN02DrywpntU4
vLBtyjTkTNNDXUgwFyolcXK8llOZBgMUg410mFehRcgnYydYVLxSXLxNgxncC+wwG8GUK2C5bmpw
bpnYrtVp7Q/aJk1MdkvdwGTD7mdHEm2eLbOACKUOuhKwItskHh7Z3tE1sd1+E81b8DyG9lWtbmys
ooBx0kwgiXJrKpLDmCQBYY6YBAsFgB4Tsek0KrYZqL1PVR47JLr71V3Cui4MX4BEnp1NKPMJKRLA
mE6DsggbRnfrF7Ce7ozYNpwaNGOnTae1l2meWzc8VitVpbfc3Zdnucernx/EdbXFcnMl6O7uh4KT
PUVBej8k8cDHqK363WbSTWAjiAUAN6HIAQvXoIhgYQUipKRAcSk5zRUJN0CCQ2m3c9fajKQaV+0l
fbuiIdD9CLA5ee68v9PjDsHQ4qZZ+T5j5EOhsE4mE9kdmP62MY0ZHaDflz8J2dfd338Z4A8wOofY
nXqqdUjjgcuByEp37hzGdfc9YOW7VvK8NFeK++sFNo57HY8ZB8j4go1cxkwvc/HP6v3BTALUJLSG
nw0mOtBzAxyAnQHZB3uFfEZdfcbzpvi1OLIjcCw2ghIBI7sE7z1rOJQC5vg7mBSPXMDPjroSAbLD
63D0zAyeZxvmYA3PO6QdoPODmbbAc4AdIjAr8t8QiJKzgyCeFaQcdQ/la1BQr51vKpkRuuV3xDcZ
kLgUj2R2A2g5jmMGxAgIO/zExDLqpKYgZpBFsExBNCAxu6SzB0x25yI/G/lIXbRGcfuJiFIFmufw
RpV/3x/L7gHBY3W+6+/BupkNHQm5V3Nx/UFS07bQkcUbrwHM9X/MqiOw+xk3MwYH0MtIcTpz9+Z6
pCG/UxXH12BLxkN3036eS7lPBPjzBJ/b5LzgGYegA9ah1ExqNoPhYYqvh8IJCG4GC4tAkOsecSoP
IOOHoiARz6F6BPXg2A8kLZPJZTRGbjcihargyDGO3asu9wElpVwe453vzyEmQBxBlRvV+drMGtgC
wHMZ3XV9rAVQEMGRvkfwBnffYIZ10CbBPQCp0QG+w6QxG6CIeCOKIPFXjAQmbgYbniP7M34Wo9yw
rn5gNgOZd4T9wFNsNxJCIkkmCGXYD29wxiV64oAoeIMyhHiClWtAPS9YAh5CtoM23aw2QEoiDsFf
E61kie1BIVwTl8KBR5Ye6TcA2jLlLEJmkyoJJka+WbOVCwAQp2TyqDPTQ7wfMG0H/BkmYEYGOBnk
rsF6MA3gjl8ahTjEGUvr1MUDf8gN9Rdxe6D51mDx+AluD9g2gEw2nzB3+AmoSl4gnE6XlqEhXpCB
DKJh22QDcjtCnS2gS0tB/69J7yEoAIeiCch+grIKKGoJQ1BKGoJQ1BKoKKGoJQMoiVQUVEoglQQo
EqJXaE3bCEPGHjyiI6ByqfgZYTtAHYrWJiQHu0A0AD2ag7TktCkTFkrVzqQravvAIFgYVYAMTGCC
ajMAgTP+5nUs+3EkwFH1ncBg1K8KzA68lwVtSbZY5k5EeoHqE2gb4NBnEIbjEBqA4JEhySA+3Y+w
mMhg8bI0WDndTiDdyAqDwBsd3mcjAvNkEDYUrtb2U6BVtpTpcF6/YTPpAq+Y1Pc6IwxF27YjoOAe
J5oPE74hvF8SEPuyJtNwXQhEQ4wdgOwIB5g9gOwGoH+EXA1gsj8xrLVfX4TYEQhgyvldSc5FJ0Wk
EAzgH5SxcmolACthIGXjQufDTR/eSAOhuG8RvB+9tJo5iiiVKPtIaFBoYwDPygZLQLe0TtBuaBRk
yQEO9u6fU3tJOelHSJnuW8L2TVLSJMqayYMhDECHyhQkDAITjKSCc/eF0waRICTWUqhrHVgDk5IH
1ReVFAzB+Ye1l1FRi6AqDHnyE74Ol+3ibTUIjVzA34xtVwZoFG4Zlx6A8FqvvaoujWBBAhAsBCBB
AwQwEDBCQDhtYR7lubNgUhNCCTTQakBDKHK6ypBpqckCJilhj3qaj3MFQ6u9reRBWu/CVnMaNTAP
dxKEEgsGgWwXcqUuBAHK0hSoBEldHWDABACQVgvzQMZCNUiXBaDjU6wKBKgOk5HZVjzyXnS7rfB9
oPWYA0XHoEsE9Qbw9FNbfIcgcomtzD5keUQ7NDQzCaFfqzByBxuISWxR6RqQUJbkeSvxCeSdbI1E
dZDRKdBPtgEgIgfgFpPMQjtE1FkwDOpCMlcEE9AcQd/cGjNYssW+HRsfLQ1PM9AOYfYtcHZmBAzf
Dxp/eEShi3g181+IRKp5g9wMgXWCIanW94mTPUhHpvC2hiDJqDIl80CNotGK7hutRw5WuLQvwaSb
yUC/JAm8mLSafeAPAmDECsBY0OyRuOOPWztDO4Uw2feu2hTREQbpgrbGma6eS+sZBV3qwP0IaBqB
1heA1ORhgTmHZ8Cxp2TRWQTOTmymg8h+X0STRgHGkVWMUUFRFDqALbM/EEJVSTMvAPPNnDNsNyLF
ixRYsUUFBRQ9GZC+cU1ST9UAQsvXtJZQpRgvcuMWIWciFCJySoM4Bmd7mjhJKBbgglrWyywLoB+p
nIG2jsHziXryBvnQ31bThG1gYza63FXJTCWiyd3TyBlRxQeicHOhSPGHGHRFNJXQOBSFEB1ML/jT
8vgJnC3NBpB30miGQwq0gEzQrYAYgBKgBnA2CQXcwW2C/CFlLFZhcl4NdErQcx02QnPpj0KX26HX
C8vWyfzkwl7cAHKDaDaDbCs670EzgEYy8HX9lZwmXWDlAZJjYe8T0I5w3cwZGoI2Bv02wglDgDWw
DDAONdIrWn0GJK+ca2kd0pTiMi1hL4XNCUAJNcD7leNWZX5iNIebWrxCQvWO08Gy2Ac7pUMva/TE
Jo7tZtOd1NAS1HnRkwR0qP71SnCYAE6A5xPRnG8HYDIQ2kNE2Bzb8mZ4/kABlfIS01ZUbmSuarbR
j3qzM8Zi0YaAeFWTAQ1ienOnyY0vZgrY606j1A2DmXnEsqYfhI2jQxpQ7TMCEeolgNmJnRHserkl
6RLhPMGKqLnDBd4DEUq7wwIc5Q6xKFD6QX2M3ShipvGQPoryR8FeBvKUfovjoyKjjUjeLsUgYlKZ
N4kzAxIT6pcWnZ8C0NOAia5JhPiMUiqqwMQ7w7w2r4Ot7doPIYHr4B6mAmG4OYIFLRIDive/EdAb
QbA7ZieAnuDuHxgghTxhCk4SwfgWKCkiCHzglrNS/+Vew+aj3NjC6JDxIu/s3B3n5Fo9p5DgYbbX
8vJ7tutzr6VIxWf+LuSKcKEhvh9U/A==
_______________________________________________
squid-dev mailing list
[email protected]
http://lists.squid-cache.org/listinfo/squid-dev

Reply via email to