From 855145d5c03c4b4faf60736c38d7a299c682af4a Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Sat, 7 Feb 2015 14:06:02 -0500 Subject: cmd/ld: set alignment for the .rel.plt section on 32-bit architectures Fixes #9802. Change-Id: I22c52a37bdb23a14cc4615c9519431bb14ca81ca Reviewed-on: https://go-review.googlesource.com/4170 Reviewed-by: Ian Lance Taylor --- src/cmd/ld/elf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 12ced98107..97ed4bd20d 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -1363,6 +1363,7 @@ asmbelf(vlong symo) sh->type = SHT_REL; sh->flags = SHF_ALLOC; sh->entsize = ELF32RELSIZE; + sh->addralign = 4; sh->link = elfshname(".dynsym")->shnum; shsym(sh, linklookup(ctxt, ".rel.plt", 0)); -- cgit v1.2.3-54-g00ecf From 69937d213192b1a87d6ca8a71337b7aa05f3566e Mon Sep 17 00:00:00 2001 From: "Hyang-Ah (Hana) Kim" Date: Fri, 13 Feb 2015 15:31:00 -0500 Subject: androidtest.bash: remove use of cp --preserve. --preserve flag is not a valid flag for some versions of cp. Change-Id: I57f5bf21cbe726057fdadcd55b040ef7ff5d7479 Reviewed-on: https://go-review.googlesource.com/4835 Reviewed-by: David Crawshaw --- src/androidtest.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/androidtest.bash b/src/androidtest.bash index 4968a00f6e..ee97e30d58 100755 --- a/src/androidtest.bash +++ b/src/androidtest.bash @@ -44,9 +44,9 @@ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \ export ANDROID_PRODUCT_OUT=/tmp/androidtest-$$ FAKE_GOROOT=$ANDROID_PRODUCT_OUT/data/local/tmp/goroot mkdir -p $FAKE_GOROOT -cp -R --preserve=all "${GOROOT}/src" "${FAKE_GOROOT}/" -cp -R --preserve=all "${GOROOT}/test" "${FAKE_GOROOT}/" -cp -R --preserve=all "${GOROOT}/lib" "${FAKE_GOROOT}/" +cp -a "${GOROOT}/src" "${FAKE_GOROOT}/" +cp -a "${GOROOT}/test" "${FAKE_GOROOT}/" +cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/" echo '# Syncing test files to android device' time adb sync data &> /dev/null echo '' -- cgit v1.2.3-54-g00ecf From ae3229ae5c12a2bfce2961e21c299f286e8b8cb1 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Fri, 13 Feb 2015 14:52:07 -0500 Subject: cmd/ld: always mark tlsg STLSBSS Android apps build again. Defining TLSG in runtime/tls_arm.s gives it the type SNOPTRBSS, so its type was never being set when GOOS=android. I considered modifying the if statement, but I no longer understand the intention of the original change (in d738c6b0cad). We were always setting it before, what platform is this not valid for? Fixes #9829 Change-Id: I3eaa4a9590893eff67695797eb22547a170cdbcd Reviewed-on: https://go-review.googlesource.com/4834 Reviewed-by: Minux Ma Reviewed-by: Hyang-Ah Hana Kim Run-TryBot: David Crawshaw --- src/cmd/ld/lib.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index 72c903b4d2..200c96da96 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -269,11 +269,13 @@ loadlib(void) tlsg = linklookup(ctxt, "runtime.tlsg", 0); // For most ports, runtime.tlsg is a placeholder symbol for TLS - // relocation. However, the Android and Darwin ports need it to - // be a real variable. Instead of hard-coding which platforms - // need it to be a real variable, we set the type to STLSBSS only - // when the runtime has not declared its type already. - if(tlsg->type == 0) + // relocation. However, the Android and Darwin arm ports need it + // to be a real variable. + // + // TODO(crawshaw): android should require leaving the tlsg->type + // alone (as the runtime-provided SNOPTRBSS) just like darwin/arm. + // But some other part of the linker is expecting STLSBSS. + if (!(strcmp(goos, "darwin") == 0 && thearch.thechar == '5')) tlsg->type = STLSBSS; tlsg->size = thearch.ptrsize; tlsg->hide = 1; -- cgit v1.2.3-54-g00ecf From ad73dc349bcb796ec99e1adb25973671d2204fba Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 13 Feb 2015 22:24:41 +0100 Subject: cmd/gc: replace NULL by nil In CL 4050, NULL was used instead of nil. However, Plan 9 doesn't declare NULL. Change-Id: I8295a3102509a1ce417278f23a37cbf65938cce1 Reviewed-on: https://go-review.googlesource.com/4814 Reviewed-by: Minux Ma Reviewed-by: Russ Cox --- src/cmd/gc/walk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 0e69f88b66..50dae8ca68 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -634,7 +634,7 @@ walkexpr(Node **np, NodeList **init) // Append captured variables to argument list. n->list = concat(n->list, n->left->enter); - n->left->enter = NULL; + n->left->enter = nil; // Replace OCLOSURE with ONAME/PFUNC. n->left = n->left->closure->nname; // Update type of OCALLFUNC node. -- cgit v1.2.3-54-g00ecf From b5b11bdbc6be59c0449f95949d68dd4151a3a8d6 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 13 Feb 2015 08:06:36 -0800 Subject: test: deflake init1.go test, tighten its bounds Per the comment at top, this test is about whether the GC runs during init, but it was testing more than that, and testing how much the GC collected in a certain amount of time. Instead, loosen this test to just see whether it ran at all and not how well it did. Fixes #9848 Change-Id: I31da7dd769140d7b49aa6c149a543fae6076aa5e Reviewed-on: https://go-review.googlesource.com/4820 Reviewed-by: Rick Hudson Reviewed-by: Russ Cox --- test/init1.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/test/init1.go b/test/init1.go index 83e9149f4c..62dfb72bf9 100644 --- a/test/init1.go +++ b/test/init1.go @@ -17,22 +17,30 @@ func init() { go send(c) <-c - const chunk = 1 << 20 - memstats := new(runtime.MemStats) - runtime.ReadMemStats(memstats) - sys := memstats.Sys - b := make([]byte, chunk) + const N = 1000 + const MB = 1 << 20 + b := make([]byte, MB) for i := range b { b[i] = byte(i%10 + '0') } s := string(b) - for i := 0; i < 1000; i++ { + + memstats := new(runtime.MemStats) + runtime.ReadMemStats(memstats) + sys, numGC := memstats.Sys, memstats.NumGC + + // Generate 1,000 MB of garbage, only retaining 1 MB total. + for i := 0; i < N; i++ { x = []byte(s) } + + // Verify that the garbage collector ran by seeing if we + // allocated fewer than N*MB bytes from the system. runtime.ReadMemStats(memstats) - sys1 := memstats.Sys - if sys1-sys > chunk*500 { - println("allocated 1000 chunks of", chunk, "and used ", sys1-sys, "memory") + sys1, numGC1 := memstats.Sys, memstats.NumGC + if sys1-sys >= N*MB || numGC1 == numGC { + println("allocated 1000 chunks of", MB, "and used ", sys1-sys, "memory") + println("numGC went", numGC, "to", numGC) panic("init1") } } -- cgit v1.2.3-54-g00ecf From 7a77d8d1e9b006ae49fd456a8912a8ec03af8ec7 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 13 Feb 2015 10:12:25 -0800 Subject: math/big: use internal validation more consistently TBR adonovan Change-Id: If77afa6474af6cad6512f6866725e3ae5acf2e3f Reviewed-on: https://go-review.googlesource.com/4840 Reviewed-by: Robert Griesemer --- src/math/big/float.go | 79 +++++++++++++++++++++++++++++++--------------- src/math/big/float_test.go | 12 +++++++ 2 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index 06b3ae2f40..f69cbe0603 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -232,7 +232,7 @@ func (z *Float) SetMantExp(mant *Float, exp int) *Float { // ±Inf are not considered integers. func (x *Float) IsInt() bool { if debugFloat { - x.validate() + validate(x) } // pick off easy cases if x.exp <= 0 { @@ -267,21 +267,23 @@ func (z *Float) setExp(e int64) { } // debugging support -func (x *Float) validate() { - const msb = 1 << (_W - 1) - m := len(x.mant) - if m == 0 { - // 0.0 or Inf - if x.exp != 0 && x.exp != infExp { - panic(fmt.Sprintf("empty matissa with invalid exponent %d", x.exp)) +func validate(args ...*Float) { + for i, x := range args { + const msb = 1 << (_W - 1) + m := len(x.mant) + if m == 0 { + // 0.0 or Inf + if x.exp != 0 && x.exp != infExp { + panic(fmt.Sprintf("#%d: %empty matissa with invalid exponent %d", i, x.exp)) + } + continue + } + if x.mant[m-1]&msb == 0 { + panic(fmt.Sprintf("#%d: msb not set in last word %#x of %s", i, x.mant[m-1], x.Format('p', 0))) + } + if x.prec <= 0 { + panic(fmt.Sprintf("#%d: invalid precision %d", i, x.prec)) } - return - } - if x.mant[m-1]&msb == 0 { - panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0))) - } - if x.prec <= 0 { - panic(fmt.Sprintf("invalid precision %d", x.prec)) } } @@ -303,7 +305,7 @@ func (z *Float) round(sbit uint) { // z.prec > 0 if debugFloat { - z.validate() + validate(z) } bits := m * _W // available mantissa bits @@ -440,7 +442,7 @@ func (z *Float) round(sbit uint) { } if debugFloat { - z.validate() + validate(z) } return @@ -668,7 +670,7 @@ func (x *Float) minPrec() uint { // for x > math.MaxUint64. func (x *Float) Uint64() (uint64, Accuracy) { if debugFloat { - x.validate() + validate(x) } switch x.ord() { case -2, -1: @@ -707,7 +709,7 @@ func (x *Float) Uint64() (uint64, Accuracy) { // (math.MaxInt64, Below) for x > math.MaxInt64. func (x *Float) Int64() (int64, Accuracy) { if debugFloat { - x.validate() + validate(x) } switch x.ord() { @@ -786,7 +788,7 @@ func (x *Float) Float64() (float64, Accuracy) { // otherwise it is Below for x > 0, and Above for x < 0. func (x *Float) Int() (res *Int, acc Accuracy) { if debugFloat { - x.validate() + validate(x) } // accuracy for inexact results acc = Below // truncation @@ -1059,6 +1061,10 @@ func (x *Float) ucmp(y *Float) int { // result error relative to the exact (not rounded) // result. func (z *Float) Add(x, y *Float) *Float { + if debugFloat { + validate(x, y) + } + if z.prec == 0 { z.prec = umax(x.prec, y.prec) } @@ -1096,6 +1102,10 @@ func (z *Float) Add(x, y *Float) *Float { // Sub sets z to the rounded difference x-y and returns z. // Precision, rounding, and accuracy reporting are as for Add. func (z *Float) Sub(x, y *Float) *Float { + if debugFloat { + validate(x, y) + } + if z.prec == 0 { z.prec = umax(x.prec, y.prec) } @@ -1135,6 +1145,10 @@ func (z *Float) Sub(x, y *Float) *Float { // Mul sets z to the rounded product x*y and returns z. // Precision, rounding, and accuracy reporting are as for Add. func (z *Float) Mul(x, y *Float) *Float { + if debugFloat { + validate(x, y) + } + if z.prec == 0 { z.prec = umax(x.prec, y.prec) } @@ -1159,6 +1173,10 @@ func (z *Float) Mul(x, y *Float) *Float { // Quo sets z to the rounded quotient x/y and returns z. // Precision, rounding, and accuracy reporting are as for Add. func (z *Float) Quo(x, y *Float) *Float { + if debugFloat { + validate(x, y) + } + if z.prec == 0 { z.prec = umax(x.prec, y.prec) } @@ -1191,28 +1209,38 @@ func (z *Float) Quo(x, y *Float) *Float { // and rounding mode; and z's accuracy reports the // result error relative to the exact (not rounded) // result. -func (z *Float) Lsh(x *Float, s uint, mode RoundingMode) *Float { +// BUG(gri) Lsh is not tested and may not work correctly. +func (z *Float) Lsh(x *Float, s uint) *Float { + if debugFloat { + validate(x) + } + if z.prec == 0 { z.prec = x.prec } // TODO(gri) handle Inf - z.Round(x, z.prec, mode) + z.round(0) z.setExp(int64(z.exp) + int64(s)) return z } // Rsh sets z to the rounded x / (1< Date: Fri, 13 Feb 2015 12:47:44 -0800 Subject: math/big: fix aliasing error in Add, Sub Also: - make representation more flexible (no need to store trailing 0 digits to match precision) - simplify rounding as a consequence - minor related fixes TBR adonovan Change-Id: Ie91075990688b506d28371ec3b633b8267397ebb Reviewed-on: https://go-review.googlesource.com/4841 Reviewed-by: Rob Pike --- src/math/big/float.go | 90 ++++++++++++++++++++-------------------------- src/math/big/float_test.go | 22 +++++++----- src/math/big/floatconv.go | 4 +-- 3 files changed, 54 insertions(+), 62 deletions(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index f69cbe0603..32e320a140 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -29,10 +29,10 @@ const debugFloat = true // enable for debugging // // Each Float value also has a precision, rounding mode, and accuracy. // -// The precision is the number of mantissa bits used to represent the -// value. The rounding mode specifies how a result should be rounded -// to fit into the mantissa bits, and accuracy describes the rounding -// error with respect to the exact result. +// The precision is the (maximum) number of mantissa bits available to +// represent the value. The rounding mode specifies how a result should +// be rounded to fit into the mantissa bits, and accuracy describes the +// rounding error with respect to the exact result. // // All operations, including setters, that specify a *Float for the result, // usually via the receiver, round their result to the result's precision @@ -48,8 +48,8 @@ const debugFloat = true // enable for debugging // or denormalized numbers). Additionally, positive and negative zeros and // infinities are fully supported. // -// The zero (uninitialized) value for a Float is ready to use and -// represents the number +0.0 of 0 bit precision. +// The zero (uninitialized) value for a Float is ready to use and represents +// the number +0.0 exactly, with precision 0 and rounding mode ToNearestEven. // type Float struct { mode RoundingMode @@ -60,11 +60,13 @@ type Float struct { prec uint // TODO(gri) make this a 32bit field } -// Internal representation details: The mantissa bits x.mant of a Float x -// are stored in the shortest nat slice long enough to hold x.prec bits. +// Internal representation: The mantissa bits x.mant of a Float x are stored +// in a nat slice long enough to hold up to x.prec bits; the slice may (but +// doesn't have to) be shorter if the mantissa contains trailing 0 bits. // Unless x is a zero or an infinity, x.mant is normalized such that the -// msb of x.mant == 1. Thus, if the precision is not a multiple of the -// the Word size _W, x.mant[0] contains trailing zero bits. Zero and Inf +// msb of x.mant == 1 (i.e., the msb is shifted all the way "to the left"). +// Thus, if the mantissa has trailing 0 bits or x.prec is not a multiple +// of the the Word size _W, x.mant[0] has trailing zero bits. Zero and Inf // values have an empty mantissa and a 0 or infExp exponent, respectively. // NewFloat returns a new Float with value x rounded @@ -292,52 +294,35 @@ func validate(args ...*Float) { // have before calling round. z's mantissa must be normalized (with the msb set) // or empty. func (z *Float) round(sbit uint) { + if debugFloat { + validate(z) + } + z.acc = Exact // handle zero and Inf - m := uint(len(z.mant)) // mantissa length in words for current precision + m := uint(len(z.mant)) // present mantissa length in words if m == 0 { if z.exp != infExp { z.exp = 0 } return } - // z.prec > 0 - - if debugFloat { - validate(z) - } + // m > 0 implies z.prec > 0 (checked by validate) - bits := m * _W // available mantissa bits - if bits == z.prec { - // mantissa fits Exactly => nothing to do + bits := m * _W // present mantissa bits + if bits <= z.prec { + // mantissa fits => nothing to do return } + // bits > z.prec n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision - if bits < z.prec { - // mantissa too small => extend - if m < n { - // slice too short => extend slice - if int(n) <= cap(z.mant) { - // reuse existing slice - z.mant = z.mant[:n] - copy(z.mant[n-m:], z.mant[:m]) - z.mant[:n-m].clear() - } else { - // n > cap(z.mant) => allocate new slice - const e = 4 // extra capacity (see nat.make) - new := make(nat, n, n+e) - copy(new[n-m:], z.mant) - } - } - return - } // Rounding is based on two bits: the rounding bit (rbit) and the // sticky bit (sbit). The rbit is the bit immediately before the - // mantissa bits (the "0.5"). The sbit is set if any of the bits - // before the rbit are set (the "0.25", "0.125", etc.): + // z.prec leading mantissa bits (the "0.5"). The sbit is set if any + // of the bits before the rbit are set (the "0.25", "0.125", etc.): // // rbit sbit => "fractional part" // @@ -875,14 +860,16 @@ func (z *Float) uadd(x, y *Float) { // could make this code significantly faster switch { case ex < ey: - t := z.mant.shl(y.mant, uint(ey-ex)) - z.mant = t.add(x.mant, t) + // cannot re-use z.mant w/o testing for aliasing + t := nat(nil).shl(y.mant, uint(ey-ex)) + z.mant = z.mant.add(x.mant, t) default: // ex == ey, no shift needed z.mant = z.mant.add(x.mant, y.mant) case ex > ey: - t := z.mant.shl(x.mant, uint(ex-ey)) - z.mant = t.add(t, y.mant) + // cannot re-use z.mant w/o testing for aliasing + t := nat(nil).shl(x.mant, uint(ex-ey)) + z.mant = z.mant.add(t, y.mant) ex = ey } // len(z.mant) > 0 @@ -908,13 +895,15 @@ func (z *Float) usub(x, y *Float) { switch { case ex < ey: - t := z.mant.shl(y.mant, uint(ey-ex)) + // cannot re-use z.mant w/o testing for aliasing + t := nat(nil).shl(y.mant, uint(ey-ex)) z.mant = t.sub(x.mant, t) default: // ex == ey, no shift needed z.mant = z.mant.sub(x.mant, y.mant) case ex > ey: - t := z.mant.shl(x.mant, uint(ex-ey)) + // cannot re-use z.mant w/o testing for aliasing + t := nat(nil).shl(x.mant, uint(ex-ey)) z.mant = t.sub(t, y.mant) ex = ey } @@ -1072,11 +1061,11 @@ func (z *Float) Add(x, y *Float) *Float { // TODO(gri) what about -0? if len(y.mant) == 0 { // TODO(gri) handle Inf - return z.Round(x, z.prec, z.mode) + return z.Set(x) } if len(x.mant) == 0 { // TODO(gri) handle Inf - return z.Round(y, z.prec, z.mode) + return z.Set(y) } // x, y != 0 @@ -1113,13 +1102,10 @@ func (z *Float) Sub(x, y *Float) *Float { // TODO(gri) what about -0? if len(y.mant) == 0 { // TODO(gri) handle Inf - return z.Round(x, z.prec, z.mode) + return z.Set(x) } if len(x.mant) == 0 { - prec := z.prec - mode := z.mode - z.Neg(y) - return z.Round(z, prec, mode) + return z.Neg(y) } // x, y != 0 diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go index 2f804fa569..be2ac6ff06 100644 --- a/src/math/big/float_test.go +++ b/src/math/big/float_test.go @@ -729,14 +729,20 @@ func TestFloatNeg(t *testing.T) { } func TestFloatInc(t *testing.T) { - var x, one Float - // x.prec = 256 TODO(gri) This doesn't work at the moment - one.SetInt64(1) - for i := 0; i < 10; i++ { - x.Add(&x, &one) - } - if s := x.Format('g', 10); s != "10" { - t.Errorf("got %s; want 10", s) + const n = 10 + for _, prec := range precList { + if 1< Date: Fri, 13 Feb 2015 13:44:39 -0800 Subject: math/big: implement/rename accessors for precision and rounding mode Also: remove NewFloat - not needed anymore. Work-around for places where has been used so far: NewFloat(x, prec, mode) === new(Float).SetMode(mode).SetPrec(prec).SetFloat64(x) However, if mode == ToNearestEven, SetMode is not needed. SetPrec is needed if the default precision (53 after SetFloat64) is not adequate. TBR adonovan Change-Id: Ifda12c479ba157f2dea306c32b47c7afbf31e759 Reviewed-on: https://go-review.googlesource.com/4842 Reviewed-by: Robert Griesemer --- src/math/big/float.go | 55 ++++++++++++++++++----------------- src/math/big/float_test.go | 71 +++++++++++++++++++++++----------------------- src/math/big/floatconv.go | 4 +-- 3 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index 32e320a140..971a9e5c56 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -29,7 +29,7 @@ const debugFloat = true // enable for debugging // // Each Float value also has a precision, rounding mode, and accuracy. // -// The precision is the (maximum) number of mantissa bits available to +// The precision is the maximum number of mantissa bits available to // represent the value. The rounding mode specifies how a result should // be rounded to fit into the mantissa bits, and accuracy describes the // rounding error with respect to the exact result. @@ -39,8 +39,10 @@ const debugFloat = true // enable for debugging // and according to its rounding mode, unless specified otherwise. If the // result precision is 0 (see below), it is set to the precision of the // argument with the largest precision value before any rounding takes -// place. -// TODO(gri) should the rounding mode also be copied in this case? +// place. The rounding mode remains unchanged, thus uninitialized Floats +// provided as result arguments will "inherit" a reasonble precision from +// the incoming arguments and their mode is the zero value for RoundingMode +// (ToNearestEven). // // By setting the desired precision to 24 or 53 and using ToNearestEven // rounding, Float operations produce the same results as the corresponding @@ -69,24 +71,6 @@ type Float struct { // of the the Word size _W, x.mant[0] has trailing zero bits. Zero and Inf // values have an empty mantissa and a 0 or infExp exponent, respectively. -// NewFloat returns a new Float with value x rounded -// to prec bits according to the given rounding mode. -// If prec == 0, the result has value 0.0 independent -// of the value of x. -// BUG(gri) For prec == 0 and x == Inf, the result -// should be Inf as well. -// TODO(gri) rethink this signature. -func NewFloat(x float64, prec uint, mode RoundingMode) *Float { - var z Float - if prec > 0 { - // TODO(gri) should make this more efficient - z.SetFloat64(x) - return z.Round(&z, prec, mode) - } - z.mode = mode // TODO(gri) don't do this twice for prec > 0 - return &z -} - const ( MaxExp = math.MaxInt32 // largest supported exponent magnitude infExp = -MaxExp - 1 // exponent for Inf values @@ -158,14 +142,33 @@ func (mode RoundingMode) String() string { panic("unreachable") } -// Precision returns the mantissa precision of x in bits. -// The precision may be 0 for |x| == 0 or |x| == Inf. -func (x *Float) Precision() uint { +// SetPrec sets z's precision to prec and returns the (possibly) rounded +// value of z. Rounding occurs according to z's rounding mode if the mantissa +// cannot be represented in prec bits without loss of precision. +func (z *Float) SetPrec(prec uint) *Float { + old := z.prec + z.prec = prec + if prec < old { + z.round(0) + } + return z +} + +// SetMode sets z's rounding mode to mode and returns z. +// z remains unchanged otherwise. +func (z *Float) SetMode(mode RoundingMode) *Float { + z.mode = mode + return z +} + +// Prec returns the mantissa precision of x in bits. +// The result may be 0 for |x| == 0 or |x| == Inf. +func (x *Float) Prec() uint { return uint(x.prec) } -// Accuracy returns the accuracy of x produced by the most recent operation. -func (x *Float) Accuracy() Accuracy { +// Acc returns the accuracy of x produced by the most recent operation. +func (x *Float) Acc() Accuracy { return x.acc } diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go index be2ac6ff06..db4b52b4e0 100644 --- a/src/math/big/float_test.go +++ b/src/math/big/float_test.go @@ -37,16 +37,18 @@ func TestFloatZeroValue(t *testing.T) { } // zero value has precision 0 - if prec := x.Precision(); prec != 0 { + if prec := x.Prec(); prec != 0 { t.Errorf("prec = %d; want 0", prec) } // zero value can be used in any and all positions of binary operations make := func(x int) *Float { - if x == 0 { - return new(Float) // 0 translates into the zero value + var f Float + if x != 0 { + f.SetInt64(int64(x)) } - return NewFloat(float64(x), 10, 0) + // x == 0 translates into the zero value + return &f } for _, test := range []struct { z, x, y, want int @@ -95,7 +97,7 @@ func makeFloat(s string) *Float { return NewInf(-1) } var x Float - x.prec = 1000 // TODO(gri) find a better way to do this + x.SetPrec(1000) if _, ok := x.SetString(s); !ok { panic(fmt.Sprintf("%q is not a valid float", s)) } @@ -266,8 +268,8 @@ func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) { // check result r1 := f.int64() - p1 := f.Precision() - a1 := f.Accuracy() + p1 := f.Prec() + a1 := f.Acc() if r1 != r || p1 != prec || a1 != a { t.Errorf("Round(%s, %d, %s): got %s (%d bits, %s); want %s (%d bits, %s)", toBinary(x), prec, mode, @@ -412,7 +414,7 @@ func TestFloatSetUint64(t *testing.T) { // test basic rounding behavior (exhaustive rounding testing is done elsewhere) const x uint64 = 0x8765432187654321 // 64 bits needed for prec := uint(1); prec <= 64; prec++ { - f := NewFloat(0, prec, ToZero).SetUint64(x) + f := new(Float).SetPrec(prec).SetMode(ToZero).SetUint64(x) got := f.uint64() want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits if got != want { @@ -447,7 +449,7 @@ func TestFloatSetInt64(t *testing.T) { // test basic rounding behavior (exhaustive rounding testing is done elsewhere) const x int64 = 0x7654321076543210 // 63 bits needed for prec := uint(1); prec <= 63; prec++ { - f := NewFloat(0, prec, ToZero).SetInt64(x) + f := new(Float).SetPrec(prec).SetMode(ToZero).SetInt64(x) got := f.int64() want := x &^ (1<<(63-prec) - 1) // cut off (round to zero) low 63-prec bits if got != want { @@ -486,7 +488,7 @@ func TestFloatSetFloat64(t *testing.T) { // test basic rounding behavior (exhaustive rounding testing is done elsewhere) const x uint64 = 0x8765432143218 // 53 bits needed for prec := uint(1); prec <= 52; prec++ { - f := NewFloat(0, prec, ToZero).SetFloat64(float64(x)) + f := new(Float).SetPrec(prec).SetMode(ToZero).SetFloat64(float64(x)) got, _ := f.Float64() want := float64(x &^ (1<<(52-prec) - 1)) // cut off (round to zero) low 53-prec bits if got != want { @@ -519,7 +521,7 @@ func TestFloatSetInt(t *testing.T) { if n < 64 { n = 64 } - if prec := f.Precision(); prec != uint(n) { + if prec := f.Prec(); prec != uint(n) { t.Errorf("got prec = %d; want %d", prec, n) } @@ -553,8 +555,8 @@ func TestFloatSetRat(t *testing.T) { } n := max(x.Num().BitLen(), x.Denom().BitLen()) - var f1 Float - var f2 = NewFloat(0, 1000, 0) // set a high precision - TODO(gri) find a cleaner way + var f1, f2 Float + f2.SetPrec(1000) f1.SetRat(&x) f2.SetRat(&x) @@ -562,7 +564,7 @@ func TestFloatSetRat(t *testing.T) { if n < 64 { n = 64 } - if prec := f1.Precision(); prec != uint(n) { + if prec := f1.Prec(); prec != uint(n) { t.Errorf("got prec = %d; want %d", prec, n) } @@ -735,7 +737,7 @@ func TestFloatInc(t *testing.T) { continue // prec must be large enough to hold all numbers from 0 to n } var x, one Float - x.prec = prec + x.SetPrec(prec) one.SetInt64(1) for i := 0; i < n; i++ { x.Add(&x, &one) @@ -778,7 +780,7 @@ func TestFloatAdd(t *testing.T) { for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { for _, prec := range precList { - got := NewFloat(0, prec, mode) + got := new(Float).SetPrec(prec).SetMode(mode) got.Add(x, y) want := roundBits(zbits, prec, mode) if got.Cmp(want) != 0 { @@ -818,7 +820,7 @@ func TestFloatAdd32(t *testing.T) { x := new(Float).SetFloat64(x0) y := new(Float).SetFloat64(y0) - z := NewFloat(0, 24, ToNearestEven) + z := new(Float).SetPrec(24) z.Add(x, y) got, acc := z.Float64() @@ -851,7 +853,7 @@ func TestFloatAdd64(t *testing.T) { x := new(Float).SetFloat64(x0) y := new(Float).SetFloat64(y0) - z := NewFloat(0, 53, ToNearestEven) + z := new(Float).SetPrec(53) z.Add(x, y) got, acc := z.Float64() @@ -903,7 +905,7 @@ func TestFloatMul64(t *testing.T) { x := new(Float).SetFloat64(x0) y := new(Float).SetFloat64(y0) - z := NewFloat(0, 53, ToNearestEven) + z := new(Float).SetPrec(53) z.Mul(x, y) got, _ := z.Float64() @@ -927,15 +929,15 @@ func TestFloatMul64(t *testing.T) { func TestIssue6866(t *testing.T) { for _, prec := range precList { - two := NewFloat(2, prec, ToNearestEven) - one := NewFloat(1, prec, ToNearestEven) - three := NewFloat(3, prec, ToNearestEven) - msix := NewFloat(-6, prec, ToNearestEven) - psix := NewFloat(+6, prec, ToNearestEven) + two := new(Float).SetPrec(prec).SetInt64(2) + one := new(Float).SetPrec(prec).SetInt64(1) + three := new(Float).SetPrec(prec).SetInt64(3) + msix := new(Float).SetPrec(prec).SetInt64(-6) + psix := new(Float).SetPrec(prec).SetInt64(+6) - p := NewFloat(0, prec, ToNearestEven) - z1 := NewFloat(0, prec, ToNearestEven) - z2 := NewFloat(0, prec, ToNearestEven) + p := new(Float).SetPrec(prec) + z1 := new(Float).SetPrec(prec) + z2 := new(Float).SetPrec(prec) // z1 = 2 + 1.0/3*-6 p.Quo(one, three) @@ -981,13 +983,13 @@ func TestFloatQuo(t *testing.T) { // compute accurate x as z*y y := new(Float).SetFloat64(3.14159265358979323e123) - x := NewFloat(0, z.Precision()+y.Precision(), ToZero) + x := new(Float).SetPrec(z.Prec() + y.Prec()).SetMode(ToZero) x.Mul(z, y) // leave for debugging // fmt.Printf("x = %s\ny = %s\nz = %s\n", x, y, z) - if got := x.Accuracy(); got != Exact { + if got := x.Acc(); got != Exact { t.Errorf("got acc = %s; want exact", got) } @@ -996,7 +998,7 @@ func TestFloatQuo(t *testing.T) { for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} { for d := -5; d < 5; d++ { prec := uint(preci + d) - got := NewFloat(0, prec, mode).Quo(x, y) + got := new(Float).SetPrec(prec).SetMode(mode).Quo(x, y) want := roundBits(bits, prec, mode) if got.Cmp(want) != 0 { t.Errorf("i = %d, prec = %d, %s:\n\t %s\n\t/ %s\n\t= %s\n\twant %s", @@ -1030,9 +1032,9 @@ func TestFloatQuoSmoke(t *testing.T) { // vary operand precision (only ok as long as a, b can be represented correctly) for ad := -dprec; ad <= dprec; ad++ { for bd := -dprec; bd <= dprec; bd++ { - A := NewFloat(a, uint(prec+ad), 0) - B := NewFloat(b, uint(prec+bd), 0) - C := NewFloat(0, 53, 0).Quo(A, B) // C has float64 mantissa width + A := new(Float).SetPrec(uint(prec + ad)).SetFloat64(a) + B := new(Float).SetPrec(uint(prec + bd)).SetFloat64(b) + C := new(Float).SetPrec(53).Quo(A, B) // C has float64 mantissa width cc, acc := C.Float64() if cc != c { @@ -1143,7 +1145,7 @@ func roundBits(x []int, prec uint, mode RoundingMode) *Float { } if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero { // round away from zero - f.Round(f, prec, ToZero) // extend precision // TODO(gri) better approach? + f.SetMode(ToZero).SetPrec(prec) f.Add(f, fromBits(int(r)+1)) } return f @@ -1157,7 +1159,6 @@ func fromBits(bits ...int) *Float { // handle 0 if len(bits) == 0 { return new(Float) - // z.prec = ? } // len(bits) > 0 diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go index 511cc51889..04f9a4e1b4 100644 --- a/src/math/big/floatconv.go +++ b/src/math/big/floatconv.go @@ -151,13 +151,13 @@ func (z *Float) Parse(s string, base int) (f *Float, b int, err error) { // ScanFloat is like f.Scan(r, base) with f set to the given precision // and rounding mode. func ScanFloat(r io.ByteScanner, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) { - return NewFloat(0, prec, mode).Scan(r, base) + return new(Float).SetPrec(prec).SetMode(mode).Scan(r, base) } // ParseFloat is like f.Parse(s, base) with f set to the given precision // and rounding mode. func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) { - return NewFloat(0, prec, mode).Parse(s, base) + return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base) } // Format converts the floating-point number x to a string according -- cgit v1.2.3-54-g00ecf From 2e3c738649832d13ecaddc0c72f64d0354a89dae Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 13 Feb 2015 16:30:21 -0800 Subject: math/big: remove Float.Round (not needed anymore), fix a bug in SetInt64 TBR adonovan Change-Id: I30020f39be9183b37275e10a4fd1e1a3b4c48c89 Reviewed-on: https://go-review.googlesource.com/4880 Reviewed-by: Robert Griesemer --- src/math/big/float.go | 40 ++++++++++++++++++++-------------------- src/math/big/float_test.go | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index 971a9e5c56..dd6700137b 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -147,6 +147,7 @@ func (mode RoundingMode) String() string { // cannot be represented in prec bits without loss of precision. func (z *Float) SetPrec(prec uint) *Float { old := z.prec + z.acc = Exact z.prec = prec if prec < old { z.round(0) @@ -154,9 +155,10 @@ func (z *Float) SetPrec(prec uint) *Float { return z } -// SetMode sets z's rounding mode to mode and returns z. +// SetMode sets z's rounding mode to mode and returns an exact z. // z remains unchanged otherwise. func (z *Float) SetMode(mode RoundingMode) *Float { + z.acc = Exact z.mode = mode return z } @@ -436,16 +438,6 @@ func (z *Float) round(sbit uint) { return } -// Round sets z to the value of x rounded according to mode to prec bits and returns z. -// TODO(gri) rethink this signature. -func (z *Float) Round(x *Float, prec uint, mode RoundingMode) *Float { - z.Copy(x) - z.prec = prec - z.mode = mode - z.round(0) - return z -} - // nlz returns the number of leading zero bits in x. func nlz(x Word) uint { return _W - uint(bitLen(x)) @@ -465,15 +457,12 @@ func nlz64(x uint64) uint { panic("unreachable") } -// SetUint64 sets z to the (possibly rounded) value of x and returns z. -// If z's precision is 0, it is changed to 64 (and rounding will have -// no effect). -func (z *Float) SetUint64(x uint64) *Float { +func (z *Float) setBits64(neg bool, x uint64) *Float { if z.prec == 0 { z.prec = 64 } z.acc = Exact - z.neg = false + z.neg = neg if x == 0 { z.mant = z.mant[:0] z.exp = 0 @@ -489,6 +478,13 @@ func (z *Float) SetUint64(x uint64) *Float { return z } +// SetUint64 sets z to the (possibly rounded) value of x and returns z. +// If z's precision is 0, it is changed to 64 (and rounding will have +// no effect). +func (z *Float) SetUint64(x uint64) *Float { + return z.setBits64(false, x) +} + // SetInt64 sets z to the (possibly rounded) value of x and returns z. // If z's precision is 0, it is changed to 64 (and rounding will have // no effect). @@ -497,9 +493,9 @@ func (z *Float) SetInt64(x int64) *Float { if u < 0 { u = -u } - z.SetUint64(uint64(u)) - z.neg = x < 0 - return z + // We cannot simply call z.SetUint64(uint64(u)) and change + // the sign afterwards because the sign affects rounding. + return z.setBits64(x < 0, uint64(u)) } // SetFloat64 sets z to the (possibly rounded) value of x and returns z. @@ -599,6 +595,7 @@ func (z *Float) SetRat(x *Rat) *Float { // mode; and z's accuracy reports the result error relative to the // exact (not rounded) result. func (z *Float) Set(x *Float) *Float { + // TODO(gri) what about z.acc? should it be always Exact? if z != x { if z.prec == 0 { z.prec = x.prec @@ -617,6 +614,7 @@ func (z *Float) Set(x *Float) *Float { // Copy sets z to x, with the same precision and rounding mode as x, // and returns z. func (z *Float) Copy(x *Float) *Float { + // TODO(gri) what about z.acc? should it be always Exact? if z != x { z.acc = Exact z.neg = x.neg @@ -761,7 +759,9 @@ func (x *Float) Float64() (float64, Accuracy) { return 0, Exact } // x != 0 - r := new(Float).Round(x, 53, ToNearestEven) + var r Float + r.prec = 53 + r.Set(x) var s uint64 if r.neg { s = 1 << 63 diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go index db4b52b4e0..8ed7f0a4ad 100644 --- a/src/math/big/float_test.go +++ b/src/math/big/float_test.go @@ -263,18 +263,46 @@ func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) { } // round - f := new(Float).SetInt64(x) - f.Round(f, prec, mode) + f := new(Float).SetMode(mode).SetInt64(x).SetPrec(prec) // check result r1 := f.int64() p1 := f.Prec() a1 := f.Acc() if r1 != r || p1 != prec || a1 != a { - t.Errorf("Round(%s, %d, %s): got %s (%d bits, %s); want %s (%d bits, %s)", + t.Errorf("round %s (%d bits, %s) incorrect: got %s (%d bits, %s); want %s (%d bits, %s)", toBinary(x), prec, mode, toBinary(r1), p1, a1, toBinary(r), prec, a) + return + } + + // g and f should be the same + // (rounding by SetPrec after SetInt64 using default precision + // should be the same as rounding by SetInt64 after setting the + // precision) + g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x) + if !feq(g, f) { + t.Errorf("round %s (%d bits, %s) not symmetric: got %s and %s; want %s", + toBinary(x), prec, mode, + toBinary(g.int64()), + toBinary(r1), + toBinary(r), + ) + return + } + + // h and f should be the same + // (repeated rounding should be idempotent) + h := new(Float).SetMode(mode).SetPrec(prec).Set(f) + if !feq(h, f) { + t.Errorf("round %s (%d bits, %s) not idempotent: got %s and %s; want %s", + toBinary(x), prec, mode, + toBinary(h.int64()), + toBinary(r1), + toBinary(r), + ) + return } } @@ -383,8 +411,7 @@ func TestFloatRound24(t *testing.T) { const x0 = 1<<26 - 0x10 // 11...110000 (26 bits) for d := 0; d <= 0x10; d++ { x := float64(x0 + d) - f := new(Float).SetFloat64(x) - f.Round(f, 24, ToNearestEven) + f := new(Float).SetPrec(24).SetFloat64(x) got, _ := f.Float64() want := float64(float32(x)) if got != want { -- cgit v1.2.3-54-g00ecf From ccdbfe31747621fbdb15ade5c4d34b339e45407f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 12 Feb 2015 14:52:46 -0800 Subject: math/big: only permit bases 2, 10, 16 when scanning number w/ "decimal" point TBR adonovan Change-Id: I4fd694101c2cf1c0c39bf73d16cab18502742dd9 Reviewed-on: https://go-review.googlesource.com/4881 Reviewed-by: Robert Griesemer --- src/math/big/natconv.go | 20 +++++++++++++------- src/math/big/natconv_test.go | 6 +----- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/math/big/natconv.go b/src/math/big/natconv.go index e094d22193..b5c37731fa 100644 --- a/src/math/big/natconv.go +++ b/src/math/big/natconv.go @@ -8,6 +8,7 @@ package big import ( "errors" + "fmt" "io" "math" "sync" @@ -50,7 +51,7 @@ func pow(x Word, n int) (p Word) { // scan scans the number corresponding to the longest possible prefix // from r representing an unsigned number in a given conversion base. // It returns the corresponding natural number res, the actual base b, -// a digit count, and an error err, if any. +// a digit count, and a read or syntax error err, if any. // // number = [ prefix ] mantissa . // prefix = "0" [ "x" | "X" | "b" | "B" ] . @@ -58,12 +59,15 @@ func pow(x Word, n int) (p Word) { // digits = digit { digit } . // digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . // -// The base argument must be 0 or a value between 0 through MaxBase. +// Unless fracOk is set, the base argument must be 0 or a value between +// 2 through MaxBase. If fracOk is set, the base argument must be one of +// 0, 2, 10, or 16. Providing an invalid base argument leads to a run- +// time panic. // // For base 0, the number prefix determines the actual base: A prefix of // ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix // selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise -// the selected base is 10 and no prefix is permitted. +// the selected base is 10 and no prefix is accepted. // // If fracOk is set, an octal prefix is ignored (a leading ``0'' simply // stands for a zero digit), and a period followed by a fractional part @@ -73,13 +77,15 @@ func pow(x Word, n int) (p Word) { // A result digit count > 0 corresponds to the number of (non-prefix) digits // parsed. A digit count <= 0 indicates the presence of a period (if fracOk // is set, only), and -count is the number of fractional digits found. -// In this case, the value of the scanned number is res * 10**count. +// In this case, the actual value of the scanned number is res * b**count. // func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) { // reject illegal bases - if base != 0 && base < 2 || base > MaxBase { - err = errors.New("illegal number base") - return + baseOk := base == 0 || + !fracOk && 2 <= base && base <= MaxBase || + fracOk && (base == 2 || base == 10 || base == 16) + if !baseOk { + panic(fmt.Sprintf("illegal number base %d", base)) } // one char look-ahead diff --git a/src/math/big/natconv_test.go b/src/math/big/natconv_test.go index d4c3fb4b34..f321fbc2df 100644 --- a/src/math/big/natconv_test.go +++ b/src/math/big/natconv_test.go @@ -98,10 +98,6 @@ var natScanTests = []struct { ok bool // expected success next rune // next character (or 0, if at EOF) }{ - // error: illegal base - {base: -1}, - {base: 37}, - // error: no mantissa {}, {s: "?"}, @@ -114,7 +110,7 @@ var natScanTests = []struct { // error: incorrect use of decimal point {s: ".0"}, {s: ".0", base: 10}, - {s: ".", base: 1}, + {s: ".", base: 0}, {s: "0x.0"}, // no errors -- cgit v1.2.3-54-g00ecf From a809dc7adb8065368c73900a8256048c55cde79b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 12 Feb 2015 15:09:56 -0800 Subject: math/big: don't scan past a binary exponent if not accepted syntactically TBR adonovan Change-Id: I842cbc855dbd560f65e76c9a557dff1a22c5d610 Reviewed-on: https://go-review.googlesource.com/4882 Reviewed-by: Robert Griesemer --- src/math/big/floatconv.go | 7 ++++--- src/math/big/ratconv.go | 23 ++++++++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go index 04f9a4e1b4..a857fa6513 100644 --- a/src/math/big/floatconv.go +++ b/src/math/big/floatconv.go @@ -46,11 +46,12 @@ func (z *Float) SetString(s string) (*Float, bool) { // digits = digit { digit } . // digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . // -// The base argument must be 0 or a value between 2 through MaxBase. +// The base argument must be 0, 2, 10, or 16. Providing an invalid base +// argument will lead to a run-time panic. // // For base 0, the number prefix determines the actual base: A prefix of // ``0x'' or ``0X'' selects base 16, and a ``0b'' or ``0B'' prefix selects -// base 2; otherwise, the actual base is 10 and no prefix is permitted. +// base 2; otherwise, the actual base is 10 and no prefix is accepted. // The octal prefix ``0'' is not supported. // // A "p" exponent indicates power of 2 for the exponent; for instance "1.2p3" @@ -75,7 +76,7 @@ func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) { // exponent var exp int64 var ebase int - exp, ebase, err = scanExponent(r) + exp, ebase, err = scanExponent(r, true) if err != nil { return } diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go index da4915e74d..778077b96e 100644 --- a/src/math/big/ratconv.go +++ b/src/math/big/ratconv.go @@ -78,9 +78,8 @@ func (z *Rat) SetString(s string) (*Rat, bool) { // exponent var exp int64 - var ebase int - exp, ebase, err = scanExponent(r) - if ebase == 2 || err != nil { + exp, _, err = scanExponent(r, false) + if err != nil { return nil, false } @@ -115,7 +114,17 @@ func (z *Rat) SetString(s string) (*Rat, bool) { return z, true } -func scanExponent(r io.ByteScanner) (exp int64, base int, err error) { +// scanExponent scans the longest possible prefix of r representing a decimal +// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the +// exponent base (10 or 2), or a read or syntax error, if any. +// +// exponent = ( "E" | "e" | "p" ) [ sign ] digits . +// sign = "+" | "-" . +// digits = digit { digit } . +// digit = "0" ... "9" . +// +// A binary exponent is only permitted if binExpOk is set. +func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) { base = 10 var ch byte @@ -130,7 +139,11 @@ func scanExponent(r io.ByteScanner) (exp int64, base int, err error) { case 'e', 'E': // ok case 'p': - base = 2 + if binExpOk { + base = 2 + break // ok + } + fallthrough // binary exponent not permitted default: r.UnreadByte() return // no exponent; same as e0 -- cgit v1.2.3-54-g00ecf From b7bfb54eaa84a7de187df905ae8f74c8fed515f4 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 13 Feb 2015 20:15:40 -0800 Subject: math/big: fix aliasing bug in Float.Quo TBR r, adonovan Change-Id: I1a38e2d724bf1147c7307a7e5ae855c42c60428c Reviewed-on: https://go-review.googlesource.com/4875 Reviewed-by: Robert Griesemer --- src/math/big/float.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index dd6700137b..314fd689ed 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -967,12 +967,16 @@ func (z *Float) uquo(x, y *Float) { // to shorten x for faster division. But we must be extra careful // with rounding in that case. + // Compute d before division since there may be aliasing of x.mant + // (via xadj) or y.mant with z.mant. + d := len(xadj) - len(y.mant) + // divide var r nat z.mant, r = z.mant.div(nil, xadj, y.mant) // determine exponent - e := int64(x.exp) - int64(y.exp) - int64(len(xadj)-len(y.mant)-len(z.mant))*_W + e := int64(x.exp) - int64(y.exp) - int64(d-len(z.mant))*_W // normalize mantissa z.setExp(e - int64(fnorm(z.mant))) -- cgit v1.2.3-54-g00ecf From 5aa448ff8cc5aed0832a7e1218e0d6b032b89d07 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 13 Feb 2015 18:31:30 -0800 Subject: test: add test case for issue 4365 This is an update of http://golang.org/cl/151410043 by Tim Shen. Change-Id: I43ab7fcedd785059c535f45a3c8cdb7b618c1499 Reviewed-on: https://go-review.googlesource.com/4873 Reviewed-by: David Crawshaw --- test/fixedbugs/issue4365.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/fixedbugs/issue4365.go diff --git a/test/fixedbugs/issue4365.go b/test/fixedbugs/issue4365.go new file mode 100644 index 0000000000..8fcbd3cf2f --- /dev/null +++ b/test/fixedbugs/issue4365.go @@ -0,0 +1,27 @@ +// errorcheck + +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that fields hide promoted methods. +// http://golang.org/issue/4365 + +package main + +type T interface { + M() +} + +type M struct{} + +func (M) M() {} + +type Foo struct { + M +} + +func main() { + var v T = Foo{} // ERROR "has no methods|not a method|cannot use" + _ = v +} -- cgit v1.2.3-54-g00ecf From 788f78ad08a4d8a66808eb4c197521223599b063 Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Sat, 14 Feb 2015 00:40:21 -0500 Subject: cmd/go: remove script and script.txt Fixes #9824. Change-Id: Id318c61b6884e4fd294f7b0946dcc306f746ee0a Reviewed-on: https://go-review.googlesource.com/4891 Reviewed-by: Brad Fitzpatrick --- src/cmd/go/script | 23 ---- src/cmd/go/script.txt | 352 -------------------------------------------------- 2 files changed, 375 deletions(-) delete mode 100755 src/cmd/go/script delete mode 100644 src/cmd/go/script.txt diff --git a/src/cmd/go/script b/src/cmd/go/script deleted file mode 100755 index 340a7e824c..0000000000 --- a/src/cmd/go/script +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -x() { - echo '--- ' "$@" - "$@" - echo '---' - echo -} - -x go help -x go help build -x go help clean -x go help install -x go help fix -x go help fmt -x go help get -x go help list -x go help test -x go help version -x go help vet -x go help gopath -x go help importpath -x go help remote diff --git a/src/cmd/go/script.txt b/src/cmd/go/script.txt deleted file mode 100644 index a672146584..0000000000 --- a/src/cmd/go/script.txt +++ /dev/null @@ -1,352 +0,0 @@ ---- go help -usage: go command [arguments] - -go manages Go source code. - -The commands are: - - build compile and install packages and dependencies - clean remove intermediate objects - fix run gofix on packages - fmt run gofmt -w on packages - get download and install packages and dependencies - install install packages and dependencies - list list packages - test test packages - version print Go version - vet run govet on packages - -Use "go help [command]" for more information about a command. - -Additional help topics: - - gopath GOPATH environment variable - importpath description of import paths - remote remote import path syntax - -Use "go help [topic]" for more information about that topic. - ---- - ---- go help build -usage: go build [-n] [-v] [importpath...] - -Build compiles the packages named by the import paths, -along with their dependencies, but it does not install the results. - -The -n flag prints the commands but does not run them. -The -v flag prints the commands. - -For more about import paths, see 'go help importpath'. - -See also: go install, go get, go clean. ---- - ---- go help clean -usage: go clean [-nuke] [importpath...] - -Clean removes intermediate object files generated during -the compilation of the packages named by the import paths, -but by default it does not remove the installed package binaries. - -The -nuke flag causes clean to remove the installed package binaries too. - -TODO: Clean does not clean dependencies of the packages. - -For more about import paths, see 'go help importpath'. ---- - ---- go help install -usage: go install [-n] [-v] [importpath...] - -Install compiles and installs the packages named by the import paths, -along with their dependencies. - -The -n flag prints the commands but does not run them. -The -v flag prints the commands. - -For more about import paths, see 'go help importpath'. - -See also: go build, go get, go clean. ---- - ---- go help fix -usage: go fix [importpath...] - -Fix runs the gofix command on the packages named by the import paths. - -For more about gofix, see 'godoc gofix'. -For more about import paths, see 'go help importpath'. - -To run gofix with specific options, run gofix itself. - -See also: go fmt, go vet. ---- - ---- go help fmt -usage: go fmt [importpath...] - -Fmt runs the command 'gofmt -w' on the packages named by the import paths. - -For more about gofmt, see 'godoc gofmt'. -For more about import paths, see 'go help importpath'. - -To run gofmt with specific options, run gofmt itself. - -See also: go fix, go vet. ---- - ---- go help get -usage: go get [importpath...] - -Get downloads and installs the packages named by the import paths, -along with their dependencies. - -After downloading the code, 'go get' looks for a tag beginning -with "go." that corresponds to the local Go version. -For Go "release.r58" it looks for a tag named "go.r58". -For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03". -If the specific "go.X" tag is not found, it uses the latest earlier -version it can find. Otherwise, it uses the default version for -the version control system: HEAD for git, tip for Mercurial, -and so on. - -TODO: Explain versions better. - -For more about import paths, see 'go help importpath'. - -For more about how 'go get' finds source code to -download, see 'go help remote'. - -See also: go build, go install, go clean. ---- - ---- go help list -usage: go list [-f format] [-json] [importpath...] - -List lists the packages named by the import paths. - -The default output shows the package name and file system location: - - books /home/you/src/google-api-go-client.googlecode.com/hg/books/v1 - oauth /home/you/src/goauth2.googlecode.com/hg/oauth - sqlite /home/you/src/gosqlite.googlecode.com/hg/sqlite - -The -f flag specifies an alternate format for the list, -using the syntax of package template. The default output -is equivalent to -f '{{.Name}} {{.Dir}}' The struct -being passed to the template is: - - type Package struct { - Name string // package name - Doc string // package documentation string - GoFiles []string // names of Go source files in package - ImportPath string // import path denoting package - Imports []string // import paths used by this package - Deps []string // all (recursively) imported dependencies - Dir string // directory containing package sources - Version string // version of installed package - } - -The -json flag causes the package data to be printed in JSON format. - -For more about import paths, see 'go help importpath'. ---- - ---- go help test -usage: go test [importpath...] - -Test runs gotest to test the packages named by the import paths. -It prints a summary of the test results in the format: - - test archive/tar - FAIL archive/zip - test compress/gzip - ... - -followed by gotest output for each failed package. - -For more about import paths, see 'go help importpath'. - -See also: go build, go compile, go vet. ---- - ---- go help version -usage: go version - -Version prints the Go version, as reported by runtime.Version. ---- - ---- go help vet -usage: go vet [importpath...] - -Vet runs the govet command on the packages named by the import paths. - -For more about govet, see 'godoc govet'. -For more about import paths, see 'go help importpath'. - -To run govet with specific options, run govet itself. - -See also: go fmt, go fix. ---- - ---- go help gopath -The GOPATH environment variable lists places to look for Go code. -On Unix, the value is a colon-separated string. -On Windows, the value is a semicolon-separated string. -On Plan 9, the value is a list. - -GOPATH must be set to build and install packages outside the -standard Go tree. - -Each directory listed in GOPATH must have a prescribed structure: - -The src/ directory holds source code. The path below 'src' -determines the import path or executable name. - -The pkg/ directory holds installed package objects. -As in the Go tree, each target operating system and -architecture pair has its own subdirectory of pkg -(pkg/GOOS_GOARCH). - -If DIR is a directory listed in the GOPATH, a package with -source in DIR/src/foo/bar can be imported as "foo/bar" and -has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a". - -The bin/ directory holds compiled commands. -Each command is named for its source directory, but only -the final element, not the entire path. That is, the -command with source in DIR/src/foo/quux is installed into -DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped -so that you can add DIR/bin to your PATH to get at the -installed commands. - -Here's an example directory layout: - - GOPATH=/home/user/gocode - - /home/user/gocode/ - src/ - foo/ - bar/ (go code in package bar) - x.go - quux/ (go code in package main) - y.go - bin/ - quux (installed command) - pkg/ - linux_amd64/ - foo/ - bar.a (installed package object) - -Go searches each directory listed in GOPATH to find source code, -but new packages are always downloaded into the first directory -in the list. ---- - ---- go help importpath -Many commands apply to a set of packages named by import paths: - - go action [importpath...] - -An import path that is a rooted path or that begins with -a . or .. element is interpreted as a file system path and -denotes the package in that directory. - -Otherwise, the import path P denotes the package found in -the directory DIR/src/P for some DIR listed in the GOPATH -environment variable (see 'go help gopath'). - -If no import paths are given, the action applies to the -package in the current directory. - -The special import path "all" expands to all package directories -found in all the GOPATH trees. For example, 'go list all' -lists all the packages on the local system. - -An import path can also name a package to be downloaded from -a remote repository. Run 'go help remote' for details. - -Every package in a program must have a unique import path. -By convention, this is arranged by starting each path with a -unique prefix that belongs to you. For example, paths used -internally at Google all begin with 'google', and paths -denoting remote repositories begin with the path to the code, -such as 'project.googlecode.com/'. ---- - ---- go help remote -An import path (see 'go help importpath') denotes a package -stored in the local file system. Certain import paths also -describe how to obtain the source code for the package using -a revision control system. - -A few common code hosting sites have special syntax: - - BitBucket (Mercurial) - - import "bitbucket.org/user/project" - import "bitbucket.org/user/project/sub/directory" - - GitHub (Git) - - import "github.com/user/project" - import "github.com/user/project/sub/directory" - - Google Code Project Hosting (Git, Mercurial, Subversion) - - import "project.googlecode.com/git" - import "project.googlecode.com/git/sub/directory" - - import "project.googlecode.com/hg" - import "project.googlecode.com/hg/sub/directory" - - import "project.googlecode.com/svn/trunk" - import "project.googlecode.com/svn/trunk/sub/directory" - - Launchpad (Bazaar) - - import "launchpad.net/project" - import "launchpad.net/project/series" - import "launchpad.net/project/series/sub/directory" - - import "launchpad.net/~user/project/branch" - import "launchpad.net/~user/project/branch/sub/directory" - -For code hosted on other servers, an import path of the form - - repository.vcs/path - -specifies the given repository, with or without the .vcs suffix, -using the named version control system, and then the path inside -that repository. The supported version control systems are: - - Bazaar .bzr - Git .git - Mercurial .hg - Subversion .svn - -For example, - - import "example.org/user/foo.hg" - -denotes the root directory of the Mercurial repository at -example.org/user/foo or foo.hg, and - - import "example.org/repo.git/foo/bar" - -denotes the foo/bar directory of the Git repository at -example.com/repo or repo.git. - -When a version control system supports multiple protocols, -each is tried in turn when downloading. For example, a Git -download tries git://, then https://, then http://. - -New downloaded packages are written to the first directory -listed in the GOPATH environment variable (see 'go help gopath'). - -The go command attempts to download the version of the -package appropriate for the Go release being used. -Run 'go help install' for more. ---- - -- cgit v1.2.3-54-g00ecf From 7aa68756c5518e0fc2e2f65cab6b933c1c48534a Mon Sep 17 00:00:00 2001 From: Shenghou Ma Date: Thu, 8 Jan 2015 21:43:47 -0500 Subject: doc/asm: document that assembly function must use short name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit e.g. ·Name instead of package·Name for automatic stack map to be applied from its Go prototype. The underlying reason is that liblink look up name with suffix ".args_stackmap" for the stackmap coming from its Go prototype, but all the Go functions are named "".Name as this stage. Thus an assembly function named package·Name will never find its stackmap, which is named "".package.Name.args_stackmap. Perhaps cmd/vet should give a warning for this. Change-Id: I10d154a73ec969d574d20af877f747424350fbd1 Reviewed-on: https://go-review.googlesource.com/2588 Reviewed-by: Ian Lance Taylor --- doc/asm.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/asm.html b/doc/asm.html index 771c493cc2..43382fc96b 100644 --- a/doc/asm.html +++ b/doc/asm.html @@ -350,7 +350,11 @@ live pointers in its arguments, results, and local stack frame. For an assembly function with no pointer results and either no local stack frame or no function calls, the only requirement is to define a Go prototype for the function -in a Go source file in the same package. +in a Go source file in the same package. The name of the assembly +function must not contain the package name component (for example, +function Syscall in package syscall should +use the name ·Syscall instead of the equivalent name +syscall·Syscall in its TEXT directive). For more complex situations, explicit annotation is needed. These annotations use pseudo-instructions defined in the standard #include file funcdata.h. -- cgit v1.2.3-54-g00ecf From 2dd7a6d41f2d28d7eb2209e8887ca80c461b52cb Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 13 Feb 2015 21:47:10 -0800 Subject: math/big: always round after the sign is set Some rounding modes are affected by the sign of the value to be rounded. Make sure the sign is set before round is called. Added tests (that failed before the fix). Change-Id: Idd09b8fcbab89894fede0b9bc922cda5ddc87930 Reviewed-on: https://go-review.googlesource.com/4876 Reviewed-by: Rob Pike --- src/math/big/float.go | 16 +++++++------- src/math/big/float_test.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index 314fd689ed..739d30f7ad 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -298,6 +298,10 @@ func validate(args ...*Float) { // sbit must be 0 or 1 and summarizes any "sticky bit" information one might // have before calling round. z's mantissa must be normalized (with the msb set) // or empty. +// +// CAUTION: The rounding modes ToNegativeInf, ToPositiveInf are affected by the +// sign of z. For correct rounding, the sign of z must be set correctly before +// calling round. func (z *Float) round(sbit uint) { if debugFloat { validate(z) @@ -1076,7 +1080,7 @@ func (z *Float) Add(x, y *Float) *Float { } // x, y != 0 - neg := x.neg + z.neg = x.neg if x.neg == y.neg { // x + y == x + y // (-x) + (-y) == -(x + y) @@ -1087,11 +1091,10 @@ func (z *Float) Add(x, y *Float) *Float { if x.ucmp(y) >= 0 { z.usub(x, y) } else { - neg = !neg + z.neg = !z.neg z.usub(y, x) } } - z.neg = neg return z } @@ -1116,7 +1119,7 @@ func (z *Float) Sub(x, y *Float) *Float { } // x, y != 0 - neg := x.neg + z.neg = x.neg if x.neg != y.neg { // x - (-y) == x + y // (-x) - y == -(x + y) @@ -1127,11 +1130,10 @@ func (z *Float) Sub(x, y *Float) *Float { if x.ucmp(y) >= 0 { z.usub(x, y) } else { - neg = !neg + z.neg = !z.neg z.usub(y, x) } } - z.neg = neg return z } @@ -1158,8 +1160,8 @@ func (z *Float) Mul(x, y *Float) *Float { } // x, y != 0 - z.umul(x, y) z.neg = x.neg != y.neg + z.umul(x, y) return z } diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go index 8ed7f0a4ad..17247b1eb2 100644 --- a/src/math/big/float_test.go +++ b/src/math/big/float_test.go @@ -1077,6 +1077,58 @@ func TestFloatQuoSmoke(t *testing.T) { } } +// For rounding modes ToNegativeInf and ToPositiveInf, rounding is affected +// by the sign of the value to be rounded. Test that rounding happens after +// the sign of a result has been set. +// This test uses specific values that are known to fail if rounding is +// "factored" out before setting the result sign. +func TestFloatArithmeticRounding(t *testing.T) { + for _, test := range []struct { + mode RoundingMode + prec uint + x, y, want int64 + op byte + }{ + {ToZero, 3, -0x8, -0x1, -0x8, '+'}, + {AwayFromZero, 3, -0x8, -0x1, -0xa, '+'}, + {ToNegativeInf, 3, -0x8, -0x1, -0xa, '+'}, + + {ToZero, 3, -0x8, 0x1, -0x8, '-'}, + {AwayFromZero, 3, -0x8, 0x1, -0xa, '-'}, + {ToNegativeInf, 3, -0x8, 0x1, -0xa, '-'}, + + {ToZero, 3, -0x9, 0x1, -0x8, '*'}, + {AwayFromZero, 3, -0x9, 0x1, -0xa, '*'}, + {ToNegativeInf, 3, -0x9, 0x1, -0xa, '*'}, + + {ToZero, 3, -0x9, 0x1, -0x8, '/'}, + {AwayFromZero, 3, -0x9, 0x1, -0xa, '/'}, + {ToNegativeInf, 3, -0x9, 0x1, -0xa, '/'}, + } { + var x, y, z Float + x.SetInt64(test.x) + y.SetInt64(test.y) + z.SetPrec(test.prec).SetMode(test.mode) + switch test.op { + case '+': + z.Add(&x, &y) + case '-': + z.Sub(&x, &y) + case '*': + z.Mul(&x, &y) + case '/': + z.Quo(&x, &y) + default: + panic("unreachable") + } + if got, acc := z.Int64(); got != test.want || acc != Exact { + t.Errorf("%s, %d bits: %d %c %d = %d (%s); want %d (Exact)", + test.mode, test.prec, test.x, test.op, test.y, got, acc, test.want, + ) + } + } +} + func TestFloatCmp(t *testing.T) { // TODO(gri) implement this } -- cgit v1.2.3-54-g00ecf From 52dadc1f31f8e509ad22902a41f0fe40b3b0a365 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sat, 14 Feb 2015 16:10:06 +0300 Subject: cmd/gc: fix noscan maps Change 85e7bee introduced a bug: it marks map buckets as noscan when key and val do not contain pointers. However, buckets with large/outline key or val do contain pointers. This change takes key/val size into consideration when marking buckets as noscan. Change-Id: I7172a0df482657be39faa59e2579dd9f209cb54d Reviewed-on: https://go-review.googlesource.com/4901 Reviewed-by: Keith Randall --- src/cmd/gc/reflect.c | 3 ++- src/reflect/type.go | 3 ++- src/runtime/hashmap.go | 2 +- src/runtime/map_test.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 14a1f13e33..9390ab9a86 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -179,7 +179,8 @@ mapbucket(Type *t) bucket->width += widthreg - widthptr; // See comment on hmap.overflow in ../../runtime/hashmap.go. - if(!haspointers(t->type) && !haspointers(t->down)) + if(!haspointers(t->type) && !haspointers(t->down) && + t->type->width <= MAXKEYSIZE && t->down->width <= MAXVALSIZE) bucket->haspointers = 1; // no pointers t->bucket = bucket; diff --git a/src/reflect/type.go b/src/reflect/type.go index 0a8c40808a..1752dddd8d 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1659,7 +1659,8 @@ const ( func bucketOf(ktyp, etyp *rtype) *rtype { // See comment on hmap.overflow in ../runtime/hashmap.go. var kind uint8 - if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 { + if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 && + ktyp.size <= maxKeySize && etyp.size <= maxValSize { kind = kindNoPointers } diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index c7c1198259..ca049dd632 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -114,7 +114,7 @@ type hmap struct { oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated) - // If both key and value do not contain pointers, then we mark bucket + // If both key and value do not contain pointers and are inline, then we mark bucket // type as containing no pointers. This avoids scanning such maps. // However, bmap.overflow is a pointer. In order to keep overflow buckets // alive, we store pointers to all overflow buckets in hmap.overflow. diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go index 55f1f82625..9d2894cb6f 100644 --- a/src/runtime/map_test.go +++ b/src/runtime/map_test.go @@ -515,6 +515,61 @@ func TestMapStringBytesLookup(t *testing.T) { } } +func TestMapLargeKeyNoPointer(t *testing.T) { + const ( + I = 1000 + N = 64 + ) + type T [N]int + m := make(map[T]int) + for i := 0; i < I; i++ { + var v T + for j := 0; j < N; j++ { + v[j] = i + j + } + m[v] = i + } + runtime.GC() + for i := 0; i < I; i++ { + var v T + for j := 0; j < N; j++ { + v[j] = i + j + } + if m[v] != i { + t.Fatalf("corrupted map: want %+v, got %+v", i, m[v]) + } + } +} + +func TestMapLargeValNoPointer(t *testing.T) { + const ( + I = 1000 + N = 64 + ) + type T [N]int + m := make(map[int]T) + for i := 0; i < I; i++ { + var v T + for j := 0; j < N; j++ { + v[j] = i + j + } + m[i] = v + } + runtime.GC() + for i := 0; i < I; i++ { + var v T + for j := 0; j < N; j++ { + v[j] = i + j + } + v1 := m[i] + for j := 0; j < N; j++ { + if v1[j] != v[j] { + t.Fatalf("corrupted map: want %+v, got %+v", v, v1) + } + } + } +} + func benchmarkMapPop(b *testing.B, n int) { m := map[int]int{} for i := 0; i < b.N; i++ { -- cgit v1.2.3-54-g00ecf From 61c9c3ddc4f972cef41aad8e78bdc1746d5c5a4a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Sat, 14 Feb 2015 21:29:37 -0800 Subject: math/big: implement fast path in Float.SetRat if argument is integer Change-Id: Ib82500e198b86e9fade278c7eea7a4b0c6b0b2e1 Reviewed-on: https://go-review.googlesource.com/4921 Reviewed-by: Rob Pike --- src/math/big/float.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index 739d30f7ad..877379c901 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -582,7 +582,9 @@ func (z *Float) SetInt(x *Int) *Float { // If z's precision is 0, it is changed to the largest of a.BitLen(), // b.BitLen(), or 64; with x = a/b. func (z *Float) SetRat(x *Rat) *Float { - // TODO(gri) can be more efficient if x is an integer + if x.IsInt() { + return z.SetInt(x.Num()) + } var a, b Float a.SetInt(x.Num()) b.SetInt(x.Denom()) -- cgit v1.2.3-54-g00ecf From b5c3a9e572a1257c0db47d74b45f8e03f2f91f27 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 13 Feb 2015 18:12:48 +1100 Subject: image: add image.CMYK and color.CMYK types. Change-Id: Icf212a4b890725c803b16e76e1a88294b8b62cb8 Reviewed-on: https://go-review.googlesource.com/4800 Reviewed-by: Rob Pike --- src/image/color/ycbcr.go | 55 +++++++++++++++++++++++++++ src/image/color/ycbcr_test.go | 23 ++++++++++-- src/image/image.go | 86 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 3 deletions(-) diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go index 4c2f29ea02..b7df672784 100644 --- a/src/image/color/ycbcr.go +++ b/src/image/color/ycbcr.go @@ -97,3 +97,58 @@ func yCbCrModel(c Color) Color { y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8)) return YCbCr{y, u, v} } + +// RGBToCMYK converts an RGB triple to a CMYK quadruple. +func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) { + rr := uint32(r) + gg := uint32(g) + bb := uint32(b) + w := rr + if w < gg { + w = gg + } + if w < bb { + w = bb + } + if w == 0 { + return 0, 0, 0, 255 + } + c := (w - rr) * 255 / w + m := (w - gg) * 255 / w + y := (w - bb) * 255 / w + return uint8(c), uint8(m), uint8(y), uint8(255 - w) +} + +// CMYKToRGB converts a CMYK quadruple to an RGB triple. +func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) { + w := uint32(255 - k) + r := uint32(255-c) * w / 255 + g := uint32(255-m) * w / 255 + b := uint32(255-y) * w / 255 + return uint8(r), uint8(g), uint8(b) +} + +// CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan, +// magenta, yellow and black. +// +// It is not associated with any particular color profile. +type CMYK struct { + C, M, Y, K uint8 +} + +func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) { + r, g, b := CMYKToRGB(c.C, c.M, c.Y, c.K) + return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff +} + +// CMYKModel is the Model for CMYK colors. +var CMYKModel Model = ModelFunc(cmykModel) + +func cmykModel(c Color) Color { + if _, ok := c.(CMYK); ok { + return c + } + r, g, b, _ := c.RGBA() + cc, mm, yy, kk := RGBToCMYK(uint8(r>>8), uint8(g>>8), uint8(b>>8)) + return CMYK{cc, mm, yy, kk} +} diff --git a/src/image/color/ycbcr_test.go b/src/image/color/ycbcr_test.go index 92a0e6ff1e..94c23dd9ea 100644 --- a/src/image/color/ycbcr_test.go +++ b/src/image/color/ycbcr_test.go @@ -15,9 +15,9 @@ func delta(x, y uint8) uint8 { return y - x } -// Test that a subset of RGB space can be converted to YCbCr and back to within -// 1/256 tolerance. -func TestRoundtrip(t *testing.T) { +// TestYCbCrRoundtrip tests that a subset of RGB space can be converted to YCbCr +// and back to within 1/256 tolerance. +func TestYCbCrRoundtrip(t *testing.T) { for r := 0; r < 255; r += 7 { for g := 0; g < 255; g += 5 { for b := 0; b < 255; b += 3 { @@ -31,3 +31,20 @@ func TestRoundtrip(t *testing.T) { } } } + +// TestCMYKRoundtrip tests that a subset of RGB space can be converted to CMYK +// and back to within 1/256 tolerance. +func TestCMYKRoundtrip(t *testing.T) { + for r := 0; r < 255; r += 7 { + for g := 0; g < 255; g += 5 { + for b := 0; b < 255; b += 3 { + r0, g0, b0 := uint8(r), uint8(g), uint8(b) + c, m, y, k := RGBToCMYK(r0, g0, b0) + r1, g1, b1 := CMYKToRGB(c, m, y, k) + if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 { + t.Fatalf("r0, g0, b0 = %d, %d, %d r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1) + } + } + } + } +} diff --git a/src/image/image.go b/src/image/image.go index 951cc8ae05..a5993d217a 100644 --- a/src/image/image.go +++ b/src/image/image.go @@ -826,6 +826,92 @@ func NewGray16(r Rectangle) *Gray16 { return &Gray16{pix, 2 * w, r} } +// CMYK is an in-memory image whose At method returns color.CMYK values. +type CMYK struct { + // Pix holds the image's pixels, in C, M, Y, K order. The pixel at + // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4]. + Pix []uint8 + // Stride is the Pix stride (in bytes) between vertically adjacent pixels. + Stride int + // Rect is the image's bounds. + Rect Rectangle +} + +func (p *CMYK) ColorModel() color.Model { return color.CMYKModel } + +func (p *CMYK) Bounds() Rectangle { return p.Rect } + +func (p *CMYK) At(x, y int) color.Color { + return p.CMYKAt(x, y) +} + +func (p *CMYK) CMYKAt(x, y int) color.CMYK { + if !(Point{x, y}.In(p.Rect)) { + return color.CMYK{} + } + i := p.PixOffset(x, y) + return color.CMYK{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]} +} + +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *CMYK) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 +} + +func (p *CMYK) Set(x, y int, c color.Color) { + if !(Point{x, y}.In(p.Rect)) { + return + } + i := p.PixOffset(x, y) + c1 := color.CMYKModel.Convert(c).(color.CMYK) + p.Pix[i+0] = c1.C + p.Pix[i+1] = c1.M + p.Pix[i+2] = c1.Y + p.Pix[i+3] = c1.K +} + +func (p *CMYK) SetCMYK(x, y int, c color.CMYK) { + if !(Point{x, y}.In(p.Rect)) { + return + } + i := p.PixOffset(x, y) + p.Pix[i+0] = c.C + p.Pix[i+1] = c.M + p.Pix[i+2] = c.Y + p.Pix[i+3] = c.K +} + +// SubImage returns an image representing the portion of the image p visible +// through r. The returned value shares pixels with the original image. +func (p *CMYK) SubImage(r Rectangle) Image { + r = r.Intersect(p.Rect) + // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside + // either r1 or r2 if the intersection is empty. Without explicitly checking for + // this, the Pix[i:] expression below can panic. + if r.Empty() { + return &CMYK{} + } + i := p.PixOffset(r.Min.X, r.Min.Y) + return &CMYK{ + Pix: p.Pix[i:], + Stride: p.Stride, + Rect: r, + } +} + +// Opaque scans the entire image and reports whether it is fully opaque. +func (p *CMYK) Opaque() bool { + return true +} + +// NewCMYK returns a new CMYK with the given bounds. +func NewCMYK(r Rectangle) *CMYK { + w, h := r.Dx(), r.Dy() + buf := make([]uint8, 4*w*h) + return &CMYK{buf, 4 * w, r} +} + // Paletted is an in-memory image of uint8 indices into a given palette. type Paletted struct { // Pix holds the image's pixels, as palette indices. The pixel at -- cgit v1.2.3-54-g00ecf From f10e03770c9702b3ee3bcc2ccdb78691f389c1a3 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 13 Feb 2015 18:09:21 +1100 Subject: image/jpeg: support decoding CMYK and YCbCrK images. The new testdata was created by: convert video-001.png -colorspace cmyk video-001.cmyk.jpeg video-001.cmyk.jpeg was then converted back to video-001.cmyk.png via the GIMP. ImageMagick (convert) wasn't used for this second conversion because IM's default color profiles complicates things. Fixes #4500. Change-Id: Ibf533f6a6c7e76883acc493ce3a4289d7875df3f Reviewed-on: https://go-review.googlesource.com/4801 Reviewed-by: Rob Pike --- src/image/decode_test.go | 1 + src/image/jpeg/reader.go | 259 ++++++++++++++++++++++++++------- src/image/jpeg/scan.go | 19 ++- src/image/testdata/video-001.cmyk.jpeg | Bin 0 -> 19477 bytes src/image/testdata/video-001.cmyk.png | Bin 0 -> 25439 bytes 5 files changed, 221 insertions(+), 58 deletions(-) create mode 100644 src/image/testdata/video-001.cmyk.jpeg create mode 100644 src/image/testdata/video-001.cmyk.png diff --git a/src/image/decode_test.go b/src/image/decode_test.go index 8dee57ee46..e88bfdaaae 100644 --- a/src/image/decode_test.go +++ b/src/image/decode_test.go @@ -32,6 +32,7 @@ var imageTests = []imageTest{ // JPEG is a lossy format and hence needs a non-zero tolerance. {"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8}, {"testdata/video-001.png", "testdata/video-001.progressive.jpeg", 8 << 8}, + {"testdata/video-001.cmyk.png", "testdata/video-001.cmyk.jpeg", 8 << 8}, // Grayscale images. {"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8}, {"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0}, diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go index 6d8b1d1d03..72c3f064c0 100644 --- a/src/image/jpeg/reader.go +++ b/src/image/jpeg/reader.go @@ -10,6 +10,7 @@ package jpeg import ( "image" "image/color" + "image/draw" "io" ) @@ -41,10 +42,7 @@ const ( maxTh = 3 maxTq = 3 - // A grayscale JPEG image has only a Y component. - nGrayComponent = 1 - // A color JPEG image has Y, Cb and Cr components. - nColorComponent = 3 + maxComponents = 4 // We only support 4:4:4, 4:4:0, 4:2:2 and 4:2:0 downsampling, and therefore the // number of luma samples per chroma sample is at most 2 in the horizontal @@ -54,19 +52,30 @@ const ( ) const ( - soiMarker = 0xd8 // Start Of Image. - eoiMarker = 0xd9 // End Of Image. - sof0Marker = 0xc0 // Start Of Frame (Baseline). - sof2Marker = 0xc2 // Start Of Frame (Progressive). - dhtMarker = 0xc4 // Define Huffman Table. - dqtMarker = 0xdb // Define Quantization Table. - sosMarker = 0xda // Start Of Scan. - driMarker = 0xdd // Define Restart Interval. - rst0Marker = 0xd0 // ReSTart (0). - rst7Marker = 0xd7 // ReSTart (7). - app0Marker = 0xe0 // APPlication specific (0). - app15Marker = 0xef // APPlication specific (15). - comMarker = 0xfe // COMment. + soiMarker = 0xd8 // Start Of Image. + eoiMarker = 0xd9 // End Of Image. + sof0Marker = 0xc0 // Start Of Frame (Baseline). + sof2Marker = 0xc2 // Start Of Frame (Progressive). + dhtMarker = 0xc4 // Define Huffman Table. + dqtMarker = 0xdb // Define Quantization Table. + sosMarker = 0xda // Start Of Scan. + driMarker = 0xdd // Define Restart Interval. + rst0Marker = 0xd0 // ReSTart (0). + rst7Marker = 0xd7 // ReSTart (7). + comMarker = 0xfe // COMment. + // "APPlication specific" markers aren't part of the JPEG spec per se, + // but in practice, their use is described at + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html + app0Marker = 0xe0 + app14Marker = 0xee + app15Marker = 0xef +) + +// See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe +const ( + adobeTransformUnknown = 0 + adobeTransformYCbCr = 1 + adobeTransformYCbCrK = 2 ) // unzig maps from the zig-zag ordering to the natural ordering. For example, @@ -114,17 +123,24 @@ type decoder struct { nUnreadable int } width, height int - img1 *image.Gray - img3 *image.YCbCr - ri int // Restart Interval. - nComp int - progressive bool - eobRun uint16 // End-of-Band run, specified in section G.1.2.2. - comp [nColorComponent]component - progCoeffs [nColorComponent][]block // Saved state between progressive-mode scans. - huff [maxTc + 1][maxTh + 1]huffman - quant [maxTq + 1]block // Quantization tables, in zig-zag order. - tmp [blockSize + 1]byte + + img1 *image.Gray + img3 *image.YCbCr + blackPix []byte + blackStride int + + ri int // Restart Interval. + nComp int + progressive bool + adobeTransformValid bool + adobeTransform uint8 + eobRun uint16 // End-of-Band run, specified in section G.1.2.2. + + comp [maxComponents]component + progCoeffs [maxComponents][]block // Saved state between progressive-mode scans. + huff [maxTc + 1][maxTh + 1]huffman + quant [maxTq + 1]block // Quantization tables, in zig-zag order. + tmp [blockSize + 1]byte } // fill fills up the d.bytes.buf buffer from the underlying io.Reader. It @@ -285,10 +301,12 @@ func (d *decoder) ignore(n int) error { // Specified in section B.2.2. func (d *decoder) processSOF(n int) error { switch n { - case 6 + 3*nGrayComponent: - d.nComp = nGrayComponent - case 6 + 3*nColorComponent: - d.nComp = nColorComponent + case 6 + 3*1: // Grayscale image. + d.nComp = 1 + case 6 + 3*3: // YCbCr image. (TODO(nigeltao): or RGB image.) + d.nComp = 3 + case 6 + 3*4: // YCbCrK or CMYK image. + d.nComp = 4 default: return UnsupportedError("SOF has wrong length") } @@ -307,7 +325,7 @@ func (d *decoder) processSOF(n int) error { for i := 0; i < d.nComp; i++ { d.comp[i].c = d.tmp[6+3*i] d.comp[i].tq = d.tmp[8+3*i] - if d.nComp == nGrayComponent { + if d.nComp == 1 { // If a JPEG image has only one component, section A.2 says "this data // is non-interleaved by definition" and section A.2.2 says "[in this // case...] the order of data units within a scan shall be left-to-right @@ -326,16 +344,43 @@ func (d *decoder) processSOF(n int) error { hv := d.tmp[7+3*i] d.comp[i].h = int(hv >> 4) d.comp[i].v = int(hv & 0x0f) - // For color images, we only support 4:4:4, 4:4:0, 4:2:2 or 4:2:0 chroma - // downsampling ratios. This implies that the (h, v) values for the Y - // component are either (1, 1), (1, 2), (2, 1) or (2, 2), and the (h, v) - // values for the Cr and Cb components must be (1, 1). - if i == 0 { - if hv != 0x11 && hv != 0x21 && hv != 0x22 && hv != 0x12 { + switch d.nComp { + case 3: + // For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2 or 4:2:0 chroma + // downsampling ratios. This implies that the (h, v) values for the Y + // component are either (1, 1), (1, 2), (2, 1) or (2, 2), and the (h, v) + // values for the Cr and Cb components must be (1, 1). + if i == 0 { + if hv != 0x11 && hv != 0x21 && hv != 0x22 && hv != 0x12 { + return UnsupportedError("luma/chroma downsample ratio") + } + } else if hv != 0x11 { return UnsupportedError("luma/chroma downsample ratio") } - } else if hv != 0x11 { - return UnsupportedError("luma/chroma downsample ratio") + case 4: + // For 4-component images (either CMYK or YCbCrK), we only support two + // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22]. + // Theoretically, 4-component JPEG images could mix and match hv values + // but in practice, those two combinations are the only ones in use, + // and it simplifies the applyBlack code below if we can assume that: + // - for CMYK, the C and K channels have full samples, and if the M + // and Y channels subsample, they subsample both horizontally and + // vertically. + // - for YCbCrK, the Y and K channels have full samples. + switch i { + case 0: + if hv != 0x11 && hv != 0x22 { + return UnsupportedError("luma/chroma downsample ratio") + } + case 1, 2: + if hv != 0x11 { + return UnsupportedError("luma/chroma downsample ratio") + } + case 3: + if d.comp[0].h != d.comp[3].h || d.comp[0].v != d.comp[3].v { + return UnsupportedError("luma/chroma downsample ratio") + } + } } } return nil @@ -378,6 +423,26 @@ func (d *decoder) processDRI(n int) error { return nil } +func (d *decoder) processApp14Marker(n int) error { + if n < 12 { + return d.ignore(n) + } + if err := d.readFull(d.tmp[:12]); err != nil { + return err + } + n -= 12 + + if d.tmp[0] == 'A' && d.tmp[1] == 'd' && d.tmp[2] == 'o' && d.tmp[3] == 'b' && d.tmp[4] == 'e' { + d.adobeTransformValid = true + d.adobeTransform = d.tmp[11] + } + + if n > 0 { + return d.ignore(n) + } + return nil +} + // decode reads a JPEG image from r and returns it as an image.Image. func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) { d.r = r @@ -459,25 +524,29 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) { return nil, FormatError("short segment length") } - switch { - case marker == sof0Marker || marker == sof2Marker: // Start Of Frame. + switch marker { + case sof0Marker, sof2Marker: d.progressive = marker == sof2Marker err = d.processSOF(n) if configOnly { return nil, err } - case marker == dhtMarker: // Define Huffman Table. + case dhtMarker: err = d.processDHT(n) - case marker == dqtMarker: // Define Quantization Table. + case dqtMarker: err = d.processDQT(n) - case marker == sosMarker: // Start Of Scan. + case sosMarker: err = d.processSOS(n) - case marker == driMarker: // Define Restart Interval. + case driMarker: err = d.processDRI(n) - case app0Marker <= marker && marker <= app15Marker || marker == comMarker: // APPlication specific, or COMment. - err = d.ignore(n) + case app14Marker: + err = d.processApp14Marker(n) default: - err = UnsupportedError("unknown marker") + if app0Marker <= marker && marker <= app15Marker || marker == comMarker { + err = d.ignore(n) + } else { + err = UnsupportedError("unknown marker") + } } if err != nil { return nil, err @@ -487,11 +556,89 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) { return d.img1, nil } if d.img3 != nil { + if d.blackPix != nil { + return d.applyBlack() + } return d.img3, nil } return nil, FormatError("missing SOS marker") } +// applyBlack combines d.img3 and d.blackPix into a CMYK image. The formula +// used depends on whether the JPEG image is stored as CMYK or YCbCrK, +// indicated by the APP14 (Adobe) metadata. +// +// Adobe CMYK JPEG images are inverted, where 255 means no ink instead of full +// ink, so we apply "v = 255 - v" at various points. Note that a double +// inversion is a no-op, so inversions might be implicit in the code below. +func (d *decoder) applyBlack() (image.Image, error) { + if !d.adobeTransformValid { + return nil, UnsupportedError("unknown color model: 4-component JPEG doesn't have Adobe APP14 metadata") + } + + // If the 4-component JPEG image isn't explicitly marked as "Unknown (RGB + // or CMYK)" as per + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe + // we assume that it is YCbCrK. This matches libjpeg's jdapimin.c. + if d.adobeTransform != adobeTransformUnknown { + // Convert the YCbCr part of the YCbCrK to RGB, invert the RGB to get + // CMY, and patch in the original K. The RGB to CMY inversion cancels + // out the 'Adobe inversion' described in the applyBlack doc comment + // above, so in practice, only the fourth channel (black) is inverted. + bounds := d.img3.Bounds() + img := image.NewRGBA(bounds) + // TODO(nigeltao): do the draw.Draw YCbCr -> RGB conversion directly, + // instead of having the image/jpeg package depend on the image/draw + // package. + draw.Draw(img, bounds, d.img3, bounds.Min, draw.Src) + for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 { + for i, x := iBase+3, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 { + img.Pix[i] = 255 - d.blackPix[(y-bounds.Min.Y)*d.blackStride+(x-bounds.Min.X)] + } + } + return &image.CMYK{ + Pix: img.Pix, + Stride: img.Stride, + Rect: img.Rect, + }, nil + } + + // The first three channels (cyan, magenta, yellow) of the CMYK + // were decoded into d.img3, but each channel was decoded into a separate + // []byte slice, and some channels may be subsampled. We interleave the + // separate channels into an image.CMYK's single []byte slice containing 4 + // contiguous bytes per pixel. + bounds := d.img3.Bounds() + img := image.NewCMYK(bounds) + + translations := [4]struct { + src []byte + stride int + }{ + {d.img3.Y, d.img3.YStride}, + {d.img3.Cb, d.img3.CStride}, + {d.img3.Cr, d.img3.CStride}, + {d.blackPix, d.blackStride}, + } + for t, translation := range translations { + subsample := d.comp[t].h != d.comp[0].h || d.comp[t].v != d.comp[0].v + for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 { + sy := y - bounds.Min.Y + if subsample { + sy /= 2 + } + for i, x := iBase+t, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 { + sx := x - bounds.Min.X + if subsample { + sx /= 2 + } + img.Pix[i] = 255 - translation.src[sy*translation.stride+sx] + } + } + } + return img, nil +} + // Decode reads a JPEG image from r and returns it as an image.Image. func Decode(r io.Reader) (image.Image, error) { var d decoder @@ -506,15 +653,21 @@ func DecodeConfig(r io.Reader) (image.Config, error) { return image.Config{}, err } switch d.nComp { - case nGrayComponent: + case 1: return image.Config{ ColorModel: color.GrayModel, Width: d.width, Height: d.height, }, nil - case nColorComponent: + case 3: + return image.Config{ + ColorModel: color.YCbCrModel, // TODO(nigeltao): support RGB JPEGs. + Width: d.width, + Height: d.height, + }, nil + case 4: return image.Config{ - ColorModel: color.YCbCrModel, + ColorModel: color.CMYKModel, Width: d.width, Height: d.height, }, nil diff --git a/src/image/jpeg/scan.go b/src/image/jpeg/scan.go index 2bd1d9d531..4168936312 100644 --- a/src/image/jpeg/scan.go +++ b/src/image/jpeg/scan.go @@ -10,11 +10,12 @@ import ( // makeImg allocates and initializes the destination image. func (d *decoder) makeImg(h0, v0, mxx, myy int) { - if d.nComp == nGrayComponent { + if d.nComp == 1 { m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy)) d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray) return } + var subsampleRatio image.YCbCrSubsampleRatio switch { case h0 == 1 && v0 == 1: @@ -30,6 +31,12 @@ func (d *decoder) makeImg(h0, v0, mxx, myy int) { } m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio) d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr) + + if d.nComp == 4 { + h3, v3 := d.comp[3].h, d.comp[3].v + d.blackPix = make([]byte, 8*h3*mxx*8*v3*myy) + d.blackStride = 8 * h3 * mxx + } } // Specified in section B.2.3. @@ -47,7 +54,7 @@ func (d *decoder) processSOS(n int) error { if n != 4+2*nComp { return FormatError("SOS length inconsistent with number of components") } - var scan [nColorComponent]struct { + var scan [maxComponents]struct { compIndex uint8 td uint8 // DC table selector. ta uint8 // AC table selector. @@ -128,7 +135,7 @@ func (d *decoder) processSOS(n int) error { var ( // b is the decoded coefficients, in natural (not zig-zag) order. b block - dc [nColorComponent]int32 + dc [maxComponents]int32 // bx and by are the location of the current (in terms of 8x8 blocks). // For example, with 4:2:0 chroma subsampling, the block whose top left // pixel co-ordinates are (16, 8) is the third block in the first row: @@ -276,7 +283,7 @@ func (d *decoder) processSOS(n int) error { } idct(&b) dst, stride := []byte(nil), 0 - if d.nComp == nGrayComponent { + if d.nComp == 1 { dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride } else { switch compIndex { @@ -286,6 +293,8 @@ func (d *decoder) processSOS(n int) error { dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride case 2: dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride + case 3: + dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride default: return UnsupportedError("too many components") } @@ -325,7 +334,7 @@ func (d *decoder) processSOS(n int) error { // Reset the Huffman decoder. d.bits = bits{} // Reset the DC components, as per section F.2.1.3.1. - dc = [nColorComponent]int32{} + dc = [maxComponents]int32{} // Reset the progressive decoder state, as per section G.1.2.2. d.eobRun = 0 } diff --git a/src/image/testdata/video-001.cmyk.jpeg b/src/image/testdata/video-001.cmyk.jpeg new file mode 100644 index 0000000000..507df843b5 Binary files /dev/null and b/src/image/testdata/video-001.cmyk.jpeg differ diff --git a/src/image/testdata/video-001.cmyk.png b/src/image/testdata/video-001.cmyk.png new file mode 100644 index 0000000000..ef7b2b88d8 Binary files /dev/null and b/src/image/testdata/video-001.cmyk.png differ -- cgit v1.2.3-54-g00ecf From 7b36227002b8b442a55dfb975490a861a8aa2ff2 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Fri, 13 Feb 2015 12:09:12 +0900 Subject: runtime: remove C-style strcmp and strncmp helpers Change-Id: I4aa23e3a0e765651c91907507a0194fd528b6223 Reviewed-on: https://go-review.googlesource.com/4662 Reviewed-by: Ian Lance Taylor --- src/runtime/os3_plan9.go | 15 +++++---------- src/runtime/signal_plan9.go | 30 +++++++++++++++--------------- src/runtime/string1.go | 39 --------------------------------------- 3 files changed, 20 insertions(+), 64 deletions(-) diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go index facaab2546..8ecbca0174 100644 --- a/src/runtime/os3_plan9.go +++ b/src/runtime/os3_plan9.go @@ -10,11 +10,11 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { _g_ := getg() var t sigTabT var docrash bool - var length int var sig int var flags int c := &sigctxt{_ureg} + notestr := gostringnocopy(note) // The kernel will never pass us a nil note or ureg so we probably // made a mistake somewhere in sigtramp. @@ -24,8 +24,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { } // Check that the note is no more than ERRMAX bytes (including // the trailing NUL). We should never receive a longer note. - length = findnull(note) - if length > _ERRMAX-1 { + if len(notestr) > _ERRMAX-1 { print("sighandler: note is longer than ERRMAX\n") goto Throw } @@ -34,11 +33,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { // level by the program but will otherwise be ignored. flags = _SigNotify for sig, t = range sigtable { - n := len(t.name) - if length < n { - continue - } - if strncmp(note, &t.name[0], uintptr(n)) == 0 { + if hasprefix(notestr, t.name) { flags = t.flags break } @@ -49,7 +44,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { if flags&_SigPanic != 0 { // Copy the error string from sigtramp's stack into m->notesig so // we can reliably access it from the panic routines. - memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(length+1)) + memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(len(notestr)+1)) gp.sig = uint32(sig) gp.sigpc = c.pc() // Only push sigpanic if PC != 0. @@ -86,7 +81,7 @@ Throw: _g_.m.throwing = 1 _g_.m.caughtsig = gp startpanic() - print(gostringnocopy(note), "\n") + print(notestr, "\n") print("PC=", hex(c.pc()), "\n") print("\n") if gotraceback(&docrash) > 0 { diff --git a/src/runtime/signal_plan9.go b/src/runtime/signal_plan9.go index 37d24359bf..302f1561b8 100644 --- a/src/runtime/signal_plan9.go +++ b/src/runtime/signal_plan9.go @@ -6,7 +6,7 @@ package runtime type sigTabT struct { flags int - name []byte + name string } // Incoming notes are compared against this table using strncmp, so the @@ -18,37 +18,37 @@ type sigTabT struct { // and also update the constant values is os2_plan9.go. var sigtable = [...]sigTabT{ // Traps that we cannot be recovered. - {_SigThrow, []byte("sys: trap: debug exception")}, - {_SigThrow, []byte("sys: trap: invalid opcode")}, + {_SigThrow, "sys: trap: debug exception"}, + {_SigThrow, "sys: trap: invalid opcode"}, // We can recover from some memory errors in runtime·sigpanic. - {_SigPanic, []byte("sys: trap: fault read addr")}, // SIGRFAULT - {_SigPanic, []byte("sys: trap: fault write addr")}, // SIGWFAULT + {_SigPanic, "sys: trap: fault read addr"}, // SIGRFAULT + {_SigPanic, "sys: trap: fault write addr"}, // SIGWFAULT // We can also recover from math errors. - {_SigPanic, []byte("sys: trap: divide error")}, // SIGINTDIV - {_SigPanic, []byte("sys: fp:")}, // SIGFLOAT + {_SigPanic, "sys: trap: divide error"}, // SIGINTDIV + {_SigPanic, "sys: fp:"}, // SIGFLOAT // All other traps are normally handled as if they were marked SigThrow. // We mark them SigPanic here so that debug.SetPanicOnFault will work. - {_SigPanic, []byte("sys: trap:")}, // SIGTRAP + {_SigPanic, "sys: trap:"}, // SIGTRAP // Writes to a closed pipe can be handled if desired, otherwise they're ignored. - {_SigNotify, []byte("sys: write on closed pipe")}, + {_SigNotify, "sys: write on closed pipe"}, // Other system notes are more serious and cannot be recovered. - {_SigThrow, []byte("sys:")}, + {_SigThrow, "sys:"}, // Issued to all other procs when calling runtime·exit. - {_SigGoExit, []byte("go: exit ")}, + {_SigGoExit, "go: exit "}, // Kill is sent by external programs to cause an exit. - {_SigKill, []byte("kill")}, + {_SigKill, "kill"}, // Interrupts can be handled if desired, otherwise they cause an exit. - {_SigNotify + _SigKill, []byte("interrupt")}, - {_SigNotify + _SigKill, []byte("hangup")}, + {_SigNotify + _SigKill, "interrupt"}, + {_SigNotify + _SigKill, "hangup"}, // Alarms can be handled if desired, otherwise they're ignored. - {_SigNotify, []byte("alarm")}, + {_SigNotify, "alarm"}, } diff --git a/src/runtime/string1.go b/src/runtime/string1.go index 35cde43be0..feeb341b62 100644 --- a/src/runtime/string1.go +++ b/src/runtime/string1.go @@ -67,42 +67,3 @@ func gostringw(strw *uint16) string { b[n2] = 0 // for luck return s[:n2] } - -func strcmp(s1, s2 *byte) int32 { - p1 := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s1)) - p2 := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s2)) - - for i := uintptr(0); ; i++ { - c1 := p1[i] - c2 := p2[i] - if c1 < c2 { - return -1 - } - if c1 > c2 { - return +1 - } - if c1 == 0 { - return 0 - } - } -} - -func strncmp(s1, s2 *byte, n uintptr) int32 { - p1 := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s1)) - p2 := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s2)) - - for i := uintptr(0); i < n; i++ { - c1 := p1[i] - c2 := p2[i] - if c1 < c2 { - return -1 - } - if c1 > c2 { - return +1 - } - if c1 == 0 { - break - } - } - return 0 -} -- cgit v1.2.3-54-g00ecf From 10a4696fb8d080b334a31f0cf43a7ffe3c588ad7 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Mon, 16 Feb 2015 15:10:50 +1100 Subject: image/jpeg: remove the (temporary) dependency on image/draw. Change-Id: Idd66f9c3c9eaa4ff1f950fb90e4800dc625dec08 Reviewed-on: https://go-review.googlesource.com/4916 Reviewed-by: Alex Brainman --- src/image/draw/draw.go | 2 ++ src/image/jpeg/reader.go | 82 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go index cffdcbc0d7..b1fc979a7d 100644 --- a/src/image/draw/draw.go +++ b/src/image/draw/draw.go @@ -392,6 +392,8 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image } } +// TODO(nigeltao): this function is copy/pasted to image/jpeg/reader.go. We +// should un-copy/paste it. func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) { // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil // (i.e. fully opaque) then the op is effectively always Src. diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go index 72c3f064c0..863f55bf25 100644 --- a/src/image/jpeg/reader.go +++ b/src/image/jpeg/reader.go @@ -10,7 +10,6 @@ package jpeg import ( "image" "image/color" - "image/draw" "io" ) @@ -587,10 +586,7 @@ func (d *decoder) applyBlack() (image.Image, error) { // above, so in practice, only the fourth channel (black) is inverted. bounds := d.img3.Bounds() img := image.NewRGBA(bounds) - // TODO(nigeltao): do the draw.Draw YCbCr -> RGB conversion directly, - // instead of having the image/jpeg package depend on the image/draw - // package. - draw.Draw(img, bounds, d.img3, bounds.Min, draw.Src) + drawYCbCr(img, bounds, d.img3, bounds.Min) for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 { for i, x := iBase+3, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 { img.Pix[i] = 255 - d.blackPix[(y-bounds.Min.Y)*d.blackStride+(x-bounds.Min.X)] @@ -639,6 +635,82 @@ func (d *decoder) applyBlack() (image.Image, error) { return img, nil } +// drawYCbCr is the non-exported drawYCbCr function copy/pasted from the +// image/draw package. It is copy/pasted because it doesn't seem right for the +// image/jpeg package to depend on image/draw. +// +// TODO(nigeltao): remove the copy/paste, possibly by moving this to be an +// exported method on *image.YCbCr. We'd need to make sure we're totally happy +// with the API (for the rest of Go 1 compatibility) though, and if we want to +// have a more general purpose DrawToRGBA method for other image types. +func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) { + // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil + // (i.e. fully opaque) then the op is effectively always Src. + x0 := (r.Min.X - dst.Rect.Min.X) * 4 + x1 := (r.Max.X - dst.Rect.Min.X) * 4 + y0 := r.Min.Y - dst.Rect.Min.Y + y1 := r.Max.Y - dst.Rect.Min.Y + switch src.SubsampleRatio { + case image.YCbCrSubsampleRatio444: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } + case image.YCbCrSubsampleRatio422: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } + case image.YCbCrSubsampleRatio420: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } + case image.YCbCrSubsampleRatio440: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) + dpix[x+0] = rr + dpix[x+1] = gg + dpix[x+2] = bb + dpix[x+3] = 255 + } + } + default: + return false + } + return true +} + // Decode reads a JPEG image from r and returns it as an image.Image. func Decode(r io.Reader) (image.Image, error) { var d decoder -- cgit v1.2.3-54-g00ecf From 194ad16b834daf7ad8fb468845c5532f528970a6 Mon Sep 17 00:00:00 2001 From: Michael MacInnis Date: Thu, 29 Jan 2015 22:37:41 -0500 Subject: os/signal: add ability to ignore signals and restore initial signal handlers There is currently no way to ignore signals using the os/signal package. It is possible to catch a signal and do nothing but this is not the same as ignoring it. The new function Ignore allows a set of signals to be ignored. The new function Reset allows the initial handlers for a set of signals to be restored. Fixes #5572 Change-Id: I5c0f07956971e3a9ff9b9d9631e6e3a08c20df15 Reviewed-on: https://go-review.googlesource.com/3580 Reviewed-by: Ian Lance Taylor --- src/os/signal/sig.s | 3 ++ src/os/signal/signal.go | 57 ++++++++++++++++++++++++++++++++-- src/os/signal/signal_plan9.go | 5 +++ src/os/signal/signal_test.go | 66 ++++++++++++++++++++++++++++++++++++++++ src/os/signal/signal_unix.go | 5 +++ src/runtime/os1_nacl.go | 1 + src/runtime/os1_windows_386.go | 3 ++ src/runtime/os1_windows_amd64.go | 3 ++ src/runtime/os3_plan9.go | 3 ++ src/runtime/signal1_unix.go | 12 ++++++++ src/runtime/sigqueue.go | 9 ++++++ src/runtime/sigqueue_plan9.go | 4 +++ 12 files changed, 169 insertions(+), 2 deletions(-) diff --git a/src/os/signal/sig.s b/src/os/signal/sig.s index 5a042a0964..f54e6ff9c0 100644 --- a/src/os/signal/sig.s +++ b/src/os/signal/sig.s @@ -24,6 +24,9 @@ TEXT ·signal_disable(SB),NOSPLIT,$0 TEXT ·signal_enable(SB),NOSPLIT,$0 JMP runtime·signal_enable(SB) +TEXT ·signal_ignore(SB),NOSPLIT,$0 + JMP runtime·signal_ignore(SB) + TEXT ·signal_recv(SB),NOSPLIT,$0 JMP runtime·signal_recv(SB) diff --git a/src/os/signal/signal.go b/src/os/signal/signal.go index 81906d6f40..1625786d49 100644 --- a/src/os/signal/signal.go +++ b/src/os/signal/signal.go @@ -28,9 +28,55 @@ func (h *handler) set(sig int) { h.mask[sig/32] |= 1 << uint(sig&31) } +func (h *handler) clear(sig int) { + h.mask[sig/32] &^= 1 << uint(sig&31) +} + +// Stop relaying the signals, sigs, to any channels previously registered to +// receive them and either reset the signal handlers to their original values +// (action=disableSignal) or ignore the signals (action=ignoreSignal). +func cancel(sigs []os.Signal, action func(int)) { + handlers.Lock() + defer handlers.Unlock() + + remove := func(n int) { + var zerohandler handler + + for c, h := range handlers.m { + if h.want(n) { + handlers.ref[n]-- + h.clear(n) + if h.mask == zerohandler.mask { + delete(handlers.m, c) + } + } + } + + action(n) + } + + if len(sigs) == 0 { + for n := 0; n < numSig; n++ { + remove(n) + } + } else { + for _, s := range sigs { + remove(signum(s)) + } + } +} + +// Ignore causes the provided signals to be ignored. If they are received by +// the program, nothing will happen. Ignore undoes the effect of any prior +// calls to Notify for the provided signals. +// If no signals are provided, all incoming signals will be ignored. +func Ignore(sig ...os.Signal) { + cancel(sig, ignoreSignal) +} + // Notify causes package signal to relay incoming signals to c. -// If no signals are listed, all incoming signals will be relayed to c. -// Otherwise, just the listed signals will. +// If no signals are provided, all incoming signals will be relayed to c. +// Otherwise, just the provided signals will. // // Package signal will not block sending to c: the caller must ensure // that c has sufficient buffer space to keep up with the expected @@ -85,6 +131,13 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) { } } +// Reset undoes the effect of any prior calls to Notify for the provided +// signals. +// If no signals are provided, all signal handlers will be reset. +func Reset(sig ...os.Signal) { + cancel(sig, disableSignal) +} + // Stop causes package signal to stop relaying incoming signals to c. // It undoes the effect of all prior calls to Notify using c. // When Stop returns, it is guaranteed that c will receive no more signals. diff --git a/src/os/signal/signal_plan9.go b/src/os/signal/signal_plan9.go index 45355da48a..b065ae520d 100644 --- a/src/os/signal/signal_plan9.go +++ b/src/os/signal/signal_plan9.go @@ -14,6 +14,7 @@ var sigtab = make(map[os.Signal]int) // In sig.s; jumps to runtime. func signal_disable(uint32) func signal_enable(uint32) +func signal_ignore(uint32) func signal_recv() string func init() { @@ -53,3 +54,7 @@ func enableSignal(sig int) { func disableSignal(sig int) { signal_disable(uint32(sig)) } + +func ignoreSignal(sig int) { + signal_ignore(uint32(sig)) +} diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go index 22337a72d4..a71633c890 100644 --- a/src/os/signal/signal_test.go +++ b/src/os/signal/signal_test.go @@ -109,6 +109,72 @@ func TestStress(t *testing.T) { time.Sleep(10 * time.Millisecond) } +func testCancel(t *testing.T, ignore bool) { + // Send SIGWINCH. By default this signal should be ignored. + syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) + time.Sleep(100 * time.Millisecond) + + // Ask to be notified on c1 when a SIGWINCH is received. + c1 := make(chan os.Signal, 1) + Notify(c1, syscall.SIGWINCH) + defer Stop(c1) + + // Ask to be notified on c2 when a SIGHUP is received. + c2 := make(chan os.Signal, 1) + Notify(c2, syscall.SIGHUP) + defer Stop(c2) + + // Send this process a SIGWINCH and wait for notification on c1. + syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) + waitSig(t, c1, syscall.SIGWINCH) + + // Send this process a SIGHUP and wait for notification on c2. + syscall.Kill(syscall.Getpid(), syscall.SIGHUP) + waitSig(t, c2, syscall.SIGHUP) + + // Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP. + if ignore { + Ignore(syscall.SIGWINCH, syscall.SIGHUP) + } else { + Reset(syscall.SIGWINCH, syscall.SIGHUP) + } + + // Send this process a SIGWINCH. It should be ignored. + syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) + + // If ignoring, Send this process a SIGHUP. It should be ignored. + if ignore { + syscall.Kill(syscall.Getpid(), syscall.SIGHUP) + } + + select { + case s := <-c1: + t.Fatalf("unexpected signal %v", s) + case <-time.After(100 * time.Millisecond): + // nothing to read - good + } + + select { + case s := <-c2: + t.Fatalf("unexpected signal %v", s) + case <-time.After(100 * time.Millisecond): + // nothing to read - good + } + + // Reset the signal handlers for all signals. + Reset() +} + +// Test that Reset cancels registration for listed signals on all channels. +func TestReset(t *testing.T) { + testCancel(t, false) +} + +// Test that Ignore cancels registration for listed signals on all channels. +func TestIgnore(t *testing.T) { + testCancel(t, true) +} + var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop") // Test that Stop cancels the channel's registrations. diff --git a/src/os/signal/signal_unix.go b/src/os/signal/signal_unix.go index 94b8ab3ddb..1bdf1d7271 100644 --- a/src/os/signal/signal_unix.go +++ b/src/os/signal/signal_unix.go @@ -14,6 +14,7 @@ import ( // In assembly. func signal_disable(uint32) func signal_enable(uint32) +func signal_ignore(uint32) func signal_recv() uint32 func loop() { @@ -51,3 +52,7 @@ func enableSignal(sig int) { func disableSignal(sig int) { signal_disable(uint32(sig)) } + +func ignoreSignal(sig int) { + signal_ignore(uint32(sig)) +} diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go index c44d87645e..a27a13f114 100644 --- a/src/runtime/os1_nacl.go +++ b/src/runtime/os1_nacl.go @@ -174,6 +174,7 @@ func munmap(addr unsafe.Pointer, n uintptr) {} func resetcpuprofiler(hz int32) {} func sigdisable(uint32) {} func sigenable(uint32) {} +func sigignore(uint32) {} func closeonexec(int32) {} var writelock uint32 // test-and-set spin lock for write diff --git a/src/runtime/os1_windows_386.go b/src/runtime/os1_windows_386.go index b7eae204d1..f105539659 100644 --- a/src/runtime/os1_windows_386.go +++ b/src/runtime/os1_windows_386.go @@ -118,3 +118,6 @@ func sigenable(sig uint32) { func sigdisable(sig uint32) { } + +func sigignore(sig uint32) { +} diff --git a/src/runtime/os1_windows_amd64.go b/src/runtime/os1_windows_amd64.go index 4163fcf23d..1b6b99988d 100644 --- a/src/runtime/os1_windows_amd64.go +++ b/src/runtime/os1_windows_amd64.go @@ -137,3 +137,6 @@ func sigenable(sig uint32) { func sigdisable(sig uint32) { } + +func sigignore(sig uint32) { +} diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go index 8ecbca0174..27519debd3 100644 --- a/src/runtime/os3_plan9.go +++ b/src/runtime/os3_plan9.go @@ -106,6 +106,9 @@ func sigenable(sig uint32) { func sigdisable(sig uint32) { } +func sigignore(sig uint32) { +} + func resetcpuprofiler(hz int32) { // TODO: Enable profiling interrupts. getg().m.profilehz = hz diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go index 253ee9f465..184fd125fb 100644 --- a/src/runtime/signal1_unix.go +++ b/src/runtime/signal1_unix.go @@ -78,6 +78,18 @@ func sigdisable(sig uint32) { } } +func sigignore(sig uint32) { + if sig >= uint32(len(sigtable)) { + return + } + + t := &sigtable[sig] + if t.flags&_SigNotify != 0 { + t.flags &^= _SigHandling + setsig(int32(sig), _SIG_IGN, true) + } +} + func resetcpuprofiler(hz int32) { var it itimerval if hz == 0 { diff --git a/src/runtime/sigqueue.go b/src/runtime/sigqueue.go index 5cfc926f67..df3c9c0e61 100644 --- a/src/runtime/sigqueue.go +++ b/src/runtime/sigqueue.go @@ -153,6 +153,15 @@ func signal_disable(s uint32) { sigdisable(s) } +// Must only be called from a single goroutine at a time. +func signal_ignore(s uint32) { + if int(s) >= len(sig.wanted)*32 { + return + } + sig.wanted[s/32] &^= 1 << (s & 31) + sigignore(s) +} + // This runs on a foreign stack, without an m or a g. No stack split. //go:nosplit func badsignal(sig uintptr) { diff --git a/src/runtime/sigqueue_plan9.go b/src/runtime/sigqueue_plan9.go index b029a300a8..38f0a57b90 100644 --- a/src/runtime/sigqueue_plan9.go +++ b/src/runtime/sigqueue_plan9.go @@ -113,3 +113,7 @@ func signal_enable(s uint32) { // Must only be called from a single goroutine at a time. func signal_disable(s uint32) { } + +// Must only be called from a single goroutine at a time. +func signal_ignore(s uint32) { +} -- cgit v1.2.3-54-g00ecf From 18f273ff92d3c4c6a327ee04f1cc0aee6e36d28c Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Mon, 16 Feb 2015 23:14:34 +0900 Subject: cmd/dist: don't use "uname -v" to recognize GOHOSTARCH We can use processor architecture or hardware platform as part of hostname and it leads to misconfiguration of GOHOSARCH. For example, $ uname -m -v FreeBSD 10.1-RELEASE-p5 #0: Tue Jan 27 08:52:50 UTC 2015 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC i386 Change-Id: I499efd98338beff6a27c03f03273331ecb6fd698 Reviewed-on: https://go-review.googlesource.com/4944 Reviewed-by: Minux Ma --- src/cmd/dist/util.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go index e686e42fe1..f6f0b42e9e 100644 --- a/src/cmd/dist/util.go +++ b/src/cmd/dist/util.go @@ -376,7 +376,7 @@ func main() { if gohostarch == "" { // Default Unix system. - out := run("", CheckExit, "uname", "-m", "-v") + out := run("", CheckExit, "uname", "-m") switch { case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"): gohostarch = "amd64" @@ -389,7 +389,7 @@ func main() { case strings.Contains(out, "ppc64"): gohostarch = "ppc64" case gohostos == "darwin": - if strings.Contains(out, "RELEASE_ARM_") { + if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM_") { gohostarch = "arm" } default: -- cgit v1.2.3-54-g00ecf From a25e40df4755cd05b8e142d2b4280c36756a9360 Mon Sep 17 00:00:00 2001 From: Michael MacInnis Date: Mon, 16 Feb 2015 16:27:20 -0500 Subject: doc: Add reminder to go1.5.txt for os/signal changes Document addition of Ignore and Reset: https://golang.org/cl/3580 Change-Id: I33aac149cd1921b87f887028c0365ba0ab9adb02 Reviewed-on: https://go-review.googlesource.com/4980 Reviewed-by: Minux Ma --- doc/go1.5.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.5.txt b/doc/go1.5.txt index 620ad7f85b..c26a6fa427 100644 --- a/doc/go1.5.txt +++ b/doc/go1.5.txt @@ -15,6 +15,7 @@ encoding/base64: add unpadded encodings (https://golang.org/cl/1511) log: add SetOutput functions (https://golang.org/cl/2686, https://golang.org/cl/3023) net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157) net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151) +os/signal: add Ignore and Reset (https://golang.org/cl/3580) runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020) strings: add Compare(x, y string) int, for symmetry with bytes.Compare (https://golang.org/cl/2828) testing/quick: support generation of arrays (https://golang.org/cl/3865) -- cgit v1.2.3-54-g00ecf From 490af4fd83132c6ab98de702dd9c0051820cb49c Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 17 Feb 2015 08:21:14 +1100 Subject: unicode: Fixed an out of date comment (MaxLatin1, not Latin1Max). Change-Id: I3ca878e9685f650a9ff02aaac0e2e3cca89634c6 Reviewed-on: https://go-review.googlesource.com/4970 Reviewed-by: Minux Ma --- src/unicode/graphic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unicode/graphic.go b/src/unicode/graphic.go index ba90b4e518..81eae3e762 100644 --- a/src/unicode/graphic.go +++ b/src/unicode/graphic.go @@ -82,7 +82,7 @@ func IsControl(r rune) bool { if uint32(r) <= MaxLatin1 { return properties[uint8(r)]&pC != 0 } - // All control characters are < Latin1Max. + // All control characters are < MaxLatin1. return false } -- cgit v1.2.3-54-g00ecf From 37a61746ee491d1ab9ffddb2d3b3bdce524a0852 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Mon, 16 Feb 2015 17:41:28 +1100 Subject: image/draw: add CMYK test. This just adds test cases. Optimizing CMYK draws will be a follow-up change. Change-Id: Ic0d6343d420cd021e21f88623ad7182e93017da9 Reviewed-on: https://go-review.googlesource.com/4941 Reviewed-by: Rob Pike --- src/image/draw/draw_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/image/draw/draw_test.go b/src/image/draw/draw_test.go index 0dd7fbd479..8b4ca029eb 100644 --- a/src/image/draw/draw_test.go +++ b/src/image/draw/draw_test.go @@ -74,6 +74,16 @@ func vgradCr() image.Image { return m } +func vgradMagenta() image.Image { + m := image.NewCMYK(image.Rect(0, 0, 16, 16)) + for y := 0; y < 16; y++ { + for x := 0; x < 16; x++ { + m.Set(x, y, color.CMYK{0, uint8(y * 0x11), 0, 0x3f}) + } + } + return m +} + func hgradRed(alpha int) Image { m := image.NewRGBA(image.Rect(0, 0, 16, 16)) for y := 0; y < 16; y++ { @@ -147,6 +157,16 @@ var drawTests = []drawTest{ {"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 0, 192}}, {"ycbcrNil", vgradCr(), nil, Over, color.RGBA{11, 38, 0, 255}}, {"ycbcrNilSrc", vgradCr(), nil, Src, color.RGBA{11, 38, 0, 255}}, + // Uniform mask (100%, 75%, nil) and variable CMYK source. + // At (x, y) == (8, 8): + // The destination pixel is {136, 0, 0, 255}. + // The source pixel is {0, 136, 0, 63} in CMYK-space, which is {192, 89, 192} in RGB-space. + {"cmyk", vgradMagenta(), fillAlpha(255), Over, color.RGBA{192, 89, 192, 255}}, + {"cmykSrc", vgradMagenta(), fillAlpha(255), Src, color.RGBA{192, 89, 192, 255}}, + {"cmykAlpha", vgradMagenta(), fillAlpha(192), Over, color.RGBA{178, 67, 145, 255}}, + {"cmykAlphaSrc", vgradMagenta(), fillAlpha(192), Src, color.RGBA{145, 67, 145, 192}}, + {"cmykNil", vgradMagenta(), nil, Over, color.RGBA{192, 89, 192, 255}}, + {"cmykNilSrc", vgradMagenta(), nil, Src, color.RGBA{192, 89, 192, 255}}, // Variable mask and variable source. // At (x, y) == (8, 8): // The destination pixel is {136, 0, 0, 255}. -- cgit v1.2.3-54-g00ecf From 38be309dcfebb07dd7ca286509c1ee1f4abd9592 Mon Sep 17 00:00:00 2001 From: mattn Date: Tue, 17 Feb 2015 09:16:06 +0900 Subject: os: fix typo in doc Change-Id: I9797b44dfa7c2c853b7a656f4f722df2c862824b Reviewed-on: https://go-review.googlesource.com/4991 Reviewed-by: Andrew Gerrand --- src/os/env.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/os/env.go b/src/os/env.go index d0494a4763..5c22fbc3d7 100644 --- a/src/os/env.go +++ b/src/os/env.go @@ -48,7 +48,7 @@ func isAlphaNum(c uint8) bool { return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' } -// getName returns the name that begins the string and the number of bytes +// getShellName returns the name that begins the string and the number of bytes // consumed to extract it. If the name is enclosed in {}, it's part of a ${} // expansion and two more bytes are needed than the length of the name. func getShellName(s string) (string, int) { -- cgit v1.2.3-54-g00ecf From 5c8f9e38eb96d274f82a93c936a8ec8015f90845 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Tue, 17 Feb 2015 11:15:06 +1100 Subject: image: fix Rectangle.Overlaps and Rectangle.Union for empty rectangles. Fixes #9895. Change-Id: I37d78ced9ff8196e32d299504908a1c41ad4592d Reviewed-on: https://go-review.googlesource.com/4990 Reviewed-by: Rob Pike --- src/image/geom.go | 9 ++++- src/image/geom_test.go | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/image/geom_test.go diff --git a/src/image/geom.go b/src/image/geom.go index 6ebaf67da8..7c56010653 100644 --- a/src/image/geom.go +++ b/src/image/geom.go @@ -164,6 +164,12 @@ func (r Rectangle) Intersect(s Rectangle) Rectangle { // Union returns the smallest rectangle that contains both r and s. func (r Rectangle) Union(s Rectangle) Rectangle { + if r.Empty() { + return s + } + if s.Empty() { + return r + } if r.Min.X > s.Min.X { r.Min.X = s.Min.X } @@ -192,7 +198,8 @@ func (r Rectangle) Eq(s Rectangle) bool { // Overlaps reports whether r and s have a non-empty intersection. func (r Rectangle) Overlaps(s Rectangle) bool { - return r.Min.X < s.Max.X && s.Min.X < r.Max.X && + return !r.Empty() && !s.Empty() && + r.Min.X < s.Max.X && s.Min.X < r.Max.X && r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y } diff --git a/src/image/geom_test.go b/src/image/geom_test.go new file mode 100644 index 0000000000..5bbd8a9492 --- /dev/null +++ b/src/image/geom_test.go @@ -0,0 +1,103 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package image + +import ( + "fmt" + "testing" +) + +func TestRectangle(t *testing.T) { + // in checks that every point in f is in g. + in := func(f, g Rectangle) error { + if !f.In(g) { + return fmt.Errorf("f=%s, f.In(%s): got false, want true", f, g) + } + for y := f.Min.Y; y < f.Max.Y; y++ { + for x := f.Min.X; x < f.Max.X; x++ { + p := Point{x, y} + if !p.In(g) { + return fmt.Errorf("p=%s, p.In(%s): got false, want true", p, g) + } + } + } + return nil + } + + rects := []Rectangle{ + Rect(0, 0, 10, 10), + Rect(1, 2, 3, 4), + Rect(4, 6, 10, 10), + Rect(2, 3, 12, 5), + Rect(-1, -2, 0, 0), + Rect(-1, -2, 4, 6), + Rect(-10, -20, 30, 40), + Rect(8, 8, 8, 8), + Rect(88, 88, 88, 88), + Rect(6, 5, 4, 3), + } + + // The intersection should be the largest rectangle a such that every point + // in a is both in r and in s. + for _, r := range rects { + for _, s := range rects { + a := r.Intersect(s) + if err := in(a, r); err != nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in r: %v", r, s, a, err) + } + if err := in(a, s); err != nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in s: %v", r, s, a, err) + } + if a.Empty() == r.Overlaps(s) { + t.Errorf("Intersect: r=%s, s=%s, a=%s: empty=%t same as overlaps=%t", + r, s, a, a.Empty(), r.Overlaps(s)) + } + largerThanA := [4]Rectangle{a, a, a, a} + largerThanA[0].Min.X-- + largerThanA[1].Min.Y-- + largerThanA[2].Max.X++ + largerThanA[3].Max.Y++ + for i, b := range largerThanA { + if b.Empty() { + // b isn't actually larger than a. + continue + } + if in(b, r) == nil && in(b, s) == nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, b=%s, i=%d: intersection could be larger", + r, s, a, b, i) + } + } + } + } + + // The union should be the smallest rectangle a such that every point in r + // is in a and every point in s is in a. + for _, r := range rects { + for _, s := range rects { + a := r.Union(s) + if err := in(r, a); err != nil { + t.Errorf("Union: r=%s, s=%s, a=%s, r not in a: %v", r, s, a, err) + } + if err := in(s, a); err != nil { + t.Errorf("Union: r=%s, s=%s, a=%s, s not in a: %v", r, s, a, err) + } + if a.Empty() { + // You can't get any smaller than a. + continue + } + smallerThanA := [4]Rectangle{a, a, a, a} + smallerThanA[0].Min.X++ + smallerThanA[1].Min.Y++ + smallerThanA[2].Max.X-- + smallerThanA[3].Max.Y-- + for i, b := range smallerThanA { + if in(r, b) == nil && in(s, b) == nil { + t.Errorf("Union: r=%s, s=%s, a=%s, b=%s, i=%d: union could be smaller", + r, s, a, b, i) + } + } + } + } +} -- cgit v1.2.3-54-g00ecf From d866cd6817e5b139fe70b79f125318a4d2a15a96 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Tue, 17 Feb 2015 11:04:07 +0900 Subject: all: fix typo in doc Change-Id: I89fdda2914030dfea3183a8b4681dd4b33489729 Reviewed-on: https://go-review.googlesource.com/4996 Reviewed-by: Minux Ma --- src/net/ip.go | 2 +- src/os/env.go | 2 +- src/runtime/race1.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/net/ip.go b/src/net/ip.go index 7bcc40e8f6..f83658ccb9 100644 --- a/src/net/ip.go +++ b/src/net/ip.go @@ -132,7 +132,7 @@ func (ip IP) IsMulticast() bool { return ip[0] == 0xff } -// IsInterfaceLinkLocalMulticast returns true if ip is +// IsInterfaceLocalMulticast returns true if ip is // an interface-local multicast address. func (ip IP) IsInterfaceLocalMulticast() bool { return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01 diff --git a/src/os/env.go b/src/os/env.go index 5c22fbc3d7..4bc6dade44 100644 --- a/src/os/env.go +++ b/src/os/env.go @@ -33,7 +33,7 @@ func ExpandEnv(s string) string { return Expand(s, Getenv) } -// isSpellSpecialVar reports whether the character identifies a special +// isShellSpecialVar reports whether the character identifies a special // shell variable such as $*. func isShellSpecialVar(c uint8) bool { switch c { diff --git a/src/runtime/race1.go b/src/runtime/race1.go index 7e011fe247..41f4938e87 100644 --- a/src/runtime/race1.go +++ b/src/runtime/race1.go @@ -314,7 +314,7 @@ func RaceReleaseMerge(addr unsafe.Pointer) { //go:nosplit -// RaceEnable re-enables handling of race events in the current goroutine. +// RaceDisable disables handling of race events in the current goroutine. func RaceDisable() { _g_ := getg() if _g_.raceignore == 0 { @@ -325,7 +325,7 @@ func RaceDisable() { //go:nosplit -// RaceDisable disables handling of race events in the current goroutine. +// RaceEnable re-enables handling of race events in the current goroutine. func RaceEnable() { _g_ := getg() _g_.raceignore-- -- cgit v1.2.3-54-g00ecf From f20826692bbf35ae09d3a988dbc4a028fb00a50f Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Tue, 17 Feb 2015 15:21:11 +1100 Subject: syscall: make mksyscall_windows.go to work even when output does not uses unsafe package Fixes #9900 Change-Id: I5dd401e8d2040e84ccb97c2fe9f5c5a28095b538 Reviewed-on: https://go-review.googlesource.com/5005 Reviewed-by: Minux Ma --- src/syscall/mksyscall_windows.go | 2 ++ src/syscall/zsyscall_windows.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go index cb540d3956..d4c09273d6 100644 --- a/src/syscall/mksyscall_windows.go +++ b/src/syscall/mksyscall_windows.go @@ -736,6 +736,8 @@ package {{packagename}} import "unsafe"{{if syscalldot}} import "syscall"{{end}} +var _ unsafe.Pointer + var ( {{template "dlls" .}} {{template "funcnames" .}}) diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go index 9c15cf1a1c..ba62499f4e 100644 --- a/src/syscall/zsyscall_windows.go +++ b/src/syscall/zsyscall_windows.go @@ -4,6 +4,8 @@ package syscall import "unsafe" +var _ unsafe.Pointer + var ( modkernel32 = NewLazyDLL("kernel32.dll") modadvapi32 = NewLazyDLL("advapi32.dll") -- cgit v1.2.3-54-g00ecf From 04774336b15c2eeda76080d60c57844a22b77c99 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Mon, 16 Feb 2015 14:22:22 -0500 Subject: cmd/go: skip stat check when using -toolexec Change-Id: Idc88b1ee950e33cfe757a27e9a3383d879793af7 Reviewed-on: https://go-review.googlesource.com/4934 Reviewed-by: Ian Lance Taylor --- src/cmd/go/tool.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go index dc8d34ba08..29feb1d3b2 100644 --- a/src/cmd/go/tool.go +++ b/src/cmd/go/tool.go @@ -50,6 +50,9 @@ func tool(toolName string) string { if toolIsWindows { toolPath += toolWindowsExtension } + if len(buildToolExec) > 0 { + return toolPath + } // Give a nice message if there is no tool with that name. if _, err := os.Stat(toolPath); err != nil { if isInGoToolsRepo(toolName) { -- cgit v1.2.3-54-g00ecf From 277eddb8f236b76c1028110ca89c9fc596f3074f Mon Sep 17 00:00:00 2001 From: Ivan Ukhov Date: Tue, 17 Feb 2015 07:53:44 +0100 Subject: math: change Nextafter64 to Nextafter in the description of Nextafter Change-Id: I3419d6247fbff36aa1ed5451bb3cfb7502c3d07e Reviewed-on: https://go-review.googlesource.com/5030 Reviewed-by: David Crawshaw --- src/math/nextafter.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/math/nextafter.go b/src/math/nextafter.go index 4314a05714..9088e4d248 100644 --- a/src/math/nextafter.go +++ b/src/math/nextafter.go @@ -29,9 +29,9 @@ func Nextafter32(x, y float32) (r float32) { // Nextafter returns the next representable float64 value after x towards y. // // Special cases are: -// Nextafter64(x, x) = x -// Nextafter64(NaN, y) = NaN -// Nextafter64(x, NaN) = NaN +// Nextafter(x, x) = x +// Nextafter(NaN, y) = NaN +// Nextafter(x, NaN) = NaN func Nextafter(x, y float64) (r float64) { switch { case IsNaN(x) || IsNaN(y): // special case -- cgit v1.2.3-54-g00ecf From 545686857bc4c2e7a5306d97e5ef48f631d277bc Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 16 Feb 2015 21:56:10 -0500 Subject: runtime: fix GDB "info goroutines" for Go 1.5 "info goroutines" is failing because it hasn't kept up with changes in the 1.5 runtime. This fixes three issues preventing "info goroutines" from working. allg is no longer a linked list, so switch to using the allgs slice. The g struct's 'status' field is now called 'atomicstatus', so rename uses of 'status'. Finally, this was trying to parse str(pc) as an int, but str(pc) can return symbolic information after the raw hex value; fix this by stripping everything after the first space. This also adds a test for "info goroutines" to runtime-gdb_test, which was previously quite skeletal. Change-Id: I8ad83ee8640891cdd88ecd28dad31ed9b5833b7a Reviewed-on: https://go-review.googlesource.com/4935 Reviewed-by: Minux Ma --- src/runtime/runtime-gdb.py | 40 ++++++++++++++++++++++++++++++++++------ src/runtime/runtime-gdb_test.go | 27 ++++++++++++++++++++++++--- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py index cee025eb6c..33fcc76931 100644 --- a/src/runtime/runtime-gdb.py +++ b/src/runtime/runtime-gdb.py @@ -27,6 +27,31 @@ if sys.version > '3': goobjfile = gdb.current_objfile() or gdb.objfiles()[0] goobjfile.pretty_printers = [] +# +# Value wrappers +# + +class SliceValue: + "Wrapper for slice values." + + def __init__(self, val): + self.val = val + + @property + def len(self): + return int(self.val['len']) + + @property + def cap(self): + return int(self.val['cap']) + + def __getitem__(self, i): + if i < 0 or i >= self.len: + raise IndexError(i) + ptr = self.val["array"] + return (ptr + i).dereference() + + # # Pretty Printers # @@ -355,8 +380,8 @@ class GoroutinesCmd(gdb.Command): def invoke(self, _arg, _from_tty): # args = gdb.string_to_argv(arg) vp = gdb.lookup_type('void').pointer() - for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'): - if ptr['status'] == 6: # 'gdead' + for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")): + if ptr['atomicstatus'] == 6: # 'gdead' continue s = ' ' if ptr['m']: @@ -370,9 +395,12 @@ class GoroutinesCmd(gdb.Command): #python3 / newer versions of gdb pc = int(pc) except gdb.error: - pc = int(str(pc), 16) + # str(pc) can return things like + # "0x429d6c ", so + # chop at first space. + pc = int(str(pc).split(None, 1)[0], 16) blk = gdb.block_for_pc(pc) - print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['status'])]), blk.function) + print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['atomicstatus'])]), blk.function) def find_goroutine(goid): @@ -386,8 +414,8 @@ def find_goroutine(goid): @return tuple (gdb.Value, gdb.Value) """ vp = gdb.lookup_type('void').pointer() - for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'): - if ptr['status'] == 6: # 'gdead' + for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")): + if ptr['atomicstatus'] == 6: # 'gdead' continue if ptr['goid'] == goid: return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp')) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 4911dc000d..a946749f47 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -1,11 +1,13 @@ package runtime_test import ( + "bytes" "fmt" "io/ioutil" "os" "os/exec" "path/filepath" + "regexp" "runtime" "testing" ) @@ -30,7 +32,7 @@ func main() { } ` -func TestGdbLoadRuntimeSupport(t *testing.T) { +func TestGdbPython(t *testing.T) { checkGdbPython(t) dir, err := ioutil.TempDir("", "go-build") @@ -54,8 +56,27 @@ func TestGdbLoadRuntimeSupport(t *testing.T) { got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()), + "-ex", "br 'main.main'", + "-ex", "run", + "-ex", "echo BEGIN info goroutines\n", + "-ex", "info goroutines", + "-ex", "echo END\n", filepath.Join(dir, "a.exe")).CombinedOutput() - if string(got) != "Loading Go Runtime support.\n" { - t.Fatalf("%s", got) + + firstLine := bytes.SplitN(got, []byte("\n"), 2)[0] + if string(firstLine) != "Loading Go Runtime support." { + t.Fatalf("failed to load Go runtime support: %s", firstLine) + } + + // Extract named BEGIN...END blocks from output + partRe := regexp.MustCompile(`(?ms)^BEGIN ([^\n]*)\n(.*?)\nEND`) + blocks := map[string]string{} + for _, subs := range partRe.FindAllSubmatch(got, -1) { + blocks[string(subs[1])] = string(subs[2]) + } + + infoGoroutinesRe := regexp.MustCompile(`\d+\s+running\s+runtime`) + if bl := blocks["info goroutines"]; !infoGoroutinesRe.MatchString(bl) { + t.Fatalf("info goroutines failed: %s", bl) } } -- cgit v1.2.3-54-g00ecf From 98651d6edf32e4cfcff407b4441d0b537d0ad745 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 16 Feb 2015 22:04:24 -0500 Subject: runtime: in runtime-gdb.py, use SliceValue wrapper Rather than reaching in to slices directly in the slice pretty printer, use the newly introduced SliceValue wrapper. Change-Id: Ibb25f8c618c2ffb3fe1a8dd044bb9a6a085df5b7 Reviewed-on: https://go-review.googlesource.com/4936 Reviewed-by: Minux Ma --- src/runtime/runtime-gdb.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py index 33fcc76931..6076bcb11b 100644 --- a/src/runtime/runtime-gdb.py +++ b/src/runtime/runtime-gdb.py @@ -88,11 +88,11 @@ class SliceTypePrinter: return str(self.val.type)[6:] # skip 'struct ' def children(self): - if self.val["len"] > self.val["cap"]: + sval = SliceValue(self.val) + if sval.len > sval.cap: return - ptr = self.val["array"] - for idx in range(int(self.val["len"])): - yield ('[{0}]'.format(idx), (ptr + idx).dereference()) + for idx, item in enumerate(sval): + yield ('[{0}]'.format(idx), item) class MapTypePrinter: -- cgit v1.2.3-54-g00ecf From 8ed95a942ce331e5581f3f58b1dc7673e2cc97bb Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 13 Feb 2015 17:30:16 -0500 Subject: runtime: rename gcwork.go to mgcwork.go All of the other memory-related source files start with "m". Keep up the tradition. Change-Id: Idd88fdbf2a1453374fa12109b949b1c4d149a4f8 Reviewed-on: https://go-review.googlesource.com/4853 Reviewed-by: Minux Ma --- src/runtime/gcwork.go | 338 ------------------------------------------------- src/runtime/mgcwork.go | 338 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 338 insertions(+), 338 deletions(-) delete mode 100644 src/runtime/gcwork.go create mode 100644 src/runtime/mgcwork.go diff --git a/src/runtime/gcwork.go b/src/runtime/gcwork.go deleted file mode 100644 index cf5a97957f..0000000000 --- a/src/runtime/gcwork.go +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -const ( - _Debugwbufs = true // if true check wbufs consistency - _WorkbufSize = 1 * 256 // in bytes - if small wbufs are passed to GC in a timely fashion. -) - -type workbufhdr struct { - node lfnode // must be first - nobj uintptr - id uintptr - inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues. - log [4]uintptr // line numbers forming a history of ownership changes to workbuf -} - -type workbuf struct { - workbufhdr - // account for the above fields - obj [(_WorkbufSize - unsafe.Sizeof(workbufhdr{})) / ptrSize]uintptr -} - -// workbuf factory routines. These funcs are used to manage the -// workbufs. They cache workbuf in the m struct field currentwbuf. -// If the GC asks for some work these are the only routines that -// make partially full wbufs available to the GC. -// Each of the gets and puts also take an distinct integer that is used -// to record a brief history of changes to ownership of the workbuf. -// The convention is to use a unique line number but any encoding -// is permissible. For example if you want to pass in 2 bits of information -// you could simple add lineno1*100000+lineno2. - -// logget records the past few values of entry to aid in debugging. -// logget checks the buffer b is not currently in use. -func (b *workbuf) logget(entry uintptr) { - if !_Debugwbufs { - return - } - if b.inuse { - println("runtime: logget fails log entry=", entry, - "b.log[0]=", b.log[0], "b.log[1]=", b.log[1], - "b.log[2]=", b.log[2], "b.log[3]=", b.log[3]) - throw("logget: get not legal") - } - b.inuse = true - copy(b.log[1:], b.log[:]) - b.log[0] = entry -} - -// logput records the past few values of entry to aid in debugging. -// logput checks the buffer b is currently in use. -func (b *workbuf) logput(entry uintptr) { - if !_Debugwbufs { - return - } - if !b.inuse { - println("runtime:logput fails log entry=", entry, - "b.log[0]=", b.log[0], "b.log[1]=", b.log[1], - "b.log[2]=", b.log[2], "b.log[3]=", b.log[3]) - throw("logput: put not legal") - } - b.inuse = false - copy(b.log[1:], b.log[:]) - b.log[0] = entry -} - -func (b *workbuf) checknonempty() { - if b.nobj == 0 { - println("runtime: nonempty check fails", - "b.log[0]=", b.log[0], "b.log[1]=", b.log[1], - "b.log[2]=", b.log[2], "b.log[3]=", b.log[3]) - throw("workbuf is empty") - } -} - -func (b *workbuf) checkempty() { - if b.nobj != 0 { - println("runtime: empty check fails", - "b.log[0]=", b.log[0], "b.log[1]=", b.log[1], - "b.log[2]=", b.log[2], "b.log[3]=", b.log[3]) - throw("workbuf is not empty") - } -} - -// checknocurrentwbuf checks that the m's currentwbuf field is empty -func checknocurrentwbuf() { - if getg().m.currentwbuf != 0 { - throw("unexpected currentwbuf") - } -} - -// getempty pops an empty work buffer off the work.empty list, -// allocating new buffers if none are available. -// entry is used to record a brief history of ownership. -//go:nowritebarrier -func getempty(entry uintptr) *workbuf { - var b *workbuf - if work.empty != 0 { - b = (*workbuf)(lfstackpop(&work.empty)) - if b != nil { - b.checkempty() - } - } - if b == nil { - b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), _CacheLineSize, &memstats.gc_sys)) - } - b.logget(entry) - return b -} - -// putempty puts a workbuf onto the work.empty list. -// Upon entry this go routine owns b. The lfstackpush relinquishes ownership. -//go:nowritebarrier -func putempty(b *workbuf, entry uintptr) { - b.checkempty() - b.logput(entry) - lfstackpush(&work.empty, &b.node) -} - -// putfull puts the workbuf on the work.full list for the GC. -// putfull accepts partially full buffers so the GC can avoid competing -// with the mutators for ownership of partially full buffers. -//go:nowritebarrier -func putfull(b *workbuf, entry uintptr) { - b.checknonempty() - b.logput(entry) - lfstackpush(&work.full, &b.node) -} - -// getpartialorempty tries to return a partially empty -// and if none are available returns an empty one. -// entry is used to provide a brief histoy of ownership -// using entry + xxx00000 to -// indicating that two line numbers in the call chain. -//go:nowritebarrier -func getpartialorempty(entry uintptr) *workbuf { - var b *workbuf - // If this m has a buf in currentwbuf then as an optimization - // simply return that buffer. If it turns out currentwbuf - // is full, put it on the work.full queue and get another - // workbuf off the partial or empty queue. - if getg().m.currentwbuf != 0 { - b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) - if b != nil { - if b.nobj <= uintptr(len(b.obj)) { - return b - } - putfull(b, entry+80100000) - } - } - b = (*workbuf)(lfstackpop(&work.partial)) - if b != nil { - b.logget(entry) - return b - } - // Let getempty do the logget check but - // use the entry to encode that it passed - // through this routine. - b = getempty(entry + 80700000) - return b -} - -// putpartial puts empty buffers on the work.empty queue, -// full buffers on the work.full queue and -// others on the work.partial queue. -// entry is used to provide a brief histoy of ownership -// using entry + xxx00000 to -// indicating that two call chain line numbers. -//go:nowritebarrier -func putpartial(b *workbuf, entry uintptr) { - if b.nobj == 0 { - putempty(b, entry+81500000) - } else if b.nobj < uintptr(len(b.obj)) { - b.logput(entry) - lfstackpush(&work.partial, &b.node) - } else if b.nobj == uintptr(len(b.obj)) { - b.logput(entry) - lfstackpush(&work.full, &b.node) - } else { - throw("putpartial: bad Workbuf b.nobj") - } -} - -// trygetfull tries to get a full or partially empty workbuffer. -// If one is not immediately available return nil -//go:nowritebarrier -func trygetfull(entry uintptr) *workbuf { - b := (*workbuf)(lfstackpop(&work.full)) - if b == nil { - b = (*workbuf)(lfstackpop(&work.partial)) - } - if b != nil { - b.logget(entry) - b.checknonempty() - return b - } - // full and partial are both empty so see if there - // is an work available on currentwbuf. - // This is an optimization to shift - // processing from the STW marktermination phase into - // the concurrent mark phase. - if getg().m.currentwbuf != 0 { - b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) - if b != nil { - if b.nobj != 0 { - return b - } - putempty(b, 839) - b = nil - } - } - return b -} - -// Get a full work buffer off the work.full or a partially -// filled one off the work.partial list. If nothing is available -// wait until all the other gc helpers have finished and then -// return nil. -// getfull acts as a barrier for work.nproc helpers. As long as one -// gchelper is actively marking objects it -// may create a workbuffer that the other helpers can work on. -// The for loop either exits when a work buffer is found -// or when _all_ of the work.nproc GC helpers are in the loop -// looking for work and thus not capable of creating new work. -// This is in fact the termination condition for the STW mark -// phase. -//go:nowritebarrier -func getfull(entry uintptr) *workbuf { - b := (*workbuf)(lfstackpop(&work.full)) - if b != nil { - b.logget(entry) - b.checknonempty() - return b - } - b = (*workbuf)(lfstackpop(&work.partial)) - if b != nil { - b.logget(entry) - return b - } - // Make sure that currentwbuf is also not a source for pointers to be - // processed. This is an optimization that shifts processing - // from the mark termination STW phase to the concurrent mark phase. - if getg().m.currentwbuf != 0 { - b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) - if b != nil { - if b.nobj != 0 { - return b - } - putempty(b, 877) - b = nil - } - } - - xadd(&work.nwait, +1) - for i := 0; ; i++ { - if work.full != 0 { - xadd(&work.nwait, -1) - b = (*workbuf)(lfstackpop(&work.full)) - if b == nil { - b = (*workbuf)(lfstackpop(&work.partial)) - } - if b != nil { - b.logget(entry) - b.checknonempty() - return b - } - xadd(&work.nwait, +1) - } - if work.nwait == work.nproc { - return nil - } - _g_ := getg() - if i < 10 { - _g_.m.gcstats.nprocyield++ - procyield(20) - } else if i < 20 { - _g_.m.gcstats.nosyield++ - osyield() - } else { - _g_.m.gcstats.nsleep++ - usleep(100) - } - } -} - -//go:nowritebarrier -func handoff(b *workbuf) *workbuf { - // Make new buffer with half of b's pointers. - b1 := getempty(915) - n := b.nobj / 2 - b.nobj -= n - b1.nobj = n - memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), n*unsafe.Sizeof(b1.obj[0])) - _g_ := getg() - _g_.m.gcstats.nhandoff++ - _g_.m.gcstats.nhandoffcnt += uint64(n) - - // Put b on full list - let first half of b get stolen. - putfull(b, 942) - return b1 -} - -// 1 when you are harvesting so that the write buffer code shade can -// detect calls during a presumable STW write barrier. -var harvestingwbufs uint32 - -// harvestwbufs moves non-empty workbufs to work.full from m.currentwuf -// Must be in a STW phase. -// xchguintptr is used since there are write barrier calls from the GC helper -// routines even during a STW phase. -// TODO: chase down write barrier calls in STW phase and understand and eliminate -// them. -//go:nowritebarrier -func harvestwbufs() { - // announce to write buffer that you are harvesting the currentwbufs - atomicstore(&harvestingwbufs, 1) - - for mp := allm; mp != nil; mp = mp.alllink { - wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&mp.currentwbuf, 0))) - // TODO: beat write barriers out of the mark termination and eliminate xchg - // tempwbuf := (*workbuf)(unsafe.Pointer(tempm.currentwbuf)) - // tempm.currentwbuf = 0 - if wbuf != nil { - if wbuf.nobj == 0 { - putempty(wbuf, 945) - } else { - putfull(wbuf, 947) //use full instead of partial so GC doesn't compete to get wbuf - } - } - } - - atomicstore(&harvestingwbufs, 0) -} diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go new file mode 100644 index 0000000000..cf5a97957f --- /dev/null +++ b/src/runtime/mgcwork.go @@ -0,0 +1,338 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +const ( + _Debugwbufs = true // if true check wbufs consistency + _WorkbufSize = 1 * 256 // in bytes - if small wbufs are passed to GC in a timely fashion. +) + +type workbufhdr struct { + node lfnode // must be first + nobj uintptr + id uintptr + inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues. + log [4]uintptr // line numbers forming a history of ownership changes to workbuf +} + +type workbuf struct { + workbufhdr + // account for the above fields + obj [(_WorkbufSize - unsafe.Sizeof(workbufhdr{})) / ptrSize]uintptr +} + +// workbuf factory routines. These funcs are used to manage the +// workbufs. They cache workbuf in the m struct field currentwbuf. +// If the GC asks for some work these are the only routines that +// make partially full wbufs available to the GC. +// Each of the gets and puts also take an distinct integer that is used +// to record a brief history of changes to ownership of the workbuf. +// The convention is to use a unique line number but any encoding +// is permissible. For example if you want to pass in 2 bits of information +// you could simple add lineno1*100000+lineno2. + +// logget records the past few values of entry to aid in debugging. +// logget checks the buffer b is not currently in use. +func (b *workbuf) logget(entry uintptr) { + if !_Debugwbufs { + return + } + if b.inuse { + println("runtime: logget fails log entry=", entry, + "b.log[0]=", b.log[0], "b.log[1]=", b.log[1], + "b.log[2]=", b.log[2], "b.log[3]=", b.log[3]) + throw("logget: get not legal") + } + b.inuse = true + copy(b.log[1:], b.log[:]) + b.log[0] = entry +} + +// logput records the past few values of entry to aid in debugging. +// logput checks the buffer b is currently in use. +func (b *workbuf) logput(entry uintptr) { + if !_Debugwbufs { + return + } + if !b.inuse { + println("runtime:logput fails log entry=", entry, + "b.log[0]=", b.log[0], "b.log[1]=", b.log[1], + "b.log[2]=", b.log[2], "b.log[3]=", b.log[3]) + throw("logput: put not legal") + } + b.inuse = false + copy(b.log[1:], b.log[:]) + b.log[0] = entry +} + +func (b *workbuf) checknonempty() { + if b.nobj == 0 { + println("runtime: nonempty check fails", + "b.log[0]=", b.log[0], "b.log[1]=", b.log[1], + "b.log[2]=", b.log[2], "b.log[3]=", b.log[3]) + throw("workbuf is empty") + } +} + +func (b *workbuf) checkempty() { + if b.nobj != 0 { + println("runtime: empty check fails", + "b.log[0]=", b.log[0], "b.log[1]=", b.log[1], + "b.log[2]=", b.log[2], "b.log[3]=", b.log[3]) + throw("workbuf is not empty") + } +} + +// checknocurrentwbuf checks that the m's currentwbuf field is empty +func checknocurrentwbuf() { + if getg().m.currentwbuf != 0 { + throw("unexpected currentwbuf") + } +} + +// getempty pops an empty work buffer off the work.empty list, +// allocating new buffers if none are available. +// entry is used to record a brief history of ownership. +//go:nowritebarrier +func getempty(entry uintptr) *workbuf { + var b *workbuf + if work.empty != 0 { + b = (*workbuf)(lfstackpop(&work.empty)) + if b != nil { + b.checkempty() + } + } + if b == nil { + b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), _CacheLineSize, &memstats.gc_sys)) + } + b.logget(entry) + return b +} + +// putempty puts a workbuf onto the work.empty list. +// Upon entry this go routine owns b. The lfstackpush relinquishes ownership. +//go:nowritebarrier +func putempty(b *workbuf, entry uintptr) { + b.checkempty() + b.logput(entry) + lfstackpush(&work.empty, &b.node) +} + +// putfull puts the workbuf on the work.full list for the GC. +// putfull accepts partially full buffers so the GC can avoid competing +// with the mutators for ownership of partially full buffers. +//go:nowritebarrier +func putfull(b *workbuf, entry uintptr) { + b.checknonempty() + b.logput(entry) + lfstackpush(&work.full, &b.node) +} + +// getpartialorempty tries to return a partially empty +// and if none are available returns an empty one. +// entry is used to provide a brief histoy of ownership +// using entry + xxx00000 to +// indicating that two line numbers in the call chain. +//go:nowritebarrier +func getpartialorempty(entry uintptr) *workbuf { + var b *workbuf + // If this m has a buf in currentwbuf then as an optimization + // simply return that buffer. If it turns out currentwbuf + // is full, put it on the work.full queue and get another + // workbuf off the partial or empty queue. + if getg().m.currentwbuf != 0 { + b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) + if b != nil { + if b.nobj <= uintptr(len(b.obj)) { + return b + } + putfull(b, entry+80100000) + } + } + b = (*workbuf)(lfstackpop(&work.partial)) + if b != nil { + b.logget(entry) + return b + } + // Let getempty do the logget check but + // use the entry to encode that it passed + // through this routine. + b = getempty(entry + 80700000) + return b +} + +// putpartial puts empty buffers on the work.empty queue, +// full buffers on the work.full queue and +// others on the work.partial queue. +// entry is used to provide a brief histoy of ownership +// using entry + xxx00000 to +// indicating that two call chain line numbers. +//go:nowritebarrier +func putpartial(b *workbuf, entry uintptr) { + if b.nobj == 0 { + putempty(b, entry+81500000) + } else if b.nobj < uintptr(len(b.obj)) { + b.logput(entry) + lfstackpush(&work.partial, &b.node) + } else if b.nobj == uintptr(len(b.obj)) { + b.logput(entry) + lfstackpush(&work.full, &b.node) + } else { + throw("putpartial: bad Workbuf b.nobj") + } +} + +// trygetfull tries to get a full or partially empty workbuffer. +// If one is not immediately available return nil +//go:nowritebarrier +func trygetfull(entry uintptr) *workbuf { + b := (*workbuf)(lfstackpop(&work.full)) + if b == nil { + b = (*workbuf)(lfstackpop(&work.partial)) + } + if b != nil { + b.logget(entry) + b.checknonempty() + return b + } + // full and partial are both empty so see if there + // is an work available on currentwbuf. + // This is an optimization to shift + // processing from the STW marktermination phase into + // the concurrent mark phase. + if getg().m.currentwbuf != 0 { + b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) + if b != nil { + if b.nobj != 0 { + return b + } + putempty(b, 839) + b = nil + } + } + return b +} + +// Get a full work buffer off the work.full or a partially +// filled one off the work.partial list. If nothing is available +// wait until all the other gc helpers have finished and then +// return nil. +// getfull acts as a barrier for work.nproc helpers. As long as one +// gchelper is actively marking objects it +// may create a workbuffer that the other helpers can work on. +// The for loop either exits when a work buffer is found +// or when _all_ of the work.nproc GC helpers are in the loop +// looking for work and thus not capable of creating new work. +// This is in fact the termination condition for the STW mark +// phase. +//go:nowritebarrier +func getfull(entry uintptr) *workbuf { + b := (*workbuf)(lfstackpop(&work.full)) + if b != nil { + b.logget(entry) + b.checknonempty() + return b + } + b = (*workbuf)(lfstackpop(&work.partial)) + if b != nil { + b.logget(entry) + return b + } + // Make sure that currentwbuf is also not a source for pointers to be + // processed. This is an optimization that shifts processing + // from the mark termination STW phase to the concurrent mark phase. + if getg().m.currentwbuf != 0 { + b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) + if b != nil { + if b.nobj != 0 { + return b + } + putempty(b, 877) + b = nil + } + } + + xadd(&work.nwait, +1) + for i := 0; ; i++ { + if work.full != 0 { + xadd(&work.nwait, -1) + b = (*workbuf)(lfstackpop(&work.full)) + if b == nil { + b = (*workbuf)(lfstackpop(&work.partial)) + } + if b != nil { + b.logget(entry) + b.checknonempty() + return b + } + xadd(&work.nwait, +1) + } + if work.nwait == work.nproc { + return nil + } + _g_ := getg() + if i < 10 { + _g_.m.gcstats.nprocyield++ + procyield(20) + } else if i < 20 { + _g_.m.gcstats.nosyield++ + osyield() + } else { + _g_.m.gcstats.nsleep++ + usleep(100) + } + } +} + +//go:nowritebarrier +func handoff(b *workbuf) *workbuf { + // Make new buffer with half of b's pointers. + b1 := getempty(915) + n := b.nobj / 2 + b.nobj -= n + b1.nobj = n + memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), n*unsafe.Sizeof(b1.obj[0])) + _g_ := getg() + _g_.m.gcstats.nhandoff++ + _g_.m.gcstats.nhandoffcnt += uint64(n) + + // Put b on full list - let first half of b get stolen. + putfull(b, 942) + return b1 +} + +// 1 when you are harvesting so that the write buffer code shade can +// detect calls during a presumable STW write barrier. +var harvestingwbufs uint32 + +// harvestwbufs moves non-empty workbufs to work.full from m.currentwuf +// Must be in a STW phase. +// xchguintptr is used since there are write barrier calls from the GC helper +// routines even during a STW phase. +// TODO: chase down write barrier calls in STW phase and understand and eliminate +// them. +//go:nowritebarrier +func harvestwbufs() { + // announce to write buffer that you are harvesting the currentwbufs + atomicstore(&harvestingwbufs, 1) + + for mp := allm; mp != nil; mp = mp.alllink { + wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&mp.currentwbuf, 0))) + // TODO: beat write barriers out of the mark termination and eliminate xchg + // tempwbuf := (*workbuf)(unsafe.Pointer(tempm.currentwbuf)) + // tempm.currentwbuf = 0 + if wbuf != nil { + if wbuf.nobj == 0 { + putempty(wbuf, 945) + } else { + putfull(wbuf, 947) //use full instead of partial so GC doesn't compete to get wbuf + } + } + } + + atomicstore(&harvestingwbufs, 0) +} -- cgit v1.2.3-54-g00ecf From 1ab55a3f047502d8d59616c823facb7cd3ded487 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 17 Feb 2015 15:01:43 -0500 Subject: runtime: fix runtime-gdb_test on arm Apparently when ARM stops at a GDB breakpoint, it appears to be in syscall.Syscall. The "info goroutines" test expected it to be in a runtime function. Since this isn't fundamental to the test, simply tweak the test's regexp to make sure "info goroutines" prints some running goroutine with an active M, but don't require it to be in any particular function. Change-Id: Iba2618b46d3dc49cef62ffb72484b83ea7b0317d Reviewed-on: https://go-review.googlesource.com/5060 Reviewed-by: Dave Cheney --- src/runtime/runtime-gdb_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index a946749f47..a926f5fb85 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -75,7 +75,7 @@ func TestGdbPython(t *testing.T) { blocks[string(subs[1])] = string(subs[2]) } - infoGoroutinesRe := regexp.MustCompile(`\d+\s+running\s+runtime`) + infoGoroutinesRe := regexp.MustCompile(`\*\s+\d+\s+running\s+`) if bl := blocks["info goroutines"]; !infoGoroutinesRe.MatchString(bl) { t.Fatalf("info goroutines failed: %s", bl) } -- cgit v1.2.3-54-g00ecf From 391805b14b03455107783e4d4b349b2fc3f53e26 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Tue, 17 Feb 2015 17:29:54 +1100 Subject: image/draw: add CMYK fast path. Change-Id: I9582aff7ca141a8aead5692af74b9c708b1700cc Reviewed-on: https://go-review.googlesource.com/5020 Reviewed-by: Rob Pike --- src/image/draw/draw.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go index b1fc979a7d..7f9127168e 100644 --- a/src/image/draw/draw.go +++ b/src/image/draw/draw.go @@ -127,6 +127,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas if drawYCbCr(dst0, r, src0, sp) { return } + case *image.CMYK: + drawCMYK(dst0, r, src0, sp) + return } } else if mask0, ok := mask.(*image.Alpha); ok { switch src0 := src.(type) { @@ -151,6 +154,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas if drawYCbCr(dst0, r, src0, sp) { return } + case *image.CMYK: + drawCMYK(dst0, r, src0, sp) + return } } } @@ -462,6 +468,28 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po return true } +func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) { + // An image.CMYK is always fully opaque, and so if the mask is implicitly nil + // (i.e. fully opaque) then the op is effectively always Src. + i0 := (r.Min.X - dst.Rect.Min.X) * 4 + i1 := (r.Max.X - dst.Rect.Min.X) * 4 + si0 := (sp.X - src.Rect.Min.X) * 4 + yMax := r.Max.Y - dst.Rect.Min.Y + + y := r.Min.Y - dst.Rect.Min.Y + sy := sp.Y - src.Rect.Min.Y + for ; y != yMax; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + spix := src.Pix[sy*src.Stride:] + + for i, si := i0, si0; i < i1; i, si = i+4, si+4 { + dpix[i+0], dpix[i+1], dpix[i+2] = + color.CMYKToRGB(spix[si+0], spix[si+1], spix[si+2], spix[si+3]) + dpix[i+3] = 255 + } + } +} + func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) { i0 := dst.PixOffset(r.Min.X, r.Min.Y) i1 := i0 + r.Dx()*4 -- cgit v1.2.3-54-g00ecf From 3ad906b20874f28a4bc48ef767d2138be1b53f28 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Wed, 18 Feb 2015 13:40:57 +1100 Subject: doc: document Go 1.4.2 Change-Id: Ia87047cbc720fb03d2f67aec48abe18bce8dbf78 Reviewed-on: https://go-review.googlesource.com/5112 Reviewed-by: Russ Cox --- doc/devel/release.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/devel/release.html b/doc/devel/release.html index f2c878f2c1..c4540aff96 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -26,6 +26,11 @@ go1.4.1 (released 2015/01/15) includes bug fixes to the linker and the log See the Go 1.4.1 milestone on our issue tracker for details.

+

+go1.4.2 (released 2015/02/17) includes bug fixes to the go command, the compiler and linker, and the runtime, syscall, reflect, and math/big packages. +See the Go 1.4.2 milestone on our issue tracker for details. +

+

go1.3 (released 2014/06/18)

-- cgit v1.2.3-54-g00ecf From 3a0fbfab57b133f4703cc7693a2af745570785ba Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 5 Feb 2015 16:08:29 +0300 Subject: cmd/gc: generate simpler names for closures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #8291 There were several complaints about closure names in the issue tracker. The first problem is that you see names like net/http.func·001 in profiles, traces, etc. And there is no way to figure out what is that function. Another issue is non-US-ascii symbols. All programs out there should accept UTF-8. But unfortunately it is not true in reality. For example, less does not render middle dot properly. This change prepends outer function name to closure name and replaces middle dot with dot. Now names look like: main.glob.func1 main.glob.func2 main.glob.func2.1 main.init.1 main.init.1.func1 main.init.1.func1.1 main.main.func1 main.main.func1.1 Change-Id: I725726af88f2ad3ced2e3450f0f06bf459fd91c0 Reviewed-on: https://go-review.googlesource.com/3964 Reviewed-by: Russ Cox --- src/cmd/gc/closure.c | 61 ++++++++++++++++++++++++++++++++++++++++++++-------- src/cmd/gc/go.h | 2 ++ src/cmd/gc/init.c | 11 +++++----- src/cmd/gc/pgen.c | 2 +- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index 0391ece379..9aeac8aba4 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -19,6 +19,7 @@ closurehdr(Node *ntype) n = nod(OCLOSURE, N, N); n->ntype = ntype; n->funcdepth = funcdepth; + n->outerfunc = curfn; funchdr(n); @@ -124,11 +125,55 @@ typecheckclosure(Node *func, int top) xtop = list(xtop, makeclosure(func)); } +// closurename returns name for OCLOSURE n. +// It is not as simple as it ought to be, because we typecheck nested closures +// starting from the innermost one. So when we check the inner closure, +// we don't yet have name for the outer closure. This function uses recursion +// to generate names all the way up if necessary. +static Sym* +closurename(Node *n) +{ + static int closgen; + char *outer, *prefix; + int gen; + + if(n->sym != S) + return n->sym; + gen = 0; + outer = NULL; + prefix = NULL; + if(n->outerfunc == N) { + // Global closure. + outer = "glob"; + prefix = "func"; + gen = ++closgen; + } else if(n->outerfunc->op == ODCLFUNC) { + // The outermost closure inside of a named function. + outer = n->outerfunc->nname->sym->name; + prefix = "func"; + // Yes, functions can be named _. + // Can't use function closgen in such case, + // because it would lead to name clashes. + if(!isblank(n->outerfunc->nname)) + gen = ++n->outerfunc->closgen; + else + gen = ++closgen; + } else if(n->outerfunc->op == OCLOSURE) { + // Nested closure, recurse. + outer = closurename(n->outerfunc)->name; + prefix = ""; + gen = ++n->outerfunc->closgen; + } else + fatal("closurename called for %hN", n); + snprint(namebuf, sizeof namebuf, "%s.%s%d", outer, prefix, gen); + n->sym = lookup(namebuf); + return n->sym; +} + static Node* makeclosure(Node *func) { Node *xtype, *xfunc; - static int closgen; /* * wrap body in external function @@ -140,8 +185,7 @@ makeclosure(Node *func) // create the function xfunc = nod(ODCLFUNC, N, N); - snprint(namebuf, sizeof namebuf, "func·%.3d", ++closgen); - xfunc->nname = newname(lookup(namebuf)); + xfunc->nname = newname(closurename(func)); xfunc->nname->sym->flags |= SymExported; // disable export xfunc->nname->ntype = xtype; xfunc->nname->defn = xfunc; @@ -158,7 +202,7 @@ makeclosure(Node *func) xfunc->closure = func; func->closure = xfunc; - + func->nbody = nil; func->list = nil; func->rlist = nil; @@ -368,7 +412,7 @@ walkclosure(Node *func, NodeList **init) // and has one float64 argument and no results, // the generated code looks like: // - // clos = &struct{F uintptr; A0 *int; A1 *string}{func·001, &i, &s} + // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s} // // The use of the struct provides type information to the garbage // collector so that it can walk the closure. We could use (in this case) @@ -378,7 +422,7 @@ walkclosure(Node *func, NodeList **init) // same struct type can share the descriptor. typ = nod(OTSTRUCT, N, N); - typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR]))); + typ->list = list1(nod(ODCLFIELD, newname(lookup(".F")), typenod(types[TUINTPTR]))); for(l=func->cvars; l; l=l->next) { v = l->n; if(v->op == OXXX) @@ -447,12 +491,11 @@ makepartialcall(Node *fn, Type *t0, Node *meth) static Pkg* gopkg; int i, ddd; - // TODO: names are not right rcvrtype = fn->left->type; if(exportname(meth->sym->name)) - p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name); + p = smprint("(%-hT).%s-fm", rcvrtype, meth->sym->name); else - p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym); + p = smprint("(%-hT).(%-S)-fm", rcvrtype, meth->sym); basetype = rcvrtype; if(isptr[rcvrtype->etype]) basetype = basetype->type; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index c5ef74586d..92584f6c58 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -310,6 +310,8 @@ struct Node NodeList* dcl; // autodcl for this func/closure NodeList* inl; // copy of the body for use in inlining NodeList* inldcl; // copy of dcl for use in inlining + int closgen; + Node* outerfunc; // OLITERAL/OREGISTER Val val; diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c index c769ec27f0..f1484ea1a6 100644 --- a/src/cmd/gc/init.c +++ b/src/cmd/gc/init.c @@ -11,14 +11,14 @@ * it is called by the initialization before * main is run. to make it unique within a * package and also uncallable, the name, - * normally "pkg.init", is altered to "pkg.init·1". + * normally "pkg.init", is altered to "pkg.init.1". */ Sym* renameinit(void) { static int initgen; - snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen); + snprint(namebuf, sizeof(namebuf), "init.%d", ++initgen); return lookup(namebuf); } @@ -35,7 +35,7 @@ renameinit(void) * // over all matching imported symbols * .init() (7) * { } (8) - * init·() // if any (9) + * init.() // if any (9) * initdone· = 2; (10) * return (11) * } @@ -69,8 +69,7 @@ anyinit(NodeList *n) return 1; // is there an explicit init function - snprint(namebuf, sizeof(namebuf), "init·1"); - s = lookup(namebuf); + s = lookup("init.1"); if(s->def != N) return 1; @@ -167,7 +166,7 @@ fninit(NodeList *n) // (9) // could check that it is fn of no args/returns for(i=1;; i++) { - snprint(namebuf, sizeof(namebuf), "init·%d", i); + snprint(namebuf, sizeof(namebuf), "init.%d", i); s = lookup(namebuf); if(s->def == N) break; diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index 3df78e7f9a..16a869181d 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -180,7 +180,7 @@ compile(Node *fn) dowidth(curfn->type); if(fn->nbody == nil) { - if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) { + if(pure_go || strncmp(fn->nname->sym->name, "init.", 5) == 0) { yyerror("missing function body", fn); goto ret; } -- cgit v1.2.3-54-g00ecf From 2bcfe8b9357f5f823211157c3b67bb03e2f89a2d Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 18 Feb 2015 08:25:30 +0100 Subject: cmd/gc: replace NULL by nil In CL 3964, NULL was used instead of nil. However, Plan 9 doesn't declare NULL. Change-Id: Ied3850aca5c8bca5974105129a37d575df33f6ec Reviewed-on: https://go-review.googlesource.com/5150 Reviewed-by: Minux Ma --- src/cmd/gc/closure.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index 9aeac8aba4..35b6d4b1b4 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -140,8 +140,8 @@ closurename(Node *n) if(n->sym != S) return n->sym; gen = 0; - outer = NULL; - prefix = NULL; + outer = nil; + prefix = nil; if(n->outerfunc == N) { // Global closure. outer = "glob"; -- cgit v1.2.3-54-g00ecf From b2c2bc48564a322a0d68ae429ec6a19836dfd6c1 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 17 Feb 2015 15:17:46 -0500 Subject: crypto/x509: embed certificates on darwin/arm Change-Id: Ia6b06f19e5ac424f01a1b90b78b507363b0c4577 Reviewed-on: https://go-review.googlesource.com/5061 Reviewed-by: Josh Bleecher Snyder --- src/crypto/x509/root_cgo_darwin.go | 2 +- src/crypto/x509/root_darwin.go | 2 + src/crypto/x509/root_darwin_arm.go | 4903 ++++++++++++++++++++++++++++++++ src/crypto/x509/root_darwin_arm_gen.go | 187 ++ 4 files changed, 5093 insertions(+), 1 deletion(-) create mode 100644 src/crypto/x509/root_darwin_arm.go create mode 100644 src/crypto/x509/root_darwin_arm_gen.go diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go index bdcc2c1708..39a5781a8e 100644 --- a/src/crypto/x509/root_cgo_darwin.go +++ b/src/crypto/x509/root_cgo_darwin.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build cgo +// +build cgo,!arm package x509 diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go index 2a61d36eae..96b6599dac 100644 --- a/src/crypto/x509/root_darwin.go +++ b/src/crypto/x509/root_darwin.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:generate go run root_darwin_arm_gen.go -output root_darwin_arm.go + package x509 import "os/exec" diff --git a/src/crypto/x509/root_darwin_arm.go b/src/crypto/x509/root_darwin_arm.go new file mode 100644 index 0000000000..43cd9ec2bd --- /dev/null +++ b/src/crypto/x509/root_darwin_arm.go @@ -0,0 +1,4903 @@ +// Created by root_darwin_arm_gen --output root_darwin_arm.go; DO NOT EDIT + +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x509 + +func initSystemRoots() { + systemRoots = NewCertPool() + systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM)) +} + +const systemRootsPEM = ` +-----BEGIN CERTIFICATE----- +MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx +CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl +bnBlLmNvbTAeFw0wNzEyMTMxMzA4MjdaFw0zNzEyMTMwODI3MjVaMDgxCzAJBgNV +BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXplbnBlLmNv +bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnTesoPHqynhugWZWqx +whtFMnGV2f4QW8yv56V5AY+Jw8ryVXH3d753lPNypCxE2J6SmxQ6oeckkAoKVo7F +2CaU4dlI4S0+2gpy3aOZFdqBoof0e24md4lYrdbrDLJBenNubdt6eEHpCIgSfocu +ZhFjbFT7PJ1ywLwu/8K33Q124zrX97RovqL144FuwUZvXY3gTcZUVYkaMzEKsVe5 +o4qYw+w7NMWVQWl+dcI8IMVhulFHoCCQk6GQS/NOfIVFVJrRBSZBsLVNHTO+xAPI +JXzBcNs79AktVCdIrC/hxKw+yMuSTFM5NyPs0wH54AlETU1kwOENWocivK0bo/4m +tRXzp/yEGensoYi0RGmEg/OJ0XQGqcwL1sLeJ4VQJsoXuMl6h1YsGgEebL4TrRCs +tST1OJGh1kva8bvS3ke18byB9llrzxlT6Y0Vy0rLqW9E5RtBz+GGp8rQap+8TI0G +M1qiheWQNaBiXBZO8OOi+gMatCxxs1gs3nsL2xoP694hHwZ3BgOwye+Z/MC5TwuG +KP7Suerj2qXDR2kS4Nvw9hmL7Xtw1wLW7YcYKCwEJEx35EiKGsY7mtQPyvp10gFA +Wo15v4vPS8+qFsGV5K1Mij4XkdSxYuWC5YAEpAN+jb/af6IPl08M0w3719Hlcn4c +yHf/W5oPt64FRuXxqBbsR6QXAgMBAAGjgfYwgfMwgbAGA1UdEQSBqDCBpYEPaW5m +b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB +MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG +A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw +IFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUHRxlDqjyJXu0kc/ksbHmvVV0bAUwDQYJKoZIhvcNAQEFBQAD +ggIBAMeBRm8hGE+gBe/n1bqXUKJg7aWSFBpSm/nxiEqg3Hh10dUflU7F57dp5iL0 ++CmoKom+z892j+Mxc50m0xwbRxYpB2iEitL7sRskPtKYGCwkjq/2e+pEFhsqxPqg +l+nqbFik73WrAGLRne0TNtsiC7bw0fRue0aHwp28vb5CO7dz0JoqPLRbEhYArxk5 +ja2DUBzIgU+9Ag89njWW7u/kwgN8KRwCfr00J16vU9adF79XbOnQgxCvv11N75B7 +XSus7Op9ACYXzAJcY9cZGKfsK8eKPlgOiofmg59OsjQerFQJTx0CCzl+gQgVuaBp +E8gyK+OtbBPWg50jLbJtooiGfqgNASYJQNntKE6MkyQP2/EeTXp6WuKlWPHcj1+Z +ggwuz7LdmMySlD/5CbOlliVbN/UShUHiGUzGigjB3Bh6Dx4/glmimj4/+eAJn/3B +kUtdyXvWton83x18hqrNA/ILUpLxYm9/h+qrdslsUMIZgq+qHfUgKGgu1fxkN0/P +pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K +7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi +o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu +IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw +WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD +ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y +IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn +IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ +6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob +jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw +izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl ++zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY +zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP +pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF +KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW +ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB +AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 +ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW +IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA +A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 +uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ +FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 +jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ +u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D +YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 +puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa +icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG +DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x +kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z +Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg +b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa +MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB +ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw +IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B +AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb +unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d +BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq +7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 +0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX +roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG +A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j +aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p +26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA +BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud +EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN +BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB +AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd +p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi +1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc +XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 +eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu +tGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJVUzEY +MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT +A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMjAeFw0wNDEyMTMxNTAwMTBaFw0y +OTEyMDUxNTAwMTBaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy +bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg +Um9vdCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCzB9o07 +rP8/PNZxvrh0IgfscEEV/KtA4weqwcPYn/7aTDq/P8jYKHtLNgHArEUlw9IOCo+F +GGQQPRoTcCpvjtfcjZOzQQ84Ic2tq8I9KgXTVxE3Dc2MUfmT48xGSSGOFLTNyxQ+ +OM1yMe6rEvJl6jQuVl3/7mN1y226kTT8nvP0LRy+UMRC31mI/2qz+qhsPctWcXEF +lrufgOWARVlnQbDrw61gpIB1BhecDvRD4JkOG/t/9bPMsoGCsf0ywbi+QaRktWA6 +WlEwjM7eQSwZR1xJEGS5dKmHQa99brrBuKG/ZTE6BGf5tbuOkooAY7ix5ow4X4P/ +UNU7ol1rshDMYwIDAQABoz8wPTAdBgNVHQ4EFgQUSXS7DF66ev4CVO97oMaVxgmA +cJYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBAJiRjT+JyLv1wGlzKTs1rLqzCHY9cAmS6YREIQF9FHYb7lFsHY0VNy17MWn0 +mkS4r0bMNPojywMnGdKDIXUr5+AbmSbchECV6KjSzPZYXGbvP0qXEIIdugqi3VsG +K52nZE7rLgE1pLQ/E61V5NVzqGmbEfGY8jEeb0DU+HifjpGgb3AEkGaqBivO4XqS +tX3h4NGW56E6LcyxnR8FRO2HmdNNGnA5wQQM5X7Z8a/XIA7xInolpHOZzD+kByeW +qKKV7YK5FtOeC4fCwfKI9WLfaN/HvGlR7bFc3FRUKQ8JOZqsA8HbDE2ubwp6Fknx +v5HSOJTT9pUst2zJQraNypCNhdk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz +cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 +MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz +IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ +ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR +VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL +kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd +EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas +H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 +HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud +DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 +QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu +Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ +AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 +yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR +FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA +ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB +kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB +lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w +HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl +YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE +BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT +eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAy +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzOkFyGOFyz9AYxe9GPo15gRn +V2WYKaRPyVyPDzTS+NqoE2KquB5QZ3iwFkygOakVeq7t0qLA8JA3KRgmXOgNPLZs +ST/B4NzZS7YUGQum05bh1gnjGSYc+R9lS/kaQxwAg9bQqkmi1NvmYji6UBRDbfkx ++FYW2TgCkc/rbN27OU6Z4TBnRfHU8I3D3/7yOAchfQBeVkSz5GC9kSucq1sEcg+y +KNlyqwUgQiWpWwNqIBDMMfAr2jUs0Pual07wgksr2F82owstr2MNHSV/oW5cYqGN +KD6h/Bwg+AEvulWaEbAZ0shQeWsOagXXqgQ2sqPy4V93p3ec5R7c6d9qwWVdAgMB +AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSHjCCVyJhK0daABkqQNETfHE2/sDANBgkqhkiG9w0BAQsFAAOCAQEAgY6ypWaW +tyGltu9vI1pf24HFQqV4wWn99DzX+VxrcHIa/FqXTQCAiIiCisNxDY7FiZss7Y0L +0nJU9X3UXENX6fOupQIR9nYrgVfdfdp0MP1UR/bgFm6mtApI5ud1Bw8pGTnOefS2 +bMVfmdUfS/rfbSw8DVSAcPCIC4DPxmiiuB1w2XaM/O6lyc+tHc+ZJVdaYkXLFmu9 +Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm +KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+ +b/xa5IJVWa8xqQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB +lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG +A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe +MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v +d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh +cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn +0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ +M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a +MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd +oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI +DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy +oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 +dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy +bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF +BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli +CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE +CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t +3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS +KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw +CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h +dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l +cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h +2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E +lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV +ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq +299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t +vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL +dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF +AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR +zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 +LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd +7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw +++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP +bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 +MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft +ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC +206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci +KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 +JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 +BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e +Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B +PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 +Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq +Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ +o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 ++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj +YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj +FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn +xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 +LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc +obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 +CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe +IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA +DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F +AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX +Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb +AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl +Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw +RY8mkaKO/qk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHqTCCBZGgAwIBAgIQYwaGp8U3ZaVDkKhqWMzUMjANBgkqhkiG9w0BAQUFADCB +jzELMAkGA1UEBhMCTFYxNTAzBgNVBAoTLFZBUyBMYXR2aWphcyBQYXN0cyAtIFZp +ZW4ucmVnLk5yLjQwMDAzMDUyNzkwMSMwIQYDVQQLExpTZXJ0aWZpa2FjaWphcyBw +YWthbHBvanVtaTEkMCIGA1UEAxMbVkFTIExhdHZpamFzIFBhc3RzIFNTSShSQ0Ep +MB4XDTA2MDkxMzA5MjIxMFoXDTI0MDkxMzA5Mjc1N1owgY8xCzAJBgNVBAYTAkxW +MTUwMwYDVQQKEyxWQVMgTGF0dmlqYXMgUGFzdHMgLSBWaWVuLnJlZy5Oci40MDAw +MzA1Mjc5MDEjMCEGA1UECxMaU2VydGlmaWthY2lqYXMgcGFrYWxwb2p1bWkxJDAi +BgNVBAMTG1ZBUyBMYXR2aWphcyBQYXN0cyBTU0koUkNBKTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAJu4+f1hVS9PpKUUtS6OuSSPrPuxVD9A/0/F5YZo +e1OT+zWCNahQLpRSoNuDPnXaFXCsCc/ugkmtNkm5tHGLtAChQgbKCApjl7YI/O60 +3Jh4GYLJ+H9kPqrJ/rGN67Bk9bzzxD46kOpOjj8bGbxqg8ORPGxV+wpSwOjhXXeF +M8VJ3+xqv79sN/6OSaIVGM6LjmseOKMwb4iBfnJWRBrEejkP9sSPltSy6wBOXN67 +5zu35iQFk2tN5pFEv+6YG8eFGxFBeyI2p74+6Ho33BjekJ2PzbLXmj/iF39bDOHv +P2Y9biTksM7DDIhslNo4JXxSOeNzFLMARWOaDEJAXgTG93JkzsluM7Pk020klTeT +fvIAXRmLH/NDc6ifRdIGqey0Qrv67gzHTz9RH9Gv0KwYf4eBIv6p3QeWbXz4TtlN +OlBp1UF+xdp02I5z5X6D4cMZgbe9v0COvi6aogyqTgIuuyrhCF0xA8msJ7Cv3NXI +FH1AnVWJIfmQzNTJYEFzq+jN2DpVOQqCmf6b9fU8HJHLwPpGVK4h/CqsXHveepdx +/WxrzUiapNuBfBg3L5B9YZS9F8lctlQWd8oJSqrpvE+UdQFaVryS0o+515feVnQB +9xZxSbH1GEaZQe5i4bMsZXVpKXJDA/ibH/o49J7sQBCOrJfVsDO+nxjcLfdBeFRK +YkTnAgMBAAGjggH9MIIB+TAOBgNVHQ8BAf8EBAMCAQYwGAYIKwYBBQUHAQMEDDAK +MAgGBgQAjkYBATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTMw/Vm/3OsOFqW +GyGJuIFMH8teJTAQBgkrBgEEAYI3FQEEAwIBADCCAYkGA1UdIASCAYAwggF8MIIB +eAYLKwYBBAGBxFkBAQIwggFnMIIBOAYIKwYBBQUHAgIwggEqHoIBJgBTAGkAcwAg +AGkAcgAgAHMAZQByAHQAaQBmAGkAawBhAHQAcwAsACAAawBvACAAaQB6AGQAZQB2 +AGkAcwAgAFYAQQBTACAATABhAHQAdgBpAGoAYQBzACAAUABhAHMAdABzACwAIABu +AG8AZAByAG8AcwBpAG4AbwB0ACAAYQB0AGIAaQBsAHMAdABpAGIAdQAgAEUAbABl +AGsAdAByAG8AbgBpAHMAawBvACAAZABvAGsAdQBtAGUAbgB0AHUAIABsAGkAawB1 +AG0AYQBtACAAdQBuACAARQBpAHIAbwBwAGEAcwAgAFAAYQByAGwAYQBtAGUAbgB0 +AGEAIABkAGkAcgBlAGsAdABpAHYAYQBpACAAMQA5ADkAOQAvADkAMwAvAEUASzAp +BggrBgEFBQcCARYdaHR0cDovL3d3dy5lLW1lLmx2L3JlcG9zaXRvcnkwDQYJKoZI +hvcNAQEFBQADggIBAB8oSjWQIWNoCi94r6MegiaXoz8nGdJLo0J6BhNlW8EEy+t9 +fO+U8vGJ9bffUgIhadLqljTloM+XuJxVDhCFoxReLAX4tTp28/l6uN62DCdp8suU +kQsdudWOb5kvzfIZVjk6SFbwAf+Cdbay/dHU9fJjV0xNoX7MELoEae/0FPyzlx9F +7m9KKH/Rxie8x6Opa3vtghNvq94P+3HrXBEaqSzQMJ/8NjdW75XpurcTtq6fAmGt +nuxrBG82nw+Z98LJyEwouSjUIdeeVNXAzvSO5FWUe48kxjj8q3qkVnc9qEXvZJKk +0Ep+u3OL9A1Sc7g6SF5DgNOpcHdi/8coHHMeQ+YnJFtJueY2pI79xS0veqV5EnrX +IbIlbcgPosNhS+VI4le6n/KKId3bZPDaGd/OwJuAOcJ3d2MVU3KE+qSPBzeGIX1Q ++j1qN9uRDjez/c4Lynth0Jx0nH04aG3pex3W8Sq07ztgUncF5gLCX4xbvPB9t3PH +kWuyKrNjozTVq60lcUf/Gj56to2VdsPups0DCWzuRWeYz5lIdsHOinSaaFIBNCLI +7eIUC4S9bhCMsXKbvugI11fVf+q0AT1O5OLoZ+eMfunnQhHvlUbIkda+JxeAGTSY +58bfHvwhX56GPbx+8Jy9cp70R4JbcWfz+txUTKhc2FnH0AcOEzMnvPRp8Gsh +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET +MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE +AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw +CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg +YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE +Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX +mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD +XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW +S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp +FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD +AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu +ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z +ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv +Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw +DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6 +yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq +EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB +EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN +PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIDAOJCMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNVBAYTAkFU +MRAwDgYDVQQKEwdBLVRydXN0MRkwFwYDVQQLExBBLVRydXN0LW5RdWFsLTAxMRkw +FwYDVQQDExBBLVRydXN0LW5RdWFsLTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEz +MDIzMDAwMFowVTELMAkGA1UEBhMCQVQxEDAOBgNVBAoTB0EtVHJ1c3QxGTAXBgNV +BAsTEEEtVHJ1c3QtblF1YWwtMDExGTAXBgNVBAMTEEEtVHJ1c3QtblF1YWwtMDEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD/9RyAEZ6eHmhYzNJ328f0 +jmdSUFi6EqRqOxb3jHNPTIpK82CR6z5lmSnZQNUuCPD+htbNZffd2DKVB06NOyZ1 +2zcOMCgj4GtkZoqE0zPpPT3bpoE55nkZZe/qWEX/64wz/L/4EdkvKDSKG/UsP75M +tmCVY5m2Eg73RVFRz4ccBIMpHel4lzEqSkdDtZOY5fnkrE333hx67nxq21vY8Eyf +8O4fPQ5RtN8eohQCcPQ1z6ypU1R7N9jPRpnI+yzMOiwd3+QcKhHi1miCzo0pkOaB +1CwmfsTyNl8qU0NJUL9Ta6cea7WThwTiWol2yD88cd2cy388xpbNkfrCPmZNGLoV +AgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECE5ZzscCMocwMA4G +A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEA69I9R1hU9Gbl9vV7W7AH +QpUJAlFAvv2It/eY8p2ouQUPVaSZikaKtAYrCD/arzfXB43Qet+dM6CpHsn8ikYR +vQKePjXv3Evf+C1bxwJAimcnZV6W+bNOTpdo8lXljxkmfN+Z5S+XzvK2ttUtP4Et +YOVaxHw2mPMNbvDeY+foJkiBn3KYjGabMaR8moZqof5ofj4iS/WyamTZti6v/fKx +n1vII+/uWkcxV5DT5+r9HLon0NYF0Vg317Wh+gWDV59VZo+dcwJDb+keYqMFYoqp +77SGkZGu41S8NGYkQY3X9rNHRkDbLfpKYDmy6NanpOE1EHW1/sNSFAs43qZZKJEQ +xg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB +rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt +Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa +Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV +BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l +dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE +AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B +YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 +hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l +L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm +SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM +1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws +6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw +Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 +aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH +AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u +7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 +xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ +rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim +eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk +USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx +MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB +ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV +BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV +6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX +GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP +dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH +1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF +62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW +BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL +MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU +cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv +b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 +IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ +iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh +4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm +XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEajCCA1KgAwIBAgIBATANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJKUDEN +MAsGA1UECgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24g +Rm9yIEpQS0kxETAPBgNVBAsMCEJyaWRnZUNBMB4XDTAzMTIyNzA1MDgxNVoXDTEz +MTIyNjE0NTk1OVowWjELMAkGA1UEBhMCSlAxDTALBgNVBAoMBEpQS0kxKTAnBgNV +BAsMIFByZWZlY3R1cmFsIEFzc29jaWF0aW9uIEZvciBKUEtJMREwDwYDVQQLDAhC +cmlkZ2VDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTnUmg7K3m8 +52vd77kwkq156euwoWm5no8E8kmaTSc7x2RABPpqNTlMKdZ6ttsyYrqREeDkcvPL +yF7yf/I8+innasNtsytcTAy8xY8Avsbd4JkCGW9dyPjk9pzzc3yLQ64Rx2fujRn2 +agcEVdPCr/XpJygX8FD5bbhkZ0CVoiASBmlHOcC3YpFlfbT1QcpOSOb7o+VdKVEi +MMfbBuU2IlYIaSr/R1nO7RPNtkqkFWJ1/nKjKHyzZje7j70qSxb+BTGcNgTHa1YA +UrogKB+UpBftmb4ds+XlkEJ1dvwokiSbCDaWFKD+YD4B2s0bvjCbw8xuZFYGhNyR +/2D5XfN1s2MCAwEAAaOCATkwggE1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MG0GA1UdHwRmMGQwYqBgoF6kXDBaMQswCQYDVQQGEwJKUDENMAsGA1UE +CgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24gRm9yIEpQ +S0kxETAPBgNVBAsMCEJyaWRnZUNBMIGDBgNVHREEfDB6pHgwdjELMAkGA1UEBhMC +SlAxJzAlBgNVBAoMHuWFrOeahOWAi+S6uuiqjeiovOOCteODvOODk+OCuTEeMBwG +A1UECwwV6YO96YGT5bqc55yM5Y2U6K2w5LyaMR4wHAYDVQQLDBXjg5bjg6rjg4Pj +grjoqo3oqLzlsYAwHQYDVR0OBBYEFNQXMiCqQNkR2OaZmQgLtf8mR8p8MA0GCSqG +SIb3DQEBBQUAA4IBAQATjJo4reTNPC5CsvAKu1RYT8PyXFVYHbKsEpGt4GR8pDCg +HEGAiAhHSNrGh9CagZMXADvlG0gmMOnXowriQQixrtpkmx0TB8tNAlZptZWkZC+R +8TnjOkHrk2nFAEC3ezbdK0R7MR4tJLDQCnhEWbg50rf0wZ/aF8uAaVeEtHXa6W0M +Xq3dSe0XAcrLbX4zZHQTaWvdpLAIjl6DZ3SCieRMyoWUL+LXaLFdTP5WBCd+No58 +IounD9X4xxze2aeRVaiV/WnQ0OSPNS7n7YXy6xQdnaOU4KRW/Lne1EDf5IfWC/ih +bVAmhZMbcrkWWcsR6aCPG+2mV3zTD6AUzuKPal8Y +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU +YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7 +5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q +gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR +rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7 +ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o +Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE +SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg +Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV +BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl +cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA +vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu +Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a +0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 +4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN +eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD +R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG +A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu +dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME +Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 +WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw +HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ +KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO +Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX +wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 +9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 +jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 +aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDhDCCAmygAwIBAgIBCTANBgkqhkiG9w0BAQUFADAzMQswCQYDVQQGEwJDTjER +MA8GA1UEChMIVW5pVHJ1c3QxETAPBgNVBAMTCFVDQSBSb290MB4XDTA0MDEwMTAw +MDAwMFoXDTI5MTIzMTAwMDAwMFowMzELMAkGA1UEBhMCQ04xETAPBgNVBAoTCFVu +aVRydXN0MREwDwYDVQQDEwhVQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBALNdB8qGJn1r4vs4CQ7MgsJqGgCiFV/W6dQBt1YDAVmP9ThpJHbC +XivF9iu/r/tB/Q9a/KvXg3BNMJjRnrJ2u5LWu+kQKGkoNkTo8SzXWHwk1n8COvCB +a2FgP/Qz3m3l6ihST/ypHWN8C7rqrsRoRuTej8GnsrZYWm0dLNmMOreIy4XU9+gD +Xv2yTVDo1h//rgI/i0+WITyb1yXJHT/7mLFZ5PCpO6+zzYUs4mBGzG+OoOvwNMXx +QhhgrhLtRnUc5dipllq+3lrWeGeWW5N3UPJuG96WUUqm1ktDdSFmjXfsAoR2XEQQ +th1hbOSjIH23jboPkXXHjd+8AmCoKai9PUMCAwEAAaOBojCBnzALBgNVHQ8EBAMC +AQYwDAYDVR0TBAUwAwEB/zBjBgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIG +CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcD +BwYIKwYBBQUHAwgGCCsGAQUFBwMJMB0GA1UdDgQWBBTbHzXza0z/QjFkm827Wh4d +SBC37jANBgkqhkiG9w0BAQUFAAOCAQEAOGy3iPGt+lg3dNHocN6cJ1nL5BXXoMNg +14iABMUwTD3UGusGXllH5rxmy+AI/Og17GJ9ysDawXiv5UZv+4mCI4/211NmVaDe +JRI7cTYWVRJ2+z34VFsxugAG+H1V5ad2g6pcSpemKijfvcZsCyOVjjN/Hl5AHxNU +LJzltQ7dFyiuawHTUin1Ih+QOfTcYmjwPIZH7LgFRbu3DJaUxmfLI3HQjnQi1kHr +A6i26r7EARK1s11AdgYg1GS4KUYGis4fk5oQ7vuqWrTcL9Ury/bXBYSYBZELhPc9 ++tb5evosFeo2gkO3t7jj83EB7UNDogVFwygFBzXjAaU4HoDU18PZ3g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIQWAsFbFMk27JQVxhf+eWmUDANBgkqhkiG9w0BAQUFADAn +MQswCQYDVQQGEwJCRTEYMBYGA1UEAxMPQmVsZ2l1bSBSb290IENBMB4XDTAzMDEy +NjIzMDAwMFoXDTE0MDEyNjIzMDAwMFowJzELMAkGA1UEBhMCQkUxGDAWBgNVBAMT +D0JlbGdpdW0gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AMihcekcRkJ5eHFvna6pqKsot03HIOswkVp19eLSz8hMFJhCWK3HEcVAQGpa+XQS +J4fpnOVxTiIs0RIYqjBeoiG52bv/9nTrMQHnO35YD5EWTXaJqAFPrSJmcPpLHZXB +MFjqvNll2Jq0iOtJRlLf0lMVdssUXRlJsW9q09P9vMIt7EU/CT9YvvzU7wCMgTVy +v/cY6pZifSsofxVsY9LKyn0FrMhtB20yvmi4BUCuVJhWPmbxMOjvxKuTXgfeMo8S +dKpbNCNUwOpszv42kqgJF+qhLc9s44Qd3ocuMws8dOIhUDiVLlzg5cYx+dtA+mqh +pIqTm6chBocdJ9PEoclMsG8CAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4AQEBMC4wLAYIKwYBBQUHAgEW +IGh0dHA6Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQQ8AxW +m2HqVzq2NZdtn925FI7b5jARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAU +EPAMVpth6lc6tjWXbZ/duRSO2+YwDQYJKoZIhvcNAQEFBQADggEBAMhtIlGKYfgP +lm7VILKB+MbcoxYA2s1q52sq+llIp0xJN9dzoWoBZV4yveeX09AuPHPTjHuD79ZC +wT+oqV0PN7p20kC9zC0/00RBSZz9Wyn0AiMiW3Ebv1jZKE4tRfTa57VjRUQRDSp/ +M382SbTObqkCMa5c/ciJv0J71/Fg8teH9lcuen5qE4Ad3OPQYx49cTGxYNSeCMqr +8JTHSHVUgfMbrXec6LKP24OsjzRr6L/D2fVDw2RV6xq9NoY2uiGMlxoh1OotO6y6 +7Kcdq765Sps1LxxcHVGnH1TtEpf/8m6HfUbJdNbv6z195lluBpQE5KJVhzgoaiJe +4r50ErAEQyo= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk +MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 +YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg +Q0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2MjUwNzM4MTRaMGQxCzAJBgNVBAYT +AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp +Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvEr +jw0DzpPMLgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r +0rk0X2s682Q2zsKwzxNoysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f +2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJwDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVP +ACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpHWrumnf2U5NGKpV+GY3aF +y6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1aSgJA/MTA +tukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL +6yxSNLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0 +uPoTXGiTOmekl9AbmbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrAL +acywlKinh/LTSlDcX3KwFnUey7QYYpqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velh +k6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3qPyZ7iVNTA6z00yPhOgpD/0Q +VAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw +FDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O +BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqh +b97iEoHF8TwuMA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4R +fbgZPnm3qKhyN2abGu2sEzsOv2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv +/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ82YqZh6NM4OKb3xuqFp1mrjX2lhI +REeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLzo9v/tdhZsnPdTSpx +srpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcsa0vv +aGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciAT +woCqISxxOQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99n +Bjx8Oto0QuFmtEYE3saWmA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5W +t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N +8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TCrvJcwhbtkj6EPnNgiLx2 +9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5 +wSsSnqaeG8XmDtkx2Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB +lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt +T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV +BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc +BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 +dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP +HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO +KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo +5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ +pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb +kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC +AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov +L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV +HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN +AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw +NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB +mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU +4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 +81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR +Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIIKv++n6Lw6YcwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE +BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTIwHhcNMDcxMDA0MTAwMDAw +WhcNMjExMjE1MDgwMDAwWjAoMQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1 +bSBSb290IENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZzQh6S +/3UPi790hqc/7bIYLS2X+an7mEoj39WN4IzGMhwWLQdC1i22bi+n9fzGhYJdld61 +IgDMqFNAn68KNaJ6x+HK92AQZw6nUHMXU5WfIp8MXW+2QbyM69odRr2nlL/zGsvU ++40OHjPIltfsjFPekx40HopQcSZYtF3CiInaYNKJIT/e1wEYNm7hLHADBGXvmAYr +XR5i3FVr/mZkIV/4L+HXmymvb82fqgxG0YjFnaKVn6w/Fa7yYd/vw2uaItgscf1Y +HewApDgglVrH1Tdjuk+bqv5WRi5j2Qsj1Yr6tSPwiRuhFA0m2kHwOI8w7QUmecFL +TqG4flVSOmlGhHUCAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4CQEBMC4wLAYIKwYBBQUHAgEWIGh0dHA6 +Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSFiuv0xbu+DlkD +lN7WgAEV4xCcOTARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUhYrr9MW7 +vg5ZA5Te1oABFeMQnDkwDQYJKoZIhvcNAQEFBQADggEBAFHYhd27V2/MoGy1oyCc +UwnzSgEMdL8rs5qauhjyC4isHLMzr87lEwEnkoRYmhC598wUkmt0FoqW6FHvv/pK +JaeJtmMrXZRY0c8RcrYeuTlBFk0pvDVTC9rejg7NqZV3JcqUWumyaa7YwBO+mPyW +nIR/VRPmPIfjvCCkpDZoa01gZhz5v6yAlGYuuUGK02XThIAC71AdXkbc98m6tTR8 +KvPG2F9fVJ3bTc0R5/0UAoNmXsimABKgX77OFP67H6dh96tK8QYUn8pJQsKpvO2F +sauBQeYNxUJpU4c5nUwfAA4+Bw11V0SoU7Q2dmSZ3G7rPUZuFF1eR1ONeE3gJ7uO +hXY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX +DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 +qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp +uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU +Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE +pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp +5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M +UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN +GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy +5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv +6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK +eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 +B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ +BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov +L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG +SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS +CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen +5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 +IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK +gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL ++63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL +vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm +bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk +N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC +Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z +ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx +MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy +cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG +A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl +BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed +KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 +G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 +zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 +ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG +HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 +Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V +yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e +beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r +6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog +zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW +BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr +ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp +ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk +cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt +YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC +CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow +KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI +hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ +UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz +X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x +fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz +a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd +Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd +SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O +AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso +M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge +v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF3zCCA8egAwIBAgIOGTMAAQACKBqaBLzyVUUwDQYJKoZIhvcNAQEFBQAwejEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV +BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUGA1UEAxMeVEMgVHJ1 +c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMB4XDTA2MDMyMjE1NTgzNFoXDTMwMTIz +MTIyNTk1OVowejELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVy +IEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUG +A1UEAxMeVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAi9R3azRs5TbYalxeOO781R15Azt7g2JEgk6I +7d6D/+7MUGIFBZWZdpj2ufJf2AaRksL2LWYXH/1TA+iojWOpbuHWG4y8mLOLO9Tk +Lsp9hUkmW3m4GotAnn+7yT9jLM/RWny6KCJBElpN+Rd3/IX9wkngKhh/6aAsnPlE +/AxoOUL1JwW+jhV6YJ3wO8c85j4WvK923mq3ouGrRkXrjGV90ZfzlxElq1nroCLZ +gt2Y7X7i+qBhCkoy3iwX921E6oFHWZdXNwM53V6CItQzuPomCba8OYgvURVOm8M7 +3xOCiN1LNPIz1pDp81PcNXzAw9l8eLPNcD+NauCjgUjkKa1juPD8KGQ7mbN9/pqd +iPaZIgiRRxaJNXhdd6HPv0nh/SSUK2k2e+gc5iqQilvVOzRZQtxtz7sPQRxVzfUN +Wy4WIibvYR6X/OJTyM9bo8ep8boOhhLLE8oVx+zkNo3aXBM9ZdIOXXB03L+PemrB +Lg/Txl4PK1lszGFs/sBhTtnmT0ayWuIZFHCE+CAA7QGnl37DvRJckiMXoKUdRRcV +I5qSCLUiiI3cKyTr4LEXaNOvYb3ZhXj2jbp4yjeNY77nrB/fpUcJucglMVRGURFV +DYlcjdrSGC1z8rjVJ/VIIjfRYvd7Dcg4i6FKsPzQ8eu3hmPn4A5zf/1yUbXpfeJV +BWR4Z38CAwEAAaNjMGEwHwYDVR0jBBgwFoAUzdeQoW6jv9sw1toyJZAM5jkegGUw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFM3XkKFu +o7/bMNbaMiWQDOY5HoBlMA0GCSqGSIb3DQEBBQUAA4ICAQB+FojoEw42zG4qhQc4 +xlaJeuNHIWZMUAgxWlHQ/KZeFHXeTDvs8e3MfhEHSmHu6rOOOqQzxu2KQmZP8Tx7 +yaUFQZmx7Cxb7tyW0ohTS3g0uW7muw/FeqZ8Dhjfbw90TNGp8aHp2FRkzF6WeKJW +GsFzshXGVwXf2vdIJIqOf2qp+U3pPmrOYCx9LZAI9mOPFdAtnIz/8f38DBZQVhT7 +upeG7rRJA1TuG1l/MDoCgoYhrv7wFfLfToPmmcW6NfcgkIw47XXP4S73BDD7Ua2O +giRAyn0pXdXZ92Vk/KqfdLh9kl3ShCngE+qK99CrxK7vFcXCifJ7tjtJmGHzTnKR +N4xJkunI7Cqg90lufA0kxmts8jgvynAF5X/fxisrgIDV2m/LQLvYG/AkyRDIRAJ+ +LtOYqqIN8SvQ2vqOHP9U6OFKbt2o1ni1N6WsZNUUI8cOpevhCTjXwHxgpV2Yj4wC +1dxWqPNNWKkL1HxkdAEy8t8PSoqpAqKiHYR3wvHMl700GXRd4nQ+dSf3r7/ufA5t +VIimVuImrTESPB5BeW0X6hNeH/Vcn0lZo7Ivo0LD+qh+v6WfSMlgYmIK371F3uNC +tVGW/cT1Gpm4UqJEzS1hjBWPgdVdotSQPYxuQGHDWV3Y2eH2dEcieXR92sqjbzcV +NvAsGnE8EXbfXRo+VGN4a2V+Hw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk +MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 +YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg +Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT +AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp +Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 +m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih +FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ +TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F +EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco +kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu +HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF +vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo +19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC +L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW +bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX +JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw +FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc +K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf +ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik +Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB +sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e +3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR +ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip +mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH +b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf +rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms +hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y +zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 +MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG +EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD +VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu +dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 +E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ +D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK +4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq +lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW +bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB +o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT +MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js +LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr +BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB +AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj +j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH +KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv +2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 +mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEBDCCAuygAwIBAgIIGHqpqMKWIQwwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEy +MDIwMTIyMTIxNVoXDTI3MDIwMTIyMTIxNVoweTEtMCsGA1UEAwwkRGV2ZWxvcGVy +IElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UE +BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJdk8GW5pB7qUj +KwKjX9dzP8A1sIuECj8GJH+nlT/rTw6Tr7QO0Mg+5W0Ysx/oiUe/1wkI5P9WmCkV +55SduTWjCs20wOHiYPTK7Cl4RWlpYGtfipL8niPmOsIiszFPHLrytjRZQu6wqQID +GJEEtrN4LjMfgEUNRW+7Dlpbfzrn2AjXCw4ybfuGNuRsq8QRinCEJqqfRNHxuMZ7 +lBebSPcLWBa6I8WfFTl+yl3DMl8P4FJ/QOq+rAhklVvJGpzlgMofakQcbD7EsCYf +Hex7r16gaj1HqVgSMT8gdihtHRywwk4RaSaLy9bQEYLJTg/xVnTQ2QhLZniiq6yn +4tJMh1nJAgMBAAGjgaYwgaMwHQYDVR0OBBYEFFcX7aLP3HyYoRDg/L6HLSzy4xdU +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/ +CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5j +cmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgYEAgUAMA0GCSqGSIb3DQEB +CwUAA4IBAQBCOXRrodzGpI83KoyzHQpEvJUsf7xZuKxh+weQkjK51L87wVA5akR0 +ouxbH3Dlqt1LbBwjcS1f0cWTvu6binBlgp0W4xoQF4ktqM39DHhYSQwofzPuAHob +tHastrW7T9+oG53IGZdKC1ZnL8I+trPEgzrwd210xC4jUe6apQNvYPSlSKcGwrta +4h8fRkV+5Jf1JxC3ICJyb3LaxlB1xT0lj12jAOmfNoxIOY+zO+qQgC6VmmD0eM70 +DgpTPqL6T9geroSVjTK8Vk2J6XgY4KyaQrp6RhuEoonOFOiI0ViL9q5WxCwFKkWv +C9lLqQIPNKyIx2FViUTJJ3MH7oLlTvVw +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx +IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs +cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 +MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl +bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD +DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r +WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU +Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs +HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj +z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf +SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl +AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG +KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P +AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j +BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC +VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX +ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB +ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd +/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB +A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn +k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 +iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv +2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICqDCCAi2gAwIBAgIQIW4zpcvTiKRvKQe0JzzE2DAKBggqhkjOPQQDAzCBlDEL +MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD +VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD +bGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g +RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC +VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h +bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAxIFB1 +YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATXZrUb266zYO5G6ohjdTsqlG3zXxL24w+etgoUU0hS +yNw6s8tIICYSTvqJhNTfkeQpfSgB2dsYQ2mhH7XThhbcx39nI9/fMTGDAzVwsUu3 +yBe7UcvclBfb6gk7dhLeqrWjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRlwI0l9Qy6l3eQP54u4Fr1ztXh5DAKBggqhkjOPQQD +AwNpADBmAjEApa7jRlP4mDbjIvouKEkN7jB+M/PsP3FezFWJeJmssv3cHFwzjim5 +axfIEWi13IMHAjEAnMhE2mnCNsNUGRCFAtqdR+9B52wmnQk9922Q0QVEL7C8g5No +8gxFSTm/mQQc0xCg +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV +BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1 +c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx +MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg +R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD +VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR +JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T +fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu +jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z +wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ +fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD +VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G +CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1 +7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn +8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs +ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/ +2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIOBcAAAQACQdAGCk3OdRAwDQYJKoZIhvcNAQEFBQAwdjEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV +BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDQgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 +Q2VudGVyIENsYXNzIDQgQ0EgSUkwHhcNMDYwMzIzMTQxMDIzWhcNMjUxMjMxMjI1 +OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i +SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQTElMCMGA1UEAxMc +VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALXNTJytrlG7fEjFDSmGehSt2VA9CXIgDRS2Y8b+WJ7gIV7z +jyIZ3E6RIM1viCmis8GsKnK6i1S4QF/yqvhDhsIwXMynXX/GCEnkDjkvjhjWkd0j +FnmA22xIHbzB3ygQY9GB493fL3l1oht48pQB5hBiecugfQLANIJ7x8CtHUzXapZ2 +W78mhEj9h/aECqqSB5lIPGG8ToVYx5ct/YFKocabEvVCUNFkPologiJw3fX64yhC +L04y87OjNopq1mJcrPoBbbTgci6VaLTxkwzGioLSHVPqfOA/QrcSWrjN2qUGZ8uh +d32llvCSHmcOHUJG5vnt+0dTf1cERh9GX8eu4I8CAwEAAaNCMEAwDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFB/quz4lGwa9pd1iBX7G +TFq/6A9DMA0GCSqGSIb3DQEBBQUAA4IBAQBYpCubTPfkpJKknGWYGWIi/HIy6QRd +xMRwLVpG3kxHiiW5ot3u6hKvSI3vK2fbO8w0mCr3CEf/Iq978fTr4jgCMxh1KBue +dmWsiANy8jhHHYz1nwqIUxAUu4DlDLNdjRfuHhkcho0UZ3iMksseIUn3f9MYv5x5 ++F0IebWqak2SNmy8eesOPXmK2PajVnBd3ttPedJ60pVchidlvqDTB4FAVd0Qy+BL +iILAkH0457+W4Ze6mqtCD9Of2J4VMxHL94J59bXAQVaS4d9VA61Iz9PyLrHHLVZM +ZHQqMc7cdalUR6SnQnIJ5+ECpkeyBM1CE+FhDOB4OiIgohxgQoaH96Xm +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw +MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD +VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul +CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n +tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl +dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch +PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC ++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O +BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk +ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X +7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz +43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl +pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA +WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP +bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 +MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft +ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk +hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym +1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW +OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb +2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko +O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU +AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF +Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb +LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir +oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C +MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET +MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0 +MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw +bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+ ++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1 +XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w +tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW +q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM +aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3 +R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE +ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93 +d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl +IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0 +YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj +b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp +Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc +NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP +y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7 +R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg +xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP +IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX +UKqK1drk/NAJBzewdXUh +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC +Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g +Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0 +aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa +Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg +SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo +aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp +ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z +7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA// +DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx +zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8 +hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs +4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u +gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY +NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E +FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3 +j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG +52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB +echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws +ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI +zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy +wy39FCqQmbkHzJ8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN +AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp +dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw +MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw +CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ +MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB +SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz +ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH +LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP +PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL +2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w +ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC +MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk +AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0 +AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz +AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz +AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f +BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY +P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi +CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g +kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95 +HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS +na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q +qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z +TbvGRNs2yyqcjg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS +QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcN +MTQwNDMwMTgxOTA2WhcNMzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBS +b290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABJjpLz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtf +TjjTuxxEtX/1H7YyYl3J6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517 +IDvYuVTZXpmkOlEKMaNCMEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySr +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gA +MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4 +at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM +6BgD56KyKA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo +YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 +MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy +NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G +A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA +A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 +Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s +QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV +eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 +B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh +z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T +AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i +ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w +TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH +MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD +VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE +VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B +AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM +bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi +ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG +VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c +ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ +AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN +MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkgQ2VudHJhbDEWMBQGA1UEAwwNS0lTQSBSb290Q0EgMTAeFw0wNTA4MjQw +ODA1NDZaFw0yNTA4MjQwODA1NDZaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKDARL +SVNBMS4wLAYDVQQLDCVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 +cmFsMRYwFAYDVQQDDA1LSVNBIFJvb3RDQSAxMIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAvATk+hM58DSWIGtsaLv623f/J/es7C/n/fB/bW+MKs0lCVsk +9KFo/CjsySXirO3eyDOE9bClCTqnsUdIxcxPjHmc+QZXfd3uOPbPFLKc6tPAXXdi +8EcNuRpAU1xkcK8IWsD3z3X5bI1kKB4g/rcbGdNaZoNy4rCbvdMlFQ0yb2Q3lIVG +yHK+d9VuHygvx2nt54OJM1jT3qC/QOhDUO7cTWu8peqmyGGO9cNkrwYV3CmLP3WM +vHFE2/yttRcdbYmDz8Yzvb9Fov4Kn6MRXw+5H5wawkbMnChmn3AmPC7fqoD+jMUE +CSVPzZNHPDfqAmeS/vwiJFys0izgXAEzisEZ2wIBA6MyMDAwHQYDVR0OBBYEFL+2 +J9gDWnZlTGEBQVYx5Yt7OtnMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF +BQADggEBABOvUQveimpb5poKyLGQSk6hAp3MiNKrZr097LuxQpVqslxa/6FjZJap +aBV/JV6K+KRzwYCKhQoOUugy50X4TmWAkZl0Q+VFnUkq8JSV3enhMNITbslOsXfl +BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT +2KM3LzuTa7IbB6d/CVDv0zq+IWuKkDsnSlFOa56ch534eJAx7REnxqhZvvwYC/uO +fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5 +UNkAAk/bg9ART6RCVmE6fhMy04Qfybo= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp +ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow +fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV +BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM +cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S +HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 +CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk +3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz +6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV +HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv +Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw +Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww +DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 +5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI +gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ +aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl +izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF0zCCA7ugAwIBAgIVALhZFHE/V9+PMcAzPdLWGXojF7TrMA0GCSqGSIb3DQEB +DQUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dp +ZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBIDIwHhcNMTExMDA2 +MDgzOTU2WhcNNDYxMDA2MDgzOTU2WjCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT +GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0 +d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvfl4+ObV +gAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC5SBLm9qbe7mZXdmbgEvXhEAr +J9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Vaqp3cKcniNQfrcE1K1sGzVrih +QTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ0WeNG0a+RzDVLnLRxWPa52N5 +RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet/5oCl8HGUJKbAiy9qbk0WQq/ +hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNeGWJoRVfkkIJCu0LW8GHgwaM9 +ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcVWiNoidQ+3k4nsPBADLxNF8tN +orMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbls+V1e9dBkQXcXWnjlQ1DufyD +ljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZbMI28iQzV13D4h1L92u+sUS4H +s07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+NqcnoYsylfzGuXIkosagpZ6w7xQ +EmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbljnX98sy50IdbzAYQYLuDNbde +Z95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUtqFUOQLDoD+Oirz61PgcptE6Dv0wDgYDVR0PAQH/BAQD +AgEGMA0GCSqGSIb3DQEBDQUAA4ICAQCdU8KBJdw1LK4K3VqbRjBWu9S0bEuG5gql +0pKKmo3cj7TudvQDy+ubAXirKmu1uiNOMXy1LN0taWczbmNdORgS+KAoU0SHq2rE +kpYfKqIcup3dJ/tSTbCPWujtjcNo45KgJgyHkLAD6mplKAjERnjgW7oO8DPcJ7Z+ +iD29kqSWfkGogAh71jYSvBAVmyS8q619EYkvMe340s9Tjuu0U6fnBMovpiLEEdzr +mMkiXUFq3ApSBFu8LqB9x7aSuySg8zfRK0OozPFoeBp+b2OQe590yGvZC1X2eQM9 +g8dBQJL7dgs3JRc8rz76PFwbhvlKDD+KxF4OmPGt7s/g/SE1xzNhzKI3GEN8M+mu +doKCB0VIO8lnbq2jheiWVs+8u/qry7dXJ40aL5nzIzM0jspTY9NXNFBPz0nBBbrF +qId744aP+0OiEumsUewEdkzw+o+5MRPpCLckCfmgtwc2WFfPxLt+SWaVNQS2dzW4 +qVMpX5KF+FLEWk79BmE5+33QdkeSzOwrvYRu5ptFwX1isVMtnnWg58koUNflvKiq +B3hquXS0YPOEjQPcrpHadEQNe0Kpd9YrfKHGbBNTIqkSmqX5TyhFNbCXT0ZlhcX0 +/WKiomr8NDAGft8M4HOBlslEKt4fguxscletKWSk8cYpjjVgU85r2QK+OTB14Pdc +Y2rwQMEsjQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1 +MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB +IDIwNDgwHhcNMDQwNTE0MjAxNzEyWhcNMjkwNTE0MjAyNTQyWjA1MRYwFAYDVQQK +Ew1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENBIDIwNDgwggEg +MA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCwmrmrp68Kd6ficba0ZmKUeIhH +xmJVhEAyv8CrLqUccda8bnuoqrpu0hWISEWdovyD0My5jOAmaHBKeN8hF570YQXJ +FcjPFto1YYmUQ6iEqDGYeJu5Tm8sUxJszR2tKyS7McQr/4NEb7Y9JHcJ6r8qqB9q +VvYgDxFUl4F1pyXOWWqCZe+36ufijXWLbvLdT6ZeYpzPEApk0E5tzivMW/VgpSdH +jWn0f84bcN5wGyDWbs2mAag8EtKpP6BrXruOIIt6keO1aO6g58QBdKhTCytKmg9l +Eg6CTY5j/e/rmxrbU6YTYK/CfdfHbBcl1HP7R2RQgYCUTOG/rksc35LtLgXfAgED +o1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJ/PI +FR5umgIJFq0roIlgX9p7L6owEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEF +BQADggEBAJ2dhISjQal8dwy3U8pORFBi71R803UXHOjgxkhLtv5MOhmBVrBW7hmW +Yqpao2TB9k5UM8Z3/sUcuuVdJcr18JOagxEu5sv4dEX+5wW4q+ffy0vhN4TauYuX +cB7w4ovXsNgOnbFp1iqRe6lJT37mjpXYgyc81WhJDtSd9i7rp77rMKSsH0T8lasz +Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4 +CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId +kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB +VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp +bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R +dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw +MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy +dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52 +ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM +EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj +lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ +znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH +2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1 +k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs +2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD +VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG +KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+ +8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R +FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE +DNuxUCAKGkq6ahq97BvIxYSazQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHjCCBAagAwIBAgIEAKA3oDANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMC +Q1oxOjA4BgNVBAMMMUkuQ0EgLSBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHksIDA5LzIwMDkxLTArBgNVBAoMJFBydm7DrSBjZXJ0aWZpa2HEjW7DrSBh +dXRvcml0YSwgYS5zLjE9MDsGA1UECww0SS5DQSAtIEFjY3JlZGl0ZWQgUHJvdmlk +ZXIgb2YgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlczAeFw0wOTA5MDEwMDAwMDBaFw0x +OTA5MDEwMDAwMDBaMIG3MQswCQYDVQQGEwJDWjE6MDgGA1UEAwwxSS5DQSAtIFF1 +YWxpZmllZCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSwgMDkvMjAwOTEtMCsGA1UE +CgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMuMT0wOwYDVQQL +DDRJLkNBIC0gQWNjcmVkaXRlZCBQcm92aWRlciBvZiBDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTaEy0KC8M9l +4lSaWHMs4+sVV1LwzyJYiIQNeCrv1HHm/YpGIdY/Z640ceankjQvIX7m23BK4OSC +6KO8kZYA3zopOz6GFCOKV2PvLukbc+c2imF6kLHEv6qNA8WxhPbR3xKwlHDwB2yh +Wzo7V3QVgDRG83sugqQntKYC3LnlTGbJpNP+Az72gpO9AHUn/IBhFk4ksc8lYS2L +9GCy9CsmdKSBP78p9w8Lx7vDLqkDgt1/zBrcUWmSSb7AE/BPEeMryQV1IdI6nlGn +BhWkXOYf6GSdayJw86btuxC7viDKNrbp44HjQRaSxnp6O3eto1x4DfiYdw/YbJFe +7EjkxSQBywIDAQABo4IBLjCCASowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwgecGA1UdIASB3zCB3DCB2QYEVR0gADCB0DCBzQYIKwYBBQUHAgIwgcAa +gb1UZW50byBjZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28ga3ZhbGlmaWtvdmFueSBz +eXN0ZW1vdnkgY2VydGlmaWthdCBwb2RsZSB6YWtvbmEgYy4gMjI3LzIwMDAgU2Iu +IHYgcGxhdG5lbSB6bmVuaS9UaGlzIGlzIHF1YWxpZmllZCBzeXN0ZW0gY2VydGlm +aWNhdGUgYWNjb3JkaW5nIHRvIEN6ZWNoIEFjdCBOby4gMjI3LzIwMDAgQ29sbC4w +HQYDVR0OBBYEFHnL0CPpOmdwkXRP01Hi4CD94Sj7MA0GCSqGSIb3DQEBCwUAA4IB +AQB9laU214hYaBHPZftbDS/2dIGLWdmdSbj1OZbJ8LIPBMxYjPoEMqzAR74tw96T +i6aWRa5WdOWaS6I/qibEKFZhJAVXX5mkx2ewGFLJ+0Go+eTxnjLOnhVF2V2s+57b +m8c8j6/bS6Ij6DspcHEYpfjjh64hE2r0aSpZDjGzKFM6YpqsCJN8qYe2X1qmGMLQ +wvNdjG+nPzCJOOuUEypIWt555ZDLXqS5F7ZjBjlfyDZjEfS2Es9Idok8alf563Mi +9/o+Ba46wMYOkk3P1IlU0RqCajdbliioACKDztAqubONU1guZVzV8tuMASVzbJeL +/GAB7ECTwe1RuKrLYtglMKI9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk +pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf +OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C +Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT +Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi +HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM +Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w ++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ +Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 +Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B +26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID +AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j +ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js +LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM +BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy +dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh +cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh +YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg +dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp +bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ +YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT +TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ +9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 +jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW +FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz +ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 +ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L +EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu +L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC +O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V +um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh +NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk +pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf +OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C +Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT +Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi +HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM +Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w ++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ +Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 +Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B +26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID +AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul +F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC +ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w +ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk +aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 +YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg +c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 +d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG +CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF +wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS +Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst +0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc +pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl +CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF +P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK +1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm +KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ +8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm +fyWl8kgAwKQB2j8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0 +MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG +EwJJTDAeFw0wNDAzMjQxMTMyMThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMT +CkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNpZ24xCzAJBgNVBAYTAklMMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49qROR+WCf4C9DklBKK +8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTyP2Q2 +98CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb +2CEJKHxNGGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxC +ejVb7Us6eva1jsz/D3zkYDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7Kpi +Xd3DTKaCQeQzC6zJMw9kglcq/QytNuEMrkvF7zuZ2SOzW120V+x0cAwqTwIDAQAB +o4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Zl +ZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0PAQH/BAQD +AgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRL +AZs+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWd +foPPbrxHbvUanlR2QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0M +cXS6hMTXcpuEfDhOZAYnKuGntewImbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq +8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb/627HOkthIDYIb6FUtnUdLlp +hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk +Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U +AGegcQCCSA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB +ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt +TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1 +NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 +IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD +VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS +Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2 +N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH +iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe +YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1 +axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g +yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD +AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh +ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V +VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB +BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y +IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs +QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4 +ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM +YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb +QErNaLly7HF27FSOH4UMAWr6pjisH8SE +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIETTCCAzWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJDSDEO +MAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0aWVzMRcwFQYDVQQDEw5BZG1pbkNBLUNELVQwMTAe +Fw0wNjAxMjUxMzM2MTlaFw0xNjAxMjUxMjM2MTlaMG0xCzAJBgNVBAYTAkNIMQ4w +DAYDVQQKEwVhZG1pbjERMA8GA1UECxMIU2VydmljZXMxIjAgBgNVBAsTGUNlcnRp +ZmljYXRpb24gQXV0aG9yaXRpZXMxFzAVBgNVBAMTDkFkbWluQ0EtQ0QtVDAxMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0jQlMZmpLDhV+GNR9TAoSNle +JgQB4xAXJELQf5/ySMfoFA4MmjKqYXQkB6MGPuQKwR9XRRSPf61vqb8YPsdjRmgp +byHBcUd5t0N8RX6wRZUnPMW+bCCo2VqAU4XFbnlc2gHKaam0wdTtbBTXEkv0ieIH +fxCfFxXqSsSr60IkF/2/xbrAgV/QD5yHk6Ie8feAVWwi5UtaFqtu4LiFEh2QMyxs +Oyz1OcvKzkM2g873tyiE7jzMgZP+Ww3tibk2F9+e6ZeiB37TLOmVtvgpmrws4fiI +rFNXEYSWBVrUTbn81U47yWzOgf5fEHP07bRV5QOCzCm99qNimsbL6CG7nT78CQID +AQABo4H3MIH0MBIGA1UdEwEB/wQIMAYBAf8CAQAwga4GA1UdIASBpjCBozCBoAYI +YIV0AREDFQEwgZMwSAYIKwYBBQUHAgIwPBo6VGhpcyBpcyB0aGUgQWRtaW5DQS1D +RC1UMDEgQ2VydGlmaWNhdGUgUHJhY3RpY2UgU3RhdGVtZW50LjBHBggrBgEFBQcC +ARY7aHR0cDovL3d3dy5wa2kuYWRtaW4uY2gvcG9saWN5L0NQU18yXzE2Xzc1Nl8x +XzE3XzNfMjFfMS5wZGYwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQqxGkKocZV +xgNucM6GgbOkD6oZ2zANBgkqhkiG9w0BAQUFAAOCAQEAn356bbusjI5glGXRQ1DR +v21qQf0S4s3GHyZm7cqdOkFleM70ArBT+kOP5Nm7rlSAFyVgEkmBdOg7s9tlXClU +yeZFnp6UEYRUcijPN8D1VaNRK6PIUObpDBQT0C+kAfxG9z4v29T0SxT4sgAdC/xQ +Fyv58Fp9bPn7owuKwKcyCH1XSyi/Bp4XFELlLOaigBZO/w+dPBz4FcJSdZjU+BaJ +0E3nKAjHlShO5ouBSZnaJz3p+nkw2Wyo36s6GxCK0XbkSP45iniIG4FmwwZkonYF +ypQntHbx2oL7tUQQY0PDo8bGBMcPy/G2j+dciqZRlsnfgMy10SCzQ9MUx92xUG2V +eg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFVTCCBD2gAwIBAgIEO/OB0DANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJj +aDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQDEw1BZG1pbi1Sb290LUNB +MB4XDTAxMTExNTA4NTEwN1oXDTIxMTExMDA3NTEwN1owbDELMAkGA1UEBhMCY2gx +DjAMBgNVBAoTBWFkbWluMREwDwYDVQQLEwhTZXJ2aWNlczEiMCAGA1UECxMZQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdGllczEWMBQGA1UEAxMNQWRtaW4tUm9vdC1DQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvgr0QUIv5qF0nyXZ3PXAJi +C4C5Wr+oVTN7oxIkXkxvO0GJToM9n7OVJjSmzBL0zJ2HXj0MDRcvhSY+KiZZc6Go +vDvr5Ua481l7ILFeQAFtumeza+vvxeL5Nd0Maga2miiacLNAKXbAcUYRa0Ov5VZB +++YcOYNNt/aisWbJqA2y8He+NsEgJzK5zNdayvYXQTZN+7tVgWOck16Da3+4FXdy +fH1NCWtZlebtMKtERtkVAaVbiWW24CjZKAiVfggjsiLo3yVMPGj3budLx5D9hEEm +vlyDOtcjebca+AcZglppWMX/iHIrx7740y0zd6cWEqiLIcZCrnpkr/KzwO135GkC +AwEAAaOCAf0wggH5MA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIASBkTCBjjCBiwYI +YIV0AREDAQAwfzArBggrBgEFBQcCAjAfGh1UaGlzIGlzIHRoZSBBZG1pbi1Sb290 +LUNBIENQUzBQBggrBgEFBQcCARZEaHR0cDovL3d3dy5pbmZvcm1hdGlrLmFkbWlu +LmNoL1BLSS9saW5rcy9DUFNfMl8xNl83NTZfMV8xN18zXzFfMC5wZGYwfwYDVR0f +BHgwdjB0oHKgcKRuMGwxFjAUBgNVBAMTDUFkbWluLVJvb3QtQ0ExIjAgBgNVBAsT +GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxETAPBgNVBAsTCFNlcnZpY2VzMQ4w +DAYDVQQKEwVhZG1pbjELMAkGA1UEBhMCY2gwHQYDVR0OBBYEFIKf+iNzIPGXi7JM +Tb5CxX9mzWToMIGZBgNVHSMEgZEwgY6AFIKf+iNzIPGXi7JMTb5CxX9mzWTooXCk +bjBsMQswCQYDVQQGEwJjaDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZp +Y2VzMSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQD +Ew1BZG1pbi1Sb290LUNBggQ784HQMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B +AQUFAAOCAQEAeE96XCYRpy6umkPKXDWCRn7INo96ZrWpMggcDORuofHIwdTkgOeM +vWOxDN/yuT7CC3FAaUajbPRbDw0hRMcqKz0aC8CgwcyIyhw/rFK29mfNTG3EviP9 +QSsEbnelFnjpm1wjz4EaBiFjatwpUbI6+Zv3XbEt9QQXBn+c6DeFLe4xvC4B+MTr +a440xTk59pSYux8OHhEvqIwHCkiijGqZhTS3KmGFeBopaR+dJVBRBMoXwzk4B3Hn +0Zib1dEYFZa84vPJZyvxCbLOnPRDJgH6V2uQqbG+6DXVaf/wORVOvF/wzzv0viM/ +RWbEtJZdvo8N3sdtCULzifnxP/V0T9+4ZQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx +ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 +b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD +EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz +aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w +MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G +A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh +Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l +dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh +bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq +eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe +r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 +3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd +vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l +mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC +wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg +hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 +TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh +biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg +ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg +dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 +b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl +c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 +ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 +dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu +ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo +ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 +Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u +ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA +A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ +MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ +NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR +VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY +83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 +macqaJVmlaut74nLYKkGEsaUR+ko +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBCDANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJDTjER +MA8GA1UEChMIVW5pVHJ1c3QxGDAWBgNVBAMTD1VDQSBHbG9iYWwgUm9vdDAeFw0w +ODAxMDEwMDAwMDBaFw0zNzEyMzEwMDAwMDBaMDoxCzAJBgNVBAYTAkNOMREwDwYD +VQQKEwhVbmlUcnVzdDEYMBYGA1UEAxMPVUNBIEdsb2JhbCBSb290MIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2rPlBlA/9nP3xDK/RqUlYjOHsGj+p9+I +A2N9Apb964fJ7uIIu527u+RBj8cwiQ9tJMAEbBSUgU2gDXRm8/CFr/hkGd656YGT +0CiFmUdCSiw8OCdKzP/5bBnXtfPvm65bNAbXj6ITBpyKhELVs6OQaG2BkO5NhOxM +cE4t3iQ5zhkAQ5N4+QiGHUPR9HK8BcBn+sBR0smFBySuOR56zUHSNqth6iur8CBV +mTxtLRwuLnWW2HKX4AzKaXPudSsVCeCObbvaE/9GqOgADKwHLx25urnRoPeZnnRc +GQVmMc8+KlL+b5/zub35wYH1N9ouTIElXfbZlJrTNYsgKDdfUet9Ysepk9H50DTL +qScmLCiQkjtVY7cXDlRzq6987DqrcDOsIfsiJrOGrCOp139tywgg8q9A9f9ER3Hd +J90TKKHqdjn5EKCgTUCkJ7JZFStsLSS3JGN490MYeg9NEePorIdCjedYcaSrbqLA +l3y74xNLytu7awj5abQEctXDRrl36v+6++nwOgw19o8PrgaEFt2UVdTvyie3AzzF +HCYq9TyopZWbhvGKiWf4xwxmse1Bv4KmAGg6IjTuHuvlb4l0T2qqaqhXZ1LUIGHB +zlPL/SR/XybfoQhplqCe/klD4tPq2sTxiDEhbhzhzfN1DiBEFsx9c3Q1RSw7gdQg +7LYJjD5IskkCAwEAAaOBojCBnzALBgNVHQ8EBAMCAQYwDAYDVR0TBAUwAwEB/zBj +BgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcD +BAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUHAwgGCCsGAQUF +BwMJMB0GA1UdDgQWBBTZw9P4gJJnzF3SOqLXcaK0xDiALTANBgkqhkiG9w0BAQUF +AAOCAgEA0Ih5ygiq9ws0oE4Jwul+NUiJcIQjL1HDKy9e21NrW3UIKlS6Mg7VxnGF +sZdJgPaE0PC6t3GUyHlrpsVE6EKirSUtVy/m1jEp+hmJVCl+t35HNmktbjK81HXa +QnO4TuWDQHOyXd/URHOmYgvbqm4FjMh/Rk85hZCdvBtUKayl1/7lWFZXbSyZoUkh +1WHGjGHhdSTBAd0tGzbDLxLMC9Z4i3WA6UG5iLHKPKkWxk4V43I29tSgQYWvimVw +TbVEEFDs7d9t5tnGwBLxSzovc+k8qe4bqi81pZufTcU0hF8mFGmzI7GJchT46U1R +IgP/SobEHOh7eQrbRyWBfvw0hKxZuFhD5D1DCVR0wtD92e9uWfdyYJl2b/Unp7uD +pEqB7CmB9HdL4UISVdSGKhK28FWbAS7d9qjjGcPORy/AeGEYWsdl/J1GW1fcfA67 +loMQfFUYCQSu0feLKj6g5lDWMDbX54s4U+xJRODPpN/xU3uLWrb2EZBL1nXz/gLz +Ka/wI3J9FO2pXd96gZ6bkiL8HvgBRUGXx2sBYb4zaPKgZYRmvOAqpGjTcezHCN6j +w8k2SjTxF+KAryAhk5Qe5hXTVGLxtTgv48y5ZwSpuuXu+RBuyy5+E6+SFP7zJ3N7 +OPxzbbm5iPZujAv1/P8JDrMtXnt145Ik4ubhWD5LKAN1axibRww= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdjCCAl6gAwIBAgIEOhsEBTANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJE +SzEMMAoGA1UEChMDS01EMQ8wDQYDVQQLEwZLTUQtQ0ExIzAhBgNVBAMTGktNRC1D +QSBLdmFsaWZpY2VyZXQgUGVyc29uMB4XDTAwMTEyMTIzMjQ1OVoXDTE1MTEyMjIz +MjQ1OVowUTELMAkGA1UEBhMCREsxDDAKBgNVBAoTA0tNRDEPMA0GA1UECxMGS01E +LUNBMSMwIQYDVQQDExpLTUQtQ0EgS3ZhbGlmaWNlcmV0IFBlcnNvbjCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBANriF4Xd6yD7ZlBE317UBDObn+vRMVc6 +p3wNQODdEDJe2z1ncCz9NJvhoLGdOJhyg7VVPh0P2c+KZ9WI9mWOKZI2bp2WkLju +jCcxbhTrurY3Wfc6gwLBqqFV8wWgaZKmvVWizjw9Kyi25f3yX4fOho6Qq2lvVbub +tvVFXAd51GJ+/2Yed+a4Or2bz2RcqHS81B3pywsD4mgJR5xREv5jqPfwNP+V7bkc +X+pfO4kVhZ/V+8MSPdQHgcV/iB3wP2mwgWyIBNc1reBidGTiz8unnWu55hcNfsvt +LJbTs9OHhsR7naRuy+S402nDnD5vnONOFEsiHn46w+T0rtu7h6j4OvkCAwEAAaNW +MFQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUeWLqmhI42Jxj7DifDsW+ +DlQhKD0wHwYDVR0jBBgwFoAUeWLqmhI42Jxj7DifDsW+DlQhKD0wDQYJKoZIhvcN +AQEFBQADggEBANML/P42OuJ9aUV/0fItuIyc1JhqWvSqn5bXj+9eyEegcp8bHLHY +42D1O+z0lNipdjYPSdMJ0wZOEUhr+150SdDQ1P/zQL8AUaLEBkRt7ZdzXPVH3PER +qnf9IrpYBknZKfCAoVchA6Rr9WU3Sd8bMoRfMLKg8c0M8G6EPwCTcOFriSkbtvNG +zd8r8I+WfUYIN/p8DI9JT9qfjVODnYPRMUm6KPvq27TsrGruKrqyaV94kWc8co8A +v3zFLeCtghvUiRBdx+8Q7m5t4CkuSr0WINrqjIPFW2QrM1r82y09Fd16RkqL4LOg +Lh6vB5KnTApv62rWdw7zWwYnjY6/vXYY1Aw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw +ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp +dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290 +IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD +VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy +dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg +MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx +UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD +1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH +oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR +HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/ +5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv +idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL +OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC +NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f +46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB +UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth +7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G +A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED +MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB +bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x +XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T +PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0 +Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70 +WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL +Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm +7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S +nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN +vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB +WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI +fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb +I+2ksx0WckNLIOFZfsLorSa/ovc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgIQMDAwMDk3Mzc1NzM4NjAwMDANBgkqhkiG9w0BAQUFADBV +MQswCQYDVQQGEwJGUjETMBEGA1UEChMKQ2VydGlOb21pczEcMBoGA1UECxMTQUMg +UmFjaW5lIC0gUm9vdCBDQTETMBEGA1UEAxMKQ2VydGlOb21pczAeFw0wMDExMDkw +MDAwMDBaFw0xMjExMDkwMDAwMDBaMFUxCzAJBgNVBAYTAkZSMRMwEQYDVQQKEwpD +ZXJ0aU5vbWlzMRwwGgYDVQQLExNBQyBSYWNpbmUgLSBSb290IENBMRMwEQYDVQQD +EwpDZXJ0aU5vbWlzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8SWb +4mS5RXB3ENSIcfrEzCj/TRUQuT1tMCU0YUfXFSgcPdWglIzCv3kvh07QoB+8xMl+ +fQHvSSduAxnNewz0GBY9rApCPKlP6CcnJr74OSVZIiWt9wLfl4wwhNhZOiikIpZp +EdOXWqRc84P5cUlN3Lwmr1sjCWmHfTSS4cAKxfDbFLfE61etosyoFZUTQbIhb1Bf +JL5xRXAUZudQiU42n/yAoSUrN4FLUfPQNlOe1AB81pIgX8g2ojwxDjfgqSs1JmBF +uLKJ45uVLEenQBPmQCGjL3maV86IRmR3a9UGlgvKAk0NBdh8mrQyQvcUlLBIQBCm +l7wppt6maQHUNEPQSwIDAQABoz8wPTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQU+F4ho6ijFeb4tRG7/kIEXU2OgnowDQYJKoZIhvcNAQEF +BQADggEBACe9FJayK6bXkJQrilBFMh75QPdFOks9PJuo86OMUlBDZGYFTCh9Arex +N3KYCnAEzazYIALwr7eASJJDIQMu1Q+pkx/7ACde4kP47F27M2rm+v5HnGooCLz2 +s7Fe/WUycTQqgwF5lNp03m1ce/TvovgkEZeVN5wM/7+SsZLJGDigXGeq48j2g2hn +8OckX9Ciyo0U3/1IVeigNBisiaOlsHSZOEPBZQRiZULob+NVbXVPo8nM1OyP3aHI +LQex1yYcCr9m93nOiZyKkur3Uedf1yMTBe+fflnPFKGYnVqvTGXCKVdHzQBfpILA +AuaC+5ykZhSiSMf8nmL2oPMcLO7YQw4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO +MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL +EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX +DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292 +ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4 +6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9 +hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS +c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk +FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR +xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC +AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ +KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA +A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80 +CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi +4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0 +Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG +WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq +S4CNHIkRi+xb/xfJSPzn4AYR4oRe +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1 +OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG +A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ +JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD +vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo +D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/ +Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW +RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK +HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN +nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM +0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i +UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9 +Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg +TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL +BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX +UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl +6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK +9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ +HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI +wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY +XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l +IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo +hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr +so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJKUDEO +MAwGA1UEChMFTEdQS0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMB4XDTA2 +MDMzMTE1MDAwMFoXDTE2MDMzMTE0NTk1OVowOTELMAkGA1UEBhMCSlAxDjAMBgNV +BAoTBUxHUEtJMRowGAYDVQQLExFBcHBsaWNhdGlvbiBDQSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALk1xhD422jbB8RATLAdHjbcw0H2z1UVbQh/ +XMZoVeXnV/GWUebhTXgPbkAVcDtl/hHf59PWWDU74Z8C/JRSRi6znmCbAp7JgtL2 +464JT4REtmKbAFFouDqt7GTRMkvplESDtA7OIYlrsDbAmMZLnMI+W2AqCTErLatM +3rGg/VhWwoMdILzEhAmHe6iVl8YljoPgPpMN0cd9c6mo/BkAQC4iuHozQfV4/Vpx +54LZSIhc7KiFhy1tgIlnGmm+EMBaju2IfT5vLDhrN85H2KIxMN5+U2Vsi4ZTQSBs +vUilfq8AWlYSWIHR3IlZ+bXu+E2a2EQpi3mn9yKq6nxctBaIIA0CAwEAAaOBsjCB +rzAdBgNVHQ4EFgQUf7hdjsQYa8Z9zC7prs405xdd4KEwDgYDVR0PAQH/BAQDAgEG +MEwGA1UdHwRFMEMwQaA/oD2kOzA5MQswCQYDVQQGEwJKUDEOMAwGA1UEChMFTEdQ +S0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMA8GA1UdEwEB/wQFMAMBAf8w +HwYDVR0jBBgwFoAUf7hdjsQYa8Z9zC7prs405xdd4KEwDQYJKoZIhvcNAQEFBQAD +ggEBADzYczZABkhKVBn1J0g5JaVuQue2zRvLOTS3m+xPKr535MqE/B3rmyJA1fT7 +aIdy/Eddag5SSuO1XUjGIpbmM21tq/bN18skWoyoRZ4+YYJ9lNUF8Bo1X3EvLlS1 +QQXvhg1S75yYG/EsTDrR84bTjD56L4ZFjoMyJlu/U8oOUVbcmsJaMBkNp57Vqpsg +OWl4IfSXbdEOEUwu0xtasPmXeFwqj1Jl7kxCJcI3MA5tKzWUgwbor0U7BGanMLv5 +4CE7Y259RF06alPvERck/VSyWmxzViHJbC2XpEKzJ2EFIWNt6ii8TxpvQtyYq1XT +HhvAkj+bweY7F1bixJhDJe62ywA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICZzCCAdCgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEY +MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT +A1BLSTEcMBoGA1UEAxMTRG9EIENMQVNTIDMgUm9vdCBDQTAeFw0wMDA1MTkxMzEz +MDBaFw0yMDA1MTQxMzEzMDBaMGExCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu +IEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRwwGgYDVQQD +ExNEb0QgQ0xBU1MgMyBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQC1MP5kvurMbe2BLPd/6Rm6DmlqKOGpqcuVWB/x5pppU+CIP5HFUbljl6jmIYwT +XjY8qFf6+HAsTGrLvzCnTBbkMlz4ErBR+BZXjS+0TfouqJToKmHUVw1Hzm4sL36Y +Z8wACKu2lhY1woWR5VugCsdmUmLzYXWVF668KlYppeArUwIDAQABoy8wLTAdBgNV +HQ4EFgQUbJyl8FyPbUGNxBc7kFfCD6PNbf4wDAYDVR0TBAUwAwEB/zANBgkqhkiG +9w0BAQUFAAOBgQCvcUT5lyPMaGmMQwdBuoggsyIAQciYoFUczT9usZNcrfoYmrsc +c2/9JEKPh59Rz76Gn+nXikhPCNlplKw/5g8tlw8ok3ZPYt//oM1h+KaGDDE0INx/ +L6j7Ob6V7jhZAmLB3mwVT+DfnbvkeXMk/WNklfdKqJkfSGWVx3u/eDLneg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFUjCCBDqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN +MAsGA1UEChMES0lTQTEuMCwGA1UECxMlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkgQ2VudHJhbDEWMBQGA1UEAxMNS0lTQSBSb290Q0EgMzAeFw0wNDExMTkw +NjM5NTFaFw0xNDExMTkwNjM5NTFaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKEwRL +SVNBMS4wLAYDVQQLEyVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 +cmFsMRYwFAYDVQQDEw1LSVNBIFJvb3RDQSAzMIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEA3rrtF2Wu0b1KPazbgHLMWOHn4ZPazDB6z+8Lri2nQ6u/p0LP +CFYIpEcdffqG79gwlyY0YTyADvjU65/8IjAboW0+40zSVU4WQDfC9gdu2we1pYyW +geKbXH6UYcjOhDyx+gDmctMJhXfp3F4hT7TkTvTiF6tQrxz/oTlYdVsSspa5jfBw +YkhbVigqpYeRNrkeJPW5unu2UlFbF1pgBWycwubGjD756t08jP+J3kNwrB248XXN +OMpTDUdoasY8GMq94bS+DvTQ49IT+rBRERHUQavo9DmO4TSETwuTqmo4/OXGeEeu +dhf6oYA3BgAVCP1rI476cg2V1ktisWjC3TSbXQIBA6OCAg8wggILMB8GA1UdIwQY +MBaAFI+B8NqmzXQ8vmb0FWtGpP4GKMyqMB0GA1UdDgQWBBSPgfDaps10PL5m9BVr +RqT+BijMqjAOBgNVHQ8BAf8EBAMCAQYwggEuBgNVHSAEggElMIIBITCCAR0GBFUd +IAAwggETMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LnJvb3RjYS5vci5rci9yY2Ev +Y3BzLmh0bWwwgd4GCCsGAQUFBwICMIHRHoHOx3QAIMd4yZ3BHLKUACCs9cd4x3jJ +ncEcx4WyyLLkACgAVABoAGkAcwAgAGMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGkA +cwAgAGEAYwBjAHIAZQBkAGkAdABlAGQAIAB1AG4AZABlAHIAIABFAGwAZQBjAHQA +cgBvAG4AaQBjACAAUwBpAGcAbgBhAHQAdQByAGUAIABBAGMAdAAgAG8AZgAgAHQA +aABlACAAUgBlAHAAdQBiAGwAaQBjACAAbwBmACAASwBvAHIAZQBhACkwMwYDVR0R +BCwwKqQoMCYxJDAiBgNVBAMMG+2VnOq1reygleuztOuztO2YuOynhO2dpeybkDAz +BgNVHRIELDAqpCgwJjEkMCIGA1UEAwwb7ZWc6rWt7KCV67O067O07Zi47KeE7Z2l +7JuQMA8GA1UdEwEB/wQFMAMBAf8wDAYDVR0kBAUwA4ABADANBgkqhkiG9w0BAQUF +AAOCAQEAz9b3Dv2wjG4FFY6oXCuyWtEeV6ZeGKqCEQj8mbdbp+PI0qLT+SQ09+Pk +rolUR9NpScmAwRHr4inH9gaLX7riXs+rw87P7pIl3J85Hg4D9N6QW6FwmVzHc07J +pHVJeyWhn4KSjU3sYcUMMqfHODiAVToqgx2cZHm5Dac1Smjvj/8F2LpOVmHY+Epw +mAiWk9hgxzrsX58dKzVPSBShmrtv7tIDhlPxEMcHVGJeNo7iHCsdF03m9VrvirqC +6HfZKBF+N4dKlArJQOk1pTr7ZD7yXxZ683bXzu4/RB1Fql8RqlMcOh9SUWJUD6OQ +Nc9Nb7rHviwJ8TX4Absk3TC8SA/u2Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz +IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz +MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj +dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw +EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp +MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 +28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq +VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q +DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR +5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL +ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a +Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl +UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s ++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 +Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx +hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV +HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 ++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN +YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t +L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy +ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt +IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV +HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w +DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW +PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF +5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 +glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH +FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 +pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD +xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG +tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq +jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De +fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ +d0jQ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg +Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL +MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD +VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg +isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z +NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI ++MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R +hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+ +mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD +AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP +Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s +EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2 +mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC +e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow +dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw +PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu +MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx +GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL +MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf +HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh +gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW +v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue +Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr +9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt +6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7 +MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl +Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58 +ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq +hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p +iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC +dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL +kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL +hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQUFADCB0DELMAkGA1UEBhMCRVMx +SDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMuVml0 +b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwgTWVk +aXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6MRMw +EQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5wZS5j +b20wHhcNMDMwMTMwMjMwMDAwWhcNMTgwMTMwMjMwMDAwWjCB0DELMAkGA1UEBhMC +RVMxSDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMu +Vml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwg +TWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6 +MRMwEQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5w +ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1btoCXXhp3xIW +D+Bxl8nUCxkyiazWfpt0e68t+Qt9+lZjKZSdEw2Omj4qvr+ovRmDXO3iWpWVOWDl +3JHJjAzFCe8ZEBNDH+QNYwZHmPBaMYFOYFdbAFVHWvys152C308hcFJ6xWWGmjvl +2eMiEl9P2nR2LWue368DCu+ak7j3gjAXaCOdP1a7Bfr+RW3X2SC5R4Xyp8iHlL5J +PHJD/WBkLrezwzQPdACw8m9EG7q9kUwlNpL32mROujS3ZkT6mQTzJieLiE3X04s0 +uIUqVkk5MhjcHFf7al0N5CzjtTcnXYJKN2Z9EDVskk4olAdGi46eSoZXbjUOP5gk +Ej6wVZAXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBTqVk/sPIOhFIh4gbIrBSLAB0FbQjANBgkqhkiG9w0BAQUFAAOC +AQEAYp7mEzzhw6o5Hf5+T5kcI+t4BJyiIWy7vHlLs/G8dLYXO81aN/Mzg928eMTR +TxxYZL8dd9uwsJ50TVfX6L0R4Dyw6wikh3fHRrat9ufXi63j5K91Ysr7aXqnF38d +iAgHYkrwC3kuxHBb9C0KBz6h8Q45/KCyN7d37wWAq38yyhPDlaOvyoE6bdUuK5hT +m5EYA5JmPyrhQ1moDOyueWBAjxzMEMj+OAY1H90cLv6wszsqerxRrdTOHBdv7MjB +EIpvEEQkXUxVXAzFuuT6m2t91Lfnwfl/IvljHaVC7DlyyhRYHD6D4Rx+4QKp4tWL +vpw6LkI+gKNJ/YdMCsRZQzEEFA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx +ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w +MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD +VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx +FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu +ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 +gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH +fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a +ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT +ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk +c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto +dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt +aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI +hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk +QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ +h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR +rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 +9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE5zCCA8+gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCQ0Ex +EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoTFEVj +aG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNlcnZp +Y2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMjAeFw0wNTEwMDYxMDQ5MTNa +Fw0zMDEwMDcxMDQ5MTNaMIGNMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp +bzEQMA4GA1UEBxMHVG9yb250bzEdMBsGA1UEChMURWNob3dvcnggQ29ycG9yYXRp +b24xHzAdBgNVBAsTFkNlcnRpZmljYXRpb24gU2VydmljZXMxGjAYBgNVBAMTEUVj +aG93b3J4IFJvb3QgQ0EyMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA +utU/5BkV15UBf+s+JQruKQxr77s3rjp/RpOtmhHILIiO5gsEWP8MMrfrVEiidjI6 +Qh6ans0KAWc2Dw0/j4qKAQzOSyAZgjcdypNTBZ7muv212DA2Pu41rXqwMrlBrVi/ +KTghfdLlNRu6JrC5y8HarrnRFSKF1Thbzz921kLDRoCi+FVs5eVuK5LvIfkhNAqA +byrTgO3T9zfZgk8upmEkANPDL1+8y7dGPB/d6lk0I5mv8PESKX02TlvwgRSIiTHR +k8++iOPLBWlGp7ZfqTEXkPUZhgrQQvxcrwCUo6mk8TqgxCDP5FgPoHFiPLef5szP +ZLBJDWp7GLyE1PmkQI6WiwIBA6OCAVAwggFMMA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBQ74YEboKs/OyGC1eISrq5QqxSlEzCBugYDVR0j +BIGyMIGvgBQ74YEboKs/OyGC1eISrq5QqxSlE6GBk6SBkDCBjTELMAkGA1UEBhMC +Q0ExEDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoT +FEVjaG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMoIBADBQBgNVHSAESTBH +MEUGCysGAQQB+REKAQMBMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuZWNob3dv +cnguY29tL2NhL3Jvb3QyL2Nwcy5wZGYwDQYJKoZIhvcNAQEFBQADggEBAG+nrPi/ +0RpfEzrj02C6JGPUar4nbjIhcY6N7DWNeqBoUulBSIH/PYGNHYx7/lnJefiixPGE +7TQ5xPgElxb9bK8zoAApO7U33OubqZ7M7DlHnFeCoOoIAZnG1kuwKwD5CXKB2a74 +HzcqNnFW0IsBFCYqrVh/rQgJOzDA8POGbH0DeD0xjwBBooAolkKT+7ZItJF1Pb56 +QpDL9G+16F7GkmnKlAIYT3QTS3yFGYChnJcd+6txUPhKi9sSOOmAIaKHnkH9Scz+ +A2cSi4A3wUYXVatuVNHpRb2lygfH3SuCX9MU8Ure3zBlSU1LALtMqI4JmcQmQpIq +zIzvO2jHyu9PQqo= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV +BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 +Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1 +OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i +SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc +VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf +tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg +uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J +XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK +8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99 +5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3 +kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy +dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6 +Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz +JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 +Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS +GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt +ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8 +au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV +hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI +dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYNDAeFw0wMDA5MTMwNjIyNTBaFw0yMDA5MTMwNjIyNTBa +MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UE +AxMORFNUIFJvb3QgQ0EgWDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCthX3OFEYY8gSeIYur0O4ypOT68HnDrjLfIutL5PZHRwQGjzCPb9PFo/ihboJ8 +RvfGhBAqpQCo47zwYEhpWm1jB+L/OE/dBBiyn98krfU2NiBKSom2J58RBeAwHGEy +cO+lewyjVvbDDLUy4CheY059vfMjPAftCRXjqSZIolQb9FdPcAoa90mFwB7rKniE +J7vppdrUScSS0+eBrHSUPLdvwyn4RGp+lSwbWYcbg5EpSpE0GRJdchic0YDjvIoC +YHpe7Rkj93PYRTQyU4bhC88ck8tMqbvRYqMRqR+vobbkrj5LLCOQCHV5WEoxWh+0 +E2SpIFe7RkV++MmpIAc0h1tZAgMBAAGjMjAwMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFPCD6nPIP1ubWzdf9UyPWvf0hki9MA0GCSqGSIb3DQEBBQUAA4IBAQCE +G85wl5eEWd7adH6XW/ikGN5salvpq/Fix6yVTzE6CrhlP5LBdkf6kx1bSPL18M45 +g0rw2zA/MWOhJ3+S6U+BE0zPGCuu8YQaZibR7snm3HiHUaZNMu5c8D0x0bcMxDjY +AVVcHCoNiL53Q4PLW27nbY6wwG0ffFKmgV3blxrYWfuUDgGpyPwHwkfVFvz9qjaV +mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu +8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/ +Vv4AEbT8dNfEeFxrkDbh +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 +aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla +MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD +VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW +fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt +TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL +fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW +1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 +kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G +A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v +ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo +dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu +Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ +HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS +jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ +xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn +dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID+TCCAuGgAwIBAgIQW1fXqEywr9nTb0ugMbTW4jANBgkqhkiG9w0BAQUFADB5 +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xKjAoBgNVBAMTIVZpc2EgSW5m +b3JtYXRpb24gRGVsaXZlcnkgUm9vdCBDQTAeFw0wNTA2MjcxNzQyNDJaFw0yNTA2 +MjkxNzQyNDJaMHkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQL +EyZWaXNhIEludGVybmF0aW9uYWwgU2VydmljZSBBc3NvY2lhdGlvbjEqMCgGA1UE +AxMhVmlzYSBJbmZvcm1hdGlvbiBEZWxpdmVyeSBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyREA4R/QkkfpLx0cYjga/EhIPZpchH0MZsRZ +FfP6C2ITtf/Wc+MtgD4yTK0yoiXvni3d+aCtEgK3GDvkdgYrgF76ROJFZwUQjQ9l +x42gRT05DbXvWFoy7dTglCZ9z/Tt2Cnktv9oxKgmkeHY/CyfpCBg1S8xth2JlGMR +0ug/GMO5zANuegZOv438p5Lt5So+du2Gl+RMFQqEPwqN5uJSqAe0VtmB4gWdQ8on +Bj2ZAM2R73QW7UW0Igt2vA4JaSiNtaAG/Y/58VXWHGgbq7rDtNK1R30X0kJV0rGA +ib3RSwB3LpG7bOjbIucV5mQgJoVjoA1e05w6g1x/KmNTmOGRVwIDAQABo30wezAP +BgNVHRMBAf8EBTADAQH/MDkGA1UdIAQyMDAwLgYFZ4EDAgEwJTAVBggrBgEFBQcC +ARYJMS4yLjMuNC41MAwGCCsGAQUFBwICMAAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBRPitp2/2d3I5qmgH1924h1hfeBejANBgkqhkiG9w0BAQUFAAOCAQEACUW1 +QdUHdDJydgDPmYt+telnG/Su+DPaf1cregzlN43bJaJosMP7NwjoJY/H2He4XLWb +5rXEkl+xH1UyUwF7mtaUoxbGxEvt8hPZSTB4da2mzXgwKvXuHyzF5Qjy1hOB0/pS +WaF9ARpVKJJ7TOJQdGKBsF2Ty4fSCLqZLgfxbqwMsd9sysXI3rDXjIhekqvbgeLz +PqZr+pfgFhwCCLSMQWl5Ll3u7Qk9wR094DZ6jj6+JCVCRUS3HyabH4OlM0Vc2K+j +INsF/64Or7GNtRf9HYEJvrPxHINxl3JVwhYj4ASeaO4KwhVbwtw94Tc/XrGcexDo +c5lC3rAi4/UZqweYCw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV +BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 +Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1 +OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i +SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc +VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW +Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q +Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2 +1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq +ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1 +Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX +XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy +dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6 +Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz +JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 +Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN +irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8 +TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6 +g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB +95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj +S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 +MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 +czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG +CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy +MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl +ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS +b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy +euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO +bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw +WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d +MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE +1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ +zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB +BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF +BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV +v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG +E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW +iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v +GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc +MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp +b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT +AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs +aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H +j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K +f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55 +IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw +FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht +QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm +/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ +k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ +MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC +seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ +hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+ +eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U +DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj +B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx +MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG +29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk +oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk +3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL +qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN +nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX +ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H +DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO +TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv +kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w +zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE +SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw +ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU +REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr +2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s +2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU +GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj +dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r +TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB +AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv +c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl +ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu +MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg +T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud +HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD +VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny +bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy +MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ +J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG +SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom +JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO +inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y +caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB +mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ +YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 +BKNDLdr8C2LqL19iUw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 +MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp +dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX +BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy +MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp +eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg +/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl +wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh +AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 +PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu +AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR +MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc +HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ +Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ +f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO +rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch +6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 +7CAFYd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT +ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw +MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j +LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo +RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu +WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw +Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD +AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK +eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM +zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ +WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN +/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb +BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz +MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx +FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g +Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 +fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl +LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV +WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF +TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb +5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc +CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri +wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ +wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG +m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 +F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng +WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 +2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF +AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ +0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw +F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS +g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj +qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN +h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ +ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V +btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj +Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ +8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW +gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFujCCBKKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMCVVMx +HTAbBgNVBAoTFEFwcGxlIENvbXB1dGVyLCBJbmMuMS0wKwYDVQQLEyRBcHBsZSBD +b21wdXRlciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIEFwcGxlIFJv +b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA1MDIxMDAwMTgxNFoXDTI1MDIx +MDAwMTgxNFowgYYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBcHBsZSBDb21wdXRl +ciwgSW5jLjEtMCsGA1UECxMkQXBwbGUgQ29tcHV0ZXIgQ2VydGlmaWNhdGUgQXV0 +aG9yaXR5MSkwJwYDVQQDEyBBcHBsZSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOSRqQkfkdseR1DrBe1e +eYQt6zaiV0xV7IsZid75S2z1B6siMALoGD74UAnTf0GomPnRymacJGsR0KO75Bsq +wx+VnnoMpEeLW9QWNzPLxA9NzhRp0ckZcvVdDtV/X5vyJQO6VY9NXQ3xZDUjFUsV +WR2zlPf2nJ7PULrBWFBnjwi0IPfLrCwgb3C2PwEwjLdDzw+dPfMrSSgayP7OtbkO +2V4c1ss9tTqt9A8OAJILsSEWLnTVPA3bYharo3GSR1NVwa8vQbP4++NwzeajTEV+ +H0xrUJZBicR0YgsQg0GHM4qBsTBY7FoEMoxos48d3mVz/2deZbxJ2HafMxRloXeU +yS0CAwEAAaOCAi8wggIrMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAfBgNVHSMEGDAWgBQr0GlH +lHYJ/vRrjS5ApvdHTX8IXjCCASkGA1UdIASCASAwggEcMIIBGAYJKoZIhvdjZAUB +MIIBCTBBBggrBgEFBQcCARY1aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmlj +YXRlYXV0aG9yaXR5L3Rlcm1zLmh0bWwwgcMGCCsGAQUFBwICMIG2GoGzUmVsaWFu +Y2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2Nl +cHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5k +IGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRp +ZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wRAYDVR0fBD0wOzA5oDegNYYz +aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L3Jvb3Qu +Y3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0cHM6Ly93d3cuYXBw +bGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L2Nhc2lnbmVycy5odG1sMA0GCSqG +SIb3DQEBBQUAA4IBAQCd2i0oWC99dgS5BNM+zrdmY06PL9T+S61yvaM5xlJNBZhS +9YlRASR5vhoy9+VEi0tEBzmC1lrKtCBe2a4VXR2MHTK/ODFiSF3H4ZCx+CRA+F9Y +m1FdV53B5f88zHIhbsTp6aF31ywXJsM/65roCwO66bNKcuszCVut5mIxauivL9Wv +Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961 +kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH +CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx +CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp +ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa +QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw +NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft +ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu +QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG +qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL +fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ +Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4 +Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ +54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b +MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j +ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej +YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt +A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF +rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ +pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB +lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy +YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50 +7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs +YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6 +xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc +unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/ +Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp +ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42 +gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0 +jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+ +XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD +W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/ +RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r +MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk +BYn8eNZcLCZDqQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg +Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL +MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD +VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0 +ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX +l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB +HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B +5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3 +WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD +AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP +gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+ +DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu +BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs +h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk +LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk +BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4 +Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl +cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0 +aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY +F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N +8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe +rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K +/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu +7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC +28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6 +lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E +nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB +0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09 +5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj +WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN +jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s +ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM +OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q +619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn +2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj +o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v +nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG +5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq +pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb +dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0 +BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD +TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 +MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF +Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh +IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 +dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO +V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC +GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN +v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB +AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB +Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO +76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK +OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH +ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi +yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL +buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj +2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDyzCCArOgAwIBAgIDAOJIMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYDVQQGEwJB +VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp +bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1 +YWwtMDIxGDAWBgNVBAMMD0EtVHJ1c3QtUXVhbC0wMjAeFw0wNDEyMDIyMzAwMDBa +Fw0xNDEyMDIyMzAwMDBaMIGLMQswCQYDVQQGEwJBVDFIMEYGA1UECgw/QS1UcnVz +dCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1YWwtMDIxGDAWBgNVBAMMD0Et +VHJ1c3QtUXVhbC0wMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJaR +q9eOsFm4Ab20Hq2Z/aH86gyWa48uSUjY6eQkguHYuszr3gdcSMYZggFHQgnhfLmf +ro/27l5rqKhWiDhWs+b+yZ1PNDhRPJy+86ycHMg9XJqErveULBSyZDdgjhSwOyrN +ibUir/fkf+4sKzP5jjytTKJXD/uCxY4fAd9TjMEVpN3umpIS0ijpYhclYDHvzzGU +833z5Dwhq5D8bc9jp8YSAHFJ1xzIoO1jmn3jjyjdYPnY5harJtHQL73nDQnfbtTs +5ThT9GQLulrMgLU4WeyAWWWEMWpfVZFMJOUkmoOEer6A8e5fIAeqdxdsC+JVqpZ4 +CAKel/Arrlj1gFA//jsCAwEAAaM2MDQwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4E +CgQIQj0rJKbBRc4wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBG +yxFjUA2bPkXUSC2SfJ29tmrbiLKal+g6a9M8Xwd+Ejo+oYkNP6F4GfeDtAXpm7xb +9Ly8lhdbHcpRhzCUQHJ1tBCiGdLgmhSx7TXjhhanKOdDgkdsC1T+++piuuYL72TD +gUy2Sb1GHlJ1Nc6rvB4fpxSDAOHqGpUq9LWsc3tFkXqRqmQVtqtR77npKIFBioc6 +2jTBwDMPX3hDJDR1DSPc6BnZliaNw2IHdiMQ0mBoYeRnFdq+TyDKsjmJOOQPLzzL +/saaw6F891+gBjLFEFquDyR73lAPJS279R3csi8WWk4ZYUC/1V8H3Ktip/J6ac8e +qhLCbmJ81Lo92JGHz/ot +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICpzCCAi2gAwIBAgIQTHm1miicdjFk9YlE0JEC3jAKBggqhkjOPQQDAzCBlDEL +MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD +VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD +bGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g +RzQwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UEBhMC +VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h +bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAzIFB1 +YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAARXz+qzOU0/oSHgbi84csaHl/OFC0fnD1HI0fSZm8pZ +Zf9M+eoLtyXV0vbsMS0yYhLXdoan+jjJZdT+c+KEOfhMSWIT3brViKBfPchPsD+P +oVAR5JNGrcNfy/GkapVW6MCjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBQknbzScfcdwiW+IvGJpSwVOzQeXjAKBggqhkjOPQQD +AwNoADBlAjEAuWZoZdsF0Dh9DvPIdWG40CjEsUozUVj78jwQyK5HeHbKZiQXhj5Q +Vm6lLZmIuL0kAjAD6qfnqDzqnWLGX1TamPR3vU+PGJyRXEdrQE0QHbPhicoLIsga +xcX+i93B3294n5E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGHDCCBASgAwIBAgIES45gAzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJE +SzESMBAGA1UEChMJVFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQ +cmltYXJ5IENBMB4XDTEwMDMwMzEyNDEzNFoXDTM3MTIwMzEzMTEzNFowRTELMAkG +A1UEBhMCREsxEjAQBgNVBAoTCVRSVVNUMjQwODEiMCAGA1UEAxMZVFJVU1QyNDA4 +IE9DRVMgUHJpbWFyeSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJlJodr3U1Fa+v8HnyACHV81/wLevLS0KUk58VIABl6Wfs3LLNoj5soVAZv4LBi5 +gs7E8CZ9w0F2CopW8vzM8i5HLKE4eedPdnaFqHiBZ0q5aaaQArW+qKJx1rT/AaXt +alMB63/yvJcYlXS2lpexk5H/zDBUXeEQyvfmK+slAySWT6wKxIPDwVapauFY9QaG ++VBhCa5jBstWS7A5gQfEvYqn6csZ3jW472kW6OFNz6ftBcTwufomGJBMkonf4ZLr +6t0AdRi9jflBPz3MNNRGxyjIuAmFqGocYFA/OODBRjvSHB2DygqQ8k+9tlpvzMRr +kU7jq3RKL+83G1dJ3/LTjCLz4ryEMIC/OJ/gNZfE0qXddpPtzflIPtUFVffXdbFV +1t6XZFhJ+wBHQCpJobq/BjqLWUA86upsDbfwnePtmIPRCemeXkY0qabC+2Qmd2Fe +xyZphwTyMnbqy6FG1tB65dYf3mOqStmLa3RcHn9+2dwNfUkh0tjO2FXD7drWcU0O +I9DW8oAypiPhm/QCjMU6j6t+0pzqJ/S0tdAo+BeiXK5hwk6aR+sRb608QfBbRAs3 +U/q8jSPByenggac2BtTN6cl+AA1Mfcgl8iXWNFVGegzd/VS9vINClJCe3FNVoUnR +YCKkj+x0fqxvBLopOkJkmuZw/yhgMxljUi2qYYGn90OzAgMBAAGjggESMIIBDjAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUd +IAAwgZcGA1UdHwSBjzCBjDAsoCqgKIYmaHR0cDovL2NybC5vY2VzLnRydXN0MjQw +OC5jb20vb2Nlcy5jcmwwXKBaoFikVjBUMQswCQYDVQQGEwJESzESMBAGA1UEChMJ +VFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQcmltYXJ5IENBMQ0w +CwYDVQQDEwRDUkwxMB8GA1UdIwQYMBaAFPZt+LFIs0FDAduGROUYBbdezAY3MB0G +A1UdDgQWBBT2bfixSLNBQwHbhkTlGAW3XswGNzANBgkqhkiG9w0BAQsFAAOCAgEA +VPAQGrT7dIjD3/sIbQW86f9CBPu0c7JKN6oUoRUtKqgJ2KCdcB5ANhCoyznHpu3m +/dUfVUI5hc31CaPgZyY37hch1q4/c9INcELGZVE/FWfehkH+acpdNr7j8UoRZlkN +15b/0UUBfGeiiJG/ugo4llfoPrp8bUmXEGggK3wyqIPcJatPtHwlb6ympfC2b/Ld +v/0IdIOzIOm+A89Q0utx+1cOBq72OHy8gpGb6MfncVFMoL2fjP652Ypgtr8qN9Ka +/XOazktiIf+2Pzp7hLi92hRc9QMYexrV/nnFSQoWdU8TqULFUoZ3zTEC3F/g2yj+ +FhbrgXHGo5/A4O74X+lpbY2XV47aSuw+DzcPt/EhMj2of7SA55WSgbjPMbmNX0rb +oenSIte2HRFW5Tr2W+qqkc/StixgkKdyzGLoFx/xeTWdJkZKwyjqge2wJqws2upY +EiThhC497+/mTiSuXd69eVUwKyqYp9SD2rTtNmF6TCghRM/dNsJOl+osxDVGcwvt +WIVFF/Onlu5fu1NHXdqNEfzldKDUvCfii3L2iATTZyHwU9CALE+2eIA+PIaLgnM1 +1oCfUnYBkQurTrihvzz9PryCVkLxiqRmBVvUz+D4N5G/wvvKDS6t6cPCS+hqM482 +cbBsn0R9fFLO4El62S9eH1tqOzO20OAOK65yJIsOpSE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT +ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw +MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj +dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l +c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC +UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc +58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ +o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr +aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA +A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA +Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv +8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV +BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt +ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4 +MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg +SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl +a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h +4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk +tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s +tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL +dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4 +c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um +TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z ++kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O +Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW +OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW +fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2 +l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw +FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+ +8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI +6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO +TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME +wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY +Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn +xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q +DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q +Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t +hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4 +7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7 +QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS +MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp +bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw +VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy +YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy +dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2 +ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe +Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx +GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls +aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU +QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh +xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0 +aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr +IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h +gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK +O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO +fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw +lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID +AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP +NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t +wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM +7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh +gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n +oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs +yZyQ2uypQjyttgI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc +UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS +S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg +SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx +OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry +b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC +VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE +sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F +ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY +KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG ++7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG +HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P +IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M +733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk +Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW +AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I +aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5 +mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa +XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ +qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEYDCCA0igAwIBAgICATAwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCVVMx +GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UE +AxMYRmVkZXJhbCBDb21tb24gUG9saWN5IENBMB4XDTEwMTIwMTE2NDUyN1oXDTMw +MTIwMTE2NDUyN1owWTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu +bWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UEAxMYRmVkZXJhbCBDb21tb24gUG9s +aWN5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HX7NRY0WkG/ +Wq9cMAQUHK14RLXqJup1YcfNNnn4fNi9KVFmWSHjeavUeL6wLbCh1bI1FiPQzB6+ +Duir3MPJ1hLXp3JoGDG4FyKyPn66CG3G/dFYLGmgA/Aqo/Y/ISU937cyxY4nsyOl +4FKzXZbpsLjFxZ+7xaBugkC7xScFNknWJidpDDSPzyd6KgqjQV+NHQOGgxXgVcHF +mCye7Bpy3EjBPvmE0oSCwRvDdDa3ucc2Mnr4MrbQNq4iGDGMUHMhnv6DOzCIJOPp +wX7e7ZjHH5IQip9bYi+dpLzVhW86/clTpyBLqtsgqyFOHQ1O5piF5asRR12dP8Qj +wOMUBm7+nQIDAQABo4IBMDCCASwwDwYDVR0TAQH/BAUwAwEB/zCB6QYIKwYBBQUH +AQsEgdwwgdkwPwYIKwYBBQUHMAWGM2h0dHA6Ly9odHRwLmZwa2kuZ292L2ZjcGNh +L2NhQ2VydHNJc3N1ZWRCeWZjcGNhLnA3YzCBlQYIKwYBBQUHMAWGgYhsZGFwOi8v +bGRhcC5mcGtpLmdvdi9jbj1GZWRlcmFsJTIwQ29tbW9uJTIwUG9saWN5JTIwQ0Es +b3U9RlBLSSxvPVUuUy4lMjBHb3Zlcm5tZW50LGM9VVM/Y0FDZXJ0aWZpY2F0ZTti +aW5hcnksY3Jvc3NDZXJ0aWZpY2F0ZVBhaXI7YmluYXJ5MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUrQx6dVzl85jEeZgOrCj9l/TnAvwwDQYJKoZIhvcNAQELBQAD +ggEBAI9z2uF/gLGH9uwsz9GEYx728Yi3mvIRte9UrYpuGDco71wb5O9Qt2wmGCMi +TR0mRyDpCZzicGJxqxHPkYnos/UqoEfAFMtOQsHdDA4b8Idb7OV316rgVNdF9IU+ +7LQd3nyKf1tNnJaK0KIyn9psMQz4pO9+c+iR3Ah6cFqgr2KBWfgAdKLI3VTKQVZH +venAT+0g3eOlCd+uKML80cgX2BLHb94u6b2akfI8WpQukSKAiaGMWMyDeiYZdQKl +Dn0KJnNR6obLB6jI/WNaNZvSr79PMUjBhHDbNXuaGQ/lj/RqDG8z2esccKIN47lQ +A2EC/0rskqTcLe4qNJMHtyznGI8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV +BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1 +c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy +MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl +ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm +BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF +5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv +DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v +zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT +yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj +dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh +MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI +4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz +dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY +aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G +DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV +CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH +LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDcTCCAlmgAwIBAgIVAOYJ/nrqAGiM4CS07SAbH+9StETRMA0GCSqGSIb3DQEB +BQUAMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGlj +emVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIgUk9PVCBDQTAeFw0xMTEyMDYx +MTEwNTdaFw0zMTEyMDYxMTEwNTdaMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIg +Uk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxHL49ZMTml +6g3wpYwrvQKkvc0Kc6oJ5sxfgmp1qZfluwbv88BdocHSiXlY8NzrVYzuWBp7J/9K +ULMAoWoTIzOQ6C9TNm4YbA9A1jdX1wYNL5Akylf8W5L/I4BXhT9KnlI6x+a7BVAm +nr/Ttl+utT/Asms2fRfEsF2vZPMxH4UFqOAhFjxTkmJWf2Cu4nvRQJHcttB+cEAo +ag/hERt/+tzo4URz6x6r19toYmxx4FjjBkUhWQw1X21re//Hof2+0YgiwYT84zLb +eqDqCOMOXxvH480yGDkh/QoazWX3U75HQExT/iJlwnu7I1V6HXztKIwCBjsxffbH +3jOshCJtywcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFFOSo33/gnbwM9TrkmdHYTMbaDsqMA0GCSqGSIb3DQEBBQUA +A4IBAQA5UFWd5EL/pBviIMm1zD2JLUCpp0mJG7JkwznIOzawhGmFFaxGoxAhQBEg +haP+E0KR66oAwVC6xe32QUVSHfWqWndzbODzLB8yj7WAR0cDM45ZngSBPBuFE3Wu +GLJX9g100ETfIX+4YBR/4NR/uvTnpnd9ete7Whl0ZfY94yuu4xQqB5QFv+P7IXXV +lTOjkjuGXEcyQAjQzbFaT9vIABSbeCXWBbjvOXukJy6WgAiclzGNSYprre8Ryydd +fmjW9HIGwsIO03EldivvqEYL1Hv1w/Pur+6FUEOaL68PEIUovfgwIB2BAw+vZDuw +cH0mX548PojGyg434cDjkSXa3mHF +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc +UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS +S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg +SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 +WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv +bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU +UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw +bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe +LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef +J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh +R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ +Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX +JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p +zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S +Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq +ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz +gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH +uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS +y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz +MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N +IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 +bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE +RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO +zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 +bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF +MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 +VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC +OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW +tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ +q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb +EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ +Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O +VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICqDCCAi2gAwIBAgIQNBdlEkA7t1aALYDLeVWmHjAKBggqhkjOPQQDAzCBlDEL +MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD +VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD +bGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g +RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC +VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h +bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAyIFB1 +YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATR2UqOTA2ESlG6fO/TzPo6mrWnYxM9AeBJPvrBR8mS +szrX/m+c95o6D/UOCgrDP8jnEhSO1dVtmCyzcTIK6yq99tdqIAtnRZzSsr9TImYJ +XdsR8/EFM1ij4rjPfM2Cm72jQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBQ9MvM6qQyQhPmijGkGYVQvh3L+BTAKBggqhkjOPQQD +AwNpADBmAjEAyKapr0F/tckRQhZoaUxcuCcYtpjxwH+QbYfTjEYX8D5P/OqwCMR6 +S7wIL8fip29lAjEA1lnehs5fDspU1cbQFQ78i5Ry1I4AWFPPfrFLDeVQhuuea9// +KabYR9mglhjb8kWz +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF9jCCA96gAwIBAgIQZWNxhdNvRcaPfzH5CYeSgjANBgkqhkiG9w0BAQwFADCB +lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w +HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl +YyBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzYwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE +BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT +eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC3DrL6TbyachX7d1vb/UMPywv3 +YC6zK34Mu1PyzE5l8xm7/zUd99Opu0Attd141Kb5N+qFBXttt+YTSwZ8+3ZjjyAd +LTgrBIXy6LDRX01KIclq2JTqHgJQpqqQB6BHIepm+QSg5oPwxPVeluInTWHDs8GM +IrZmoQDRVin77cF/JMo9+lqUsITDx7pDHP1kDvEo+0dZ8ibhMblE+avd+76+LDfj +rAsY0/wBovGkCjWCR0yrvYpe3xOF/CDMSFmvr0FvyyPNypOn3dVfyGQ7/wEDoApP +LW49hL6vyDKyUymQFfewBZoKPPa5BpDJpeFdoDuw/qi2v/WJKFckOiGGceTciotB +VeweMCRZ0cBZuHivqlp03iWAMJjtMERvIXAc2xJTDtamKGaTLB/MTzwbgcW59nhv +0DI6CHLbaw5GF4WU87zvvPekXo7p6bVk5bdLRRIsTDe3YEMKTXEGAJQmNXQfu3o5 +XE475rgD4seTi4QsJUlF3X8jlGAfy+nN9quX92Hn+39igcjcCjBcGHzmzu/Hbh6H +fLPpysh7avRo/IOlDFa0urKNSgrHl5fFiDAVPRAIVBVycmczM/R8t84AJ1NlziTx +WmTnNi/yLgLCl99y6AIeoPc9tftoYAP6M6nmEm0G4amoXU48/tnnAGWsthlNe4N/ +NEfq4RhtsYsceavnnQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUOXEIAD7eyIbnkP/k/SEPziQZFvYwDQYJKoZIhvcN +AQEMBQADggIBAFBriE1gSM5a4yLOZ3yEp80c/ekMA4w2rwqHDmquV64B0Da78v25 +c8FftaiuTKL6ScsHRhY2vePIVzh+OOS/JTNgxtw3nGO7XpgeGrKC8K6mdxGAREeh +KcXwszrOmPC47NMOgAZ3IzBM/3lkYyJbd5NDS3Wz2ztuO0rd8ciutTeKlYg6EGhw +OLlbcH7VQ8n8X0/l5ns27vAg7UdXEyYQXhQGDXt2B8LGLRb0rqdsD7yID08sAraj +1yLmmUc12I2lT4ESOhF9s8wLdfMecKMbA+r6mujmLjY5zJnOOj8Mt674Q5mwk25v +qtkPajGRu5zTtCj7g0x6c4JQZ9IOrO1gxbJdNZjPh34eWR0kvFa62qRa2MzmvB4Q +jxuMjvPB27e+1LBbZY8WaPNWxSoZFk0PuGWHbSSDuGLc4EdhGoh7zk5//dzGDVqa +pPO1TPbdMaboHREhMzAEYX0c4D5PjT+1ixIAWn2poQDUg+twuxj4pNIcgS23CBHI +Jnu21OUPA0Zy1CVAHr5JXW2T8VyyO3VUaTqg7kwiuqya4gitRWMFSlI1dsQ09V4H +Mq3cfCbRW4+t5OaqG3Wf61206MCpFXxOSgdy30bJ1JGSdVaw4e43NmUoxRXIK3bM +bW8Zg/T92hXiQeczeUaDV/nxpbZt07zXU+fucW14qZen7iCcGRVyFT0E +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEUzCCAzugAwIBAgIDAOJDMA0GCSqGSIb3DQEBBQUAMIHPMQswCQYDVQQGEwJB +VDGBizCBiAYDVQQKHoGAAEEALQBUAHIAdQBzAHQAIABHAGUAcwAuACAAZgD8AHIA +IABTAGkAYwBoAGUAcgBoAGUAaQB0AHMAcwB5AHMAdABlAG0AZQAgAGkAbQAgAGUA +bABlAGsAdAByAC4AIABEAGEAdABlAG4AdgBlAHIAawBlAGgAcgAgAEcAbQBiAEgx +GDAWBgNVBAsTD0EtVHJ1c3QtUXVhbC0wMTEYMBYGA1UEAxMPQS1UcnVzdC1RdWFs +LTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEzMDIzMDAwMFowgc8xCzAJBgNVBAYT +AkFUMYGLMIGIBgNVBAoegYAAQQAtAFQAcgB1AHMAdAAgAEcAZQBzAC4AIABmAPwA +cgAgAFMAaQBjAGgAZQByAGgAZQBpAHQAcwBzAHkAcwB0AGUAbQBlACAAaQBtACAA +ZQBsAGUAawB0AHIALgAgAEQAYQB0AGUAbgB2AGUAcgBrAGUAaAByACAARwBtAGIA +SDEYMBYGA1UECxMPQS1UcnVzdC1RdWFsLTAxMRgwFgYDVQQDEw9BLVRydXN0LVF1 +YWwtMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmhgdxIbxTGEOH +fXGiewI3NFldAWKFWfLofO+5I1UbvA5avt7IgsGXz/tI/f5HGUbascI0i7xG0tqV +lA5ctQgLRqxgxHtgTkMcqsAEYdsz3LZsCdXO1QrvEBGLTSABdxiL/gSWJ6z77CSw +x7Xg02HwxPV82cjGkSF3ENGJntuIAAnRDWn/ORHjFatNRymoMbHaOEZXSGhf7Y5F +rrHEqGyi9E6sv784De/T1aTvskn8cWeUmDzv//omiG/a/V9KQex/61XN8OthUQVn +X+u/liL2NKx74I2C/GgHX5B0WkPNqsSOgmlvJ/cKuT0PveUgVFDAA0oYBgcE1KDM +lBbN0kmPAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECEs8jB2F +6W+tMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAIUusmJzMJRiQ +8TAHrJAOelfuWoTGcqdIv7Tys/fNl2yF2fjvHT8J01aKialFVpbVeQ2XKb1O2bHO +QYAKgsdZ2jZ/sdL2UVFRTHmidLu6PdgWCBRhJYQELQophO9QVvfhAA0TwbESYqTz ++nlI5Gr7CZe8f6HEmhJmCtUQsdQCufGglRh4T+tIGiNGcnyVEHZ93mSVepFr1VA2 +9CTRPteuGjA81jeAz9peYiFE1CXvxK9cJiv0BcALFLWmADCoRLzIRZhA+sAwYUmw +M1rqVCPA3kBQvIC95tyQvNy2dG0Vs+O6PwLaNX/suSlElQ06X2l1VwMaYb4vZKFq +N0bOhBXEVg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIJmzCCB4OgAwIBAgIBATANBgkqhkiG9w0BAQwFADCCAR4xPjA8BgNVBAMTNUF1 +dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s +YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz +dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0 +aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh +IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ +KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyMjE4MDgy +MVoXDTMwMTIxNzIzNTk1OVowggEeMT4wPAYDVQQDEzVBdXRvcmlkYWQgZGUgQ2Vy +dGlmaWNhY2lvbiBSYWl6IGRlbCBFc3RhZG8gVmVuZXpvbGFubzELMAkGA1UEBhMC +VkUxEDAOBgNVBAcTB0NhcmFjYXMxGTAXBgNVBAgTEERpc3RyaXRvIENhcGl0YWwx +NjA0BgNVBAoTLVNpc3RlbWEgTmFjaW9uYWwgZGUgQ2VydGlmaWNhY2lvbiBFbGVj +dHJvbmljYTFDMEEGA1UECxM6U3VwZXJpbnRlbmRlbmNpYSBkZSBTZXJ2aWNpb3Mg +ZGUgQ2VydGlmaWNhY2lvbiBFbGVjdHJvbmljYTElMCMGCSqGSIb3DQEJARYWYWNy +YWl6QHN1c2NlcnRlLmdvYi52ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAME77xNS8ZlW47RsBeEaaRZhJoZ4rw785UAFCuPZOAVMqNS1wMYqzy95q6Gk +UO81ER/ugiQX/KMcq/4HBn83fwdYWxPZfwBfK7BP2p/JsFgzYeFP0BXOLmvoJIzl +Jb6FW+1MPwGBjuaZGFImWZsSmGUclb51mRYMZETh9/J5CLThR1exStxHQptwSzra +zNFpkQY/zmj7+YZNA9yDoroVFv6sybYOZ7OxNDo7zkSLo45I7gMwtxqWZ8VkJZkC +8+p0dX6mkhUT0QAV64Zc9HsZiH/oLhEkXjhrgZ28cF73MXIqLx1fyM4kPH1yOJi/ +R72nMwL7D+Sd6mZgI035TxuHXc2/uOwXfKrrTjaJDz8Jp6DdessOkxIgkKXRjP+F +K3ze3n4NUIRGhGRtyvEjK95/2g02t6PeYiYVGur6ruS49n0RAaSS0/LJb6XzaAAe +0mmO2evnEqxIKwy2mZRNPfAVW1l3wCnWiUwryBU6OsbFcFFrQm+00wOicXvOTHBM +aiCVAVZTb9RSLyi+LJ1llzJZO3pq3IRiiBj38Nooo+2ZNbMEciSgmig7YXaUcmud +SVQvLSL+Yw+SqawyezwZuASbp7d/0rutQ59d81zlbMt3J7yB567rT2IqIydQ8qBW +k+fmXzghX+/FidYsh/aK+zZ7Wy68kKHuzEw1Vqkat5DGs+VzAgMBAAGjggLeMIIC +2jASBgNVHRMBAf8ECDAGAQH/AgECMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52 +ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMB0GA1UdDgQWBBStuyIdxuDS +Aaj9dlBSk+2YwU2u0zCCAVAGA1UdIwSCAUcwggFDgBStuyIdxuDSAaj9dlBSk+2Y +wU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRpZmlj +YWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAw +DgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYD +VQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25p +Y2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEgZGUgU2VydmljaW9zIGRlIENl +cnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG9w0BCQEWFmFjcmFpekBz +dXNjZXJ0ZS5nb2IudmWCAQEwDgYDVR0PAQH/BAQDAgEGMDcGA1UdEQQwMC6CD3N1 +c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMFQGA1Ud +HwRNMEswJKAioCCGHmhodHA6Ly93d3cuc3VzY2VydGUuZ29iLnZlL2xjcjAjoCGg +H4YdbGRhcDovL2FjcmFpei5zdXNjZXJ0ZS5nb2IudmUwNwYIKwYBBQUHAQEEKzAp +MCcGCCsGAQUFBzABhhtoaHRwOi8vb2NzcC5zdXNjZXJ0ZS5nb2IudmUwQAYDVR0g +BDkwNzA1BgVghl4BAjAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRl +LmdvYi52ZS9kcGMwDQYJKoZIhvcNAQEMBQADggIBAK4qy/zmZ9zBwfW3yOYtLcBT +Oy4szJyPz7/RhNH3bPVH7HbDTGpi6JZ4YXdXMBeJE5qBF4a590Kgj8Rlnltt+Rbo +OFQOU1UDqKuTdBsA//Zry5899fmn8jBUkg4nh09jhHHbLlaUScdz704Zz2+UVg7i +s/r3Legxap60KzmdrmTAE9VKte1TQRgavQwVX5/2mO/J+SCas//UngI+h8SyOucq +mjudYEgBrZaodUsagUfn/+AzFNrGLy+al+5nZeHb8JnCfLHWS0M9ZyhgoeO/czyn +99+5G93VWNv4zfc4KiavHZKrkn8F9pg0ycIZh+OwPT/RE2zq4gTazBMlP3ACIe/p +olkNaOEa8KvgzW96sjBZpMW49zFmyINYkcj+uaNCJrVGsXgdBmkuRGJNWFZ9r0cG +woIaxViFBypsz045r1ESfYPlfDOavBhZ/giR/Xocm9CHkPRY2BApMMR0DUCyGETg +Ql+L3kfdTKzuDjUp2DM9FqysQmaM81YDZufWkMhlZPfHwC7KbNougoLroa5Umeos +bqAXWmk46SwIdWRPLLqbUpDTKooynZKpSYIkkotdgJoVZUUCY+RCO8jsVPEU6ece +SxztNUm5UOta1OJPMwSAKRHOo3ilVb9c6lAixDdvV8MeNbqe6asM1mpCHWbJ/0rg +5Ls9Cxx8hracyp0ev7b0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGATCCA+mgAwIBAgIRAI9hcRW6eVgXjH0ROqzW264wDQYJKoZIhvcNAQELBQAw +RTEfMB0GA1UEAxMWQ29tU2lnbiBHbG9iYWwgUm9vdCBDQTEVMBMGA1UEChMMQ29t +U2lnbiBMdGQuMQswCQYDVQQGEwJJTDAeFw0xMTA3MTgxMDI0NTRaFw0zNjA3MTYx +MDI0NTVaMEUxHzAdBgNVBAMTFkNvbVNpZ24gR2xvYmFsIFJvb3QgQ0ExFTATBgNV +BAoTDENvbVNpZ24gTHRkLjELMAkGA1UEBhMCSUwwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCyKClzKh3rm6n1nvigmV/VU1D4hSwYW2ro3VqpzpPo0Ph3 +3LguqjXd5juDwN4mpxTpD99d7Xu5X6KGTlMVtfN+bTbA4t3x7DU0Zqn0BE5XuOgs +3GLH41Vmr5wox1bShVpM+IsjcN4E/hMnDtt/Bkb5s33xCG+ohz5dlq0gA9qfr/g4 +O9lkHZXTCeYrmVzd/il4x79CqNvGkdL3um+OKYl8rg1dPtD8UsytMaDgBAopKR+W +igc16QJzCbvcinlETlrzP/Ny76BWPnAQgaYBULax/Q5thVU+N3sEOKp6uviTdD+X +O6i96gARU4H0xxPFI75PK/YdHrHjfjQevXl4J37FJfPMSHAbgPBhHC+qn/014DOx +46fEGXcdw2BFeIIIwbj2GH70VyJWmuk/xLMCHHpJ/nIF8w25BQtkPpkwESL6esaU +b1CyB4Vgjyf16/0nRiCAKAyC/DY/Yh+rDWtXK8c6QkXD2XamrVJo43DVNFqGZzbf +5bsUXqiVDOz71AxqqK+p4ek9374xPNMJ2rB5MLPAPycwI0bUuLHhLy6nAIFHLhut +TNI+6Y/soYpi5JSaEjcY7pxI8WIkUAzr2r+6UoT0vAdyOt7nt1y8844a7szo/aKf +woziHl2O1w6ZXUC30K+ptXVaOiW79pBDcbLZ9ZdbONhS7Ea3iH4HJNwktrBJLQID +AQABo4HrMIHoMA8GA1UdEwEB/wQFMAMBAf8wgYQGA1UdHwR9MHswPKA6oDiGNmh0 +dHA6Ly9mZWRpci5jb21zaWduLmNvLmlsL2NybC9jb21zaWduZ2xvYmFscm9vdGNh +LmNybDA7oDmgN4Y1aHR0cDovL2NybDEuY29tc2lnbi5jby5pbC9jcmwvY29tc2ln +bmdsb2JhbHJvb3RjYS5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQCRZPY +DUhirGm6rgZbPvuqJpFQsTAfBgNVHSMEGDAWgBQCRZPYDUhirGm6rgZbPvuqJpFQ +sTANBgkqhkiG9w0BAQsFAAOCAgEAk1V5V9701xsfy4mfX+tP9Ln5e9h3N+QMwUfj +kr+k3e8iXOqADjTpUHeBkEee5tJq09ZLp/43F5tZ2eHdYq2ZEX7iWHCnOQet6Yw9 +SU1TahsrGDA6JJD9sdPFnNZooGsU1520e0zNB0dNWwxrWAmu4RsBxvEpWCJbvzQL +dOfyX85RWwli81OiVMBc5XvJ1mxsIIqli45oRynKtsWP7E+b0ISJ1n+XFLdQo/Nm +WA/5sDfT0F5YPzWdZymudMbXitimxC+n4oQE4mbQ4Zm718Iwg3pP9gMMcSc7Qc1J +kJHPH9O7gVubkKHuSYj9T3Ym6c6egL1pb4pz/uT7cT26Fiopc/jdqbe2EAfoJZkv +hlp/zdzOoXTWjiKNA5zmgWnZn943FuE9KMRyKtyi/ezJXCh8ypnqLIKxeFfZl69C +BwJsPXUTuqj8Fic0s3aZmmr7C4jXycP+Q8V+akMEIoHAxcd960b4wVWKqOcI/kZS +Q0cYqWOY1LNjznRt9lweWEfwDBL3FhrHOmD4++1N3FkkM4W+Q1b2WOL24clDMj+i +2n9Iw0lc1llHMSMvA5D0vpsXZpOgcCVahfXczQKi9wQ3oZyonJeWx4/rXdMtagAB +VBYGFuMEUEQtybI+eIbnp5peO2WAAblQI4eTy/jMVowe5tfMEXovV3sz9ULgmGb3 +DscLP1I= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICmDCCAgGgAwIBAgIBDjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJVUzEY +MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNFQ0ExFDASBgNVBAMT +C0VDQSBSb290IENBMB4XDTA0MDYxNDEwMjAwOVoXDTQwMDYxNDEwMjAwOVowSzEL +MAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMD +RUNBMRQwEgYDVQQDEwtFQ0EgUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEArkr2eXIS6oAKIpDkOlcQZdMGdncoygCEIU+ktqY3of5SVVXU7/it7kJ1 +EUzR4ii2vthQtbww9aAnpQxcEmXZk8eEyiGEPy+cCQMllBY+efOtKgjbQNDZ3lB9 +19qzUJwBl2BMxslU1XsJQw9SK10lPbQm4asa8E8e5zTUknZBWnECAwEAAaOBizCB +iDAfBgNVHSMEGDAWgBT2uAQnDlYW2blj2f2hVGVBoAhILzAdBgNVHQ4EFgQU9rgE +Jw5WFtm5Y9n9oVRlQaAISC8wDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wJQYDVR0gBB4wHDAMBgpghkgBZQMCAQwBMAwGCmCGSAFlAwIBDAIwDQYJKoZI +hvcNAQEFBQADgYEAHh0EQY2cZ209aBb5q0wW1ER0dc4OGzsLyqjHfaQ4TEaMmUwL +AJRta/c4KVWLiwbODsvgJk+CaWmSL03gRW/ciVb/qDV7qh9Pyd1cOlanZTAnPog2 +i82yL3i2fK9DCC84uoxEQbgqK2jx9bIjFTwlAqITk9fGAm5mdT84IEwq1Gw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFSzCCAzOgAwIBAgIRALZLiAfiI+7IXBKtpg4GofIwDQYJKoZIhvcNAQELBQAw +PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xMjA5MjgwODU4NTFaFw0zNzEyMzExNTU5NTla +MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQC2/5c8gb4BWCQnr44BK9ZykjAyG1+bfNTUf+ihYHMwVxAA+lCWJP5Q5ow6ldFX +eYTVZ1MMKoI+GFy4MCYa1l7GLbIEUQ7v3wxjR+vEEghRK5lxXtVpe+FdyXcdIOxW +juVhYC386RyA3/pqg7sFtR4jEpyCygrzFB0g5AaPQySZn7YKk1pzGxY5vgW28Yyl +ZJKPBeRcdvc5w88tvQ7Yy6gOMZvJRg9nU0MEj8iyyIOAX7ryD6uBNaIgIZfOD4k0 +eA/PH07p+4woPN405+2f0mb1xcoxeNLOUNFggmOd4Ez3B66DNJ1JSUPUfr0t4urH +cWWACOQ2nnlwCjyHKenkkpTqBpIpJ3jmrdc96QoLXvTg1oadLXLLi2RW5vSueKWg +OTNYPNyoj420ai39iHPplVBzBN8RiD5C1gJ0+yzEb7xs1uCAb9GGpTJXA9ZN9E4K +mSJ2fkpAgvjJ5E7LUy3Hsbbi08J1J265DnGyNPy/HE7CPfg26QrMWJqhGIZO4uGq +s3NZbl6dtMIIr69c/aQCb/+4DbvVq9dunxpPkUDwH0ZVbaCSw4nNt7H/HLPLo5wK +4/7NqrwB7N1UypHdTxOHpPaY7/1J1lcqPKZc9mA3v9g+fk5oKiMyOr5u5CI9ByTP +isubXVGzMNJxbc5Gim18SjNE2hIvNkvy6fFRCW3bapcOFwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTVZx3gnHosnMvFmOcdByYqhux0zTAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAJA75cJTQijq9TFOjj2Rnk0J +89ixUuZPrAwxIbvx6pnMg/y2KOTshAcOD06Xu29oRo8OURWV+Do7H1+CDgxxDryR +T64zLiNB9CZrTxOH+nj2LsIPkQWXqmrBap+8hJ4IKifd2ocXhuGzyl3tOKkpboTe +Rmv8JxlQpRJ6jH1i/NrnzLyfSa8GuCcn8on3Fj0Y5r3e9YwSkZ/jBI3+BxQaWqw5 +ghvxOBnhY+OvbLamURfr+kvriyL2l/4QOl+UoEtTcT9a4RD4co+WgN2NApgAYT2N +vC2xR8zaXeEgp4wxXPHj2rkKhkfIoT0Hozymc26Uke1uJDr5yTDRB6iBfSZ9fYTf +hsmL5a4NHr6JSFEVg5iWL0rrczTXdM3Jb9DCuiv2mv6Z3WAUjhv5nDk8f0OJU+jl +wqu+Iq0nOJt3KLejY2OngeepaUXrjnhWzAWEx/uttjB8YwWfLYwkf0uLkvw4Hp+g +pVezbp3YZLhwmmBScMip0P/GnO0QYV7Ngw5u6E0CQUridgR51lQ/ipgyFKDdLZzn +uoJxo4ZVKZnSKdt1OvfbQ/+2W/u3fjWAjg1srnm3Ni2XUqGwB5wH5Ss2zQOXlL0t +DjQG/MAWifw3VOTWzz0TBPKR2ck2Lj7FWtClTILD/y58Jnb38/1FoqVuVa4uzM8s +iTTa9g3nkagQ6hed8vbs +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy +MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk +D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o +OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A +fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe +IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n +oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK +/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj +rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD +3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE +7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC +yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd +qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI +hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA +SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo +HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB +emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC +AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb +7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x +DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk +F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF +a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT +Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB +lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w +HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl +YyBDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE +BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT +eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAx +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHOddJZKmZgiJM6kXZBxbje/SD +6Jlz+muxNuCad6BAwoGNAcfMjL2Pffd543pMA03Z+/2HOCgs3ZqLVAjbZ/sbjP4o +ki++t7JIp4Gh2F6Iw8w5QEFa0dzl2hCfL9oBTf0uRnz5LicKaTfukaMbasxEvxvH +w9QRslBglwm9LiL1QYRmn81ApqkAgMEflZKf3vNI79sdd2H8f9/ulqRy0LY+/3gn +r8uSFWkI22MQ4uaXrG7crPaizh5HmbmJtxLmodTNWRFnw2+F2EJOKL5ZVVkElauP +N4C/DfD8HzpkMViBeNfiNfYgPym4jxZuPkjctUwH4fIa6n4KedaovetdhitNAgMB +AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBQzQejIORIVk0jyljIuWvXalF9TYDANBgkqhkiG9w0BAQsFAAOCAQEAFeNzV7EX +tl9JaUSm9l56Z6zS3nVJq/4lVcc6yUQVEG6/MWvL2QeTfxyFYwDjMhLgzMv7OWyP +4lPiPEAz2aSMR+atWPuJr+PehilWNCxFuBL6RIluLRQlKCQBZdbqUqwFblYSCT3Q +dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz +5zbRIWhLLTjmU64cJVYIVgNnhJ3Gw84kYsdMNs+wBkS39V8C3dlU6S+QTnrIToNA +DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0 +0jPg/73RVDkpDw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG +STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz +a3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNl +czEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJLIEdvdi4g +Um9vdCBDQTAeFw0wMjEyMTgxMzUzMDBaFw0yMzEyMTgxMzUxMDhaMIGjMQswCQYD +VQQGEwJGSTEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0 +ZXJpa2Vza3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBT +ZXJ2aWNlczEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJL +IEdvdi4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCF +FdrIAzfQo0Y3bBseljDCWoUSZyPyu5/nioFgJ/gTqTy894aqqvTzJSm0/nWuHoGG +igWyHWWyOOi0zCia+xc28ZPVec7Bg4shT8MNrUHfeJ1I4x9CRPw8bSEga60ihCRC +jxdNwlAfZM0tOSJWiP2yY51U2kJpwMhP1xjiPshphJQ9LIDGfM6911Mf64i5psu7 +hVfvV3ZdDIvTXhJBnyHAOfQmbQj6OLOhd7HuFtjQaNq0mKWgZUZKa41+qk1guPjI +DfxxPu45h4G02fhukO4/DmHXHSto5i7hQkQmeCxY8n0Wf2HASSQqiYe2XS8pGfim +545SnkFLWg6quMJmQlMCAwEAAaNVMFMwDwYDVR0TAQH/BAUwAwEB/zARBglghkgB +hvhCAQEEBAMCAAcwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBTb6eGb0tEkC/yr +46Bn6q6cS3f0sDANBgkqhkiG9w0BAQUFAAOCAQEArX1ID1QRnljurw2bEi8hpM2b +uoRH5sklVSPj3xhYKizbXvfNVPVRJHtiZ+GxH0mvNNDrsczZog1Sf0JLiGCXzyVy +t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j +8/G7cdqehSO9Gu8u5Hp5t8OdhkktY7ktdM9lDzJmid87Ie4pbzlj2RXBbvbfgD5Q +eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k +UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO +TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy +MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk +ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn +ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 +9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO +hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U +tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o +BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh +SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww +OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv +cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA +7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k +/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm +eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 +u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy +7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 +MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK +EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh +BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq +xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G +87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i +2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U +WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 +0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G +A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr +pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL +ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm +aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv +hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm +hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 +P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y +iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no +xqE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy +MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA +vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G +CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA +WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ +h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 +f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN +B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy +vUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIIAeDltYNno+AwDQYJKoZIhvcNAQEMBQAwZzEbMBkGA1UE +AwwSQXBwbGUgUm9vdCBDQSAtIEcyMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMw +HhcNMTQwNDMwMTgxMDA5WhcNMzkwNDMwMTgxMDA5WjBnMRswGQYDVQQDDBJBcHBs +ZSBSb290IENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgREkhI2imKScUcx+xuM23+TfvgHN6s +XuI2pyT5f1BrTM65MFQn5bPW7SXmMLYFN14UIhHF6Kob0vuy0gmVOKTvKkmMXT5x +ZgM4+xb1hYjkWpIMBDLyyED7Ul+f9sDx47pFoFDVEovy3d6RhiPw9bZyLgHaC/Yu +OQhfGaFjQQscp5TBhsRTL3b2CtcM0YM/GlMZ81fVJ3/8E7j4ko380yhDPLVoACVd +J2LT3VXdRCCQgzWTxb+4Gftr49wIQuavbfqeQMpOhYV4SbHXw8EwOTKrfl+q04tv +ny0aIWhwZ7Oj8ZhBbZF8+NfbqOdfIRqMM78xdLe40fTgIvS/cjTf94FNcX1RoeKz +8NMoFnNvzcytN31O661A4T+B/fc9Cj6i8b0xlilZ3MIZgIxbdMYs0xBTJh0UT8TU +gWY8h2czJxQI6bR3hDRSj4n4aJgXv8O7qhOTH11UL6jHfPsNFL4VPSQ08prcdUFm +IrQB1guvkJ4M6mL4m1k8COKWNORj3rw31OsMiANDC1CvoDTdUE0V+1ok2Az6DGOe +HwOx4e7hqkP0ZmUoNwIx7wHHHtHMn23KVDpA287PT0aLSmWaasZobNfMmRtHsHLD +d4/E92GcdB/O/WuhwpyUgquUoue9G7q5cDmVF8Up8zlYNPXEpMZ7YLlmQ1A/bmH8 +DvmGqmAMQ0uVAgMBAAGjQjBAMB0GA1UdDgQWBBTEmRNsGAPCe8CjoA1/coB6HHcm +jTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwF +AAOCAgEAUabz4vS4PZO/Lc4Pu1vhVRROTtHlznldgX/+tvCHM/jvlOV+3Gp5pxy+ +8JS3ptEwnMgNCnWefZKVfhidfsJxaXwU6s+DDuQUQp50DhDNqxq6EWGBeNjxtUVA +eKuowM77fWM3aPbn+6/Gw0vsHzYmE1SGlHKy6gLti23kDKaQwFd1z4xCfVzmMX3z +ybKSaUYOiPjjLUKyOKimGY3xn83uamW8GrAlvacp/fQ+onVJv57byfenHmOZ4VxG +/5IFjPoeIPmGlFYl5bRXOJ3riGQUIUkhOb9iZqmxospvPyFgxYnURTbImHy99v6Z +SYA7LNKmp4gDBDEZt7Y6YUX6yfIjyGNzv1aJMbDZfGKnexWoiIqrOEDCzBL/FePw +N983csvMmOa/orz6JopxVtfnJBtIRD6e/J/JzBrsQzwBvDR4yGn1xuZW7AYJNpDr +FEobXsmII9oDMJELuDY++ee1KG++P+w8j2Ud5cAeh6Squpj9kuNsJnfdBrRkBof0 +Tta6SqoWqPQFZ2aWuuJVecMsXUmPgEkrihLHdoBR37q9ZV0+N0djMenl9MU/S60E +inpxLK8JQzcPqOMyT/RFtm2XNuyE9QoB6he7hY1Ck3DDUOUUi78/w0EP3SIEIwiK +um1xRKtzCTrJ+VKACd+66eYWyi4uTLLT3OUEVLLUNIAytbwPF+E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtDCCApygAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJKUDEc +MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEOMAwGA1UECxMFTVBIUFQxJjAk +BgNVBAsTHU1QSFBUIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTAyMDMxNDA3 +NTAyNloXDTEyMDMxMzE0NTk1OVowYzELMAkGA1UEBhMCSlAxHDAaBgNVBAoTE0ph +cGFuZXNlIEdvdmVybm1lbnQxDjAMBgNVBAsTBU1QSFBUMSYwJAYDVQQLEx1NUEhQ +VCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAI3GUWlK9G9FVm8DhpKu5t37oxZbj6lZcFvEZY07YrYojWO657ub +z56WE7q/PI/6Sm7i7qYE+Vp80r6thJvfmn7SS3BENrRqiapSenhooYD12jIe3iZQ +2SXqx7WgYwyBGdQwGaYTijzbRFpgc0K8o4a99fIoHhz9J8AKqXasddMCqfJRaH30 +YJ7HnOvRYGL6HBrGhJ7X4Rzijyk9a9+3VOBsYcnIlx9iODoiYhA6r0ojuIu8/JA1 +oTTZrS0MyU/SLdFdJze2O1wnqTULXQybzJz3ad6oC/F5a69c0m92akYd9nGBrPxj +EhucaQynC/QoCLs3aciLgioAnEJqy7i3EgUCAwEAAaNzMHEwHwYDVR0jBBgwFoAU +YML3pLoA0h93Yngl8Gb/UgAh73owHQYDVR0OBBYEFGDC96S6ANIfd2J4JfBm/1IA +Ie96MAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQE +AwIABTANBgkqhkiG9w0BAQUFAAOCAQEANPR8DN66iWZBs/lSm1vOzhqRkXDLT6xL +LvJtjPLqmE469szGyFSKzsof6y+/8YgZlOoeX1inF4ox/SH1ATnwdIIsPbXuRLjt +axboXvBh5y2ffC3hmzJVvJ87tb6mVWQeL9VFUhNhAI0ib+9OIZVEYI/64MFkDk4e +iWG5ts6oqIJH1V7dVZg6pQ1Tc0Ckhn6N1m1hD30S0/zoPn/20Wq6OCF3he8VJrRG +dcW9BD/Bkesko1HKhMBDjHVrJ8cFwbnDSoo+Ki47eJWaz/cOzaSsaMVUsR5POava +/abhhgHn/eOJdXiVslyK0DYscjsdB3aBUfwZlomxYOzG6CgjQPhJdw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG +A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT +BEdQS0kxHDAaBgNVBAMTE0FwcGxpY2F0aW9uQ0EyIFJvb3QwHhcNMTMwMzEyMTUw +MDAwWhcNMzMwMzEyMTUwMDAwWjBYMQswCQYDVQQGEwJKUDEcMBoGA1UEChMTSmFw +YW5lc2UgR292ZXJubWVudDENMAsGA1UECxMER1BLSTEcMBoGA1UEAxMTQXBwbGlj +YXRpb25DQTIgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaq +rSVl1gAR1uh6dqr05rRL88zDUrSNrKZPtZJxb0a11a2LEiIXJc5F6BR6hZrkIxCo ++rFnUOVtR+BqiRPjrq418fRCxQX3TZd+PCj8sCaRHoweOBqW3FhEl2LjMsjRFUFN +dZh4vqtoqV7tR76kuo6hApfek3SZbWe0BSXulMjtqqS6MmxCEeu+yxcGkOGThchk +KM4fR8fAXWDudjbcMztR63vPctgPeKgZggiQPhqYjY60zxU2pm7dt+JNQCBT2XYq +0HisifBPizJtROouurCp64ndt295D6uBbrjmiykLWa+2SQ1RLKn9nShjZrhwlXOa +2Po7M7xCQhsyrLEy+z0CAwEAAaOBwTCBvjAdBgNVHQ4EFgQUVqesqgIdsqw9kA6g +by5Bxnbne9owDgYDVR0PAQH/BAQDAgEGMHwGA1UdEQR1MHOkcTBvMQswCQYDVQQG +EwJKUDEYMBYGA1UECgwP5pel5pys5Zu95pS/5bqcMRswGQYDVQQLDBLmlL/lupzo +qo3oqLzln7rnm6QxKTAnBgNVBAMMIOOCouODl+ODquOCseODvOOCt+ODp+ODs0NB +MiBSb290MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH+aCXWs +B9FydC53VzDCBJzUgKaD56WgG5/+q/OAvdVKo6GPtkxgEefK4WCB10jBIFmlYTKL +nZ6X02aD2mUuWD7b5S+lzYxzplG+WCigeVxpL0PfY7KJR8q73rk0EWOgDiUX5Yf0 +HbCwpc9BqHTG6FPVQvSCLVMJEWgmcZR1E02qdog8dLHW40xPYsNJTE5t8XB+w3+m +Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i +Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf +SUJiOxMfFui61/0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc +MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj +IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB +IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE +RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl +U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 +IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU +ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC +QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr +rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S +NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc +QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH +txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP +BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp +tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa +IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl +6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ +xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIIBhDCeat3PfIwDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE +BhMCQ0gxEjAQBgNVBAoTCVN3aXNzU2lnbjEyMDAGA1UEAxMpU3dpc3NTaWduIENB +IChSU0EgSUsgTWF5IDYgMTk5OSAxODowMDo1OCkxHzAdBgkqhkiG9w0BCQEWEGNh +QFN3aXNzU2lnbi5jb20wHhcNMDAxMTI2MjMyNzQxWhcNMzExMTI2MjMyNzQxWjB2 +MQswCQYDVQQGEwJDSDESMBAGA1UEChMJU3dpc3NTaWduMTIwMAYDVQQDEylTd2lz +c1NpZ24gQ0EgKFJTQSBJSyBNYXkgNiAxOTk5IDE4OjAwOjU4KTEfMB0GCSqGSIb3 +DQEJARYQY2FAU3dpc3NTaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKw5fjnmNneLQlUCQG8jQLwwfbrOZoUwNX8cbNqhxK03/xUloFVgAt+S +Te2RxNXaCAXLBPn5ZST35TLV57aLmbHCtifv3YZqaaQGvjedltIBMJihJhZ+h3LY +SKsUb+xEJ3x5ZUf8jP+Q1g57y1s8SnBFWN/ni5NkF1Y1y31VwOi9wiOf/VISL+uu +SC4i1CP1Kbz3BDs6Hht1GpRYCbJ/K0bc9oJSpWpT5PGONsGIawqMbJuyoDghsXQ1 +pbn2e8K64BSscGZVZTNooSGgNiHmACNJBYXiWVWrwXPF4l6SddmC3Rj0aKXjgECc +FkHLDQcsM5JsK2ZLryTDUsQFbxVP2ikCAwEAAaNHMEUwCwYDVR0PBAQDAgEGMAwG +A1UdEwQFMAMBAf8wHQYDVR0OBBYEFJbXcc05KtT8iLGKq1N4ae+PR34WMAkGA1Ud +IwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAKMy6W8HvZdS1fBpEUzl6Lvw50bgE1Xc +HU1JypSBG9mhdcXZo5AlPB4sCvx9Dmfwhyrdsshc0TP2V3Vh6eQqnEF5qB4lVziT +Bko9mW6Ot+pPnwsy4SHpx3rw6jCYnOqfUcZjWqqqRrq/3P1waz+Mn4cLMVEg3Xaz +qYov/khvSqS0JniwjRlo2H6f/1oVUKZvP+dUhpQepfZrOqMAWZW4otp6FolyQyeU +NN6UCRNiUKl5vTijbKwUUwfER/1Vci3M1/O1QCfttQ4vRN4Buc0xqYtGL3cd5WiO +vWzyhlTzAI6VUdNkQhhHJSAyTpj6dmXDRzrryoFGa2PjgESxz7XBaSI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL +ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx +MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc +MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ +AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH +iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj +vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA +0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB +OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ +BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E +FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 +GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW +zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 +1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE +f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F +jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN +ZetX2fNXlrtIzYE= +-----END CERTIFICATE----- +` diff --git a/src/crypto/x509/root_darwin_arm_gen.go b/src/crypto/x509/root_darwin_arm_gen.go new file mode 100644 index 0000000000..194e016045 --- /dev/null +++ b/src/crypto/x509/root_darwin_arm_gen.go @@ -0,0 +1,187 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Generates root_darwin_arm.go. +// +// As of iOS 8, there is no API for querying the system trusted X.509 root +// certificates. We could use SecTrustEvaluate to verify that a trust chain +// exists for a certificate, but the x509 API requires returning the entire +// chain. +// +// Apple publishes the list of trusted root certificates for iOS on +// support.apple.com. So we parse the list and extract the certificates from +// an OS X machine and embed them into the x509 package. +package main + +import ( + "bytes" + "crypto/x509" + "encoding/pem" + "flag" + "fmt" + "go/format" + "io/ioutil" + "log" + "math/big" + "net/http" + "os/exec" + "strings" +) + +var output = flag.String("output", "root_darwin_arm.go", "file name to write") + +func main() { + certs, err := selectCerts() + if err != nil { + log.Fatal(err) + } + + buf := new(bytes.Buffer) + + fmt.Fprintf(buf, "// Created by root_darwin_arm_gen --output %s; DO NOT EDIT\n", *output) + fmt.Fprintf(buf, "%s", header) + + fmt.Fprintf(buf, "const systemRootsPEM = `\n") + for _, cert := range certs { + b := &pem.Block{ + Type: "CERTIFICATE", + Bytes: cert.Raw, + } + if err := pem.Encode(buf, b); err != nil { + log.Fatal(err) + } + } + fmt.Fprintf(buf, "`") + + source, err := format.Source(buf.Bytes()) + if err != nil { + log.Fatal("source format error:", err) + } + if err := ioutil.WriteFile(*output, source, 0644); err != nil { + log.Fatal(err) + } +} + +func selectCerts() ([]*x509.Certificate, error) { + ids, err := fetchCertIDs() + if err != nil { + return nil, err + } + + scerts, err := sysCerts() + if err != nil { + return nil, err + } + + var certs []*x509.Certificate + for _, id := range ids { + sn, ok := big.NewInt(0).SetString(id.serialNumber, 0) // 0x prefix selects hex + if !ok { + return nil, fmt.Errorf("invalid serial number: %q", id.serialNumber) + } + ski, ok := big.NewInt(0).SetString(id.subjectKeyID, 0) + if !ok { + return nil, fmt.Errorf("invalid Subject Key ID: %q", id.subjectKeyID) + } + + for _, cert := range scerts { + if sn.Cmp(cert.SerialNumber) != 0 { + continue + } + cski := big.NewInt(0).SetBytes(cert.SubjectKeyId) + if ski.Cmp(cski) != 0 { + continue + } + certs = append(certs, cert) + break + } + } + return certs, nil +} + +func sysCerts() (certs []*x509.Certificate, err error) { + cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain") + data, err := cmd.Output() + if err != nil { + return nil, err + } + for len(data) > 0 { + var block *pem.Block + block, data = pem.Decode(data) + if block == nil { + break + } + if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { + continue + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + continue + } + certs = append(certs, cert) + } + return certs, nil +} + +type certID struct { + serialNumber string + subjectKeyID string +} + +// fetchCertIDs fetches IDs of iOS X509 certificates from apple.com. +func fetchCertIDs() ([]certID, error) { + resp, err := http.Get("https://support.apple.com/en-us/HT204132") + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + text := string(body) + text = text[strings.Index(text, "

")] + + lines := strings.Split(text, "\n") + var ids []certID + var id certID + for i, ln := range lines { + if i == len(lines)-1 { + break + } + const sn = "Serial Number:" + if ln == sn { + id.serialNumber = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1) + continue + } + if strings.HasPrefix(ln, sn) { + // extract hex value from parentheses. + id.serialNumber = ln[strings.Index(ln, "(")+1 : len(ln)-1] + continue + } + if strings.TrimSpace(ln) == "X509v3 Subject Key Identifier:" { + id.subjectKeyID = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1) + ids = append(ids, id) + id = certID{} + } + } + return ids, nil +} + +const header = ` +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x509 + +func initSystemRoots() { + systemRoots = NewCertPool() + systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM)) +} +` -- cgit v1.2.3-54-g00ecf From eaf8e8cbe576a8553214ffc8e2ce09e9fbc6e87e Mon Sep 17 00:00:00 2001 From: Alex Sergeyev Date: Mon, 16 Feb 2015 09:29:37 -0500 Subject: net/http/cgi: fix REMOTE_ADDR, REMOTE_HOST, add REMOTE_PORT Env vars were incorrectly copying whole value of http.RemoteAddr to REMOTE_ADDR and REMOTE_HOST. They contained IP:port pair which instead should only have IP (RFC 3875, other sources). Module also was not setting REMOTE_PORT variable which become de-facto standard for passing TCP client port to CGI scripts (Apache mod_cgi, IIS, and probably others) Fixes #9861 Change-Id: Ia73e664c48539e3c7db4997d09d957884e98d8a5 Reviewed-on: https://go-review.googlesource.com/4933 Reviewed-by: Brad Fitzpatrick --- src/net/http/cgi/host.go | 10 +++++++-- src/net/http/cgi/host_test.go | 43 ++++++++++++++++++++++++++++++++++--- src/net/http/cgi/matryoshka_test.go | 1 + 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/net/http/cgi/host.go b/src/net/http/cgi/host.go index ec95a972c1..4efbe7abee 100644 --- a/src/net/http/cgi/host.go +++ b/src/net/http/cgi/host.go @@ -19,6 +19,7 @@ import ( "fmt" "io" "log" + "net" "net/http" "os" "os/exec" @@ -128,11 +129,16 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { "PATH_INFO=" + pathInfo, "SCRIPT_NAME=" + root, "SCRIPT_FILENAME=" + h.Path, - "REMOTE_ADDR=" + req.RemoteAddr, - "REMOTE_HOST=" + req.RemoteAddr, "SERVER_PORT=" + port, } + if remoteIP, remotePort, err := net.SplitHostPort(req.RemoteAddr); err == nil { + env = append(env, "REMOTE_ADDR="+remoteIP, "REMOTE_HOST="+remoteIP, "REMOTE_PORT="+remotePort) + } else { + // could not parse ip:port, let's use whole RemoteAddr and leave REMOTE_PORT undefined + env = append(env, "REMOTE_ADDR="+req.RemoteAddr, "REMOTE_HOST="+req.RemoteAddr) + } + if req.TLS != nil { env = append(env, "HTTPS=on") } diff --git a/src/net/http/cgi/host_test.go b/src/net/http/cgi/host_test.go index 8c16e6897f..4aa67e4e5f 100644 --- a/src/net/http/cgi/host_test.go +++ b/src/net/http/cgi/host_test.go @@ -29,7 +29,7 @@ func newRequest(httpreq string) *http.Request { if err != nil { panic("cgi: bogus http request in test: " + httpreq) } - req.RemoteAddr = "1.2.3.4" + req.RemoteAddr = "1.2.3.4:1234" return req } @@ -37,7 +37,11 @@ func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string rw := httptest.NewRecorder() req := newRequest(httpreq) h.ServeHTTP(rw, req) + runResponseChecks(t, rw, expectedMap) + return rw +} +func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder, expectedMap map[string]string) { // Make a map to hold the test map that the CGI returns. m := make(map[string]string) m["_body"] = rw.Body.String() @@ -75,7 +79,6 @@ readlines: t.Errorf("for key %q got %q; expected %q", key, got, expected) } } - return rw } var cgiTested, cgiWorks bool @@ -108,6 +111,7 @@ func TestCGIBasicGet(t *testing.T) { "env-QUERY_STRING": "foo=bar&a=b", "env-REMOTE_ADDR": "1.2.3.4", "env-REMOTE_HOST": "1.2.3.4", + "env-REMOTE_PORT": "1234", "env-REQUEST_METHOD": "GET", "env-REQUEST_URI": "/test.cgi?foo=bar&a=b", "env-SCRIPT_FILENAME": "testdata/test.cgi", @@ -126,6 +130,39 @@ func TestCGIBasicGet(t *testing.T) { } } +func TestCGIEnvIPv6(t *testing.T) { + check(t) + h := &Handler{ + Path: "testdata/test.cgi", + Root: "/test.cgi", + } + expectedMap := map[string]string{ + "test": "Hello CGI", + "param-a": "b", + "param-foo": "bar", + "env-GATEWAY_INTERFACE": "CGI/1.1", + "env-HTTP_HOST": "example.com", + "env-PATH_INFO": "", + "env-QUERY_STRING": "foo=bar&a=b", + "env-REMOTE_ADDR": "2000::3000", + "env-REMOTE_HOST": "2000::3000", + "env-REMOTE_PORT": "12345", + "env-REQUEST_METHOD": "GET", + "env-REQUEST_URI": "/test.cgi?foo=bar&a=b", + "env-SCRIPT_FILENAME": "testdata/test.cgi", + "env-SCRIPT_NAME": "/test.cgi", + "env-SERVER_NAME": "example.com", + "env-SERVER_PORT": "80", + "env-SERVER_SOFTWARE": "go", + } + + rw := httptest.NewRecorder() + req := newRequest("GET /test.cgi?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n") + req.RemoteAddr = "[2000::3000]:12345" + h.ServeHTTP(rw, req) + runResponseChecks(t, rw, expectedMap) +} + func TestCGIBasicGetAbsPath(t *testing.T) { check(t) pwd, err := os.Getwd() @@ -289,7 +326,7 @@ func TestInternalRedirect(t *testing.T) { } expectedMap := map[string]string{ "basepath": "/foo", - "remoteaddr": "1.2.3.4", + "remoteaddr": "1.2.3.4:1234", } runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap) } diff --git a/src/net/http/cgi/matryoshka_test.go b/src/net/http/cgi/matryoshka_test.go index 18c4803e71..244acf1e8c 100644 --- a/src/net/http/cgi/matryoshka_test.go +++ b/src/net/http/cgi/matryoshka_test.go @@ -43,6 +43,7 @@ func TestHostingOurselves(t *testing.T) { "env-QUERY_STRING": "foo=bar&a=b", "env-REMOTE_ADDR": "1.2.3.4", "env-REMOTE_HOST": "1.2.3.4", + "env-REMOTE_PORT": "1234", "env-REQUEST_METHOD": "GET", "env-REQUEST_URI": "/test.go?foo=bar&a=b", "env-SCRIPT_FILENAME": os.Args[0], -- cgit v1.2.3-54-g00ecf From bbf38e931a8a4e8a49b45206ff7ed679eece70d7 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Wed, 18 Feb 2015 11:59:16 -0800 Subject: doc: add cgi change go1.5.txt Change-Id: I829529929906d4758c7ba10d356c251b44e35a8d Reviewed-on: https://go-review.googlesource.com/5190 Reviewed-by: Brad Fitzpatrick --- doc/go1.5.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.5.txt b/doc/go1.5.txt index c26a6fa427..95db022c74 100644 --- a/doc/go1.5.txt +++ b/doc/go1.5.txt @@ -14,6 +14,7 @@ crypto/tls: change default minimum version to TLS 1.0. (https://golang.org/cl/17 encoding/base64: add unpadded encodings (https://golang.org/cl/1511) log: add SetOutput functions (https://golang.org/cl/2686, https://golang.org/cl/3023) net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157) +net/http/cgi: fix REMOTE_ADDR, REMOTE_HOST, add REMOTE_PORT (https://golang.org/cl/4933) net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151) os/signal: add Ignore and Reset (https://golang.org/cl/3580) runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020) -- cgit v1.2.3-54-g00ecf From 84c7a6583aac493fec25e87c60be7b98508c5b43 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Tue, 17 Feb 2015 16:28:10 +1100 Subject: image: change Rectangle.Eq to return true for all empty rectangles, even if their nominal Min and Max points differ. This is a behavior change, but arguably a bug fix, as Eq wasn't previously consistent with In, and the concept of a rectangle being a set of points. This is demonstrated by the new geom_test.go test. It does mean that r.Eq(s) no longer implies that Inset'ting both r and s with a negative inset results in two rectangles that are still Eq, but that seems acceptable to me. The previous behavior is still available as "r == s". Also clarify the image.Rect doc comment when the inputs are non-canonical. Also simplify the Point and Rectangle Eq implementations dating from before Go 1.0, when you couldn't compare structs via the == operator. Change-Id: Ic39e628db31dc5fe5220f4b444e6d5000eeace5b Reviewed-on: https://go-review.googlesource.com/5006 Reviewed-by: Rob Pike --- src/image/geom.go | 12 +++++++----- src/image/geom_test.go | 12 ++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/image/geom.go b/src/image/geom.go index 7c56010653..70e3ff0288 100644 --- a/src/image/geom.go +++ b/src/image/geom.go @@ -62,7 +62,7 @@ func (p Point) Mod(r Rectangle) Point { // Eq reports whether p and q are equal. func (p Point) Eq(q Point) bool { - return p.X == q.X && p.Y == q.Y + return p == q } // ZP is the zero Point. @@ -190,10 +190,10 @@ func (r Rectangle) Empty() bool { return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y } -// Eq reports whether r and s are equal. +// Eq reports whether r and s contain the same set of points. All empty +// rectangles are considered equal. func (r Rectangle) Eq(s Rectangle) bool { - return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y && - r.Max.X == s.Max.X && r.Max.Y == s.Max.Y + return r == s || r.Empty() && s.Empty() } // Overlaps reports whether r and s have a non-empty intersection. @@ -229,7 +229,9 @@ func (r Rectangle) Canon() Rectangle { // ZR is the zero Rectangle. var ZR Rectangle -// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}. +// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}. The returned +// rectangle has minimum and maximum coordinates swapped if necessary so that +// it is well-formed. func Rect(x0, y0, x1, y1 int) Rectangle { if x0 > x1 { x0, x1 = x1, x0 diff --git a/src/image/geom_test.go b/src/image/geom_test.go index 5bbd8a9492..6e9c6a13c2 100644 --- a/src/image/geom_test.go +++ b/src/image/geom_test.go @@ -39,6 +39,18 @@ func TestRectangle(t *testing.T) { Rect(6, 5, 4, 3), } + // r.Eq(s) should be equivalent to every point in r being in s, and every + // point in s being in r. + for _, r := range rects { + for _, s := range rects { + got := r.Eq(s) + want := in(r, s) == nil && in(s, r) == nil + if got != want { + t.Errorf("Eq: r=%s, s=%s: got %t, want %t", r, s, got, want) + } + } + } + // The intersection should be the largest rectangle a such that every point // in a is both in r and in s. for _, r := range rects { -- cgit v1.2.3-54-g00ecf From 9df81f822128b4057f6713bff1421b8ee3fec555 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Thu, 19 Feb 2015 09:35:28 +1100 Subject: encoding/json: Fixed the comment specifying Marshal behavior for maps. The comment previously was reversed in sense (it appeared to be describing unmarshaling). I've fixed that, and added the caveat that map keys are subject to UTF-8 coercion like other strings. Change-Id: Id08082aa71401a6e7530a42f979fbb50bd1f4e6a Reviewed-on: https://go-review.googlesource.com/5221 Run-TryBot: Brad Fitzpatrick Reviewed-by: Andrew Gerrand --- src/encoding/json/encode.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index e59a0b3bbf..4db9f35e69 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -113,8 +113,8 @@ import ( // a JSON tag of "-". // // Map values encode as JSON objects. -// The map's key type must be string; the object keys are used directly -// as map keys. +// The map's key type must be string; the map keys are used as JSON object +// keys, subject to the UTF-8 coercion described for string values above. // // Pointer values encode as the value pointed to. // A nil pointer encodes as the null JSON object. -- cgit v1.2.3-54-g00ecf From 95ab84a34f67742b59227e6c7b45d287071d87b0 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 16 Feb 2015 18:18:13 +0900 Subject: runtime: fix accidentally exported OpenBSD constants Change-Id: I2de63668a1c0152cc329df55c2d6d014e8183158 Reviewed-on: https://go-review.googlesource.com/4943 Reviewed-by: Minux Ma --- src/runtime/os1_openbsd.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os1_openbsd.go index 87158f2b73..dcf205b841 100644 --- a/src/runtime/os1_openbsd.go +++ b/src/runtime/os1_openbsd.go @@ -7,16 +7,16 @@ package runtime import "unsafe" const ( - ESRCH = 3 - EAGAIN = 35 - EWOULDBLOCK = EAGAIN - ENOTSUP = 91 + _ESRCH = 3 + _EAGAIN = 35 + _EWOULDBLOCK = _EAGAIN + _ENOTSUP = 91 // From OpenBSD's sys/time.h - CLOCK_REALTIME = 0 - CLOCK_VIRTUAL = 1 - CLOCK_PROF = 2 - CLOCK_MONOTONIC = 3 + _CLOCK_REALTIME = 0 + _CLOCK_VIRTUAL = 1 + _CLOCK_PROF = 2 + _CLOCK_MONOTONIC = 3 ) var sigset_none = uint32(0) @@ -24,12 +24,12 @@ var sigset_all = ^sigset_none // From OpenBSD's const ( - CTL_HW = 6 - HW_NCPU = 3 + _CTL_HW = 6 + _HW_NCPU = 3 ) func getncpu() int32 { - mib := [2]uint32{CTL_HW, HW_NCPU} + mib := [2]uint32{_CTL_HW, _HW_NCPU} out := uint32(0) nout := unsafe.Sizeof(out) @@ -80,8 +80,8 @@ func semasleep(ns int64) int32 { // sleep until semaphore != 0 or timeout. // thrsleep unlocks m.waitsemalock. - ret := thrsleep((uintptr)(unsafe.Pointer(&_g_.m.waitsemacount)), CLOCK_MONOTONIC, tsp, (uintptr)(unsafe.Pointer(&_g_.m.waitsemalock)), (*int32)(unsafe.Pointer(&_g_.m.waitsemacount))) - if ret == EWOULDBLOCK { + ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, uintptr(unsafe.Pointer(&_g_.m.waitsemalock)), (*int32)(unsafe.Pointer(&_g_.m.waitsemacount))) + if ret == _EWOULDBLOCK { return -1 } } @@ -98,7 +98,7 @@ func semawakeup(mp *m) { } mp.waitsemacount++ ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1) - if ret != 0 && ret != ESRCH { + if ret != 0 && ret != _ESRCH { // semawakeup can be called on signal stack. systemstack(func() { print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") @@ -127,7 +127,7 @@ func newosproc(mp *m, stk unsafe.Pointer) { if ret < 0 { print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") - if ret == -ENOTSUP { + if ret == -_ENOTSUP { print("runtime: is kern.rthreads disabled?\n") } throw("runtime.newosproc") -- cgit v1.2.3-54-g00ecf From 1ae124b5ff38045008402b51017c8303eef2cda1 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 18 Feb 2015 16:40:31 -0500 Subject: runtime: make gcDrainN take an int instead of uintptr Nit. There's no reason to take a uintptr and doing so just requires casts in annoying places. Change-Id: Ifeb9638c6d94eae619c490930cf724cc315680ba Reviewed-on: https://go-review.googlesource.com/5230 Reviewed-by: Russ Cox --- src/runtime/mgc.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 1a3e70fcdd..7d68d5bf5f 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -494,9 +494,9 @@ func gcDrain(wbuf *workbuf) { // gcDrainN scans n objects starting with those in wbuf, blackening // grey objects. //go:nowritebarrier -func gcDrainN(wbuf *workbuf, n uintptr) *workbuf { +func gcDrainN(wbuf *workbuf, n int) *workbuf { checknocurrentwbuf() - for i := uintptr(0); i < n; i++ { + for i := 0; i < n; i++ { if wbuf.nobj == 0 { putempty(wbuf, 544) wbuf = trygetfull(545) @@ -817,7 +817,7 @@ func gchelpwork() { wbuf = trygetfull(1228) } if wbuf != nil { - wbuf = gcDrainN(wbuf, uintptr(len(wbuf.obj))) // drain upto one buffer's worth of objects + wbuf = gcDrainN(wbuf, len(wbuf.obj)) // drain upto one buffer's worth of objects if wbuf != nil { if wbuf.nobj != 0 { putfull(wbuf, 1175) -- cgit v1.2.3-54-g00ecf From 270f8447d6e4847db6e54f1f3befc8c70079fac7 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Thu, 19 Feb 2015 14:00:16 +1100 Subject: image/jpeg: support 16-bit quantization tables and Extended Sequential frames. Fixes #9888. Change-Id: I60f1d843e72e1b7bc77ab984f149c9ddb5258a06 Reviewed-on: https://go-review.googlesource.com/5251 Reviewed-by: Rob Pike --- src/image/jpeg/reader.go | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go index 863f55bf25..5d7fefc6cd 100644 --- a/src/image/jpeg/reader.go +++ b/src/image/jpeg/reader.go @@ -54,6 +54,7 @@ const ( soiMarker = 0xd8 // Start Of Image. eoiMarker = 0xd9 // End Of Image. sof0Marker = 0xc0 // Start Of Frame (Baseline). + sof1Marker = 0xc1 // Start Of Frame (Extended Sequential). sof2Marker = 0xc2 // Start Of Frame (Progressive). dhtMarker = 0xc4 // Define Huffman Table. dqtMarker = 0xdb // Define Quantization Table. @@ -139,7 +140,7 @@ type decoder struct { progCoeffs [maxComponents][]block // Saved state between progressive-mode scans. huff [maxTc + 1][maxTh + 1]huffman quant [maxTq + 1]block // Quantization tables, in zig-zag order. - tmp [blockSize + 1]byte + tmp [2 * blockSize]byte } // fill fills up the d.bytes.buf buffer from the underlying io.Reader. It @@ -387,21 +388,42 @@ func (d *decoder) processSOF(n int) error { // Specified in section B.2.4.1. func (d *decoder) processDQT(n int) error { - const qtLength = 1 + blockSize - for ; n >= qtLength; n -= qtLength { - if err := d.readFull(d.tmp[:qtLength]); err != nil { +loop: + for n > 0 { + n-- + x, err := d.readByte() + if err != nil { return err } - pq := d.tmp[0] >> 4 - if pq != 0 { - return UnsupportedError("bad Pq value") - } - tq := d.tmp[0] & 0x0f + tq := x & 0x0f if tq > maxTq { return FormatError("bad Tq value") } - for i := range d.quant[tq] { - d.quant[tq][i] = int32(d.tmp[i+1]) + switch x >> 4 { + default: + return FormatError("bad Pq value") + case 0: + if n < blockSize { + break loop + } + n -= blockSize + if err := d.readFull(d.tmp[:blockSize]); err != nil { + return err + } + for i := range d.quant[tq] { + d.quant[tq][i] = int32(d.tmp[i]) + } + case 1: + if n < 2*blockSize { + break loop + } + n -= 2 * blockSize + if err := d.readFull(d.tmp[:2*blockSize]); err != nil { + return err + } + for i := range d.quant[tq] { + d.quant[tq][i] = int32(d.tmp[2*i])<<8 | int32(d.tmp[2*i+1]) + } } } if n != 0 { @@ -524,7 +546,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) { } switch marker { - case sof0Marker, sof2Marker: + case sof0Marker, sof1Marker, sof2Marker: d.progressive = marker == sof2Marker err = d.processSOF(n) if configOnly { -- cgit v1.2.3-54-g00ecf From ac452349e4f40c30d50f9922bf2c4592e748ce5e Mon Sep 17 00:00:00 2001 From: Ryan Seys Date: Wed, 18 Feb 2015 21:34:44 -0500 Subject: doc: fix broken link in README Change-Id: I73450aeb59571f3285ff59ae214739e1866c9aa0 Reviewed-on: https://go-review.googlesource.com/5270 Reviewed-by: Andrew Gerrand --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 4b79b5b902..4e6d7bde1f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ visit https://golang.org/ or load doc/install-source.html in your web browser. Our canonical Git repository is located at https://go.googlesource.com/go. -(There is a mirror of the repository at https://github.com/golang/go.) +There is a mirror of the repository at https://github.com/golang/go. Please report issues here: https://golang.org/issue/new @@ -43,4 +43,3 @@ put the following in your .profile: export PATH=$PATH:$GOROOT/bin See https://golang.org/doc/install or doc/install.html for more details. - -- cgit v1.2.3-54-g00ecf From 1b205857a46d0241a980c1c8e548ad2e225bcbb8 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 18 Feb 2015 21:59:41 -0500 Subject: runtime: drop unused workbufhdr.id field Change-Id: If7729b3c7df6dc7fcd41f293e2ef2472c769fe8b Reviewed-on: https://go-review.googlesource.com/5261 Reviewed-by: Rick Hudson --- src/runtime/mgcwork.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go index cf5a97957f..ac02d35e73 100644 --- a/src/runtime/mgcwork.go +++ b/src/runtime/mgcwork.go @@ -14,7 +14,6 @@ const ( type workbufhdr struct { node lfnode // must be first nobj uintptr - id uintptr inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues. log [4]uintptr // line numbers forming a history of ownership changes to workbuf } -- cgit v1.2.3-54-g00ecf From b30d19de59cc43723573af06ec2df8aaf053c0b8 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 12 Feb 2015 12:53:48 -0500 Subject: runtime: introduce higher-level GC work abstraction This introduces a producer/consumer abstraction for GC work pointers that internally handles the details of filling, draining, and shuffling work buffers. In addition to simplifying the GC code, this should make it easy for us to change how we use work buffers, including cleaning up how we use the work.partial queue, reintroducing a FIFO lookahead cache, adding prefetching, and using dual buffers to avoid flapping. This commit doesn't change any existing code. The following commit will switch the garbage collector from explicit workbuf manipulation to gcWork. Change-Id: Ifbfe5fff45bf0362d6d7c3cecb061f0c9874077d Reviewed-on: https://go-review.googlesource.com/5231 Reviewed-by: Russ Cox Reviewed-by: Rick Hudson --- src/runtime/mgc.go | 3 +- src/runtime/mgcwork.go | 186 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 1 deletion(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 7d68d5bf5f..ea7d57e769 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -817,7 +817,8 @@ func gchelpwork() { wbuf = trygetfull(1228) } if wbuf != nil { - wbuf = gcDrainN(wbuf, len(wbuf.obj)) // drain upto one buffer's worth of objects + const n = len(workbuf{}.obj) + wbuf = gcDrainN(wbuf, n) // drain upto one buffer's worth of objects if wbuf != nil { if wbuf.nobj != 0 { putfull(wbuf, 1175) diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go index ac02d35e73..d413f9edb3 100644 --- a/src/runtime/mgcwork.go +++ b/src/runtime/mgcwork.go @@ -11,6 +11,192 @@ const ( _WorkbufSize = 1 * 256 // in bytes - if small wbufs are passed to GC in a timely fashion. ) +// Garbage collector work pool abstraction. +// +// This implements a producer/consumer model for pointers to grey +// objects. A grey object is one that is marked and on a work +// queue. A black object is marked and not on a work queue. +// +// Write barriers, root discovery, stack scanning, and object scanning +// produce pointers to grey objects. Scanning consumes pointers to +// grey objects, thus blackening them, and then scans them, +// potentially producing new pointers to grey objects. + +// A wbufptr holds a workbuf*, but protects it from write barriers. +// workbufs never live on the heap, so write barriers are unnecessary. +// Write barriers on workbuf pointers may also be dangerous in the GC. +type wbufptr uintptr + +func wbufptrOf(w *workbuf) wbufptr { + return wbufptr(unsafe.Pointer(w)) +} + +func (wp wbufptr) ptr() *workbuf { + return (*workbuf)(unsafe.Pointer(wp)) +} + +// A gcWorkProducer provides the interface to produce work for the +// garbage collector. +// +// The usual pattern for using gcWorkProducer is: +// +// var gcw gcWorkProducer +// .. call gcw.put() .. +// gcw.dispose() +type gcWorkProducer struct { + // Invariant: wbuf is never full or empty + wbuf wbufptr +} + +// A gcWork provides the interface to both produce and consume work +// for the garbage collector. +// +// The pattern for using gcWork is the same as gcWorkProducer. +type gcWork struct { + gcWorkProducer +} + +// Note that there is no need for a gcWorkConsumer because everything +// that consumes pointers also produces them. + +// initFromCache fetches work from this M's currentwbuf cache. +//go:nowritebarrier +func (w *gcWorkProducer) initFromCache() { + // TODO: Instead of making gcWorkProducer pull from the + // currentwbuf cache, use a gcWorkProducer as the cache and + // make shade pass around that gcWorkProducer. + if w.wbuf == 0 { + w.wbuf = wbufptr(xchguintptr(&getg().m.currentwbuf, 0)) + } +} + +// put enqueues a pointer for the garbage collector to trace. +//go:nowritebarrier +func (ww *gcWorkProducer) put(obj uintptr) { + w := (*gcWorkProducer)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed + + wbuf := w.wbuf.ptr() + if wbuf == nil { + wbuf = getpartialorempty(42) + w.wbuf = wbufptrOf(wbuf) + } + + wbuf.obj[wbuf.nobj] = obj + wbuf.nobj++ + + if wbuf.nobj == uintptr(len(wbuf.obj)) { + putfull(wbuf, 50) + w.wbuf = 0 + } +} + +// dispose returns any cached pointers to the global queue. +//go:nowritebarrier +func (w *gcWorkProducer) dispose() { + if wbuf := w.wbuf; wbuf != 0 { + putpartial(wbuf.ptr(), 58) + w.wbuf = 0 + } +} + +// disposeToCache returns any cached pointers to this M's currentwbuf. +// It calls throw if currentwbuf is non-nil. +//go:nowritebarrier +func (w *gcWorkProducer) disposeToCache() { + if wbuf := w.wbuf; wbuf != 0 { + wbuf = wbufptr(xchguintptr(&getg().m.currentwbuf, uintptr(wbuf))) + if wbuf != 0 { + throw("m.currentwbuf non-nil in disposeToCache") + } + w.wbuf = 0 + } +} + +// tryGet dequeues a pointer for the garbage collector to trace. +// +// If there are no pointers remaining in this gcWork or in the global +// queue, tryGet returns 0. Note that there may still be pointers in +// other gcWork instances or other caches. +//go:nowritebarrier +func (ww *gcWork) tryGet() uintptr { + w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed + + wbuf := w.wbuf.ptr() + if wbuf == nil { + wbuf = trygetfull(74) + if wbuf == nil { + return 0 + } + w.wbuf = wbufptrOf(wbuf) + } + + wbuf.nobj-- + obj := wbuf.obj[wbuf.nobj] + + if wbuf.nobj == 0 { + putempty(wbuf, 86) + w.wbuf = 0 + } + + return obj +} + +// get dequeues a pointer for the garbage collector to trace, blocking +// if necessary to ensure all pointers from all queues and caches have +// been retrieved. get returns 0 if there are no pointers remaining. +//go:nowritebarrier +func (ww *gcWork) get() uintptr { + w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed + + wbuf := w.wbuf.ptr() + if wbuf == nil { + wbuf = getfull(103) + if wbuf == nil { + return 0 + } + wbuf.checknonempty() + w.wbuf = wbufptrOf(wbuf) + } + + // TODO: This might be a good place to add prefetch code + + wbuf.nobj-- + obj := wbuf.obj[wbuf.nobj] + + if wbuf.nobj == 0 { + putempty(wbuf, 115) + w.wbuf = 0 + } + + return obj +} + +// dispose returns any cached pointers to the global queue. +//go:nowritebarrier +func (w *gcWork) dispose() { + if wbuf := w.wbuf; wbuf != 0 { + // Even though wbuf may only be partially full, we + // want to keep it on the consumer's queues rather + // than putting it back on the producer's queues. + // Hence, we use putfull here. + putfull(wbuf.ptr(), 133) + w.wbuf = 0 + } +} + +// balance moves some work that's cached in this gcWork back on the +// global queue. +//go:nowritebarrier +func (w *gcWork) balance() { + if wbuf := w.wbuf; wbuf != 0 && wbuf.ptr().nobj > 4 { + w.wbuf = wbufptrOf(handoff(wbuf.ptr())) + } +} + +// Internally, the GC work pool is kept in arrays in work buffers. +// The gcWork interface caches a work buffer until full (or empty) to +// avoid contending on the global work buffer lists. + type workbufhdr struct { node lfnode // must be first nobj uintptr -- cgit v1.2.3-54-g00ecf From 02dcdba7c8d2c180ce2f4aa9e7bf805967b9d74d Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 17 Feb 2015 10:53:31 -0500 Subject: runtime: switch to gcWork abstraction This converts the garbage collector from directly manipulating work buffers to using the new gcWork abstraction. The previous management of work buffers was rather ad hoc. As a result, switching to the gcWork abstraction changes many details of work buffer management. If greyobject fills a work buffer, it can now pull from work.partial in addition to work.empty. Previously, gcDrain started with a partial or empty work buffer and fetched an empty work buffer if it filled its current buffer (in greyobject). Now, gcDrain starts with a full work buffer and fetches an partial or empty work buffer if it fills its current buffer (in greyobject). The original behavior was bad because gcDrain would immediately drop the empty work buffer returned by greyobject and fetch a full work buffer, which greyobject was likely to immediately overflow, fetching another empty work buffer, etc. The new behavior isn't great at the start because greyobject is likely to immediately overflow the full buffer, but the steady-state behavior should be more stable. Both before and after this change, gcDrain fetches a full work buffer if it drains its current buffer. Basically all of these choices are bad; the right answer is to use a dual work buffer scheme. Previously, shade always fetched a work buffer (though usually from m.currentwbuf), even if the object was already marked. Now it only fetches a work buffer if it actually greys an object. Change-Id: I8b880ed660eb63135236fa5d5678f0c1c041881f Reviewed-on: https://go-review.googlesource.com/5232 Reviewed-by: Russ Cox Reviewed-by: Rick Hudson --- src/runtime/mgc.go | 190 ++++++++++++++++++++--------------------------------- 1 file changed, 72 insertions(+), 118 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index ea7d57e769..0e9756c3e9 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -257,7 +257,7 @@ func gcmarknewobject_m(obj uintptr) { // Return possibly new workbuf to use. // base and off are for debugging only and could be removed. //go:nowritebarrier -func greyobject(obj, base, off uintptr, hbits heapBits, wbuf *workbuf) *workbuf { +func greyobject(obj, base, off uintptr, hbits heapBits, gcw *gcWorkProducer) { // obj should be start of allocation, and so must be at least pointer-aligned. if obj&(ptrSize-1) != 0 { throw("greyobject: obj not pointer-aligned") @@ -307,7 +307,7 @@ func greyobject(obj, base, off uintptr, hbits heapBits, wbuf *workbuf) *workbuf throw("checkmark found unmarked object") } if !hbits.isCheckmarked() { - return wbuf + return } hbits.setCheckmarked() if !hbits.isCheckmarked() { @@ -316,7 +316,7 @@ func greyobject(obj, base, off uintptr, hbits heapBits, wbuf *workbuf) *workbuf } else { // If marked we have nothing to do. if hbits.isMarked() { - return wbuf + return } // Each byte of GC bitmap holds info for two words. @@ -327,7 +327,7 @@ func greyobject(obj, base, off uintptr, hbits heapBits, wbuf *workbuf) *workbuf } if !checkmarkphase && hbits.typeBits() == typeDead { - return wbuf // noscan object + return // noscan object } // Queue the obj for scanning. The PREFETCH(obj) logic has been removed but @@ -337,15 +337,7 @@ func greyobject(obj, base, off uintptr, hbits heapBits, wbuf *workbuf) *workbuf // to give the PREFETCH time to do its work. // Use of PREFETCHNTA might be more appropriate than PREFETCH - // If workbuf is full, obtain an empty one. - if wbuf.nobj >= uintptr(len(wbuf.obj)) { - putfull(wbuf, 358) - wbuf = getempty(359) - } - - wbuf.obj[wbuf.nobj] = obj - wbuf.nobj++ - return wbuf + gcw.put(obj) } // Scan the object b of size n, adding pointers to wbuf. @@ -355,7 +347,7 @@ func greyobject(obj, base, off uintptr, hbits heapBits, wbuf *workbuf) *workbuf // In this case, n may be an overestimate of the size; the GC bitmap // must also be used to make sure the scan stops at the end of b. //go:nowritebarrier -func scanobject(b, n uintptr, ptrmask *uint8, wbuf *workbuf) *workbuf { +func scanobject(b, n uintptr, ptrmask *uint8, gcw *gcWorkProducer) { arena_start := mheap_.arena_start arena_used := mheap_.arena_used @@ -364,7 +356,7 @@ func scanobject(b, n uintptr, ptrmask *uint8, wbuf *workbuf) *workbuf { if ptrmask == nil { b, hbits = heapBitsForObject(b) if b == 0 { - return wbuf + return } if n == 0 { n = mheap_.arena_used - b @@ -413,16 +405,15 @@ func scanobject(b, n uintptr, ptrmask *uint8, wbuf *workbuf) *workbuf { // Mark the object. if obj, hbits := heapBitsForObject(obj); obj != 0 { - wbuf = greyobject(obj, b, i, hbits, wbuf) + greyobject(obj, b, i, hbits, gcw) } } - return wbuf } // scanblock scans b as scanobject would. // If the gcphase is GCscan, scanblock performs additional checks. //go:nowritebarrier -func scanblock(b0, n0 uintptr, ptrmask *uint8, wbuf *workbuf) *workbuf { +func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWorkProducer) { // Use local copies of original parameters, so that a stack trace // due to one of the throws below shows the original block // base and extent. @@ -433,103 +424,78 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, wbuf *workbuf) *workbuf { // 1. nil - obtain pointer mask from GC bitmap. // 2. pointer to a compact mask (for stacks and data). - if wbuf == nil { - wbuf = getpartialorempty(460) // no wbuf passed in. - } - wbuf = scanobject(b, n, ptrmask, wbuf) + scanobject(b, n, ptrmask, gcw) if gcphase == _GCscan { if inheap(b) && ptrmask == nil { // b is in heap, we are in GCscan so there should be a ptrmask. throw("scanblock: In GCscan phase and inheap is true.") } } - return wbuf } -// gcDrain scans objects in work buffers (starting with wbuf), blackening grey -// objects until all work buffers have been drained. +// gcDrain scans objects in work buffers, blackening grey +// objects until all work has been drained. //go:nowritebarrier -func gcDrain(wbuf *workbuf) { - if wbuf == nil { - wbuf = getpartialorempty(472) - } - checknocurrentwbuf() +func gcDrain(gcw *gcWork) { if gcphase != _GCmark && gcphase != _GCmarktermination { throw("scanblock phase incorrect") } for { - if wbuf.nobj == 0 { - putempty(wbuf, 496) - // Refill workbuf from global queue. - wbuf = getfull(504) - if wbuf == nil { // nil means out of work barrier reached - break - } - wbuf.checknonempty() - } - // If another proc wants a pointer, give it some. - if work.nwait > 0 && wbuf.nobj > 4 && work.full == 0 { - wbuf = handoff(wbuf) + if work.nwait > 0 && work.full == 0 { + gcw.balance() } - // This might be a good place to add prefetch code... - // if(wbuf.nobj > 4) { - // PREFETCH(wbuf->obj[wbuf.nobj - 3]; - // } - wbuf.nobj-- - b := wbuf.obj[wbuf.nobj] + b := gcw.get() + if b == 0 { + // work barrier reached + break + } // If the current wbuf is filled by the scan a new wbuf might be // returned that could possibly hold only a single object. This // could result in each iteration draining only a single object // out of the wbuf passed in + a single object placed // into an empty wbuf in scanobject so there could be // a performance hit as we keep fetching fresh wbufs. - wbuf = scanobject(b, 0, nil, wbuf) + scanobject(b, 0, nil, &gcw.gcWorkProducer) } checknocurrentwbuf() } -// gcDrainN scans n objects starting with those in wbuf, blackening -// grey objects. +// gcDrainN scans n objects, blackening grey objects. //go:nowritebarrier -func gcDrainN(wbuf *workbuf, n int) *workbuf { +func gcDrainN(gcw *gcWork, n int) { checknocurrentwbuf() for i := 0; i < n; i++ { - if wbuf.nobj == 0 { - putempty(wbuf, 544) - wbuf = trygetfull(545) - if wbuf == nil { - return nil - } - } - // This might be a good place to add prefetch code... // if(wbuf.nobj > 4) { // PREFETCH(wbuf->obj[wbuf.nobj - 3]; // } - wbuf.nobj-- - b := wbuf.obj[wbuf.nobj] - wbuf = scanobject(b, 0, nil, wbuf) + b := gcw.tryGet() + if b == 0 { + return + } + scanobject(b, 0, nil, &gcw.gcWorkProducer) } - return wbuf } //go:nowritebarrier func markroot(desc *parfor, i uint32) { + var gcw gcWorkProducer + gcw.initFromCache() + // Note: if you add a case here, please also update heapdump.c:dumproots. - wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) switch i { case _RootData: - wbuf = scanblock(uintptr(unsafe.Pointer(&data)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)), gcdatamask.bytedata, wbuf) + scanblock(uintptr(unsafe.Pointer(&data)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)), gcdatamask.bytedata, &gcw) case _RootBss: - wbuf = scanblock(uintptr(unsafe.Pointer(&bss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)), gcbssmask.bytedata, wbuf) + scanblock(uintptr(unsafe.Pointer(&bss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)), gcbssmask.bytedata, &gcw) case _RootFinalizers: for fb := allfin; fb != nil; fb = fb.alllink { - wbuf = scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], wbuf) + scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], &gcw) } case _RootSpans: @@ -555,9 +521,9 @@ func markroot(desc *parfor, i uint32) { // A finalizer can be set for an inner byte of an object, find object beginning. p := uintptr(s.start<<_PageShift) + uintptr(spf.special.offset)/s.elemsize*s.elemsize if gcphase != _GCscan { - wbuf = scanblock(p, s.elemsize, nil, wbuf) // scanned during mark phase + scanblock(p, s.elemsize, nil, &gcw) // scanned during mark phase } - wbuf = scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptr[0], wbuf) + scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptr[0], &gcw) } } @@ -617,11 +583,7 @@ func markroot(desc *parfor, i uint32) { restartg(gp) } } - if wbuf == nil { - return - } else { - putpartial(wbuf, 670) - } + gcw.dispose() } //go:nowritebarrier @@ -634,13 +596,13 @@ func stackmapdata(stkmap *stackmap, n int32) bitvector { // Scan a stack frame: local variables and function arguments/results. //go:nowritebarrier -func scanframeworker(frame *stkframe, unused unsafe.Pointer, wbuf *workbuf) *workbuf { +func scanframeworker(frame *stkframe, unused unsafe.Pointer, gcw *gcWorkProducer) { f := frame.fn targetpc := frame.continpc if targetpc == 0 { // Frame is dead. - return wbuf + return } if _DebugGC > 1 { print("scanframe ", funcname(f), "\n") @@ -679,7 +641,7 @@ func scanframeworker(frame *stkframe, unused unsafe.Pointer, wbuf *workbuf) *wor } bv := stackmapdata(stkmap, pcdata) size = (uintptr(bv.n) / typeBitsWidth) * ptrSize - wbuf = scanblock(frame.varp-size, size, bv.bytedata, wbuf) + scanblock(frame.varp-size, size, bv.bytedata, gcw) } // Scan arguments. @@ -700,9 +662,8 @@ func scanframeworker(frame *stkframe, unused unsafe.Pointer, wbuf *workbuf) *wor } bv = stackmapdata(stkmap, pcdata) } - wbuf = scanblock(frame.argp, uintptr(bv.n)/typeBitsWidth*ptrSize, bv.bytedata, wbuf) + scanblock(frame.argp, uintptr(bv.n)/typeBitsWidth*ptrSize, bv.bytedata, gcw) } - return wbuf } //go:nowritebarrier @@ -737,19 +698,17 @@ func scanstack(gp *g) { throw("can't scan gchelper stack") } - wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) + var gcw gcWorkProducer + gcw.initFromCache() scanframe := func(frame *stkframe, unused unsafe.Pointer) bool { - // Pick up wbuf as free variable so gentraceback and friends can + // Pick up gcw as free variable so gentraceback and friends can // keep the same signature. - wbuf = scanframeworker(frame, unused, wbuf) + scanframeworker(frame, unused, &gcw) return true } gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0) tracebackdefers(gp, scanframe, nil) - wbuf = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, uintptr(unsafe.Pointer(wbuf))))) - if wbuf != nil { - throw("wbuf not nil after stack scans") - } + gcw.disposeToCache() gp.gcscanvalid = true } @@ -757,8 +716,6 @@ func scanstack(gp *g) { // The object is not nil and known to be in the heap. //go:nowritebarrier func shade(b uintptr) { - var wbuf *workbuf - if !inheap(b) { throw("shade: passed an address not in the heap") } @@ -770,19 +727,23 @@ func shade(b uintptr) { // if atomicload(&harvestingwbufs) == uint32(1) { // // Throw here to discover write barriers // // being executed during a STW. + // throw("shade during harvest") // } - wbuf = getpartialorempty(1181) - wbuf := greyobject(obj, 0, 0, hbits, wbuf) - checknocurrentwbuf() + var gcw gcWorkProducer + greyobject(obj, 0, 0, hbits, &gcw) // This is part of the write barrier so put the wbuf back. if gcphase == _GCmarktermination { - putpartial(wbuf, 1191) // Put on full??? + gcw.dispose() } else { - wbuf = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, uintptr(unsafe.Pointer(wbuf))))) - if wbuf != nil { - throw("m.currentwbuf lost in shade") - } + // If we added any pointers to the gcw, then + // currentwbuf must be nil because 1) + // greyobject got its wbuf from currentwbuf + // and 2) shade runs on the systemstack, so + // we're still on the same M. If either of + // these becomes no longer true, we need to + // rethink this. + gcw.disposeToCache() } } } @@ -807,26 +768,13 @@ func gchelpwork() { // scanstack(gp) case _GCmark: // Get a full work buffer and empty it. - m := getg().m // drain your own currentwbuf first in the hopes that it will // be more cache friendly. - wbuf := (*workbuf)(unsafe.Pointer(xchguintptr(&m.currentwbuf, 0))) - // wbuf := (*workbuf)(unsafe.Pointer(m.currentwbuf)) - // m.currentwbuf = 0 - if wbuf == nil { - wbuf = trygetfull(1228) - } - if wbuf != nil { - const n = len(workbuf{}.obj) - wbuf = gcDrainN(wbuf, n) // drain upto one buffer's worth of objects - if wbuf != nil { - if wbuf.nobj != 0 { - putfull(wbuf, 1175) - } else { - putempty(wbuf, 1177) - } - } - } + var gcw gcWork + gcw.initFromCache() + const n = len(workbuf{}.obj) + gcDrainN(&gcw, n) // drain upto one buffer's worth of objects + gcw.dispose() case _GCmarktermination: // We should never be here since the world is stopped. // All available mark work will be emptied before returning. @@ -1140,7 +1088,9 @@ func gchelper() { // parallel mark for over GC roots parfordo(work.markfor) if gcphase != _GCscan { - gcDrain(nil) // blocks in getfull + var gcw gcWork + gcDrain(&gcw) // blocks in getfull + gcw.dispose() } if trace.enabled { @@ -1402,7 +1352,9 @@ func gcscan_m() { // This is the concurrent mark phase. //go:nowritebarrier func gcmark_m() { - gcDrain(nil) + var gcw gcWork + gcDrain(&gcw) + gcw.dispose() // TODO add another harvestwbuf and reset work.nwait=0, work.ndone=0, and work.nproc=1 // and repeat the above gcDrain. } @@ -1489,7 +1441,9 @@ func gc(start_time int64, eagersweep bool) { harvestwbufs() // move local workbufs onto global queues where the GC can find them gchelperstart() parfordo(work.markfor) - gcDrain(nil) + var gcw gcWork + gcDrain(&gcw) + gcw.dispose() if work.full != 0 { throw("work.full != 0") -- cgit v1.2.3-54-g00ecf From c25c3710986c3c71d09141c458a6f56fea4d88ab Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 18 Feb 2015 21:56:12 -0500 Subject: runtime: use more natural types in struct workbuf Until recently, struct workbuf had only lfnode and uintptr fields before the obj array to make it convenient to compute the size of the obj array. It slowly grew more fields until this became inconvenient enough that it was restructured to make the size computation easy. Now the size computation doesn't care what the field types are, so switch to more natural types. Change-Id: I966140ba7ebb4aeb41d5c66d9d2a3bdc17dd4bcf Reviewed-on: https://go-review.googlesource.com/5262 Reviewed-by: Russ Cox --- src/runtime/mgcwork.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go index d413f9edb3..5d725a5c82 100644 --- a/src/runtime/mgcwork.go +++ b/src/runtime/mgcwork.go @@ -84,7 +84,7 @@ func (ww *gcWorkProducer) put(obj uintptr) { wbuf.obj[wbuf.nobj] = obj wbuf.nobj++ - if wbuf.nobj == uintptr(len(wbuf.obj)) { + if wbuf.nobj == len(wbuf.obj) { putfull(wbuf, 50) w.wbuf = 0 } @@ -199,9 +199,9 @@ func (w *gcWork) balance() { type workbufhdr struct { node lfnode // must be first - nobj uintptr - inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues. - log [4]uintptr // line numbers forming a history of ownership changes to workbuf + nobj int + inuse bool // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues. + log [4]int // line numbers forming a history of ownership changes to workbuf } type workbuf struct { @@ -222,7 +222,7 @@ type workbuf struct { // logget records the past few values of entry to aid in debugging. // logget checks the buffer b is not currently in use. -func (b *workbuf) logget(entry uintptr) { +func (b *workbuf) logget(entry int) { if !_Debugwbufs { return } @@ -239,7 +239,7 @@ func (b *workbuf) logget(entry uintptr) { // logput records the past few values of entry to aid in debugging. // logput checks the buffer b is currently in use. -func (b *workbuf) logput(entry uintptr) { +func (b *workbuf) logput(entry int) { if !_Debugwbufs { return } @@ -283,7 +283,7 @@ func checknocurrentwbuf() { // allocating new buffers if none are available. // entry is used to record a brief history of ownership. //go:nowritebarrier -func getempty(entry uintptr) *workbuf { +func getempty(entry int) *workbuf { var b *workbuf if work.empty != 0 { b = (*workbuf)(lfstackpop(&work.empty)) @@ -301,7 +301,7 @@ func getempty(entry uintptr) *workbuf { // putempty puts a workbuf onto the work.empty list. // Upon entry this go routine owns b. The lfstackpush relinquishes ownership. //go:nowritebarrier -func putempty(b *workbuf, entry uintptr) { +func putempty(b *workbuf, entry int) { b.checkempty() b.logput(entry) lfstackpush(&work.empty, &b.node) @@ -311,7 +311,7 @@ func putempty(b *workbuf, entry uintptr) { // putfull accepts partially full buffers so the GC can avoid competing // with the mutators for ownership of partially full buffers. //go:nowritebarrier -func putfull(b *workbuf, entry uintptr) { +func putfull(b *workbuf, entry int) { b.checknonempty() b.logput(entry) lfstackpush(&work.full, &b.node) @@ -323,7 +323,7 @@ func putfull(b *workbuf, entry uintptr) { // using entry + xxx00000 to // indicating that two line numbers in the call chain. //go:nowritebarrier -func getpartialorempty(entry uintptr) *workbuf { +func getpartialorempty(entry int) *workbuf { var b *workbuf // If this m has a buf in currentwbuf then as an optimization // simply return that buffer. If it turns out currentwbuf @@ -332,7 +332,7 @@ func getpartialorempty(entry uintptr) *workbuf { if getg().m.currentwbuf != 0 { b = (*workbuf)(unsafe.Pointer(xchguintptr(&getg().m.currentwbuf, 0))) if b != nil { - if b.nobj <= uintptr(len(b.obj)) { + if b.nobj <= len(b.obj) { return b } putfull(b, entry+80100000) @@ -357,13 +357,13 @@ func getpartialorempty(entry uintptr) *workbuf { // using entry + xxx00000 to // indicating that two call chain line numbers. //go:nowritebarrier -func putpartial(b *workbuf, entry uintptr) { +func putpartial(b *workbuf, entry int) { if b.nobj == 0 { putempty(b, entry+81500000) - } else if b.nobj < uintptr(len(b.obj)) { + } else if b.nobj < len(b.obj) { b.logput(entry) lfstackpush(&work.partial, &b.node) - } else if b.nobj == uintptr(len(b.obj)) { + } else if b.nobj == len(b.obj) { b.logput(entry) lfstackpush(&work.full, &b.node) } else { @@ -374,7 +374,7 @@ func putpartial(b *workbuf, entry uintptr) { // trygetfull tries to get a full or partially empty workbuffer. // If one is not immediately available return nil //go:nowritebarrier -func trygetfull(entry uintptr) *workbuf { +func trygetfull(entry int) *workbuf { b := (*workbuf)(lfstackpop(&work.full)) if b == nil { b = (*workbuf)(lfstackpop(&work.partial)) @@ -415,7 +415,7 @@ func trygetfull(entry uintptr) *workbuf { // This is in fact the termination condition for the STW mark // phase. //go:nowritebarrier -func getfull(entry uintptr) *workbuf { +func getfull(entry int) *workbuf { b := (*workbuf)(lfstackpop(&work.full)) if b != nil { b.logget(entry) @@ -480,7 +480,7 @@ func handoff(b *workbuf) *workbuf { n := b.nobj / 2 b.nobj -= n b1.nobj = n - memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), n*unsafe.Sizeof(b1.obj[0])) + memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), uintptr(n)*unsafe.Sizeof(b1.obj[0])) _g_ := getg() _g_.m.gcstats.nhandoff++ _g_.m.gcstats.nhandoffcnt += uint64(n) -- cgit v1.2.3-54-g00ecf From 5dbbb776339fe923293c87b4ccb35673b12c112e Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 18 Feb 2015 15:29:32 -0800 Subject: runtime: don't test gdb on darwin Fixes #9927 Change-Id: I2114cc21f7a4772e3d42bcad9642a8a545cd8e16 Reviewed-on: https://go-review.googlesource.com/5285 Reviewed-by: Minux Ma --- src/runtime/runtime-gdb_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index a926f5fb85..36a0dc9e3c 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -33,6 +33,10 @@ func main() { ` func TestGdbPython(t *testing.T) { + if runtime.GOOS == "darwin" { + t.Skip("gdb does not work on darwin") + } + checkGdbPython(t) dir, err := ioutil.TempDir("", "go-build") -- cgit v1.2.3-54-g00ecf From d384545a4580cf1f6990efee5f0047ec60f4258d Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 19 Feb 2015 15:21:05 +0300 Subject: cmd/pprof: add -runtime flag The flag disables stripping of runtime frames in profiles. This is useful when analyzing runtime itself. Before: $ go tool pprof --text --alloc_objects --lines fmt.test /tmp/mprof flat flat% sum% cum cum% 2768 79.65% 79.65% 32768 79.65% fmt_test.TestComplexFormatting fmt/fmt_test.go:744 6554 15.93% 95.58% 6554 15.93% regexp/syntax.(*compiler).rune regexp/syntax/compile.go:267 1820 4.42% 100% 1820 4.42% runtime.malg runtime/proc1.go:1977 After: $ go tool pprof --text --alloc_objects --lines --runtime fmt.test /tmp/mprof flat flat% sum% cum cum% 32768 79.65% 79.65% 32768 79.65% runtime.convT2E runtime/iface.go:139 6554 15.93% 95.58% 6554 15.93% runtime.growslice runtime/slice.go:89 1820 4.42% 100% 1820 4.42% runtime.malg runtime/proc1.go:1977 Change-Id: If468dfa5c5bbd0809c45a58d912d3115fac009ed Reviewed-on: https://go-review.googlesource.com/5291 Reviewed-by: Russ Cox Reviewed-by: Rick Hudson --- src/cmd/pprof/internal/driver/driver.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cmd/pprof/internal/driver/driver.go b/src/cmd/pprof/internal/driver/driver.go index a9f6c844f4..9703bafa63 100644 --- a/src/cmd/pprof/internal/driver/driver.go +++ b/src/cmd/pprof/internal/driver/driver.go @@ -106,7 +106,9 @@ func PProf(flagset plugin.FlagSet, fetch plugin.Fetcher, sym plugin.Symbolizer, return err } - prof.RemoveUninteresting() + if !*f.flagRuntime { + prof.RemoveUninteresting() + } if *f.flagInteractive { return interactive(prof, obj, ui, f) @@ -445,6 +447,7 @@ type flags struct { flagNodeFraction *float64 // Hide nodes below *total flagEdgeFraction *float64 // Hide edges below *total flagTrim *bool // Set to false to ignore NodeCount/*Fraction + flagRuntime *bool // Show runtime call frames in memory profiles flagFocus *string // Restricts to paths going through a node matching regexp flagIgnore *string // Skips paths going through any nodes matching regexp flagHide *string // Skips sample locations matching regexp @@ -640,6 +643,7 @@ func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (* flagNodeFraction: flag.Float64("nodefraction", 0.005, "Hide nodes below *total"), flagEdgeFraction: flag.Float64("edgefraction", 0.001, "Hide edges below *total"), flagTrim: flag.Bool("trim", true, "Honor nodefraction/edgefraction/nodecount defaults"), + flagRuntime: flag.Bool("runtime", false, "Show runtime call frames in memory profiles"), flagFocus: flag.String("focus", "", "Restricts to paths going through a node matching regexp"), flagIgnore: flag.String("ignore", "", "Skips paths going through any nodes matching regexp"), flagHide: flag.String("hide", "", "Skips nodes matching regexp"), @@ -877,6 +881,7 @@ var usageMsg = "Output file parameters (for file-based output formats):\n" + " -contentions Display number of delays at each region\n" + " -mean_delay Display mean delay at each region\n" + "Filtering options:\n" + + " -runtime Show runtime call frames in memory profiles\n" + " -focus=r Restricts to paths going through a node matching regexp\n" + " -ignore=r Skips paths going through any nodes matching regexp\n" + " -tagfocus=r Restrict to samples tagged with key:value matching regexp\n" + -- cgit v1.2.3-54-g00ecf From 484f801ff4125d86f8c4072f070611afea9c79f7 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 19 Feb 2015 13:38:46 -0500 Subject: runtime: reorganize memory code Move code from malloc1.go, malloc2.go, mem.go, mgc0.go into appropriate locations. Factor mgc.go into mgc.go, mgcmark.go, mgcsweep.go, mstats.go. A lot of this code was in certain files because the right place was in a C file but it was written in Go, or vice versa. This is one step toward making things actually well-organized again. Change-Id: I6741deb88a7cfb1c17ffe0bcca3989e10207968f Reviewed-on: https://go-review.googlesource.com/5300 Reviewed-by: Austin Clements Reviewed-by: Rick Hudson --- src/runtime/heapdump.go | 18 + src/runtime/malloc.go | 754 +++++++++++++--------- src/runtime/malloc1.go | 358 ----------- src/runtime/malloc2.go | 525 ---------------- src/runtime/mbitmap.go | 6 + src/runtime/mcache.go | 57 +- src/runtime/mcentral.go | 8 + src/runtime/mem.go | 114 ---- src/runtime/mfinal.go | 17 + src/runtime/mfixalloc.go | 28 + src/runtime/mgc.go | 1544 ++++++++++++---------------------------------- src/runtime/mgc0.go | 91 --- src/runtime/mgcmark.go | 659 ++++++++++++++++++++ src/runtime/mgcsweep.go | 312 ++++++++++ src/runtime/mheap.go | 216 ++++++- src/runtime/msize.go | 18 +- src/runtime/mstats.go | 340 ++++++++++ src/runtime/proc1.go | 15 + src/runtime/stubs.go | 10 + src/runtime/symtab.go | 14 + 20 files changed, 2539 insertions(+), 2565 deletions(-) delete mode 100644 src/runtime/malloc1.go delete mode 100644 src/runtime/malloc2.go delete mode 100644 src/runtime/mem.go delete mode 100644 src/runtime/mgc0.go create mode 100644 src/runtime/mgcmark.go create mode 100644 src/runtime/mgcsweep.go create mode 100644 src/runtime/mstats.go diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 7b4a846195..f5770958fd 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -13,6 +13,24 @@ package runtime import "unsafe" +//go:linkname runtime_debug_WriteHeapDump runtime/debug.WriteHeapDump +func runtime_debug_WriteHeapDump(fd uintptr) { + semacquire(&worldsema, false) + gp := getg() + gp.m.preemptoff = "write heap dump" + systemstack(stoptheworld) + + systemstack(func() { + writeheapdump_m(fd) + }) + + gp.m.preemptoff = "" + gp.m.locks++ + semrelease(&worldsema) + systemstack(starttheworld) + gp.m.locks-- +} + const ( fieldKindEol = 0 fieldKindPtr = 1 diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 06ba124473..b65bf70656 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -2,6 +2,84 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Memory allocator, based on tcmalloc. +// http://goog-perftools.sourceforge.net/doc/tcmalloc.html + +// The main allocator works in runs of pages. +// Small allocation sizes (up to and including 32 kB) are +// rounded to one of about 100 size classes, each of which +// has its own free list of objects of exactly that size. +// Any free page of memory can be split into a set of objects +// of one size class, which are then managed using free list +// allocators. +// +// The allocator's data structures are: +// +// FixAlloc: a free-list allocator for fixed-size objects, +// used to manage storage used by the allocator. +// MHeap: the malloc heap, managed at page (4096-byte) granularity. +// MSpan: a run of pages managed by the MHeap. +// MCentral: a shared free list for a given size class. +// MCache: a per-thread (in Go, per-P) cache for small objects. +// MStats: allocation statistics. +// +// Allocating a small object proceeds up a hierarchy of caches: +// +// 1. Round the size up to one of the small size classes +// and look in the corresponding MCache free list. +// If the list is not empty, allocate an object from it. +// This can all be done without acquiring a lock. +// +// 2. If the MCache free list is empty, replenish it by +// taking a bunch of objects from the MCentral free list. +// Moving a bunch amortizes the cost of acquiring the MCentral lock. +// +// 3. If the MCentral free list is empty, replenish it by +// allocating a run of pages from the MHeap and then +// chopping that memory into objects of the given size. +// Allocating many objects amortizes the cost of locking +// the heap. +// +// 4. If the MHeap is empty or has no page runs large enough, +// allocate a new group of pages (at least 1MB) from the +// operating system. Allocating a large run of pages +// amortizes the cost of talking to the operating system. +// +// Freeing a small object proceeds up the same hierarchy: +// +// 1. Look up the size class for the object and add it to +// the MCache free list. +// +// 2. If the MCache free list is too long or the MCache has +// too much memory, return some to the MCentral free lists. +// +// 3. If all the objects in a given span have returned to +// the MCentral list, return that span to the page heap. +// +// 4. If the heap has too much memory, return some to the +// operating system. +// +// TODO(rsc): Step 4 is not implemented. +// +// Allocating and freeing a large object uses the page heap +// directly, bypassing the MCache and MCentral free lists. +// +// The small objects on the MCache and MCentral free lists +// may or may not be zeroed. They are zeroed if and only if +// the second word of the object is zero. A span in the +// page heap is zeroed unless s->needzero is set. When a span +// is allocated to break into small objects, it is zeroed if needed +// and s->needzero is set. There are two main benefits to delaying the +// zeroing this way: +// +// 1. stack frames allocated from the small object lists +// or the page heap can avoid zeroing altogether. +// 2. the cost of zeroing when reusing a small object is +// charged to the mutator, not the garbage collector. +// +// This code was written with an eye toward translating to Go +// in the future. Methods have the form Type_Method(Type *t, ...). + package runtime import "unsafe" @@ -25,29 +103,369 @@ const ( concurrentSweep = _ConcurrentSweep ) +const ( + _PageShift = 13 + _PageSize = 1 << _PageShift + _PageMask = _PageSize - 1 +) + +const ( + // _64bit = 1 on 64-bit systems, 0 on 32-bit systems + _64bit = 1 << (^uintptr(0) >> 63) / 2 + + // Computed constant. The definition of MaxSmallSize and the + // algorithm in msize.c produce some number of different allocation + // size classes. NumSizeClasses is that number. It's needed here + // because there are static arrays of this length; when msize runs its + // size choosing algorithm it double-checks that NumSizeClasses agrees. + _NumSizeClasses = 67 + + // Tunable constants. + _MaxSmallSize = 32 << 10 + + // Tiny allocator parameters, see "Tiny allocator" comment in malloc.go. + _TinySize = 16 + _TinySizeClass = 2 + + _FixAllocChunk = 16 << 10 // Chunk size for FixAlloc + _MaxMHeapList = 1 << (20 - _PageShift) // Maximum page length for fixed-size list in MHeap. + _HeapAllocChunk = 1 << 20 // Chunk size for heap growth + + // Per-P, per order stack segment cache size. + _StackCacheSize = 32 * 1024 + + // Number of orders that get caching. Order 0 is FixedStack + // and each successive order is twice as large. + // We want to cache 2KB, 4KB, 8KB, and 16KB stacks. Larger stacks + // will be allocated directly. + // Since FixedStack is different on different systems, we + // must vary NumStackOrders to keep the same maximum cached size. + // OS | FixedStack | NumStackOrders + // -----------------+------------+--------------- + // linux/darwin/bsd | 2KB | 4 + // windows/32 | 4KB | 3 + // windows/64 | 8KB | 2 + // plan9 | 4KB | 3 + _NumStackOrders = 4 - ptrSize/4*goos_windows - 1*goos_plan9 + + // Number of bits in page to span calculations (4k pages). + // On Windows 64-bit we limit the arena to 32GB or 35 bits. + // Windows counts memory used by page table into committed memory + // of the process, so we can't reserve too much memory. + // See http://golang.org/issue/5402 and http://golang.org/issue/5236. + // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits. + // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address. + _MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows))*37 + (1-_64bit)*32 + _MHeapMap_Bits = _MHeapMap_TotalBits - _PageShift + + _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1) + + // Max number of threads to run garbage collection. + // 2, 3, and 4 are all plausible maximums depending + // on the hardware details of the machine. The garbage + // collector scales well to 32 cpus. + _MaxGcproc = 32 +) + // Page number (address>>pageShift) type pageID uintptr +const _MaxArena32 = 2 << 30 + +// OS-defined helpers: +// +// sysAlloc obtains a large chunk of zeroed memory from the +// operating system, typically on the order of a hundred kilobytes +// or a megabyte. +// NOTE: sysAlloc returns OS-aligned memory, but the heap allocator +// may use larger alignment, so the caller must be careful to realign the +// memory obtained by sysAlloc. +// +// SysUnused notifies the operating system that the contents +// of the memory region are no longer needed and can be reused +// for other purposes. +// SysUsed notifies the operating system that the contents +// of the memory region are needed again. +// +// SysFree returns it unconditionally; this is only used if +// an out-of-memory error has been detected midway through +// an allocation. It is okay if SysFree is a no-op. +// +// SysReserve reserves address space without allocating memory. +// If the pointer passed to it is non-nil, the caller wants the +// reservation there, but SysReserve can still choose another +// location if that one is unavailable. On some systems and in some +// cases SysReserve will simply check that the address space is +// available and not actually reserve it. If SysReserve returns +// non-nil, it sets *reserved to true if the address space is +// reserved, false if it has merely been checked. +// NOTE: SysReserve returns OS-aligned memory, but the heap allocator +// may use larger alignment, so the caller must be careful to realign the +// memory obtained by sysAlloc. +// +// SysMap maps previously reserved address space for use. +// The reserved argument is true if the address space was really +// reserved, not merely checked. +// +// SysFault marks a (already sysAlloc'd) region to fault +// if accessed. Used only for debugging the runtime. + +func mallocinit() { + initSizes() + + if class_to_size[_TinySizeClass] != _TinySize { + throw("bad TinySizeClass") + } + + var p, bitmapSize, spansSize, pSize, limit uintptr + var reserved bool + + // limit = runtime.memlimit(); + // See https://golang.org/issue/5049 + // TODO(rsc): Fix after 1.1. + limit = 0 + + // Set up the allocation arena, a contiguous area of memory where + // allocated data will be found. The arena begins with a bitmap large + // enough to hold 4 bits per allocated word. + if ptrSize == 8 && (limit == 0 || limit > 1<<30) { + // On a 64-bit machine, allocate from a single contiguous reservation. + // 128 GB (MaxMem) should be big enough for now. + // + // The code will work with the reservation at any address, but ask + // SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f). + // Allocating a 128 GB region takes away 37 bits, and the amd64 + // doesn't let us choose the top 17 bits, so that leaves the 11 bits + // in the middle of 0x00c0 for us to choose. Choosing 0x00c0 means + // that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df. + // In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid + // UTF-8 sequences, and they are otherwise as far away from + // ff (likely a common byte) as possible. If that fails, we try other 0xXXc0 + // addresses. An earlier attempt to use 0x11f8 caused out of memory errors + // on OS X during thread allocations. 0x00c0 causes conflicts with + // AddressSanitizer which reserves all memory up to 0x0100. + // These choices are both for debuggability and to reduce the + // odds of the conservative garbage collector not collecting memory + // because some non-pointer block of memory had a bit pattern + // that matched a memory address. + // + // Actually we reserve 136 GB (because the bitmap ends up being 8 GB) + // but it hardly matters: e0 00 is not valid UTF-8 either. + // + // If this fails we fall back to the 32 bit memory mechanism + arenaSize := round(_MaxMem, _PageSize) + bitmapSize = arenaSize / (ptrSize * 8 / 4) + spansSize = arenaSize / _PageSize * ptrSize + spansSize = round(spansSize, _PageSize) + for i := 0; i <= 0x7f; i++ { + p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32) + pSize = bitmapSize + spansSize + arenaSize + _PageSize + p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved)) + if p != 0 { + break + } + } + } + + if p == 0 { + // On a 32-bit machine, we can't typically get away + // with a giant virtual address space reservation. + // Instead we map the memory information bitmap + // immediately after the data segment, large enough + // to handle another 2GB of mappings (256 MB), + // along with a reservation for an initial arena. + // When that gets used up, we'll start asking the kernel + // for any memory anywhere and hope it's in the 2GB + // following the bitmap (presumably the executable begins + // near the bottom of memory, so we'll have to use up + // most of memory before the kernel resorts to giving out + // memory before the beginning of the text segment). + // + // Alternatively we could reserve 512 MB bitmap, enough + // for 4GB of mappings, and then accept any memory the + // kernel threw at us, but normally that's a waste of 512 MB + // of address space, which is probably too much in a 32-bit world. + + // If we fail to allocate, try again with a smaller arena. + // This is necessary on Android L where we share a process + // with ART, which reserves virtual memory aggressively. + arenaSizes := []uintptr{ + 512 << 20, + 256 << 20, + } + + for _, arenaSize := range arenaSizes { + bitmapSize = _MaxArena32 / (ptrSize * 8 / 4) + spansSize = _MaxArena32 / _PageSize * ptrSize + if limit > 0 && arenaSize+bitmapSize+spansSize > limit { + bitmapSize = (limit / 9) &^ ((1 << _PageShift) - 1) + arenaSize = bitmapSize * 8 + spansSize = arenaSize / _PageSize * ptrSize + } + spansSize = round(spansSize, _PageSize) + + // SysReserve treats the address we ask for, end, as a hint, + // not as an absolute requirement. If we ask for the end + // of the data segment but the operating system requires + // a little more space before we can start allocating, it will + // give out a slightly higher pointer. Except QEMU, which + // is buggy, as usual: it won't adjust the pointer upward. + // So adjust it upward a little bit ourselves: 1/4 MB to get + // away from the running binary image and then round up + // to a MB boundary. + p = round(uintptr(unsafe.Pointer(&end))+(1<<18), 1<<20) + pSize = bitmapSize + spansSize + arenaSize + _PageSize + p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved)) + if p != 0 { + break + } + } + if p == 0 { + throw("runtime: cannot reserve arena virtual address space") + } + } + + // PageSize can be larger than OS definition of page size, + // so SysReserve can give us a PageSize-unaligned pointer. + // To overcome this we ask for PageSize more and round up the pointer. + p1 := round(p, _PageSize) + + mheap_.spans = (**mspan)(unsafe.Pointer(p1)) + mheap_.bitmap = p1 + spansSize + mheap_.arena_start = p1 + (spansSize + bitmapSize) + mheap_.arena_used = mheap_.arena_start + mheap_.arena_end = p + pSize + mheap_.arena_reserved = reserved + + if mheap_.arena_start&(_PageSize-1) != 0 { + println("bad pagesize", hex(p), hex(p1), hex(spansSize), hex(bitmapSize), hex(_PageSize), "start", hex(mheap_.arena_start)) + throw("misrounded allocation in mallocinit") + } + + // Initialize the rest of the allocator. + mHeap_Init(&mheap_, spansSize) + _g_ := getg() + _g_.m.mcache = allocmcache() +} + +// sysReserveHigh reserves space somewhere high in the address space. +// sysReserve doesn't actually reserve the full amount requested on +// 64-bit systems, because of problems with ulimit. Instead it checks +// that it can get the first 64 kB and assumes it can grab the rest as +// needed. This doesn't work well with the "let the kernel pick an address" +// mode, so don't do that. Pick a high address instead. +func sysReserveHigh(n uintptr, reserved *bool) unsafe.Pointer { + if ptrSize == 4 { + return sysReserve(nil, n, reserved) + } + + for i := 0; i <= 0x7f; i++ { + p := uintptr(i)<<40 | uintptrMask&(0x00c0<<32) + *reserved = false + p = uintptr(sysReserve(unsafe.Pointer(p), n, reserved)) + if p != 0 { + return unsafe.Pointer(p) + } + } + + return sysReserve(nil, n, reserved) +} + +func mHeap_SysAlloc(h *mheap, n uintptr) unsafe.Pointer { + if n > uintptr(h.arena_end)-uintptr(h.arena_used) { + // We are in 32-bit mode, maybe we didn't use all possible address space yet. + // Reserve some more space. + p_size := round(n+_PageSize, 256<<20) + new_end := h.arena_end + p_size + if new_end <= h.arena_start+_MaxArena32 { + // TODO: It would be bad if part of the arena + // is reserved and part is not. + var reserved bool + p := uintptr(sysReserve((unsafe.Pointer)(h.arena_end), p_size, &reserved)) + if p == h.arena_end { + h.arena_end = new_end + h.arena_reserved = reserved + } else if p+p_size <= h.arena_start+_MaxArena32 { + // Keep everything page-aligned. + // Our pages are bigger than hardware pages. + h.arena_end = p + p_size + h.arena_used = p + (-uintptr(p) & (_PageSize - 1)) + h.arena_reserved = reserved + } else { + var stat uint64 + sysFree((unsafe.Pointer)(p), p_size, &stat) + } + } + } + + if n <= uintptr(h.arena_end)-uintptr(h.arena_used) { + // Keep taking from our reservation. + p := h.arena_used + sysMap((unsafe.Pointer)(p), n, h.arena_reserved, &memstats.heap_sys) + h.arena_used += n + mHeap_MapBits(h) + mHeap_MapSpans(h) + if raceenabled { + racemapshadow((unsafe.Pointer)(p), n) + } + if mheap_.shadow_enabled { + sysMap(unsafe.Pointer(p+mheap_.shadow_heap), n, h.shadow_reserved, &memstats.other_sys) + } + + if uintptr(p)&(_PageSize-1) != 0 { + throw("misrounded allocation in MHeap_SysAlloc") + } + return (unsafe.Pointer)(p) + } + + // If using 64-bit, our reservation is all we have. + if uintptr(h.arena_end)-uintptr(h.arena_start) >= _MaxArena32 { + return nil + } + + // On 32-bit, once the reservation is gone we can + // try to get memory at a location chosen by the OS + // and hope that it is in the range we allocated bitmap for. + p_size := round(n, _PageSize) + _PageSize + p := uintptr(sysAlloc(p_size, &memstats.heap_sys)) + if p == 0 { + return nil + } + + if p < h.arena_start || uintptr(p)+p_size-uintptr(h.arena_start) >= _MaxArena32 { + print("runtime: memory allocated by OS (", p, ") not in usable range [", hex(h.arena_start), ",", hex(h.arena_start+_MaxArena32), ")\n") + sysFree((unsafe.Pointer)(p), p_size, &memstats.heap_sys) + return nil + } + + p_end := p + p_size + p += -p & (_PageSize - 1) + if uintptr(p)+n > uintptr(h.arena_used) { + h.arena_used = p + n + if p_end > h.arena_end { + h.arena_end = p_end + } + mHeap_MapBits(h) + mHeap_MapSpans(h) + if raceenabled { + racemapshadow((unsafe.Pointer)(p), n) + } + } + + if uintptr(p)&(_PageSize-1) != 0 { + throw("misrounded allocation in MHeap_SysAlloc") + } + return (unsafe.Pointer)(p) +} + // base address for all 0-byte allocations var zerobase uintptr -// Trigger the concurrent GC when 1/triggerratio memory is available to allocate. -// Adjust this ratio as part of a scheme to ensure that mutators have enough -// memory to allocate in durring a concurrent GC cycle. -var triggerratio = int64(8) - -// Determine whether to initiate a GC. -// If the GC is already working no need to trigger another one. -// This should establish a feedback loop where if the GC does not -// have sufficient time to complete then more memory will be -// requested from the OS increasing heap size thus allow future -// GCs more time to complete. -// memstat.heap_alloc and memstat.next_gc reads have benign races -// A false negative simple does not start a GC, a false positive -// will start a GC needlessly. Neither have correctness issues. -func shouldtriggergc() bool { - return triggerratio*(int64(memstats.next_gc)-int64(memstats.heap_alloc)) <= int64(memstats.next_gc) && atomicloaduint(&bggc.working) == 0 -} +const ( + // flags to malloc + _FlagNoScan = 1 << 0 // GC doesn't have to scan object + _FlagNoZero = 1 << 1 // don't zero memory +) // Allocate an object of size bytes. // Small objects are allocated from the per-P cache's free lists. @@ -250,6 +668,25 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer { return x } +func largeAlloc(size uintptr, flag uint32) *mspan { + // print("largeAlloc size=", size, "\n") + + if size+_PageSize < size { + throw("out of memory") + } + npages := size >> _PageShift + if size&_PageMask != 0 { + npages++ + } + s := mHeap_Alloc(&mheap_, npages, 0, true, flag&_FlagNoZero == 0) + if s == nil { + throw("out of memory") + } + s.limit = uintptr(s.start)<<_PageShift + size + heapBitsForSpan(s.base()).initSpan(s.layout()) + return s +} + // implementation of new builtin func newobject(typ *_type) unsafe.Pointer { flags := uint32(0) @@ -310,289 +747,6 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { mProf_Malloc(x, size) } -// For now this must be bracketed with a stoptheworld and a starttheworld to ensure -// all go routines see the new barrier. -//go:nowritebarrier -func gcinstallmarkwb() { - gcphase = _GCmark -} - -// force = 0 - start concurrent GC -// force = 1 - do STW GC regardless of current heap usage -// force = 2 - go STW GC and eager sweep -func gogc(force int32) { - // The gc is turned off (via enablegc) until the bootstrap has completed. - // Also, malloc gets called in the guts of a number of libraries that might be - // holding locks. To avoid deadlocks during stoptheworld, don't bother - // trying to run gc while holding a lock. The next mallocgc without a lock - // will do the gc instead. - - mp := acquirem() - if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 { - releasem(mp) - return - } - releasem(mp) - mp = nil - - if force == 0 { - lock(&bggc.lock) - if !bggc.started { - bggc.working = 1 - bggc.started = true - go backgroundgc() - } else if bggc.working == 0 { - bggc.working = 1 - ready(bggc.g) - } - unlock(&bggc.lock) - } else { - gcwork(force) - } -} - -func gcwork(force int32) { - - semacquire(&worldsema, false) - - // Pick up the remaining unswept/not being swept spans concurrently - for gosweepone() != ^uintptr(0) { - sweep.nbgsweep++ - } - - // Ok, we're doing it! Stop everybody else - - mp := acquirem() - mp.preemptoff = "gcing" - releasem(mp) - gctimer.count++ - if force == 0 { - gctimer.cycle.sweepterm = nanotime() - } - - if trace.enabled { - traceGoSched() - traceGCStart() - } - - // Pick up the remaining unswept/not being swept spans before we STW - for gosweepone() != ^uintptr(0) { - sweep.nbgsweep++ - } - systemstack(stoptheworld) - systemstack(finishsweep_m) // finish sweep before we start concurrent scan. - if force == 0 { // Do as much work concurrently as possible - gcphase = _GCscan - systemstack(starttheworld) - gctimer.cycle.scan = nanotime() - // Do a concurrent heap scan before we stop the world. - systemstack(gcscan_m) - gctimer.cycle.installmarkwb = nanotime() - systemstack(stoptheworld) - systemstack(gcinstallmarkwb) - systemstack(harvestwbufs) - systemstack(starttheworld) - gctimer.cycle.mark = nanotime() - systemstack(gcmark_m) - gctimer.cycle.markterm = nanotime() - systemstack(stoptheworld) - systemstack(gcinstalloffwb_m) - } else { - // For non-concurrent GC (force != 0) g stack have not been scanned so - // set gcscanvalid such that mark termination scans all stacks. - // No races here since we are in a STW phase. - for _, gp := range allgs { - gp.gcworkdone = false // set to true in gcphasework - gp.gcscanvalid = false // stack has not been scanned - } - } - - startTime := nanotime() - if mp != acquirem() { - throw("gogc: rescheduled") - } - - clearpools() - - // Run gc on the g0 stack. We do this so that the g stack - // we're currently running on will no longer change. Cuts - // the root set down a bit (g0 stacks are not scanned, and - // we don't need to scan gc's internal state). We also - // need to switch to g0 so we can shrink the stack. - n := 1 - if debug.gctrace > 1 { - n = 2 - } - eagersweep := force >= 2 - for i := 0; i < n; i++ { - if i > 0 { - // refresh start time if doing a second GC - startTime = nanotime() - } - // switch to g0, call gc, then switch back - systemstack(func() { - gc_m(startTime, eagersweep) - }) - } - - systemstack(func() { - gccheckmark_m(startTime, eagersweep) - }) - - if trace.enabled { - traceGCDone() - traceGoStart() - } - - // all done - mp.preemptoff = "" - - if force == 0 { - gctimer.cycle.sweep = nanotime() - } - - semrelease(&worldsema) - - if force == 0 { - if gctimer.verbose > 1 { - GCprinttimes() - } else if gctimer.verbose > 0 { - calctimes() // ignore result - } - } - - systemstack(starttheworld) - - releasem(mp) - mp = nil - - // now that gc is done, kick off finalizer thread if needed - if !concurrentSweep { - // give the queued finalizers, if any, a chance to run - Gosched() - } -} - -// gctimes records the time in nanoseconds of each phase of the concurrent GC. -type gctimes struct { - sweepterm int64 // stw - scan int64 - installmarkwb int64 // stw - mark int64 - markterm int64 // stw - sweep int64 -} - -// gcchronograph holds timer information related to GC phases -// max records the maximum time spent in each GC phase since GCstarttimes. -// total records the total time spent in each GC phase since GCstarttimes. -// cycle records the absolute time (as returned by nanoseconds()) that each GC phase last started at. -type gcchronograph struct { - count int64 - verbose int64 - maxpause int64 - max gctimes - total gctimes - cycle gctimes -} - -var gctimer gcchronograph - -// GCstarttimes initializes the gc times. All previous times are lost. -func GCstarttimes(verbose int64) { - gctimer = gcchronograph{verbose: verbose} -} - -// GCendtimes stops the gc timers. -func GCendtimes() { - gctimer.verbose = 0 -} - -// calctimes converts gctimer.cycle into the elapsed times, updates gctimer.total -// and updates gctimer.max with the max pause time. -func calctimes() gctimes { - var times gctimes - - var max = func(a, b int64) int64 { - if a > b { - return a - } - return b - } - - times.sweepterm = gctimer.cycle.scan - gctimer.cycle.sweepterm - gctimer.total.sweepterm += times.sweepterm - gctimer.max.sweepterm = max(gctimer.max.sweepterm, times.sweepterm) - gctimer.maxpause = max(gctimer.maxpause, gctimer.max.sweepterm) - - times.scan = gctimer.cycle.installmarkwb - gctimer.cycle.scan - gctimer.total.scan += times.scan - gctimer.max.scan = max(gctimer.max.scan, times.scan) - - times.installmarkwb = gctimer.cycle.mark - gctimer.cycle.installmarkwb - gctimer.total.installmarkwb += times.installmarkwb - gctimer.max.installmarkwb = max(gctimer.max.installmarkwb, times.installmarkwb) - gctimer.maxpause = max(gctimer.maxpause, gctimer.max.installmarkwb) - - times.mark = gctimer.cycle.markterm - gctimer.cycle.mark - gctimer.total.mark += times.mark - gctimer.max.mark = max(gctimer.max.mark, times.mark) - - times.markterm = gctimer.cycle.sweep - gctimer.cycle.markterm - gctimer.total.markterm += times.markterm - gctimer.max.markterm = max(gctimer.max.markterm, times.markterm) - gctimer.maxpause = max(gctimer.maxpause, gctimer.max.markterm) - - return times -} - -// GCprinttimes prints latency information in nanoseconds about various -// phases in the GC. The information for each phase includes the maximum pause -// and total time since the most recent call to GCstarttimes as well as -// the information from the most recent Concurent GC cycle. Calls from the -// application to runtime.GC() are ignored. -func GCprinttimes() { - if gctimer.verbose == 0 { - println("GC timers not enabled") - return - } - - // Explicitly put times on the heap so printPhase can use it. - times := new(gctimes) - *times = calctimes() - cycletime := gctimer.cycle.sweep - gctimer.cycle.sweepterm - pause := times.sweepterm + times.installmarkwb + times.markterm - gomaxprocs := GOMAXPROCS(-1) - - printlock() - print("GC: #", gctimer.count, " ", cycletime, "ns @", gctimer.cycle.sweepterm, " pause=", pause, " maxpause=", gctimer.maxpause, " goroutines=", allglen, " gomaxprocs=", gomaxprocs, "\n") - printPhase := func(label string, get func(*gctimes) int64, procs int) { - print("GC: ", label, " ", get(times), "ns\tmax=", get(&gctimer.max), "\ttotal=", get(&gctimer.total), "\tprocs=", procs, "\n") - } - printPhase("sweep term:", func(t *gctimes) int64 { return t.sweepterm }, gomaxprocs) - printPhase("scan: ", func(t *gctimes) int64 { return t.scan }, 1) - printPhase("install wb:", func(t *gctimes) int64 { return t.installmarkwb }, gomaxprocs) - printPhase("mark: ", func(t *gctimes) int64 { return t.mark }, 1) - printPhase("mark term: ", func(t *gctimes) int64 { return t.markterm }, gomaxprocs) - printunlock() -} - -// GC runs a garbage collection. -func GC() { - gogc(2) -} - -// linker-provided -var noptrdata struct{} -var enoptrdata struct{} -var noptrbss struct{} -var enoptrbss struct{} - -// round n up to a multiple of a. a must be a power of 2. -func round(n, a uintptr) uintptr { - return (n + a - 1) &^ (a - 1) -} - var persistent struct { lock mutex base unsafe.Pointer diff --git a/src/runtime/malloc1.go b/src/runtime/malloc1.go deleted file mode 100644 index 18d998b554..0000000000 --- a/src/runtime/malloc1.go +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// See malloc.h for overview. -// -// TODO(rsc): double-check stats. - -package runtime - -import "unsafe" - -const _MaxArena32 = 2 << 30 - -// For use by Go. If it were a C enum it would be made available automatically, -// but the value of MaxMem is too large for enum. -// XXX - uintptr runtime·maxmem = MaxMem; - -func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 { - _g_ := getg() - - _g_.m.mcache.local_nlookup++ - if ptrSize == 4 && _g_.m.mcache.local_nlookup >= 1<<30 { - // purge cache stats to prevent overflow - lock(&mheap_.lock) - purgecachedstats(_g_.m.mcache) - unlock(&mheap_.lock) - } - - s := mHeap_LookupMaybe(&mheap_, unsafe.Pointer(v)) - if sp != nil { - *sp = s - } - if s == nil { - if base != nil { - *base = 0 - } - if size != nil { - *size = 0 - } - return 0 - } - - p := uintptr(s.start) << _PageShift - if s.sizeclass == 0 { - // Large object. - if base != nil { - *base = p - } - if size != nil { - *size = s.npages << _PageShift - } - return 1 - } - - n := s.elemsize - if base != nil { - i := (uintptr(v) - uintptr(p)) / n - *base = p + i*n - } - if size != nil { - *size = n - } - - return 1 -} - -//go:nosplit -func purgecachedstats(c *mcache) { - // Protected by either heap or GC lock. - h := &mheap_ - memstats.heap_alloc += uint64(c.local_cachealloc) - c.local_cachealloc = 0 - if trace.enabled { - traceHeapAlloc() - } - memstats.tinyallocs += uint64(c.local_tinyallocs) - c.local_tinyallocs = 0 - memstats.nlookup += uint64(c.local_nlookup) - c.local_nlookup = 0 - h.largefree += uint64(c.local_largefree) - c.local_largefree = 0 - h.nlargefree += uint64(c.local_nlargefree) - c.local_nlargefree = 0 - for i := 0; i < len(c.local_nsmallfree); i++ { - h.nsmallfree[i] += uint64(c.local_nsmallfree[i]) - c.local_nsmallfree[i] = 0 - } -} - -func mallocinit() { - initSizes() - - if class_to_size[_TinySizeClass] != _TinySize { - throw("bad TinySizeClass") - } - - var p, bitmapSize, spansSize, pSize, limit uintptr - var reserved bool - - // limit = runtime.memlimit(); - // See https://golang.org/issue/5049 - // TODO(rsc): Fix after 1.1. - limit = 0 - - // Set up the allocation arena, a contiguous area of memory where - // allocated data will be found. The arena begins with a bitmap large - // enough to hold 4 bits per allocated word. - if ptrSize == 8 && (limit == 0 || limit > 1<<30) { - // On a 64-bit machine, allocate from a single contiguous reservation. - // 128 GB (MaxMem) should be big enough for now. - // - // The code will work with the reservation at any address, but ask - // SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f). - // Allocating a 128 GB region takes away 37 bits, and the amd64 - // doesn't let us choose the top 17 bits, so that leaves the 11 bits - // in the middle of 0x00c0 for us to choose. Choosing 0x00c0 means - // that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df. - // In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid - // UTF-8 sequences, and they are otherwise as far away from - // ff (likely a common byte) as possible. If that fails, we try other 0xXXc0 - // addresses. An earlier attempt to use 0x11f8 caused out of memory errors - // on OS X during thread allocations. 0x00c0 causes conflicts with - // AddressSanitizer which reserves all memory up to 0x0100. - // These choices are both for debuggability and to reduce the - // odds of the conservative garbage collector not collecting memory - // because some non-pointer block of memory had a bit pattern - // that matched a memory address. - // - // Actually we reserve 136 GB (because the bitmap ends up being 8 GB) - // but it hardly matters: e0 00 is not valid UTF-8 either. - // - // If this fails we fall back to the 32 bit memory mechanism - arenaSize := round(_MaxMem, _PageSize) - bitmapSize = arenaSize / (ptrSize * 8 / 4) - spansSize = arenaSize / _PageSize * ptrSize - spansSize = round(spansSize, _PageSize) - for i := 0; i <= 0x7f; i++ { - p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32) - pSize = bitmapSize + spansSize + arenaSize + _PageSize - p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved)) - if p != 0 { - break - } - } - } - - if p == 0 { - // On a 32-bit machine, we can't typically get away - // with a giant virtual address space reservation. - // Instead we map the memory information bitmap - // immediately after the data segment, large enough - // to handle another 2GB of mappings (256 MB), - // along with a reservation for an initial arena. - // When that gets used up, we'll start asking the kernel - // for any memory anywhere and hope it's in the 2GB - // following the bitmap (presumably the executable begins - // near the bottom of memory, so we'll have to use up - // most of memory before the kernel resorts to giving out - // memory before the beginning of the text segment). - // - // Alternatively we could reserve 512 MB bitmap, enough - // for 4GB of mappings, and then accept any memory the - // kernel threw at us, but normally that's a waste of 512 MB - // of address space, which is probably too much in a 32-bit world. - - // If we fail to allocate, try again with a smaller arena. - // This is necessary on Android L where we share a process - // with ART, which reserves virtual memory aggressively. - arenaSizes := []uintptr{ - 512 << 20, - 256 << 20, - } - - for _, arenaSize := range arenaSizes { - bitmapSize = _MaxArena32 / (ptrSize * 8 / 4) - spansSize = _MaxArena32 / _PageSize * ptrSize - if limit > 0 && arenaSize+bitmapSize+spansSize > limit { - bitmapSize = (limit / 9) &^ ((1 << _PageShift) - 1) - arenaSize = bitmapSize * 8 - spansSize = arenaSize / _PageSize * ptrSize - } - spansSize = round(spansSize, _PageSize) - - // SysReserve treats the address we ask for, end, as a hint, - // not as an absolute requirement. If we ask for the end - // of the data segment but the operating system requires - // a little more space before we can start allocating, it will - // give out a slightly higher pointer. Except QEMU, which - // is buggy, as usual: it won't adjust the pointer upward. - // So adjust it upward a little bit ourselves: 1/4 MB to get - // away from the running binary image and then round up - // to a MB boundary. - p = round(uintptr(unsafe.Pointer(&end))+(1<<18), 1<<20) - pSize = bitmapSize + spansSize + arenaSize + _PageSize - p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved)) - if p != 0 { - break - } - } - if p == 0 { - throw("runtime: cannot reserve arena virtual address space") - } - } - - // PageSize can be larger than OS definition of page size, - // so SysReserve can give us a PageSize-unaligned pointer. - // To overcome this we ask for PageSize more and round up the pointer. - p1 := round(p, _PageSize) - - mheap_.spans = (**mspan)(unsafe.Pointer(p1)) - mheap_.bitmap = p1 + spansSize - mheap_.arena_start = p1 + (spansSize + bitmapSize) - mheap_.arena_used = mheap_.arena_start - mheap_.arena_end = p + pSize - mheap_.arena_reserved = reserved - - if mheap_.arena_start&(_PageSize-1) != 0 { - println("bad pagesize", hex(p), hex(p1), hex(spansSize), hex(bitmapSize), hex(_PageSize), "start", hex(mheap_.arena_start)) - throw("misrounded allocation in mallocinit") - } - - // Initialize the rest of the allocator. - mHeap_Init(&mheap_, spansSize) - _g_ := getg() - _g_.m.mcache = allocmcache() -} - -// sysReserveHigh reserves space somewhere high in the address space. -// sysReserve doesn't actually reserve the full amount requested on -// 64-bit systems, because of problems with ulimit. Instead it checks -// that it can get the first 64 kB and assumes it can grab the rest as -// needed. This doesn't work well with the "let the kernel pick an address" -// mode, so don't do that. Pick a high address instead. -func sysReserveHigh(n uintptr, reserved *bool) unsafe.Pointer { - if ptrSize == 4 { - return sysReserve(nil, n, reserved) - } - - for i := 0; i <= 0x7f; i++ { - p := uintptr(i)<<40 | uintptrMask&(0x00c0<<32) - *reserved = false - p = uintptr(sysReserve(unsafe.Pointer(p), n, reserved)) - if p != 0 { - return unsafe.Pointer(p) - } - } - - return sysReserve(nil, n, reserved) -} - -func mHeap_SysAlloc(h *mheap, n uintptr) unsafe.Pointer { - if n > uintptr(h.arena_end)-uintptr(h.arena_used) { - // We are in 32-bit mode, maybe we didn't use all possible address space yet. - // Reserve some more space. - p_size := round(n+_PageSize, 256<<20) - new_end := h.arena_end + p_size - if new_end <= h.arena_start+_MaxArena32 { - // TODO: It would be bad if part of the arena - // is reserved and part is not. - var reserved bool - p := uintptr(sysReserve((unsafe.Pointer)(h.arena_end), p_size, &reserved)) - if p == h.arena_end { - h.arena_end = new_end - h.arena_reserved = reserved - } else if p+p_size <= h.arena_start+_MaxArena32 { - // Keep everything page-aligned. - // Our pages are bigger than hardware pages. - h.arena_end = p + p_size - h.arena_used = p + (-uintptr(p) & (_PageSize - 1)) - h.arena_reserved = reserved - } else { - var stat uint64 - sysFree((unsafe.Pointer)(p), p_size, &stat) - } - } - } - - if n <= uintptr(h.arena_end)-uintptr(h.arena_used) { - // Keep taking from our reservation. - p := h.arena_used - sysMap((unsafe.Pointer)(p), n, h.arena_reserved, &memstats.heap_sys) - h.arena_used += n - mHeap_MapBits(h) - mHeap_MapSpans(h) - if raceenabled { - racemapshadow((unsafe.Pointer)(p), n) - } - if mheap_.shadow_enabled { - sysMap(unsafe.Pointer(p+mheap_.shadow_heap), n, h.shadow_reserved, &memstats.other_sys) - } - - if uintptr(p)&(_PageSize-1) != 0 { - throw("misrounded allocation in MHeap_SysAlloc") - } - return (unsafe.Pointer)(p) - } - - // If using 64-bit, our reservation is all we have. - if uintptr(h.arena_end)-uintptr(h.arena_start) >= _MaxArena32 { - return nil - } - - // On 32-bit, once the reservation is gone we can - // try to get memory at a location chosen by the OS - // and hope that it is in the range we allocated bitmap for. - p_size := round(n, _PageSize) + _PageSize - p := uintptr(sysAlloc(p_size, &memstats.heap_sys)) - if p == 0 { - return nil - } - - if p < h.arena_start || uintptr(p)+p_size-uintptr(h.arena_start) >= _MaxArena32 { - print("runtime: memory allocated by OS (", p, ") not in usable range [", hex(h.arena_start), ",", hex(h.arena_start+_MaxArena32), ")\n") - sysFree((unsafe.Pointer)(p), p_size, &memstats.heap_sys) - return nil - } - - p_end := p + p_size - p += -p & (_PageSize - 1) - if uintptr(p)+n > uintptr(h.arena_used) { - h.arena_used = p + n - if p_end > h.arena_end { - h.arena_end = p_end - } - mHeap_MapBits(h) - mHeap_MapSpans(h) - if raceenabled { - racemapshadow((unsafe.Pointer)(p), n) - } - } - - if uintptr(p)&(_PageSize-1) != 0 { - throw("misrounded allocation in MHeap_SysAlloc") - } - return (unsafe.Pointer)(p) -} - -var end struct{} - -func largeAlloc(size uintptr, flag uint32) *mspan { - // print("largeAlloc size=", size, "\n") - - if size+_PageSize < size { - throw("out of memory") - } - npages := size >> _PageShift - if size&_PageMask != 0 { - npages++ - } - s := mHeap_Alloc(&mheap_, npages, 0, true, flag&_FlagNoZero == 0) - if s == nil { - throw("out of memory") - } - s.limit = uintptr(s.start)<<_PageShift + size - heapBitsForSpan(s.base()).initSpan(s.layout()) - return s -} diff --git a/src/runtime/malloc2.go b/src/runtime/malloc2.go deleted file mode 100644 index 14ffbdbb8e..0000000000 --- a/src/runtime/malloc2.go +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -// Memory allocator, based on tcmalloc. -// http://goog-perftools.sourceforge.net/doc/tcmalloc.html - -// The main allocator works in runs of pages. -// Small allocation sizes (up to and including 32 kB) are -// rounded to one of about 100 size classes, each of which -// has its own free list of objects of exactly that size. -// Any free page of memory can be split into a set of objects -// of one size class, which are then managed using free list -// allocators. -// -// The allocator's data structures are: -// -// FixAlloc: a free-list allocator for fixed-size objects, -// used to manage storage used by the allocator. -// MHeap: the malloc heap, managed at page (4096-byte) granularity. -// MSpan: a run of pages managed by the MHeap. -// MCentral: a shared free list for a given size class. -// MCache: a per-thread (in Go, per-P) cache for small objects. -// MStats: allocation statistics. -// -// Allocating a small object proceeds up a hierarchy of caches: -// -// 1. Round the size up to one of the small size classes -// and look in the corresponding MCache free list. -// If the list is not empty, allocate an object from it. -// This can all be done without acquiring a lock. -// -// 2. If the MCache free list is empty, replenish it by -// taking a bunch of objects from the MCentral free list. -// Moving a bunch amortizes the cost of acquiring the MCentral lock. -// -// 3. If the MCentral free list is empty, replenish it by -// allocating a run of pages from the MHeap and then -// chopping that memory into objects of the given size. -// Allocating many objects amortizes the cost of locking -// the heap. -// -// 4. If the MHeap is empty or has no page runs large enough, -// allocate a new group of pages (at least 1MB) from the -// operating system. Allocating a large run of pages -// amortizes the cost of talking to the operating system. -// -// Freeing a small object proceeds up the same hierarchy: -// -// 1. Look up the size class for the object and add it to -// the MCache free list. -// -// 2. If the MCache free list is too long or the MCache has -// too much memory, return some to the MCentral free lists. -// -// 3. If all the objects in a given span have returned to -// the MCentral list, return that span to the page heap. -// -// 4. If the heap has too much memory, return some to the -// operating system. -// -// TODO(rsc): Step 4 is not implemented. -// -// Allocating and freeing a large object uses the page heap -// directly, bypassing the MCache and MCentral free lists. -// -// The small objects on the MCache and MCentral free lists -// may or may not be zeroed. They are zeroed if and only if -// the second word of the object is zero. A span in the -// page heap is zeroed unless s->needzero is set. When a span -// is allocated to break into small objects, it is zeroed if needed -// and s->needzero is set. There are two main benefits to delaying the -// zeroing this way: -// -// 1. stack frames allocated from the small object lists -// or the page heap can avoid zeroing altogether. -// 2. the cost of zeroing when reusing a small object is -// charged to the mutator, not the garbage collector. -// -// This C code was written with an eye toward translating to Go -// in the future. Methods have the form Type_Method(Type *t, ...). - -const ( - _PageShift = 13 - _PageSize = 1 << _PageShift - _PageMask = _PageSize - 1 -) - -const ( - // _64bit = 1 on 64-bit systems, 0 on 32-bit systems - _64bit = 1 << (^uintptr(0) >> 63) / 2 - - // Computed constant. The definition of MaxSmallSize and the - // algorithm in msize.c produce some number of different allocation - // size classes. NumSizeClasses is that number. It's needed here - // because there are static arrays of this length; when msize runs its - // size choosing algorithm it double-checks that NumSizeClasses agrees. - _NumSizeClasses = 67 - - // Tunable constants. - _MaxSmallSize = 32 << 10 - - // Tiny allocator parameters, see "Tiny allocator" comment in malloc.go. - _TinySize = 16 - _TinySizeClass = 2 - - _FixAllocChunk = 16 << 10 // Chunk size for FixAlloc - _MaxMHeapList = 1 << (20 - _PageShift) // Maximum page length for fixed-size list in MHeap. - _HeapAllocChunk = 1 << 20 // Chunk size for heap growth - - // Per-P, per order stack segment cache size. - _StackCacheSize = 32 * 1024 - - // Number of orders that get caching. Order 0 is FixedStack - // and each successive order is twice as large. - // We want to cache 2KB, 4KB, 8KB, and 16KB stacks. Larger stacks - // will be allocated directly. - // Since FixedStack is different on different systems, we - // must vary NumStackOrders to keep the same maximum cached size. - // OS | FixedStack | NumStackOrders - // -----------------+------------+--------------- - // linux/darwin/bsd | 2KB | 4 - // windows/32 | 4KB | 3 - // windows/64 | 8KB | 2 - // plan9 | 4KB | 3 - _NumStackOrders = 4 - ptrSize/4*goos_windows - 1*goos_plan9 - - // Number of bits in page to span calculations (4k pages). - // On Windows 64-bit we limit the arena to 32GB or 35 bits. - // Windows counts memory used by page table into committed memory - // of the process, so we can't reserve too much memory. - // See http://golang.org/issue/5402 and http://golang.org/issue/5236. - // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits. - // On 32-bit, we don't bother limiting anything, so we use the full 32-bit address. - _MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows))*37 + (1-_64bit)*32 - _MHeapMap_Bits = _MHeapMap_TotalBits - _PageShift - - _MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1) - - // Max number of threads to run garbage collection. - // 2, 3, and 4 are all plausible maximums depending - // on the hardware details of the machine. The garbage - // collector scales well to 32 cpus. - _MaxGcproc = 32 -) - -// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) -// Since assignments to mlink.next will result in a write barrier being preformed -// this can not be used by some of the internal GC structures. For example when -// the sweeper is placing an unmarked object on the free list it does not want the -// write barrier to be called since that could result in the object being reachable. -type mlink struct { - next *mlink -} - -// A gclink is a node in a linked list of blocks, like mlink, -// but it is opaque to the garbage collector. -// The GC does not trace the pointers during collection, -// and the compiler does not emit write barriers for assignments -// of gclinkptr values. Code should store references to gclinks -// as gclinkptr, not as *gclink. -type gclink struct { - next gclinkptr -} - -// A gclinkptr is a pointer to a gclink, but it is opaque -// to the garbage collector. -type gclinkptr uintptr - -// ptr returns the *gclink form of p. -// The result should be used for accessing fields, not stored -// in other data structures. -func (p gclinkptr) ptr() *gclink { - return (*gclink)(unsafe.Pointer(p)) -} - -// sysAlloc obtains a large chunk of zeroed memory from the -// operating system, typically on the order of a hundred kilobytes -// or a megabyte. -// NOTE: sysAlloc returns OS-aligned memory, but the heap allocator -// may use larger alignment, so the caller must be careful to realign the -// memory obtained by sysAlloc. -// -// SysUnused notifies the operating system that the contents -// of the memory region are no longer needed and can be reused -// for other purposes. -// SysUsed notifies the operating system that the contents -// of the memory region are needed again. -// -// SysFree returns it unconditionally; this is only used if -// an out-of-memory error has been detected midway through -// an allocation. It is okay if SysFree is a no-op. -// -// SysReserve reserves address space without allocating memory. -// If the pointer passed to it is non-nil, the caller wants the -// reservation there, but SysReserve can still choose another -// location if that one is unavailable. On some systems and in some -// cases SysReserve will simply check that the address space is -// available and not actually reserve it. If SysReserve returns -// non-nil, it sets *reserved to true if the address space is -// reserved, false if it has merely been checked. -// NOTE: SysReserve returns OS-aligned memory, but the heap allocator -// may use larger alignment, so the caller must be careful to realign the -// memory obtained by sysAlloc. -// -// SysMap maps previously reserved address space for use. -// The reserved argument is true if the address space was really -// reserved, not merely checked. -// -// SysFault marks a (already sysAlloc'd) region to fault -// if accessed. Used only for debugging the runtime. - -// FixAlloc is a simple free-list allocator for fixed size objects. -// Malloc uses a FixAlloc wrapped around sysAlloc to manages its -// MCache and MSpan objects. -// -// Memory returned by FixAlloc_Alloc is not zeroed. -// The caller is responsible for locking around FixAlloc calls. -// Callers can keep state in the object but the first word is -// smashed by freeing and reallocating. -type fixalloc struct { - size uintptr - first unsafe.Pointer // go func(unsafe.pointer, unsafe.pointer); f(arg, p) called first time p is returned - arg unsafe.Pointer - list *mlink - chunk *byte - nchunk uint32 - inuse uintptr // in-use bytes now - stat *uint64 -} - -// Statistics. -// Shared with Go: if you edit this structure, also edit type MemStats in mem.go. -type mstats struct { - // General statistics. - alloc uint64 // bytes allocated and still in use - total_alloc uint64 // bytes allocated (even if freed) - sys uint64 // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate) - nlookup uint64 // number of pointer lookups - nmalloc uint64 // number of mallocs - nfree uint64 // number of frees - - // Statistics about malloc heap. - // protected by mheap.lock - heap_alloc uint64 // bytes allocated and still in use - heap_sys uint64 // bytes obtained from system - heap_idle uint64 // bytes in idle spans - heap_inuse uint64 // bytes in non-idle spans - heap_released uint64 // bytes released to the os - heap_objects uint64 // total number of allocated objects - - // Statistics about allocation of low-level fixed-size structures. - // Protected by FixAlloc locks. - stacks_inuse uint64 // this number is included in heap_inuse above - stacks_sys uint64 // always 0 in mstats - mspan_inuse uint64 // mspan structures - mspan_sys uint64 - mcache_inuse uint64 // mcache structures - mcache_sys uint64 - buckhash_sys uint64 // profiling bucket hash table - gc_sys uint64 - other_sys uint64 - - // Statistics about garbage collector. - // Protected by mheap or stopping the world during GC. - next_gc uint64 // next gc (in heap_alloc time) - last_gc uint64 // last gc (in absolute time) - pause_total_ns uint64 - pause_ns [256]uint64 // circular buffer of recent gc pause lengths - pause_end [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970) - numgc uint32 - enablegc bool - debuggc bool - - // Statistics about allocation size classes. - - by_size [_NumSizeClasses]struct { - size uint32 - nmalloc uint64 - nfree uint64 - } - - tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly -} - -var memstats mstats - -// Size classes. Computed and initialized by InitSizes. -// -// SizeToClass(0 <= n <= MaxSmallSize) returns the size class, -// 1 <= sizeclass < NumSizeClasses, for n. -// Size class 0 is reserved to mean "not small". -// -// class_to_size[i] = largest size in class i -// class_to_allocnpages[i] = number of pages to allocate when -// making new objects in class i - -var class_to_size [_NumSizeClasses]int32 -var class_to_allocnpages [_NumSizeClasses]int32 -var size_to_class8 [1024/8 + 1]int8 -var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8 - -type mcachelist struct { - list *mlink - nlist uint32 -} - -type stackfreelist struct { - list gclinkptr // linked list of free stacks - size uintptr // total size of stacks in list -} - -// Per-thread (in Go, per-P) cache for small objects. -// No locking needed because it is per-thread (per-P). -type mcache struct { - // The following members are accessed on every malloc, - // so they are grouped here for better caching. - next_sample int32 // trigger heap sample after allocating this many bytes - local_cachealloc intptr // bytes allocated (or freed) from cache since last lock of heap - // Allocator cache for tiny objects w/o pointers. - // See "Tiny allocator" comment in malloc.go. - tiny unsafe.Pointer - tinyoffset uintptr - local_tinyallocs uintptr // number of tiny allocs not counted in other stats - - // The rest is not accessed on every malloc. - alloc [_NumSizeClasses]*mspan // spans to allocate from - - stackcache [_NumStackOrders]stackfreelist - - sudogcache *sudog - - // Local allocator stats, flushed during GC. - local_nlookup uintptr // number of pointer lookups - local_largefree uintptr // bytes freed for large objects (>maxsmallsize) - local_nlargefree uintptr // number of frees for large objects (>maxsmallsize) - local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize) -} - -const ( - _KindSpecialFinalizer = 1 - _KindSpecialProfile = 2 - // Note: The finalizer special must be first because if we're freeing - // an object, a finalizer special will cause the freeing operation - // to abort, and we want to keep the other special records around - // if that happens. -) - -type special struct { - next *special // linked list in span - offset uint16 // span offset of object - kind byte // kind of special -} - -// The described object has a finalizer set for it. -type specialfinalizer struct { - special special - fn *funcval - nret uintptr - fint *_type - ot *ptrtype -} - -// The described object is being heap profiled. -type specialprofile struct { - special special - b *bucket -} - -// An MSpan is a run of pages. -const ( - _MSpanInUse = iota // allocated for garbage collected heap - _MSpanStack // allocated for use by stack allocator - _MSpanFree - _MSpanListHead - _MSpanDead -) - -type mspan struct { - next *mspan // in a span linked list - prev *mspan // in a span linked list - start pageID // starting page number - npages uintptr // number of pages in span - freelist gclinkptr // list of free objects - // sweep generation: - // if sweepgen == h->sweepgen - 2, the span needs sweeping - // if sweepgen == h->sweepgen - 1, the span is currently being swept - // if sweepgen == h->sweepgen, the span is swept and ready to use - // h->sweepgen is incremented by 2 after every GC - sweepgen uint32 - ref uint16 // capacity - number of objects in freelist - sizeclass uint8 // size class - incache bool // being used by an mcache - state uint8 // mspaninuse etc - needzero uint8 // needs to be zeroed before allocation - elemsize uintptr // computed from sizeclass or from npages - unusedsince int64 // first time spotted by gc in mspanfree state - npreleased uintptr // number of pages released to the os - limit uintptr // end of data in span - speciallock mutex // guards specials list - specials *special // linked list of special records sorted by offset. -} - -func (s *mspan) base() uintptr { - return uintptr(s.start << _PageShift) -} - -func (s *mspan) layout() (size, n, total uintptr) { - total = s.npages << _PageShift - size = s.elemsize - if size > 0 { - n = total / size - } - return -} - -// Every MSpan is in one doubly-linked list, -// either one of the MHeap's free lists or one of the -// MCentral's span lists. We use empty MSpan structures as list heads. - -// Central list of free objects of a given size. -type mcentral struct { - lock mutex - sizeclass int32 - nonempty mspan // list of spans with a free object - empty mspan // list of spans with no free objects (or cached in an mcache) -} - -// Main malloc heap. -// The heap itself is the "free[]" and "large" arrays, -// but all the other global data is here too. -type mheap struct { - lock mutex - free [_MaxMHeapList]mspan // free lists of given length - freelarge mspan // free lists length >= _MaxMHeapList - busy [_MaxMHeapList]mspan // busy lists of large objects of given length - busylarge mspan // busy lists of large objects length >= _MaxMHeapList - allspans **mspan // all spans out there - gcspans **mspan // copy of allspans referenced by gc marker or sweeper - nspan uint32 - sweepgen uint32 // sweep generation, see comment in mspan - sweepdone uint32 // all spans are swept - - // span lookup - spans **mspan - spans_mapped uintptr - - // range of addresses we might see in the heap - bitmap uintptr - bitmap_mapped uintptr - arena_start uintptr - arena_used uintptr - arena_end uintptr - arena_reserved bool - - // write barrier shadow data+heap. - // 64-bit systems only, enabled by GODEBUG=wbshadow=1. - shadow_enabled bool // shadow should be updated and checked - shadow_reserved bool // shadow memory is reserved - shadow_heap uintptr // heap-addr + shadow_heap = shadow heap addr - shadow_data uintptr // data-addr + shadow_data = shadow data addr - data_start uintptr // start of shadowed data addresses - data_end uintptr // end of shadowed data addresses - - // central free lists for small size classes. - // the padding makes sure that the MCentrals are - // spaced CacheLineSize bytes apart, so that each MCentral.lock - // gets its own cache line. - central [_NumSizeClasses]struct { - mcentral mcentral - pad [_CacheLineSize]byte - } - - spanalloc fixalloc // allocator for span* - cachealloc fixalloc // allocator for mcache* - specialfinalizeralloc fixalloc // allocator for specialfinalizer* - specialprofilealloc fixalloc // allocator for specialprofile* - speciallock mutex // lock for sepcial record allocators. - - // Malloc stats. - largefree uint64 // bytes freed for large objects (>maxsmallsize) - nlargefree uint64 // number of frees for large objects (>maxsmallsize) - nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize) -} - -var mheap_ mheap - -const ( - // flags to malloc - _FlagNoScan = 1 << 0 // GC doesn't have to scan object - _FlagNoZero = 1 << 1 // don't zero memory -) - -// NOTE: Layout known to queuefinalizer. -type finalizer struct { - fn *funcval // function to call - arg unsafe.Pointer // ptr to object - nret uintptr // bytes of return values from fn - fint *_type // type of first argument of fn - ot *ptrtype // type of ptr to object -} - -type finblock struct { - alllink *finblock - next *finblock - cnt int32 - _ int32 - fin [(_FinBlockSize - 2*ptrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer -} - -// Information from the compiler about the layout of stack frames. -type bitvector struct { - n int32 // # of bits - bytedata *uint8 -} - -type stackmap struct { - n int32 // number of bitmaps - nbit int32 // number of bits in each bitmap - bytedata [1]byte // bitmaps, each starting on a 32-bit boundary -} diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index d73fe60a78..dce0bd59ff 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -82,6 +82,12 @@ const ( typeShift = 2 ) +// Information from the compiler about the layout of stack frames. +type bitvector struct { + n int32 // # of bits + bytedata *uint8 +} + // addb returns the byte pointer p+n. //go:nowritebarrier func addb(p *byte, n uintptr) *byte { diff --git a/src/runtime/mcache.go b/src/runtime/mcache.go index d93a50dea3..ec9ccb4abb 100644 --- a/src/runtime/mcache.go +++ b/src/runtime/mcache.go @@ -2,14 +2,63 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Per-P malloc cache for small objects. -// -// See malloc.h for an overview. - package runtime import "unsafe" +// Per-thread (in Go, per-P) cache for small objects. +// No locking needed because it is per-thread (per-P). +type mcache struct { + // The following members are accessed on every malloc, + // so they are grouped here for better caching. + next_sample int32 // trigger heap sample after allocating this many bytes + local_cachealloc intptr // bytes allocated (or freed) from cache since last lock of heap + // Allocator cache for tiny objects w/o pointers. + // See "Tiny allocator" comment in malloc.go. + tiny unsafe.Pointer + tinyoffset uintptr + local_tinyallocs uintptr // number of tiny allocs not counted in other stats + + // The rest is not accessed on every malloc. + alloc [_NumSizeClasses]*mspan // spans to allocate from + + stackcache [_NumStackOrders]stackfreelist + + sudogcache *sudog + + // Local allocator stats, flushed during GC. + local_nlookup uintptr // number of pointer lookups + local_largefree uintptr // bytes freed for large objects (>maxsmallsize) + local_nlargefree uintptr // number of frees for large objects (>maxsmallsize) + local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize) +} + +// A gclink is a node in a linked list of blocks, like mlink, +// but it is opaque to the garbage collector. +// The GC does not trace the pointers during collection, +// and the compiler does not emit write barriers for assignments +// of gclinkptr values. Code should store references to gclinks +// as gclinkptr, not as *gclink. +type gclink struct { + next gclinkptr +} + +// A gclinkptr is a pointer to a gclink, but it is opaque +// to the garbage collector. +type gclinkptr uintptr + +// ptr returns the *gclink form of p. +// The result should be used for accessing fields, not stored +// in other data structures. +func (p gclinkptr) ptr() *gclink { + return (*gclink)(unsafe.Pointer(p)) +} + +type stackfreelist struct { + list gclinkptr // linked list of free stacks + size uintptr // total size of stacks in list +} + // dummy MSpan that contains no free objects. var emptymspan mspan diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go index 45e7553b1a..965cd10586 100644 --- a/src/runtime/mcentral.go +++ b/src/runtime/mcentral.go @@ -12,6 +12,14 @@ package runtime +// Central list of free objects of a given size. +type mcentral struct { + lock mutex + sizeclass int32 + nonempty mspan // list of spans with a free object + empty mspan // list of spans with no free objects (or cached in an mcache) +} + // Initialize a single central free list. func mCentral_Init(c *mcentral, sizeclass int32) { c.sizeclass = sizeclass diff --git a/src/runtime/mem.go b/src/runtime/mem.go deleted file mode 100644 index c145886eed..0000000000 --- a/src/runtime/mem.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -// Note: the MemStats struct should be kept in sync with -// struct MStats in malloc.h - -// A MemStats records statistics about the memory allocator. -type MemStats struct { - // General statistics. - Alloc uint64 // bytes allocated and still in use - TotalAlloc uint64 // bytes allocated (even if freed) - Sys uint64 // bytes obtained from system (sum of XxxSys below) - Lookups uint64 // number of pointer lookups - Mallocs uint64 // number of mallocs - Frees uint64 // number of frees - - // Main allocation heap statistics. - HeapAlloc uint64 // bytes allocated and still in use - HeapSys uint64 // bytes obtained from system - HeapIdle uint64 // bytes in idle spans - HeapInuse uint64 // bytes in non-idle span - HeapReleased uint64 // bytes released to the OS - HeapObjects uint64 // total number of allocated objects - - // Low-level fixed-size structure allocator statistics. - // Inuse is bytes used now. - // Sys is bytes obtained from system. - StackInuse uint64 // bytes used by stack allocator - StackSys uint64 - MSpanInuse uint64 // mspan structures - MSpanSys uint64 - MCacheInuse uint64 // mcache structures - MCacheSys uint64 - BuckHashSys uint64 // profiling bucket hash table - GCSys uint64 // GC metadata - OtherSys uint64 // other system allocations - - // Garbage collector statistics. - NextGC uint64 // next collection will happen when HeapAlloc ≥ this amount - LastGC uint64 // end time of last collection (nanoseconds since 1970) - PauseTotalNs uint64 - PauseNs [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256] - PauseEnd [256]uint64 // circular buffer of recent GC pause end times - NumGC uint32 - EnableGC bool - DebugGC bool - - // Per-size allocation statistics. - // 61 is NumSizeClasses in the C code. - BySize [61]struct { - Size uint32 - Mallocs uint64 - Frees uint64 - } -} - -// Size of the trailing by_size array differs between Go and C, -// and all data after by_size is local to runtime, not exported. -// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. -// sizeof_C_MStats is what C thinks about size of Go struct. -var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0]) - -func init() { - var memStats MemStats - if sizeof_C_MStats != unsafe.Sizeof(memStats) { - println(sizeof_C_MStats, unsafe.Sizeof(memStats)) - throw("MStats vs MemStatsType size mismatch") - } -} - -// ReadMemStats populates m with memory allocator statistics. -func ReadMemStats(m *MemStats) { - // Have to acquire worldsema to stop the world, - // because stoptheworld can only be used by - // one goroutine at a time, and there might be - // a pending garbage collection already calling it. - semacquire(&worldsema, false) - gp := getg() - gp.m.preemptoff = "read mem stats" - systemstack(stoptheworld) - - systemstack(func() { - readmemstats_m(m) - }) - - gp.m.preemptoff = "" - gp.m.locks++ - semrelease(&worldsema) - systemstack(starttheworld) - gp.m.locks-- -} - -//go:linkname runtime_debug_WriteHeapDump runtime/debug.WriteHeapDump -func runtime_debug_WriteHeapDump(fd uintptr) { - semacquire(&worldsema, false) - gp := getg() - gp.m.preemptoff = "write heap dump" - systemstack(stoptheworld) - - systemstack(func() { - writeheapdump_m(fd) - }) - - gp.m.preemptoff = "" - gp.m.locks++ - semrelease(&worldsema) - systemstack(starttheworld) - gp.m.locks-- -} diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index 525aa0955a..d066b609b7 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -8,6 +8,14 @@ package runtime import "unsafe" +type finblock struct { + alllink *finblock + next *finblock + cnt int32 + _ int32 + fin [(_FinBlockSize - 2*ptrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer +} + var finlock mutex // protects the following variables var fing *g // goroutine that runs finalizers var finq *finblock // list of finalizers that are to be executed @@ -17,6 +25,15 @@ var fingwait bool var fingwake bool var allfin *finblock // list of all blocks +// NOTE: Layout known to queuefinalizer. +type finalizer struct { + fn *funcval // function to call + arg unsafe.Pointer // ptr to object + nret uintptr // bytes of return values from fn + fint *_type // type of first argument of fn + ot *ptrtype // type of ptr to object +} + var finalizer1 = [...]byte{ // Each Finalizer is 5 words, ptr ptr uintptr ptr ptr. // Each byte describes 4 words. diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go index 3934a9e439..c1106b6281 100644 --- a/src/runtime/mfixalloc.go +++ b/src/runtime/mfixalloc.go @@ -10,6 +10,34 @@ package runtime import "unsafe" +// FixAlloc is a simple free-list allocator for fixed size objects. +// Malloc uses a FixAlloc wrapped around sysAlloc to manages its +// MCache and MSpan objects. +// +// Memory returned by FixAlloc_Alloc is not zeroed. +// The caller is responsible for locking around FixAlloc calls. +// Callers can keep state in the object but the first word is +// smashed by freeing and reallocating. +type fixalloc struct { + size uintptr + first unsafe.Pointer // go func(unsafe.pointer, unsafe.pointer); f(arg, p) called first time p is returned + arg unsafe.Pointer + list *mlink + chunk *byte + nchunk uint32 + inuse uintptr // in-use bytes now + stat *uint64 +} + +// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) +// Since assignments to mlink.next will result in a write barrier being preformed +// this can not be used by some of the internal GC structures. For example when +// the sweeper is placing an unmarked object on the free list it does not want the +// write barrier to be called since that could result in the object being reachable. +type mlink struct { + next *mlink +} + // Initialize f to allocate objects of the given size, // using the allocator to obtain chunks of memory. func fixAlloc_Init(f *fixalloc, size uintptr, first func(unsafe.Pointer, unsafe.Pointer), arg unsafe.Pointer, stat *uint64) { diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 0e9756c3e9..497695cf18 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -131,54 +131,8 @@ const ( _RootCount = 5 ) -// ptrmask for an allocation containing a single pointer. -var oneptr = [...]uint8{typePointer} - -// Initialized from $GOGC. GOGC=off means no GC. -var gcpercent int32 - -// Holding worldsema grants an M the right to try to stop the world. -// The procedure is: -// -// semacquire(&worldsema); -// m.preemptoff = "reason"; -// stoptheworld(); -// -// ... do stuff ... -// -// m.preemptoff = ""; -// semrelease(&worldsema); -// starttheworld(); -// -var worldsema uint32 = 1 - -var data, edata, bss, ebss, gcdata, gcbss struct{} - -var gcdatamask bitvector -var gcbssmask bitvector - -var gclock mutex - -var badblock [1024]uintptr -var nbadblock int32 - -type workdata struct { - full uint64 // lock-free list of full blocks workbuf - empty uint64 // lock-free list of empty blocks workbuf - partial uint64 // lock-free list of partially filled blocks workbuf - pad0 [_CacheLineSize]uint8 // prevents false-sharing between full/empty and nproc/nwait - nproc uint32 - tstart int64 - nwait uint32 - ndone uint32 - alldone note - markfor *parfor - - // Copy of mheap.allspans for marker or sweeper. - spans []*mspan -} - -var work workdata +// linker-provided +var data, edata, bss, ebss, gcdata, gcbss, noptrdata, enoptrdata, noptrbss, enoptrbss, end struct{} //go:linkname weak_cgo_allocate go.weak.runtime._cgo_allocate_internal var weak_cgo_allocate byte @@ -189,45 +143,6 @@ func have_cgo_allocate() bool { return &weak_cgo_allocate != nil } -// To help debug the concurrent GC we remark with the world -// stopped ensuring that any object encountered has their normal -// mark bit set. To do this we use an orthogonal bit -// pattern to indicate the object is marked. The following pattern -// uses the upper two bits in the object's bounday nibble. -// 01: scalar not marked -// 10: pointer not marked -// 11: pointer marked -// 00: scalar marked -// Xoring with 01 will flip the pattern from marked to unmarked and vica versa. -// The higher bit is 1 for pointers and 0 for scalars, whether the object -// is marked or not. -// The first nibble no longer holds the typeDead pattern indicating that the -// there are no more pointers in the object. This information is held -// in the second nibble. - -// When marking an object if the bool checkmarkphase is true one uses the above -// encoding, otherwise one uses the bitMarked bit in the lower two bits -// of the nibble. -var checkmarkphase = false - -// inheap reports whether b is a pointer into a (potentially dead) heap object. -// It returns false for pointers into stack spans. -//go:nowritebarrier -func inheap(b uintptr) bool { - if b == 0 || b < mheap_.arena_start || b >= mheap_.arena_used { - return false - } - // Not a beginning of a block, consult span table to find the block beginning. - k := b >> _PageShift - x := k - x -= mheap_.arena_start >> _PageShift - s := h_spans[x] - if s == nil || pageID(k) < s.start || b >= s.limit || s.state != mSpanInUse { - return false - } - return true -} - // Slow for now as we serialize this, since this is on a debug path // speed is not critical at this point. var andlock mutex @@ -239,786 +154,115 @@ func atomicand8(src *byte, val byte) { unlock(&andlock) } -// When in GCmarkterminate phase we allocate black. -//go:nowritebarrier -func gcmarknewobject_m(obj uintptr) { - if gcphase != _GCmarktermination { - throw("marking new object while not in mark termination phase") - } - if checkmarkphase { // The world should be stopped so this should not happen. - throw("gcmarknewobject called while doing checkmark") - } - - heapBitsForAddr(obj).setMarked() -} - -// obj is the start of an object with mark mbits. -// If it isn't already marked, mark it and enqueue into workbuf. -// Return possibly new workbuf to use. -// base and off are for debugging only and could be removed. -//go:nowritebarrier -func greyobject(obj, base, off uintptr, hbits heapBits, gcw *gcWorkProducer) { - // obj should be start of allocation, and so must be at least pointer-aligned. - if obj&(ptrSize-1) != 0 { - throw("greyobject: obj not pointer-aligned") - } - - if checkmarkphase { - if !hbits.isMarked() { - print("runtime:greyobject: checkmarks finds unexpected unmarked object obj=", hex(obj), "\n") - print("runtime: found obj at *(", hex(base), "+", hex(off), ")\n") - - // Dump the source (base) object - - kb := base >> _PageShift - xb := kb - xb -= mheap_.arena_start >> _PageShift - sb := h_spans[xb] - printlock() - print("runtime:greyobject Span: base=", hex(base), " kb=", hex(kb)) - if sb == nil { - print(" sb=nil\n") - } else { - print(" sb.start*_PageSize=", hex(sb.start*_PageSize), " sb.limit=", hex(sb.limit), " sb.sizeclass=", sb.sizeclass, " sb.elemsize=", sb.elemsize, "\n") - // base is (a pointer to) the source object holding the reference to object. Create a pointer to each of the fields - // fields in base and print them out as hex values. - for i := 0; i < int(sb.elemsize/ptrSize); i++ { - print(" *(base+", i*ptrSize, ") = ", hex(*(*uintptr)(unsafe.Pointer(base + uintptr(i)*ptrSize))), "\n") - } - } - - // Dump the object - - k := obj >> _PageShift - x := k - x -= mheap_.arena_start >> _PageShift - s := h_spans[x] - print("runtime:greyobject Span: obj=", hex(obj), " k=", hex(k)) - if s == nil { - print(" s=nil\n") - } else { - print(" s.start=", hex(s.start*_PageSize), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, "\n") - // NOTE(rsc): This code is using s.sizeclass as an approximation of the - // number of pointer-sized words in an object. Perhaps not what was intended. - for i := 0; i < int(s.sizeclass); i++ { - print(" *(obj+", i*ptrSize, ") = ", hex(*(*uintptr)(unsafe.Pointer(obj + uintptr(i)*ptrSize))), "\n") - } - } - throw("checkmark found unmarked object") - } - if !hbits.isCheckmarked() { - return - } - hbits.setCheckmarked() - if !hbits.isCheckmarked() { - throw("setCheckmarked and isCheckmarked disagree") - } - } else { - // If marked we have nothing to do. - if hbits.isMarked() { - return - } - - // Each byte of GC bitmap holds info for two words. - // Might be racing with other updates, so use atomic update always. - // We used to be clever here and use a non-atomic update in certain - // cases, but it's not worth the risk. - hbits.setMarked() - } - - if !checkmarkphase && hbits.typeBits() == typeDead { - return // noscan object - } - - // Queue the obj for scanning. The PREFETCH(obj) logic has been removed but - // seems like a nice optimization that can be added back in. - // There needs to be time between the PREFETCH and the use. - // Previously we put the obj in an 8 element buffer that is drained at a rate - // to give the PREFETCH time to do its work. - // Use of PREFETCHNTA might be more appropriate than PREFETCH - - gcw.put(obj) -} - -// Scan the object b of size n, adding pointers to wbuf. -// Return possibly new wbuf to use. -// If ptrmask != nil, it specifies where pointers are in b. -// If ptrmask == nil, the GC bitmap should be consulted. -// In this case, n may be an overestimate of the size; the GC bitmap -// must also be used to make sure the scan stops at the end of b. -//go:nowritebarrier -func scanobject(b, n uintptr, ptrmask *uint8, gcw *gcWorkProducer) { - arena_start := mheap_.arena_start - arena_used := mheap_.arena_used - - // Find bits of the beginning of the object. - var hbits heapBits - if ptrmask == nil { - b, hbits = heapBitsForObject(b) - if b == 0 { - return - } - if n == 0 { - n = mheap_.arena_used - b - } - } - for i := uintptr(0); i < n; i += ptrSize { - // Find bits for this word. - var bits uintptr - if ptrmask != nil { - // dense mask (stack or data) - bits = (uintptr(*(*byte)(add(unsafe.Pointer(ptrmask), (i/ptrSize)/4))) >> (((i / ptrSize) % 4) * typeBitsWidth)) & typeMask - } else { - // Check if we have reached end of span. - // n is an overestimate of the size of the object. - if (b+i)%_PageSize == 0 && h_spans[(b-arena_start)>>_PageShift] != h_spans[(b+i-arena_start)>>_PageShift] { - break - } - - bits = uintptr(hbits.typeBits()) - if i > 0 && (hbits.isBoundary() || bits == typeDead) { - break // reached beginning of the next object - } - hbits = hbits.next() - } - - if bits <= typeScalar { // typeScalar, typeDead, typeScalarMarked - continue - } - - if bits&typePointer != typePointer { - print("gc checkmarkphase=", checkmarkphase, " b=", hex(b), " ptrmask=", ptrmask, "\n") - throw("unexpected garbage collection bits") - } - - obj := *(*uintptr)(unsafe.Pointer(b + i)) - - // At this point we have extracted the next potential pointer. - // Check if it points into heap. - if obj == 0 || obj < arena_start || obj >= arena_used { - continue - } - - if mheap_.shadow_enabled && debug.wbshadow >= 2 && debug.gccheckmark > 0 && checkmarkphase { - checkwbshadow((*uintptr)(unsafe.Pointer(b + i))) - } - - // Mark the object. - if obj, hbits := heapBitsForObject(obj); obj != 0 { - greyobject(obj, b, i, hbits, gcw) - } - } -} - -// scanblock scans b as scanobject would. -// If the gcphase is GCscan, scanblock performs additional checks. -//go:nowritebarrier -func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWorkProducer) { - // Use local copies of original parameters, so that a stack trace - // due to one of the throws below shows the original block - // base and extent. - b := b0 - n := n0 - - // ptrmask can have 2 possible values: - // 1. nil - obtain pointer mask from GC bitmap. - // 2. pointer to a compact mask (for stacks and data). - - scanobject(b, n, ptrmask, gcw) - if gcphase == _GCscan { - if inheap(b) && ptrmask == nil { - // b is in heap, we are in GCscan so there should be a ptrmask. - throw("scanblock: In GCscan phase and inheap is true.") - } - } -} - -// gcDrain scans objects in work buffers, blackening grey -// objects until all work has been drained. -//go:nowritebarrier -func gcDrain(gcw *gcWork) { - if gcphase != _GCmark && gcphase != _GCmarktermination { - throw("scanblock phase incorrect") - } +var gcdatamask bitvector +var gcbssmask bitvector - for { - // If another proc wants a pointer, give it some. - if work.nwait > 0 && work.full == 0 { - gcw.balance() - } +// heapminimum is the minimum number of bytes in the heap. +// This cleans up the corner case of where we have a very small live set but a lot +// of allocations and collecting every GOGC * live set is expensive. +var heapminimum = uint64(4 << 20) - b := gcw.get() - if b == 0 { - // work barrier reached - break - } - // If the current wbuf is filled by the scan a new wbuf might be - // returned that could possibly hold only a single object. This - // could result in each iteration draining only a single object - // out of the wbuf passed in + a single object placed - // into an empty wbuf in scanobject so there could be - // a performance hit as we keep fetching fresh wbufs. - scanobject(b, 0, nil, &gcw.gcWorkProducer) - } - checknocurrentwbuf() -} +// Initialized from $GOGC. GOGC=off means no GC. +var gcpercent int32 -// gcDrainN scans n objects, blackening grey objects. -//go:nowritebarrier -func gcDrainN(gcw *gcWork, n int) { - checknocurrentwbuf() - for i := 0; i < n; i++ { - // This might be a good place to add prefetch code... - // if(wbuf.nobj > 4) { - // PREFETCH(wbuf->obj[wbuf.nobj - 3]; - // } - b := gcw.tryGet() - if b == 0 { - return - } - scanobject(b, 0, nil, &gcw.gcWorkProducer) +func gcinit() { + if unsafe.Sizeof(workbuf{}) != _WorkbufSize { + throw("size of Workbuf is suboptimal") } -} - -//go:nowritebarrier -func markroot(desc *parfor, i uint32) { - var gcw gcWorkProducer - gcw.initFromCache() - // Note: if you add a case here, please also update heapdump.c:dumproots. - switch i { - case _RootData: - scanblock(uintptr(unsafe.Pointer(&data)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)), gcdatamask.bytedata, &gcw) - - case _RootBss: - scanblock(uintptr(unsafe.Pointer(&bss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)), gcbssmask.bytedata, &gcw) - - case _RootFinalizers: - for fb := allfin; fb != nil; fb = fb.alllink { - scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], &gcw) - } - - case _RootSpans: - // mark MSpan.specials - sg := mheap_.sweepgen - for spanidx := uint32(0); spanidx < uint32(len(work.spans)); spanidx++ { - s := work.spans[spanidx] - if s.state != mSpanInUse { - continue - } - if !checkmarkphase && s.sweepgen != sg { - // sweepgen was updated (+2) during non-checkmark GC pass - print("sweep ", s.sweepgen, " ", sg, "\n") - throw("gc: unswept span") - } - for sp := s.specials; sp != nil; sp = sp.next { - if sp.kind != _KindSpecialFinalizer { - continue - } - // don't mark finalized object, but scan it so we - // retain everything it points to. - spf := (*specialfinalizer)(unsafe.Pointer(sp)) - // A finalizer can be set for an inner byte of an object, find object beginning. - p := uintptr(s.start<<_PageShift) + uintptr(spf.special.offset)/s.elemsize*s.elemsize - if gcphase != _GCscan { - scanblock(p, s.elemsize, nil, &gcw) // scanned during mark phase - } - scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptr[0], &gcw) - } - } - - case _RootFlushCaches: - if gcphase != _GCscan { // Do not flush mcaches during GCscan phase. - flushallmcaches() - } - - default: - // the rest is scanning goroutine stacks - if uintptr(i-_RootCount) >= allglen { - throw("markroot: bad index") - } - gp := allgs[i-_RootCount] - - // remember when we've first observed the G blocked - // needed only to output in traceback - status := readgstatus(gp) // We are not in a scan state - if (status == _Gwaiting || status == _Gsyscall) && gp.waitsince == 0 { - gp.waitsince = work.tstart - } - - // Shrink a stack if not much of it is being used but not in the scan phase. - if gcphase == _GCmarktermination { - // Shrink during STW GCmarktermination phase thus avoiding - // complications introduced by shrinking during - // non-STW phases. - shrinkstack(gp) - } - if readgstatus(gp) == _Gdead { - gp.gcworkdone = true - } else { - gp.gcworkdone = false - } - restart := stopg(gp) - - // goroutine will scan its own stack when it stops running. - // Wait until it has. - for readgstatus(gp) == _Grunning && !gp.gcworkdone { - } - - // scanstack(gp) is done as part of gcphasework - // But to make sure we finished we need to make sure that - // the stack traps have all responded so drop into - // this while loop until they respond. - for !gp.gcworkdone { - status = readgstatus(gp) - if status == _Gdead { - gp.gcworkdone = true // scan is a noop - break - } - if status == _Gwaiting || status == _Grunnable { - restart = stopg(gp) - } - } - if restart { - restartg(gp) - } - } - gcw.dispose() + work.markfor = parforalloc(_MaxGcproc) + gcpercent = readgogc() + gcdatamask = unrollglobgcprog((*byte)(unsafe.Pointer(&gcdata)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data))) + gcbssmask = unrollglobgcprog((*byte)(unsafe.Pointer(&gcbss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss))) + memstats.next_gc = heapminimum } -//go:nowritebarrier -func stackmapdata(stkmap *stackmap, n int32) bitvector { - if n < 0 || n >= stkmap.n { - throw("stackmapdata: index out of range") +func setGCPercent(in int32) (out int32) { + lock(&mheap_.lock) + out = gcpercent + if in < 0 { + in = -1 } - return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))} + gcpercent = in + unlock(&mheap_.lock) + return out } -// Scan a stack frame: local variables and function arguments/results. -//go:nowritebarrier -func scanframeworker(frame *stkframe, unused unsafe.Pointer, gcw *gcWorkProducer) { - - f := frame.fn - targetpc := frame.continpc - if targetpc == 0 { - // Frame is dead. - return - } - if _DebugGC > 1 { - print("scanframe ", funcname(f), "\n") - } - if targetpc != f.entry { - targetpc-- - } - pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc) - if pcdata == -1 { - // We do not have a valid pcdata value but there might be a - // stackmap for this function. It is likely that we are looking - // at the function prologue, assume so and hope for the best. - pcdata = 0 - } - - // Scan local variables if stack frame has been allocated. - size := frame.varp - frame.sp - var minsize uintptr - if thechar != '6' && thechar != '8' { - minsize = ptrSize - } else { - minsize = 0 - } - if size > minsize { - stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps)) - if stkmap == nil || stkmap.n <= 0 { - print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n") - throw("missing stackmap") - } - - // Locals bitmap information, scan just the pointers in locals. - if pcdata < 0 || pcdata >= stkmap.n { - // don't know where we are - print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n") - throw("scanframe: bad symbol table") - } - bv := stackmapdata(stkmap, pcdata) - size = (uintptr(bv.n) / typeBitsWidth) * ptrSize - scanblock(frame.varp-size, size, bv.bytedata, gcw) - } +// Trigger the concurrent GC when 1/triggerratio memory is available to allocate. +// Adjust this ratio as part of a scheme to ensure that mutators have enough +// memory to allocate in durring a concurrent GC cycle. +var triggerratio = int64(8) - // Scan arguments. - if frame.arglen > 0 { - var bv bitvector - if frame.argmap != nil { - bv = *frame.argmap - } else { - stkmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps)) - if stkmap == nil || stkmap.n <= 0 { - print("runtime: frame ", funcname(f), " untyped args ", hex(frame.argp), "+", hex(frame.arglen), "\n") - throw("missing stackmap") - } - if pcdata < 0 || pcdata >= stkmap.n { - // don't know where we are - print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " args stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n") - throw("scanframe: bad symbol table") - } - bv = stackmapdata(stkmap, pcdata) - } - scanblock(frame.argp, uintptr(bv.n)/typeBitsWidth*ptrSize, bv.bytedata, gcw) - } +// Determine whether to initiate a GC. +// If the GC is already working no need to trigger another one. +// This should establish a feedback loop where if the GC does not +// have sufficient time to complete then more memory will be +// requested from the OS increasing heap size thus allow future +// GCs more time to complete. +// memstat.heap_alloc and memstat.next_gc reads have benign races +// A false negative simple does not start a GC, a false positive +// will start a GC needlessly. Neither have correctness issues. +func shouldtriggergc() bool { + return triggerratio*(int64(memstats.next_gc)-int64(memstats.heap_alloc)) <= int64(memstats.next_gc) && atomicloaduint(&bggc.working) == 0 } -//go:nowritebarrier -func scanstack(gp *g) { - if gp.gcscanvalid { - return - } - - if readgstatus(gp)&_Gscan == 0 { - print("runtime:scanstack: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", hex(readgstatus(gp)), "\n") - throw("scanstack - bad status") - } - - switch readgstatus(gp) &^ _Gscan { - default: - print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n") - throw("mark - bad status") - case _Gdead: - return - case _Grunning: - print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n") - throw("scanstack: goroutine not stopped") - case _Grunnable, _Gsyscall, _Gwaiting: - // ok - } - - if gp == getg() { - throw("can't scan our own stack") - } - mp := gp.m - if mp != nil && mp.helpgc != 0 { - throw("can't scan gchelper stack") - } - - var gcw gcWorkProducer - gcw.initFromCache() - scanframe := func(frame *stkframe, unused unsafe.Pointer) bool { - // Pick up gcw as free variable so gentraceback and friends can - // keep the same signature. - scanframeworker(frame, unused, &gcw) - return true - } - gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0) - tracebackdefers(gp, scanframe, nil) - gcw.disposeToCache() - gp.gcscanvalid = true -} +var work workdata -// Shade the object if it isn't already. -// The object is not nil and known to be in the heap. -//go:nowritebarrier -func shade(b uintptr) { - if !inheap(b) { - throw("shade: passed an address not in the heap") - } - if obj, hbits := heapBitsForObject(b); obj != 0 { - // TODO: this would be a great place to put a check to see - // if we are harvesting and if we are then we should - // figure out why there is a call to shade when the - // harvester thinks we are in a STW. - // if atomicload(&harvestingwbufs) == uint32(1) { - // // Throw here to discover write barriers - // // being executed during a STW. - // throw("shade during harvest") - // } - - var gcw gcWorkProducer - greyobject(obj, 0, 0, hbits, &gcw) - // This is part of the write barrier so put the wbuf back. - if gcphase == _GCmarktermination { - gcw.dispose() - } else { - // If we added any pointers to the gcw, then - // currentwbuf must be nil because 1) - // greyobject got its wbuf from currentwbuf - // and 2) shade runs on the systemstack, so - // we're still on the same M. If either of - // these becomes no longer true, we need to - // rethink this. - gcw.disposeToCache() - } - } -} +type workdata struct { + full uint64 // lock-free list of full blocks workbuf + empty uint64 // lock-free list of empty blocks workbuf + partial uint64 // lock-free list of partially filled blocks workbuf + pad0 [_CacheLineSize]uint8 // prevents false-sharing between full/empty and nproc/nwait + nproc uint32 + tstart int64 + nwait uint32 + ndone uint32 + alldone note + markfor *parfor -// gchelpwork does a small bounded amount of gc work. The purpose is to -// shorten the time (as measured by allocations) spent doing a concurrent GC. -// The number of mutator calls is roughly propotional to the number of allocations -// made by that mutator. This slows down the allocation while speeding up the GC. -//go:nowritebarrier -func gchelpwork() { - switch gcphase { - default: - throw("gcphasework in bad gcphase") - case _GCoff, _GCquiesce, _GCstw: - // No work. - case _GCsweep: - // We could help by calling sweepone to sweep a single span. - // _ = sweepone() - case _GCscan: - // scan the stack, mark the objects, put pointers in work buffers - // hanging off the P where this is being run. - // scanstack(gp) - case _GCmark: - // Get a full work buffer and empty it. - // drain your own currentwbuf first in the hopes that it will - // be more cache friendly. - var gcw gcWork - gcw.initFromCache() - const n = len(workbuf{}.obj) - gcDrainN(&gcw, n) // drain upto one buffer's worth of objects - gcw.dispose() - case _GCmarktermination: - // We should never be here since the world is stopped. - // All available mark work will be emptied before returning. - throw("gcphasework in bad gcphase") - } + // Copy of mheap.allspans for marker or sweeper. + spans []*mspan } -// The gp has been moved to a GC safepoint. GC phase specific -// work is done here. -//go:nowritebarrier -func gcphasework(gp *g) { - switch gcphase { - default: - throw("gcphasework in bad gcphase") - case _GCoff, _GCquiesce, _GCstw, _GCsweep: - // No work. - case _GCscan: - // scan the stack, mark the objects, put pointers in work buffers - // hanging off the P where this is being run. - // Indicate that the scan is valid until the goroutine runs again - scanstack(gp) - case _GCmark: - // No work. - case _GCmarktermination: - scanstack(gp) - // All available mark work will be emptied before returning. - } - gp.gcworkdone = true +// GC runs a garbage collection. +func GC() { + gogc(2) } -// Returns only when span s has been swept. -//go:nowritebarrier -func mSpan_EnsureSwept(s *mspan) { - // Caller must disable preemption. - // Otherwise when this function returns the span can become unswept again - // (if GC is triggered on another goroutine). - _g_ := getg() - if _g_.m.locks == 0 && _g_.m.mallocing == 0 && _g_ != _g_.m.g0 { - throw("MSpan_EnsureSwept: m is not locked") - } +// force = 0 - start concurrent GC +// force = 1 - do STW GC regardless of current heap usage +// force = 2 - go STW GC and eager sweep +func gogc(force int32) { + // The gc is turned off (via enablegc) until the bootstrap has completed. + // Also, malloc gets called in the guts of a number of libraries that might be + // holding locks. To avoid deadlocks during stoptheworld, don't bother + // trying to run gc while holding a lock. The next mallocgc without a lock + // will do the gc instead. - sg := mheap_.sweepgen - if atomicload(&s.sweepgen) == sg { - return - } - // The caller must be sure that the span is a MSpanInUse span. - if cas(&s.sweepgen, sg-2, sg-1) { - mSpan_Sweep(s, false) + mp := acquirem() + if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 { + releasem(mp) return } - // unfortunate condition, and we don't have efficient means to wait - for atomicload(&s.sweepgen) != sg { - osyield() - } -} - -// Sweep frees or collects finalizers for blocks not marked in the mark phase. -// It clears the mark bits in preparation for the next GC round. -// Returns true if the span was returned to heap. -// If preserve=true, don't return it to heap nor relink in MCentral lists; -// caller takes care of it. -//TODO go:nowritebarrier -func mSpan_Sweep(s *mspan, preserve bool) bool { - if checkmarkphase { - throw("MSpan_Sweep: checkmark only runs in STW and after the sweep") - } - - // It's critical that we enter this function with preemption disabled, - // GC must not start while we are in the middle of this function. - _g_ := getg() - if _g_.m.locks == 0 && _g_.m.mallocing == 0 && _g_ != _g_.m.g0 { - throw("MSpan_Sweep: m is not locked") - } - sweepgen := mheap_.sweepgen - if s.state != mSpanInUse || s.sweepgen != sweepgen-1 { - print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n") - throw("MSpan_Sweep: bad span state") - } - - if trace.enabled { - traceGCSweepStart() - } - - cl := s.sizeclass - size := s.elemsize - res := false - nfree := 0 - - var head, end gclinkptr + releasem(mp) + mp = nil - c := _g_.m.mcache - sweepgenset := false - - // Mark any free objects in this span so we don't collect them. - for link := s.freelist; link.ptr() != nil; link = link.ptr().next { - heapBitsForAddr(uintptr(link)).setMarkedNonAtomic() - } - - // Unlink & free special records for any objects we're about to free. - specialp := &s.specials - special := *specialp - for special != nil { - // A finalizer can be set for an inner byte of an object, find object beginning. - p := uintptr(s.start<<_PageShift) + uintptr(special.offset)/size*size - hbits := heapBitsForAddr(p) - if !hbits.isMarked() { - // Find the exact byte for which the special was setup - // (as opposed to object beginning). - p := uintptr(s.start<<_PageShift) + uintptr(special.offset) - // about to free object: splice out special record - y := special - special = special.next - *specialp = special - if !freespecial(y, unsafe.Pointer(p), size, false) { - // stop freeing of object if it has a finalizer - hbits.setMarkedNonAtomic() - } - } else { - // object is still live: keep special record - specialp = &special.next - special = *specialp + if force == 0 { + lock(&bggc.lock) + if !bggc.started { + bggc.working = 1 + bggc.started = true + go backgroundgc() + } else if bggc.working == 0 { + bggc.working = 1 + ready(bggc.g) } + unlock(&bggc.lock) + } else { + gcwork(force) } - - // Sweep through n objects of given size starting at p. - // This thread owns the span now, so it can manipulate - // the block bitmap without atomic operations. - - size, n, _ := s.layout() - heapBitsSweepSpan(s.base(), size, n, func(p uintptr) { - // At this point we know that we are looking at garbage object - // that needs to be collected. - if debug.allocfreetrace != 0 { - tracefree(unsafe.Pointer(p), size) - } - - // Reset to allocated+noscan. - if cl == 0 { - // Free large span. - if preserve { - throw("can't preserve large span") - } - heapBitsForSpan(p).clearSpan(s.layout()) - s.needzero = 1 - - // important to set sweepgen before returning it to heap - atomicstore(&s.sweepgen, sweepgen) - sweepgenset = true - - // NOTE(rsc,dvyukov): The original implementation of efence - // in CL 22060046 used SysFree instead of SysFault, so that - // the operating system would eventually give the memory - // back to us again, so that an efence program could run - // longer without running out of memory. Unfortunately, - // calling SysFree here without any kind of adjustment of the - // heap data structures means that when the memory does - // come back to us, we have the wrong metadata for it, either in - // the MSpan structures or in the garbage collection bitmap. - // Using SysFault here means that the program will run out of - // memory fairly quickly in efence mode, but at least it won't - // have mysterious crashes due to confused memory reuse. - // It should be possible to switch back to SysFree if we also - // implement and then call some kind of MHeap_DeleteSpan. - if debug.efence > 0 { - s.limit = 0 // prevent mlookup from finding this span - sysFault(unsafe.Pointer(p), size) - } else { - mHeap_Free(&mheap_, s, 1) - } - c.local_nlargefree++ - c.local_largefree += size - reduction := int64(size) * int64(gcpercent+100) / 100 - if int64(memstats.next_gc)-reduction > int64(heapminimum) { - xadd64(&memstats.next_gc, -reduction) - } else { - atomicstore64(&memstats.next_gc, heapminimum) - } - res = true - } else { - // Free small object. - if size > 2*ptrSize { - *(*uintptr)(unsafe.Pointer(p + ptrSize)) = uintptrMask & 0xdeaddeaddeaddead // mark as "needs to be zeroed" - } else if size > ptrSize { - *(*uintptr)(unsafe.Pointer(p + ptrSize)) = 0 - } - if head.ptr() == nil { - head = gclinkptr(p) - } else { - end.ptr().next = gclinkptr(p) - } - end = gclinkptr(p) - end.ptr().next = gclinkptr(0x0bade5) - nfree++ - } - }) - - // We need to set s.sweepgen = h.sweepgen only when all blocks are swept, - // because of the potential for a concurrent free/SetFinalizer. - // But we need to set it before we make the span available for allocation - // (return it to heap or mcentral), because allocation code assumes that a - // span is already swept if available for allocation. - if !sweepgenset && nfree == 0 { - // The span must be in our exclusive ownership until we update sweepgen, - // check for potential races. - if s.state != mSpanInUse || s.sweepgen != sweepgen-1 { - print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n") - throw("MSpan_Sweep: bad span state after sweep") - } - atomicstore(&s.sweepgen, sweepgen) - } - if nfree > 0 { - c.local_nsmallfree[cl] += uintptr(nfree) - c.local_cachealloc -= intptr(uintptr(nfree) * size) - reduction := int64(nfree) * int64(size) * int64(gcpercent+100) / 100 - if int64(memstats.next_gc)-reduction > int64(heapminimum) { - xadd64(&memstats.next_gc, -reduction) - } else { - atomicstore64(&memstats.next_gc, heapminimum) - } - res = mCentral_FreeSpan(&mheap_.central[cl].mcentral, s, int32(nfree), head, end, preserve) - // MCentral_FreeSpan updates sweepgen - } - if trace.enabled { - traceGCSweepDone() - traceNextGC() - } - return res -} - -// State of background sweep. -// Protected by gclock. -type sweepdata struct { - g *g - parked bool - started bool - - spanidx uint32 // background sweeper position - - nbgsweep uint32 - npausesweep uint32 } -var sweep sweepdata - // State of the background concurrent GC goroutine. var bggc struct { lock mutex @@ -1027,237 +271,161 @@ var bggc struct { started bool } -// sweeps one span -// returns number of pages returned to heap, or ^uintptr(0) if there is nothing to sweep -//go:nowritebarrier -func sweepone() uintptr { - _g_ := getg() - - // increment locks to ensure that the goroutine is not preempted - // in the middle of sweep thus leaving the span in an inconsistent state for next GC - _g_.m.locks++ - sg := mheap_.sweepgen +// backgroundgc is running in a goroutine and does the concurrent GC work. +// bggc holds the state of the backgroundgc. +func backgroundgc() { + bggc.g = getg() for { - idx := xadd(&sweep.spanidx, 1) - 1 - if idx >= uint32(len(work.spans)) { - mheap_.sweepdone = 1 - _g_.m.locks-- - return ^uintptr(0) - } - s := work.spans[idx] - if s.state != mSpanInUse { - s.sweepgen = sg - continue - } - if s.sweepgen != sg-2 || !cas(&s.sweepgen, sg-2, sg-1) { - continue - } - npages := s.npages - if !mSpan_Sweep(s, false) { - npages = 0 - } - _g_.m.locks-- - return npages + gcwork(0) + lock(&bggc.lock) + bggc.working = 0 + goparkunlock(&bggc.lock, "Concurrent GC wait", traceEvGoBlock) } } -//go:nowritebarrier -func gosweepone() uintptr { - var ret uintptr - systemstack(func() { - ret = sweepone() - }) - return ret -} +func gcwork(force int32) { -//go:nowritebarrier -func gosweepdone() bool { - return mheap_.sweepdone != 0 -} - -//go:nowritebarrier -func gchelper() { - _g_ := getg() - _g_.m.traceback = 2 - gchelperstart() - - if trace.enabled { - traceGCScanStart() - } + semacquire(&worldsema, false) - // parallel mark for over GC roots - parfordo(work.markfor) - if gcphase != _GCscan { - var gcw gcWork - gcDrain(&gcw) // blocks in getfull - gcw.dispose() + // Pick up the remaining unswept/not being swept spans concurrently + for gosweepone() != ^uintptr(0) { + sweep.nbgsweep++ } - if trace.enabled { - traceGCScanDone() - } + // Ok, we're doing it! Stop everybody else - nproc := work.nproc // work.nproc can change right after we increment work.ndone - if xadd(&work.ndone, +1) == nproc-1 { - notewakeup(&work.alldone) + mp := acquirem() + mp.preemptoff = "gcing" + releasem(mp) + gctimer.count++ + if force == 0 { + gctimer.cycle.sweepterm = nanotime() } - _g_.m.traceback = 0 -} -//go:nowritebarrier -func cachestats() { - for i := 0; ; i++ { - p := allp[i] - if p == nil { - break - } - c := p.mcache - if c == nil { - continue + if trace.enabled { + traceGoSched() + traceGCStart() + } + + // Pick up the remaining unswept/not being swept spans before we STW + for gosweepone() != ^uintptr(0) { + sweep.nbgsweep++ + } + systemstack(stoptheworld) + systemstack(finishsweep_m) // finish sweep before we start concurrent scan. + if force == 0 { // Do as much work concurrently as possible + gcphase = _GCscan + systemstack(starttheworld) + gctimer.cycle.scan = nanotime() + // Do a concurrent heap scan before we stop the world. + systemstack(gcscan_m) + gctimer.cycle.installmarkwb = nanotime() + systemstack(stoptheworld) + systemstack(gcinstallmarkwb) + systemstack(harvestwbufs) + systemstack(starttheworld) + gctimer.cycle.mark = nanotime() + systemstack(gcmark_m) + gctimer.cycle.markterm = nanotime() + systemstack(stoptheworld) + systemstack(gcinstalloffwb_m) + } else { + // For non-concurrent GC (force != 0) g stack have not been scanned so + // set gcscanvalid such that mark termination scans all stacks. + // No races here since we are in a STW phase. + for _, gp := range allgs { + gp.gcworkdone = false // set to true in gcphasework + gp.gcscanvalid = false // stack has not been scanned } - purgecachedstats(c) } -} -//go:nowritebarrier -func flushallmcaches() { - for i := 0; ; i++ { - p := allp[i] - if p == nil { - break - } - c := p.mcache - if c == nil { - continue - } - mCache_ReleaseAll(c) - stackcache_clear(c) + startTime := nanotime() + if mp != acquirem() { + throw("gogc: rescheduled") } -} -//go:nowritebarrier -func updatememstats(stats *gcstats) { - if stats != nil { - *stats = gcstats{} + clearpools() + + // Run gc on the g0 stack. We do this so that the g stack + // we're currently running on will no longer change. Cuts + // the root set down a bit (g0 stacks are not scanned, and + // we don't need to scan gc's internal state). We also + // need to switch to g0 so we can shrink the stack. + n := 1 + if debug.gctrace > 1 { + n = 2 } - for mp := allm; mp != nil; mp = mp.alllink { - if stats != nil { - src := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(&mp.gcstats)) - dst := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(stats)) - for i, v := range src { - dst[i] += v - } - mp.gcstats = gcstats{} + eagersweep := force >= 2 + for i := 0; i < n; i++ { + if i > 0 { + // refresh start time if doing a second GC + startTime = nanotime() } + // switch to g0, call gc, then switch back + systemstack(func() { + gc_m(startTime, eagersweep) + }) } - memstats.mcache_inuse = uint64(mheap_.cachealloc.inuse) - memstats.mspan_inuse = uint64(mheap_.spanalloc.inuse) - memstats.sys = memstats.heap_sys + memstats.stacks_sys + memstats.mspan_sys + - memstats.mcache_sys + memstats.buckhash_sys + memstats.gc_sys + memstats.other_sys - - // Calculate memory allocator stats. - // During program execution we only count number of frees and amount of freed memory. - // Current number of alive object in the heap and amount of alive heap memory - // are calculated by scanning all spans. - // Total number of mallocs is calculated as number of frees plus number of alive objects. - // Similarly, total amount of allocated memory is calculated as amount of freed memory - // plus amount of alive heap memory. - memstats.alloc = 0 - memstats.total_alloc = 0 - memstats.nmalloc = 0 - memstats.nfree = 0 - for i := 0; i < len(memstats.by_size); i++ { - memstats.by_size[i].nmalloc = 0 - memstats.by_size[i].nfree = 0 - } + systemstack(func() { + gccheckmark_m(startTime, eagersweep) + }) - // Flush MCache's to MCentral. - systemstack(flushallmcaches) + if trace.enabled { + traceGCDone() + traceGoStart() + } - // Aggregate local stats. - cachestats() + // all done + mp.preemptoff = "" - // Scan all spans and count number of alive objects. - lock(&mheap_.lock) - for i := uint32(0); i < mheap_.nspan; i++ { - s := h_allspans[i] - if s.state != mSpanInUse { - continue - } - if s.sizeclass == 0 { - memstats.nmalloc++ - memstats.alloc += uint64(s.elemsize) - } else { - memstats.nmalloc += uint64(s.ref) - memstats.by_size[s.sizeclass].nmalloc += uint64(s.ref) - memstats.alloc += uint64(s.ref) * uint64(s.elemsize) - } + if force == 0 { + gctimer.cycle.sweep = nanotime() } - unlock(&mheap_.lock) - // Aggregate by size class. - smallfree := uint64(0) - memstats.nfree = mheap_.nlargefree - for i := 0; i < len(memstats.by_size); i++ { - memstats.nfree += mheap_.nsmallfree[i] - memstats.by_size[i].nfree = mheap_.nsmallfree[i] - memstats.by_size[i].nmalloc += mheap_.nsmallfree[i] - smallfree += uint64(mheap_.nsmallfree[i]) * uint64(class_to_size[i]) + semrelease(&worldsema) + + if force == 0 { + if gctimer.verbose > 1 { + GCprinttimes() + } else if gctimer.verbose > 0 { + calctimes() // ignore result + } } - memstats.nfree += memstats.tinyallocs - memstats.nmalloc += memstats.nfree - // Calculate derived stats. - memstats.total_alloc = uint64(memstats.alloc) + uint64(mheap_.largefree) + smallfree - memstats.heap_alloc = memstats.alloc - memstats.heap_objects = memstats.nmalloc - memstats.nfree -} + systemstack(starttheworld) -// heapminimum is the minimum number of bytes in the heap. -// This cleans up the corner case of where we have a very small live set but a lot -// of allocations and collecting every GOGC * live set is expensive. -var heapminimum = uint64(4 << 20) + releasem(mp) + mp = nil -func gcinit() { - if unsafe.Sizeof(workbuf{}) != _WorkbufSize { - throw("size of Workbuf is suboptimal") + // now that gc is done, kick off finalizer thread if needed + if !concurrentSweep { + // give the queued finalizers, if any, a chance to run + Gosched() } - - work.markfor = parforalloc(_MaxGcproc) - gcpercent = readgogc() - gcdatamask = unrollglobgcprog((*byte)(unsafe.Pointer(&gcdata)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data))) - gcbssmask = unrollglobgcprog((*byte)(unsafe.Pointer(&gcbss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss))) - memstats.next_gc = heapminimum } -// Called from malloc.go using systemstack, stopping and starting the world handled in caller. +// For now this must be bracketed with a stoptheworld and a starttheworld to ensure +// all go routines see the new barrier. //go:nowritebarrier -func gc_m(start_time int64, eagersweep bool) { - _g_ := getg() - gp := _g_.m.curg - casgstatus(gp, _Grunning, _Gwaiting) - gp.waitreason = "garbage collection" - - gc(start_time, eagersweep) - casgstatus(gp, _Gwaiting, _Grunning) +func gcinstalloffwb_m() { + gcphase = _GCoff } +// For now this must be bracketed with a stoptheworld and a starttheworld to ensure +// all go routines see the new barrier. //go:nowritebarrier -func initCheckmarks() { - for _, s := range work.spans { - if s.state == _MSpanInUse { - heapBitsForSpan(s.base()).initCheckmarkSpan(s.layout()) - } - } +func gcinstallmarkwb() { + gcphase = _GCmark } -func clearCheckmarks() { - for _, s := range work.spans { - if s.state == _MSpanInUse { - heapBitsForSpan(s.base()).clearCheckmarkSpan(s.layout()) - } - } +// Mark all objects that are known about. +// This is the concurrent mark phase. +//go:nowritebarrier +func gcmark_m() { + gcDrain(nil) + // TODO add another harvestwbuf and reset work.nwait=0, work.ndone=0, and work.nproc=1 + // and repeat the above gcDrain. } // Called from malloc.go using systemstack. @@ -1280,90 +448,16 @@ func gccheckmark_m(startTime int64, eagersweep bool) { gc_m(startTime, eagersweep) // turns off checkmarkphase + calls clearcheckmarkbits } +// Called from malloc.go using systemstack, stopping and starting the world handled in caller. //go:nowritebarrier -func finishsweep_m() { - // The world is stopped so we should be able to complete the sweeps - // quickly. - for sweepone() != ^uintptr(0) { - sweep.npausesweep++ - } - - // There may be some other spans being swept concurrently that - // we need to wait for. If finishsweep_m is done with the world stopped - // this code is not required. - sg := mheap_.sweepgen - for _, s := range work.spans { - if s.sweepgen != sg && s.state == _MSpanInUse { - mSpan_EnsureSwept(s) - } - } -} - -// Scan all of the stacks, greying (or graying if in America) the referents -// but not blackening them since the mark write barrier isn't installed. -//go:nowritebarrier -func gcscan_m() { +func gc_m(start_time int64, eagersweep bool) { _g_ := getg() + gp := _g_.m.curg + casgstatus(gp, _Grunning, _Gwaiting) + gp.waitreason = "garbage collection" - // Grab the g that called us and potentially allow rescheduling. - // This allows it to be scanned like other goroutines. - mastergp := _g_.m.curg - casgstatus(mastergp, _Grunning, _Gwaiting) - mastergp.waitreason = "garbage collection scan" - - // Span sweeping has been done by finishsweep_m. - // Long term we will want to make this goroutine runnable - // by placing it onto a scanenqueue state and then calling - // runtime·restartg(mastergp) to make it Grunnable. - // At the bottom we will want to return this p back to the scheduler. - - // Prepare flag indicating that the scan has not been completed. - lock(&allglock) - local_allglen := allglen - for i := uintptr(0); i < local_allglen; i++ { - gp := allgs[i] - gp.gcworkdone = false // set to true in gcphasework - gp.gcscanvalid = false // stack has not been scanned - } - unlock(&allglock) - - work.nwait = 0 - work.ndone = 0 - work.nproc = 1 // For now do not do this in parallel. - // ackgcphase is not needed since we are not scanning running goroutines. - parforsetup(work.markfor, work.nproc, uint32(_RootCount+local_allglen), false, markroot) - parfordo(work.markfor) - - lock(&allglock) - // Check that gc work is done. - for i := uintptr(0); i < local_allglen; i++ { - gp := allgs[i] - if !gp.gcworkdone { - throw("scan missed a g") - } - } - unlock(&allglock) - - casgstatus(mastergp, _Gwaiting, _Grunning) - // Let the g that called us continue to run. -} - -// Mark all objects that are known about. -// This is the concurrent mark phase. -//go:nowritebarrier -func gcmark_m() { - var gcw gcWork - gcDrain(&gcw) - gcw.dispose() - // TODO add another harvestwbuf and reset work.nwait=0, work.ndone=0, and work.nproc=1 - // and repeat the above gcDrain. -} - -// For now this must be bracketed with a stoptheworld and a starttheworld to ensure -// all go routines see the new barrier. -//go:nowritebarrier -func gcinstalloffwb_m() { - gcphase = _GCoff + gc(start_time, eagersweep) + casgstatus(gp, _Gwaiting, _Grunning) } // STW is in effect at this point. @@ -1573,68 +667,89 @@ func gc(start_time int64, eagersweep bool) { } } -func readmemstats_m(stats *MemStats) { - updatememstats(nil) - - // Size of the trailing by_size array differs between Go and C, - // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. - memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats) +// Hooks for other packages - // Stack numbers are part of the heap numbers, separate those out for user consumption - stats.StackSys = stats.StackInuse - stats.HeapInuse -= stats.StackInuse - stats.HeapSys -= stats.StackInuse +//go:linkname runtime_debug_freeOSMemory runtime/debug.freeOSMemory +func runtime_debug_freeOSMemory() { + gogc(2) // force GC and do eager sweep + systemstack(scavenge_m) } -//go:linkname readGCStats runtime/debug.readGCStats -func readGCStats(pauses *[]uint64) { - systemstack(func() { - readGCStats_m(pauses) - }) +var poolcleanup func() + +//go:linkname sync_runtime_registerPoolCleanup sync.runtime_registerPoolCleanup +func sync_runtime_registerPoolCleanup(f func()) { + poolcleanup = f } -func readGCStats_m(pauses *[]uint64) { - p := *pauses - // Calling code in runtime/debug should make the slice large enough. - if cap(p) < len(memstats.pause_ns)+3 { - throw("short slice passed to readGCStats") +func clearpools() { + // clear sync.Pools + if poolcleanup != nil { + poolcleanup() } - // Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns. - lock(&mheap_.lock) + for _, p := range &allp { + if p == nil { + break + } + // clear tinyalloc pool + if c := p.mcache; c != nil { + c.tiny = nil + c.tinyoffset = 0 + + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var sg, sgnext *sudog + for sg = c.sudogcache; sg != nil; sg = sgnext { + sgnext = sg.next + sg.next = nil + } + c.sudogcache = nil + } - n := memstats.numgc - if n > uint32(len(memstats.pause_ns)) { - n = uint32(len(memstats.pause_ns)) + // clear defer pools + for i := range p.deferpool { + // disconnect cached list before dropping it on the floor, + // so that a dangling ref to one entry does not pin all of them. + var d, dlink *_defer + for d = p.deferpool[i]; d != nil; d = dlink { + dlink = d.link + d.link = nil + } + p.deferpool[i] = nil + } } +} + +// Timing - // The pause buffer is circular. The most recent pause is at - // pause_ns[(numgc-1)%len(pause_ns)], and then backward - // from there to go back farther in time. We deliver the times - // most recent first (in p[0]). - p = p[:cap(p)] - for i := uint32(0); i < n; i++ { - j := (memstats.numgc - 1 - i) % uint32(len(memstats.pause_ns)) - p[i] = memstats.pause_ns[j] - p[n+i] = memstats.pause_end[j] +//go:nowritebarrier +func gchelper() { + _g_ := getg() + _g_.m.traceback = 2 + gchelperstart() + + if trace.enabled { + traceGCScanStart() } - p[n+n] = memstats.last_gc - p[n+n+1] = uint64(memstats.numgc) - p[n+n+2] = memstats.pause_total_ns - unlock(&mheap_.lock) - *pauses = p[:n+n+3] -} + // parallel mark for over GC roots + parfordo(work.markfor) + if gcphase != _GCscan { + var gcw gcWork + gcDrain(&gcw) // blocks in getfull + gcw.dispose() + } -func setGCPercent(in int32) (out int32) { - lock(&mheap_.lock) - out = gcpercent - if in < 0 { - in = -1 + if trace.enabled { + traceGCScanDone() } - gcpercent = in - unlock(&mheap_.lock) - return out + + nproc := work.nproc // work.nproc can change right after we increment work.ndone + if xadd(&work.ndone, +1) == nproc-1 { + notewakeup(&work.alldone) + } + _g_.m.traceback = 0 } func gchelperstart() { @@ -1648,7 +763,106 @@ func gchelperstart() { } } -func unixnanotime() int64 { - sec, nsec := time_now() - return sec*1e9 + int64(nsec) +// gcchronograph holds timer information related to GC phases +// max records the maximum time spent in each GC phase since GCstarttimes. +// total records the total time spent in each GC phase since GCstarttimes. +// cycle records the absolute time (as returned by nanoseconds()) that each GC phase last started at. +type gcchronograph struct { + count int64 + verbose int64 + maxpause int64 + max gctimes + total gctimes + cycle gctimes +} + +// gctimes records the time in nanoseconds of each phase of the concurrent GC. +type gctimes struct { + sweepterm int64 // stw + scan int64 + installmarkwb int64 // stw + mark int64 + markterm int64 // stw + sweep int64 +} + +var gctimer gcchronograph + +// GCstarttimes initializes the gc times. All previous times are lost. +func GCstarttimes(verbose int64) { + gctimer = gcchronograph{verbose: verbose} +} + +// GCendtimes stops the gc timers. +func GCendtimes() { + gctimer.verbose = 0 +} + +// calctimes converts gctimer.cycle into the elapsed times, updates gctimer.total +// and updates gctimer.max with the max pause time. +func calctimes() gctimes { + var times gctimes + + var max = func(a, b int64) int64 { + if a > b { + return a + } + return b + } + + times.sweepterm = gctimer.cycle.scan - gctimer.cycle.sweepterm + gctimer.total.sweepterm += times.sweepterm + gctimer.max.sweepterm = max(gctimer.max.sweepterm, times.sweepterm) + gctimer.maxpause = max(gctimer.maxpause, gctimer.max.sweepterm) + + times.scan = gctimer.cycle.installmarkwb - gctimer.cycle.scan + gctimer.total.scan += times.scan + gctimer.max.scan = max(gctimer.max.scan, times.scan) + + times.installmarkwb = gctimer.cycle.mark - gctimer.cycle.installmarkwb + gctimer.total.installmarkwb += times.installmarkwb + gctimer.max.installmarkwb = max(gctimer.max.installmarkwb, times.installmarkwb) + gctimer.maxpause = max(gctimer.maxpause, gctimer.max.installmarkwb) + + times.mark = gctimer.cycle.markterm - gctimer.cycle.mark + gctimer.total.mark += times.mark + gctimer.max.mark = max(gctimer.max.mark, times.mark) + + times.markterm = gctimer.cycle.sweep - gctimer.cycle.markterm + gctimer.total.markterm += times.markterm + gctimer.max.markterm = max(gctimer.max.markterm, times.markterm) + gctimer.maxpause = max(gctimer.maxpause, gctimer.max.markterm) + + return times +} + +// GCprinttimes prints latency information in nanoseconds about various +// phases in the GC. The information for each phase includes the maximum pause +// and total time since the most recent call to GCstarttimes as well as +// the information from the most recent Concurent GC cycle. Calls from the +// application to runtime.GC() are ignored. +func GCprinttimes() { + if gctimer.verbose == 0 { + println("GC timers not enabled") + return + } + + // Explicitly put times on the heap so printPhase can use it. + times := new(gctimes) + *times = calctimes() + cycletime := gctimer.cycle.sweep - gctimer.cycle.sweepterm + pause := times.sweepterm + times.installmarkwb + times.markterm + gomaxprocs := GOMAXPROCS(-1) + + printlock() + print("GC: #", gctimer.count, " ", cycletime, "ns @", gctimer.cycle.sweepterm, " pause=", pause, " maxpause=", gctimer.maxpause, " goroutines=", allglen, " gomaxprocs=", gomaxprocs, "\n") + printPhase := func(label string, get func(*gctimes) int64, procs int) { + print("GC: ", label, " ", get(times), "ns\tmax=", get(&gctimer.max), "\ttotal=", get(&gctimer.total), "\tprocs=", procs, "\n") + } + printPhase("sweep term:", func(t *gctimes) int64 { return t.sweepterm }, gomaxprocs) + printPhase("scan: ", func(t *gctimes) int64 { return t.scan }, 1) + printPhase("install wb:", func(t *gctimes) int64 { return t.installmarkwb }, gomaxprocs) + printPhase("mark: ", func(t *gctimes) int64 { return t.mark }, 1) + printPhase("mark term: ", func(t *gctimes) int64 { return t.markterm }, gomaxprocs) + printunlock() } diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go deleted file mode 100644 index f54d93377d..0000000000 --- a/src/runtime/mgc0.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import _ "unsafe" // for go:linkname - -//go:linkname runtime_debug_freeOSMemory runtime/debug.freeOSMemory -func runtime_debug_freeOSMemory() { - gogc(2) // force GC and do eager sweep - systemstack(scavenge_m) -} - -var poolcleanup func() - -//go:linkname sync_runtime_registerPoolCleanup sync.runtime_registerPoolCleanup -func sync_runtime_registerPoolCleanup(f func()) { - poolcleanup = f -} - -func clearpools() { - // clear sync.Pools - if poolcleanup != nil { - poolcleanup() - } - - for _, p := range &allp { - if p == nil { - break - } - // clear tinyalloc pool - if c := p.mcache; c != nil { - c.tiny = nil - c.tinyoffset = 0 - - // disconnect cached list before dropping it on the floor, - // so that a dangling ref to one entry does not pin all of them. - var sg, sgnext *sudog - for sg = c.sudogcache; sg != nil; sg = sgnext { - sgnext = sg.next - sg.next = nil - } - c.sudogcache = nil - } - - // clear defer pools - for i := range p.deferpool { - // disconnect cached list before dropping it on the floor, - // so that a dangling ref to one entry does not pin all of them. - var d, dlink *_defer - for d = p.deferpool[i]; d != nil; d = dlink { - dlink = d.link - d.link = nil - } - p.deferpool[i] = nil - } - } -} - -// backgroundgc is running in a goroutine and does the concurrent GC work. -// bggc holds the state of the backgroundgc. -func backgroundgc() { - bggc.g = getg() - for { - gcwork(0) - lock(&bggc.lock) - bggc.working = 0 - goparkunlock(&bggc.lock, "Concurrent GC wait", traceEvGoBlock) - } -} - -func bgsweep() { - sweep.g = getg() - for { - for gosweepone() != ^uintptr(0) { - sweep.nbgsweep++ - Gosched() - } - lock(&gclock) - if !gosweepdone() { - // This can happen if a GC runs between - // gosweepone returning ^0 above - // and the lock being acquired. - unlock(&gclock) - continue - } - sweep.parked = true - goparkunlock(&gclock, "GC sweep wait", traceEvGoBlock) - } -} diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go new file mode 100644 index 0000000000..d790af3405 --- /dev/null +++ b/src/runtime/mgcmark.go @@ -0,0 +1,659 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Garbage collector: marking and scanning + +package runtime + +import "unsafe" + +// Scan all of the stacks, greying (or graying if in America) the referents +// but not blackening them since the mark write barrier isn't installed. +//go:nowritebarrier +func gcscan_m() { + _g_ := getg() + + // Grab the g that called us and potentially allow rescheduling. + // This allows it to be scanned like other goroutines. + mastergp := _g_.m.curg + casgstatus(mastergp, _Grunning, _Gwaiting) + mastergp.waitreason = "garbage collection scan" + + // Span sweeping has been done by finishsweep_m. + // Long term we will want to make this goroutine runnable + // by placing it onto a scanenqueue state and then calling + // runtime·restartg(mastergp) to make it Grunnable. + // At the bottom we will want to return this p back to the scheduler. + + // Prepare flag indicating that the scan has not been completed. + lock(&allglock) + local_allglen := allglen + for i := uintptr(0); i < local_allglen; i++ { + gp := allgs[i] + gp.gcworkdone = false // set to true in gcphasework + gp.gcscanvalid = false // stack has not been scanned + } + unlock(&allglock) + + work.nwait = 0 + work.ndone = 0 + work.nproc = 1 // For now do not do this in parallel. + // ackgcphase is not needed since we are not scanning running goroutines. + parforsetup(work.markfor, work.nproc, uint32(_RootCount+local_allglen), false, markroot) + parfordo(work.markfor) + + lock(&allglock) + // Check that gc work is done. + for i := uintptr(0); i < local_allglen; i++ { + gp := allgs[i] + if !gp.gcworkdone { + throw("scan missed a g") + } + } + unlock(&allglock) + + casgstatus(mastergp, _Gwaiting, _Grunning) + // Let the g that called us continue to run. +} + +// ptrmask for an allocation containing a single pointer. +var oneptr = [...]uint8{typePointer} + +//go:nowritebarrier +func markroot(desc *parfor, i uint32) { + var gcw gcWorkProducer + gcw.initFromCache() + + // Note: if you add a case here, please also update heapdump.c:dumproots. + switch i { + case _RootData: + scanblock(uintptr(unsafe.Pointer(&data)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)), gcdatamask.bytedata, &gcw) + + case _RootBss: + scanblock(uintptr(unsafe.Pointer(&bss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)), gcbssmask.bytedata, &gcw) + + case _RootFinalizers: + for fb := allfin; fb != nil; fb = fb.alllink { + scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], &gcw) + } + + case _RootSpans: + // mark MSpan.specials + sg := mheap_.sweepgen + for spanidx := uint32(0); spanidx < uint32(len(work.spans)); spanidx++ { + s := work.spans[spanidx] + if s.state != mSpanInUse { + continue + } + if !checkmarkphase && s.sweepgen != sg { + // sweepgen was updated (+2) during non-checkmark GC pass + print("sweep ", s.sweepgen, " ", sg, "\n") + throw("gc: unswept span") + } + for sp := s.specials; sp != nil; sp = sp.next { + if sp.kind != _KindSpecialFinalizer { + continue + } + // don't mark finalized object, but scan it so we + // retain everything it points to. + spf := (*specialfinalizer)(unsafe.Pointer(sp)) + // A finalizer can be set for an inner byte of an object, find object beginning. + p := uintptr(s.start<<_PageShift) + uintptr(spf.special.offset)/s.elemsize*s.elemsize + if gcphase != _GCscan { + scanblock(p, s.elemsize, nil, &gcw) // scanned during mark phase + } + scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptr[0], &gcw) + } + } + + case _RootFlushCaches: + if gcphase != _GCscan { // Do not flush mcaches during GCscan phase. + flushallmcaches() + } + + default: + // the rest is scanning goroutine stacks + if uintptr(i-_RootCount) >= allglen { + throw("markroot: bad index") + } + gp := allgs[i-_RootCount] + + // remember when we've first observed the G blocked + // needed only to output in traceback + status := readgstatus(gp) // We are not in a scan state + if (status == _Gwaiting || status == _Gsyscall) && gp.waitsince == 0 { + gp.waitsince = work.tstart + } + + // Shrink a stack if not much of it is being used but not in the scan phase. + if gcphase == _GCmarktermination { + // Shrink during STW GCmarktermination phase thus avoiding + // complications introduced by shrinking during + // non-STW phases. + shrinkstack(gp) + } + if readgstatus(gp) == _Gdead { + gp.gcworkdone = true + } else { + gp.gcworkdone = false + } + restart := stopg(gp) + + // goroutine will scan its own stack when it stops running. + // Wait until it has. + for readgstatus(gp) == _Grunning && !gp.gcworkdone { + } + + // scanstack(gp) is done as part of gcphasework + // But to make sure we finished we need to make sure that + // the stack traps have all responded so drop into + // this while loop until they respond. + for !gp.gcworkdone { + status = readgstatus(gp) + if status == _Gdead { + gp.gcworkdone = true // scan is a noop + break + } + if status == _Gwaiting || status == _Grunnable { + restart = stopg(gp) + } + } + if restart { + restartg(gp) + } + } + gcw.dispose() +} + +// gchelpwork does a small bounded amount of gc work. The purpose is to +// shorten the time (as measured by allocations) spent doing a concurrent GC. +// The number of mutator calls is roughly propotional to the number of allocations +// made by that mutator. This slows down the allocation while speeding up the GC. +//go:nowritebarrier +func gchelpwork() { + switch gcphase { + default: + throw("gcphasework in bad gcphase") + case _GCoff, _GCquiesce, _GCstw: + // No work. + case _GCsweep: + // We could help by calling sweepone to sweep a single span. + // _ = sweepone() + case _GCscan: + // scan the stack, mark the objects, put pointers in work buffers + // hanging off the P where this is being run. + // scanstack(gp) + case _GCmark: + // Get a full work buffer and empty it. + // drain your own currentwbuf first in the hopes that it will + // be more cache friendly. + var gcw gcWork + gcw.initFromCache() + const n = len(workbuf{}.obj) + gcDrainN(&gcw, n) // drain upto one buffer's worth of objects + gcw.dispose() + case _GCmarktermination: + // We should never be here since the world is stopped. + // All available mark work will be emptied before returning. + throw("gcphasework in bad gcphase") + } +} + +// The gp has been moved to a GC safepoint. GC phase specific +// work is done here. +//go:nowritebarrier +func gcphasework(gp *g) { + switch gcphase { + default: + throw("gcphasework in bad gcphase") + case _GCoff, _GCquiesce, _GCstw, _GCsweep: + // No work. + case _GCscan: + // scan the stack, mark the objects, put pointers in work buffers + // hanging off the P where this is being run. + // Indicate that the scan is valid until the goroutine runs again + scanstack(gp) + case _GCmark: + // No work. + case _GCmarktermination: + scanstack(gp) + // All available mark work will be emptied before returning. + } + gp.gcworkdone = true +} + +//go:nowritebarrier +func scanstack(gp *g) { + if gp.gcscanvalid { + return + } + + if readgstatus(gp)&_Gscan == 0 { + print("runtime:scanstack: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", hex(readgstatus(gp)), "\n") + throw("scanstack - bad status") + } + + switch readgstatus(gp) &^ _Gscan { + default: + print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n") + throw("mark - bad status") + case _Gdead: + return + case _Grunning: + print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n") + throw("scanstack: goroutine not stopped") + case _Grunnable, _Gsyscall, _Gwaiting: + // ok + } + + if gp == getg() { + throw("can't scan our own stack") + } + mp := gp.m + if mp != nil && mp.helpgc != 0 { + throw("can't scan gchelper stack") + } + + var gcw gcWorkProducer + gcw.initFromCache() + scanframe := func(frame *stkframe, unused unsafe.Pointer) bool { + // Pick up gcw as free variable so gentraceback and friends can + // keep the same signature. + scanframeworker(frame, unused, &gcw) + return true + } + gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0) + tracebackdefers(gp, scanframe, nil) + gcw.disposeToCache() + gp.gcscanvalid = true +} + +// Scan a stack frame: local variables and function arguments/results. +//go:nowritebarrier +func scanframeworker(frame *stkframe, unused unsafe.Pointer, gcw *gcWorkProducer) { + + f := frame.fn + targetpc := frame.continpc + if targetpc == 0 { + // Frame is dead. + return + } + if _DebugGC > 1 { + print("scanframe ", funcname(f), "\n") + } + if targetpc != f.entry { + targetpc-- + } + pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc) + if pcdata == -1 { + // We do not have a valid pcdata value but there might be a + // stackmap for this function. It is likely that we are looking + // at the function prologue, assume so and hope for the best. + pcdata = 0 + } + + // Scan local variables if stack frame has been allocated. + size := frame.varp - frame.sp + var minsize uintptr + if thechar != '6' && thechar != '8' { + minsize = ptrSize + } else { + minsize = 0 + } + if size > minsize { + stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps)) + if stkmap == nil || stkmap.n <= 0 { + print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n") + throw("missing stackmap") + } + + // Locals bitmap information, scan just the pointers in locals. + if pcdata < 0 || pcdata >= stkmap.n { + // don't know where we are + print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n") + throw("scanframe: bad symbol table") + } + bv := stackmapdata(stkmap, pcdata) + size = (uintptr(bv.n) / typeBitsWidth) * ptrSize + scanblock(frame.varp-size, size, bv.bytedata, gcw) + } + + // Scan arguments. + if frame.arglen > 0 { + var bv bitvector + if frame.argmap != nil { + bv = *frame.argmap + } else { + stkmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps)) + if stkmap == nil || stkmap.n <= 0 { + print("runtime: frame ", funcname(f), " untyped args ", hex(frame.argp), "+", hex(frame.arglen), "\n") + throw("missing stackmap") + } + if pcdata < 0 || pcdata >= stkmap.n { + // don't know where we are + print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " args stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n") + throw("scanframe: bad symbol table") + } + bv = stackmapdata(stkmap, pcdata) + } + scanblock(frame.argp, uintptr(bv.n)/typeBitsWidth*ptrSize, bv.bytedata, gcw) + } +} + +// gcDrain scans objects in work buffers (starting with wbuf), blackening grey +// objects until all work buffers have been drained. +//go:nowritebarrier +func gcDrain(gcw *gcWork) { + if gcphase != _GCmark && gcphase != _GCmarktermination { + throw("scanblock phase incorrect") + } + + for { + // If another proc wants a pointer, give it some. + if work.nwait > 0 && work.full == 0 { + gcw.balance() + } + + b := gcw.get() + if b == 0 { + // work barrier reached + break + } + // If the current wbuf is filled by the scan a new wbuf might be + // returned that could possibly hold only a single object. This + // could result in each iteration draining only a single object + // out of the wbuf passed in + a single object placed + // into an empty wbuf in scanobject so there could be + // a performance hit as we keep fetching fresh wbufs. + scanobject(b, 0, nil, &gcw.gcWorkProducer) + } + checknocurrentwbuf() +} + +// gcDrainN scans n objects, blackening grey objects. +//go:nowritebarrier +func gcDrainN(gcw *gcWork, n int) { + checknocurrentwbuf() + for i := 0; i < n; i++ { + // This might be a good place to add prefetch code... + // if(wbuf.nobj > 4) { + // PREFETCH(wbuf->obj[wbuf.nobj - 3]; + // } + b := gcw.tryGet() + if b == 0 { + return + } + scanobject(b, 0, nil, &gcw.gcWorkProducer) + } +} + +// scanblock scans b as scanobject would. +// If the gcphase is GCscan, scanblock performs additional checks. +//go:nowritebarrier +func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWorkProducer) { + // Use local copies of original parameters, so that a stack trace + // due to one of the throws below shows the original block + // base and extent. + b := b0 + n := n0 + + // ptrmask can have 2 possible values: + // 1. nil - obtain pointer mask from GC bitmap. + // 2. pointer to a compact mask (for stacks and data). + + scanobject(b, n, ptrmask, gcw) + if gcphase == _GCscan { + if inheap(b) && ptrmask == nil { + // b is in heap, we are in GCscan so there should be a ptrmask. + throw("scanblock: In GCscan phase and inheap is true.") + } + } +} + +// Scan the object b of size n, adding pointers to wbuf. +// Return possibly new wbuf to use. +// If ptrmask != nil, it specifies where pointers are in b. +// If ptrmask == nil, the GC bitmap should be consulted. +// In this case, n may be an overestimate of the size; the GC bitmap +// must also be used to make sure the scan stops at the end of b. +//go:nowritebarrier +func scanobject(b, n uintptr, ptrmask *uint8, gcw *gcWorkProducer) { + arena_start := mheap_.arena_start + arena_used := mheap_.arena_used + + // Find bits of the beginning of the object. + var hbits heapBits + if ptrmask == nil { + b, hbits = heapBitsForObject(b) + if b == 0 { + return + } + if n == 0 { + n = mheap_.arena_used - b + } + } + for i := uintptr(0); i < n; i += ptrSize { + // Find bits for this word. + var bits uintptr + if ptrmask != nil { + // dense mask (stack or data) + bits = (uintptr(*(*byte)(add(unsafe.Pointer(ptrmask), (i/ptrSize)/4))) >> (((i / ptrSize) % 4) * typeBitsWidth)) & typeMask + } else { + // Check if we have reached end of span. + // n is an overestimate of the size of the object. + if (b+i)%_PageSize == 0 && h_spans[(b-arena_start)>>_PageShift] != h_spans[(b+i-arena_start)>>_PageShift] { + break + } + + bits = uintptr(hbits.typeBits()) + if i > 0 && (hbits.isBoundary() || bits == typeDead) { + break // reached beginning of the next object + } + hbits = hbits.next() + } + + if bits <= typeScalar { // typeScalar, typeDead, typeScalarMarked + continue + } + + if bits&typePointer != typePointer { + print("gc checkmarkphase=", checkmarkphase, " b=", hex(b), " ptrmask=", ptrmask, "\n") + throw("unexpected garbage collection bits") + } + + obj := *(*uintptr)(unsafe.Pointer(b + i)) + + // At this point we have extracted the next potential pointer. + // Check if it points into heap. + if obj == 0 || obj < arena_start || obj >= arena_used { + continue + } + + if mheap_.shadow_enabled && debug.wbshadow >= 2 && debug.gccheckmark > 0 && checkmarkphase { + checkwbshadow((*uintptr)(unsafe.Pointer(b + i))) + } + + // Mark the object. + if obj, hbits := heapBitsForObject(obj); obj != 0 { + greyobject(obj, b, i, hbits, gcw) + } + } +} + +// Shade the object if it isn't already. +// The object is not nil and known to be in the heap. +//go:nowritebarrier +func shade(b uintptr) { + if !inheap(b) { + throw("shade: passed an address not in the heap") + } + if obj, hbits := heapBitsForObject(b); obj != 0 { + // TODO: this would be a great place to put a check to see + // if we are harvesting and if we are then we should + // figure out why there is a call to shade when the + // harvester thinks we are in a STW. + // if atomicload(&harvestingwbufs) == uint32(1) { + // // Throw here to discover write barriers + // // being executed during a STW. + // throw("shade during harvest") + // } + + var gcw gcWorkProducer + greyobject(obj, 0, 0, hbits, &gcw) + // This is part of the write barrier so put the wbuf back. + if gcphase == _GCmarktermination { + gcw.dispose() + } else { + // If we added any pointers to the gcw, then + // currentwbuf must be nil because 1) + // greyobject got its wbuf from currentwbuf + // and 2) shade runs on the systemstack, so + // we're still on the same M. If either of + // these becomes no longer true, we need to + // rethink this. + gcw.disposeToCache() + } + } +} + +// obj is the start of an object with mark mbits. +// If it isn't already marked, mark it and enqueue into workbuf. +// Return possibly new workbuf to use. +// base and off are for debugging only and could be removed. +//go:nowritebarrier +func greyobject(obj, base, off uintptr, hbits heapBits, gcw *gcWorkProducer) { + // obj should be start of allocation, and so must be at least pointer-aligned. + if obj&(ptrSize-1) != 0 { + throw("greyobject: obj not pointer-aligned") + } + + if checkmarkphase { + if !hbits.isMarked() { + print("runtime:greyobject: checkmarks finds unexpected unmarked object obj=", hex(obj), "\n") + print("runtime: found obj at *(", hex(base), "+", hex(off), ")\n") + + // Dump the source (base) object + + kb := base >> _PageShift + xb := kb + xb -= mheap_.arena_start >> _PageShift + sb := h_spans[xb] + printlock() + print("runtime:greyobject Span: base=", hex(base), " kb=", hex(kb)) + if sb == nil { + print(" sb=nil\n") + } else { + print(" sb.start*_PageSize=", hex(sb.start*_PageSize), " sb.limit=", hex(sb.limit), " sb.sizeclass=", sb.sizeclass, " sb.elemsize=", sb.elemsize, "\n") + // base is (a pointer to) the source object holding the reference to object. Create a pointer to each of the fields + // fields in base and print them out as hex values. + for i := 0; i < int(sb.elemsize/ptrSize); i++ { + print(" *(base+", i*ptrSize, ") = ", hex(*(*uintptr)(unsafe.Pointer(base + uintptr(i)*ptrSize))), "\n") + } + } + + // Dump the object + + k := obj >> _PageShift + x := k + x -= mheap_.arena_start >> _PageShift + s := h_spans[x] + print("runtime:greyobject Span: obj=", hex(obj), " k=", hex(k)) + if s == nil { + print(" s=nil\n") + } else { + print(" s.start=", hex(s.start*_PageSize), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, "\n") + // NOTE(rsc): This code is using s.sizeclass as an approximation of the + // number of pointer-sized words in an object. Perhaps not what was intended. + for i := 0; i < int(s.sizeclass); i++ { + print(" *(obj+", i*ptrSize, ") = ", hex(*(*uintptr)(unsafe.Pointer(obj + uintptr(i)*ptrSize))), "\n") + } + } + throw("checkmark found unmarked object") + } + if !hbits.isCheckmarked() { + return + } + hbits.setCheckmarked() + if !hbits.isCheckmarked() { + throw("setCheckmarked and isCheckmarked disagree") + } + } else { + // If marked we have nothing to do. + if hbits.isMarked() { + return + } + + // Each byte of GC bitmap holds info for two words. + // Might be racing with other updates, so use atomic update always. + // We used to be clever here and use a non-atomic update in certain + // cases, but it's not worth the risk. + hbits.setMarked() + } + + if !checkmarkphase && hbits.typeBits() == typeDead { + return // noscan object + } + + // Queue the obj for scanning. The PREFETCH(obj) logic has been removed but + // seems like a nice optimization that can be added back in. + // There needs to be time between the PREFETCH and the use. + // Previously we put the obj in an 8 element buffer that is drained at a rate + // to give the PREFETCH time to do its work. + // Use of PREFETCHNTA might be more appropriate than PREFETCH + + gcw.put(obj) +} + +// When in GCmarkterminate phase we allocate black. +//go:nowritebarrier +func gcmarknewobject_m(obj uintptr) { + if gcphase != _GCmarktermination { + throw("marking new object while not in mark termination phase") + } + if checkmarkphase { // The world should be stopped so this should not happen. + throw("gcmarknewobject called while doing checkmark") + } + + heapBitsForAddr(obj).setMarked() +} + +// Checkmarking + +// To help debug the concurrent GC we remark with the world +// stopped ensuring that any object encountered has their normal +// mark bit set. To do this we use an orthogonal bit +// pattern to indicate the object is marked. The following pattern +// uses the upper two bits in the object's bounday nibble. +// 01: scalar not marked +// 10: pointer not marked +// 11: pointer marked +// 00: scalar marked +// Xoring with 01 will flip the pattern from marked to unmarked and vica versa. +// The higher bit is 1 for pointers and 0 for scalars, whether the object +// is marked or not. +// The first nibble no longer holds the typeDead pattern indicating that the +// there are no more pointers in the object. This information is held +// in the second nibble. + +// When marking an object if the bool checkmarkphase is true one uses the above +// encoding, otherwise one uses the bitMarked bit in the lower two bits +// of the nibble. +var checkmarkphase = false + +//go:nowritebarrier +func initCheckmarks() { + for _, s := range work.spans { + if s.state == _MSpanInUse { + heapBitsForSpan(s.base()).initCheckmarkSpan(s.layout()) + } + } +} + +func clearCheckmarks() { + for _, s := range work.spans { + if s.state == _MSpanInUse { + heapBitsForSpan(s.base()).clearCheckmarkSpan(s.layout()) + } + } +} diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go new file mode 100644 index 0000000000..92ddc51e1f --- /dev/null +++ b/src/runtime/mgcsweep.go @@ -0,0 +1,312 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Garbage collector: sweeping + +package runtime + +import "unsafe" + +var sweep sweepdata + +// State of background sweep. +// Protected by gclock. +type sweepdata struct { + g *g + parked bool + started bool + + spanidx uint32 // background sweeper position + + nbgsweep uint32 + npausesweep uint32 +} + +var gclock mutex + +//go:nowritebarrier +func finishsweep_m() { + // The world is stopped so we should be able to complete the sweeps + // quickly. + for sweepone() != ^uintptr(0) { + sweep.npausesweep++ + } + + // There may be some other spans being swept concurrently that + // we need to wait for. If finishsweep_m is done with the world stopped + // this code is not required. + sg := mheap_.sweepgen + for _, s := range work.spans { + if s.sweepgen != sg && s.state == _MSpanInUse { + mSpan_EnsureSwept(s) + } + } +} + +func bgsweep() { + sweep.g = getg() + for { + for gosweepone() != ^uintptr(0) { + sweep.nbgsweep++ + Gosched() + } + lock(&gclock) + if !gosweepdone() { + // This can happen if a GC runs between + // gosweepone returning ^0 above + // and the lock being acquired. + unlock(&gclock) + continue + } + sweep.parked = true + goparkunlock(&gclock, "GC sweep wait", traceEvGoBlock) + } +} + +// sweeps one span +// returns number of pages returned to heap, or ^uintptr(0) if there is nothing to sweep +//go:nowritebarrier +func sweepone() uintptr { + _g_ := getg() + + // increment locks to ensure that the goroutine is not preempted + // in the middle of sweep thus leaving the span in an inconsistent state for next GC + _g_.m.locks++ + sg := mheap_.sweepgen + for { + idx := xadd(&sweep.spanidx, 1) - 1 + if idx >= uint32(len(work.spans)) { + mheap_.sweepdone = 1 + _g_.m.locks-- + return ^uintptr(0) + } + s := work.spans[idx] + if s.state != mSpanInUse { + s.sweepgen = sg + continue + } + if s.sweepgen != sg-2 || !cas(&s.sweepgen, sg-2, sg-1) { + continue + } + npages := s.npages + if !mSpan_Sweep(s, false) { + npages = 0 + } + _g_.m.locks-- + return npages + } +} + +//go:nowritebarrier +func gosweepone() uintptr { + var ret uintptr + systemstack(func() { + ret = sweepone() + }) + return ret +} + +//go:nowritebarrier +func gosweepdone() bool { + return mheap_.sweepdone != 0 +} + +// Returns only when span s has been swept. +//go:nowritebarrier +func mSpan_EnsureSwept(s *mspan) { + // Caller must disable preemption. + // Otherwise when this function returns the span can become unswept again + // (if GC is triggered on another goroutine). + _g_ := getg() + if _g_.m.locks == 0 && _g_.m.mallocing == 0 && _g_ != _g_.m.g0 { + throw("MSpan_EnsureSwept: m is not locked") + } + + sg := mheap_.sweepgen + if atomicload(&s.sweepgen) == sg { + return + } + // The caller must be sure that the span is a MSpanInUse span. + if cas(&s.sweepgen, sg-2, sg-1) { + mSpan_Sweep(s, false) + return + } + // unfortunate condition, and we don't have efficient means to wait + for atomicload(&s.sweepgen) != sg { + osyield() + } +} + +// Sweep frees or collects finalizers for blocks not marked in the mark phase. +// It clears the mark bits in preparation for the next GC round. +// Returns true if the span was returned to heap. +// If preserve=true, don't return it to heap nor relink in MCentral lists; +// caller takes care of it. +//TODO go:nowritebarrier +func mSpan_Sweep(s *mspan, preserve bool) bool { + if checkmarkphase { + throw("MSpan_Sweep: checkmark only runs in STW and after the sweep") + } + + // It's critical that we enter this function with preemption disabled, + // GC must not start while we are in the middle of this function. + _g_ := getg() + if _g_.m.locks == 0 && _g_.m.mallocing == 0 && _g_ != _g_.m.g0 { + throw("MSpan_Sweep: m is not locked") + } + sweepgen := mheap_.sweepgen + if s.state != mSpanInUse || s.sweepgen != sweepgen-1 { + print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n") + throw("MSpan_Sweep: bad span state") + } + + if trace.enabled { + traceGCSweepStart() + } + + cl := s.sizeclass + size := s.elemsize + res := false + nfree := 0 + + var head, end gclinkptr + + c := _g_.m.mcache + sweepgenset := false + + // Mark any free objects in this span so we don't collect them. + for link := s.freelist; link.ptr() != nil; link = link.ptr().next { + heapBitsForAddr(uintptr(link)).setMarkedNonAtomic() + } + + // Unlink & free special records for any objects we're about to free. + specialp := &s.specials + special := *specialp + for special != nil { + // A finalizer can be set for an inner byte of an object, find object beginning. + p := uintptr(s.start<<_PageShift) + uintptr(special.offset)/size*size + hbits := heapBitsForAddr(p) + if !hbits.isMarked() { + // Find the exact byte for which the special was setup + // (as opposed to object beginning). + p := uintptr(s.start<<_PageShift) + uintptr(special.offset) + // about to free object: splice out special record + y := special + special = special.next + *specialp = special + if !freespecial(y, unsafe.Pointer(p), size, false) { + // stop freeing of object if it has a finalizer + hbits.setMarkedNonAtomic() + } + } else { + // object is still live: keep special record + specialp = &special.next + special = *specialp + } + } + + // Sweep through n objects of given size starting at p. + // This thread owns the span now, so it can manipulate + // the block bitmap without atomic operations. + + size, n, _ := s.layout() + heapBitsSweepSpan(s.base(), size, n, func(p uintptr) { + // At this point we know that we are looking at garbage object + // that needs to be collected. + if debug.allocfreetrace != 0 { + tracefree(unsafe.Pointer(p), size) + } + + // Reset to allocated+noscan. + if cl == 0 { + // Free large span. + if preserve { + throw("can't preserve large span") + } + heapBitsForSpan(p).clearSpan(s.layout()) + s.needzero = 1 + + // important to set sweepgen before returning it to heap + atomicstore(&s.sweepgen, sweepgen) + sweepgenset = true + + // NOTE(rsc,dvyukov): The original implementation of efence + // in CL 22060046 used SysFree instead of SysFault, so that + // the operating system would eventually give the memory + // back to us again, so that an efence program could run + // longer without running out of memory. Unfortunately, + // calling SysFree here without any kind of adjustment of the + // heap data structures means that when the memory does + // come back to us, we have the wrong metadata for it, either in + // the MSpan structures or in the garbage collection bitmap. + // Using SysFault here means that the program will run out of + // memory fairly quickly in efence mode, but at least it won't + // have mysterious crashes due to confused memory reuse. + // It should be possible to switch back to SysFree if we also + // implement and then call some kind of MHeap_DeleteSpan. + if debug.efence > 0 { + s.limit = 0 // prevent mlookup from finding this span + sysFault(unsafe.Pointer(p), size) + } else { + mHeap_Free(&mheap_, s, 1) + } + c.local_nlargefree++ + c.local_largefree += size + reduction := int64(size) * int64(gcpercent+100) / 100 + if int64(memstats.next_gc)-reduction > int64(heapminimum) { + xadd64(&memstats.next_gc, -reduction) + } else { + atomicstore64(&memstats.next_gc, heapminimum) + } + res = true + } else { + // Free small object. + if size > 2*ptrSize { + *(*uintptr)(unsafe.Pointer(p + ptrSize)) = uintptrMask & 0xdeaddeaddeaddead // mark as "needs to be zeroed" + } else if size > ptrSize { + *(*uintptr)(unsafe.Pointer(p + ptrSize)) = 0 + } + if head.ptr() == nil { + head = gclinkptr(p) + } else { + end.ptr().next = gclinkptr(p) + } + end = gclinkptr(p) + end.ptr().next = gclinkptr(0x0bade5) + nfree++ + } + }) + + // We need to set s.sweepgen = h.sweepgen only when all blocks are swept, + // because of the potential for a concurrent free/SetFinalizer. + // But we need to set it before we make the span available for allocation + // (return it to heap or mcentral), because allocation code assumes that a + // span is already swept if available for allocation. + if !sweepgenset && nfree == 0 { + // The span must be in our exclusive ownership until we update sweepgen, + // check for potential races. + if s.state != mSpanInUse || s.sweepgen != sweepgen-1 { + print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n") + throw("MSpan_Sweep: bad span state after sweep") + } + atomicstore(&s.sweepgen, sweepgen) + } + if nfree > 0 { + c.local_nsmallfree[cl] += uintptr(nfree) + c.local_cachealloc -= intptr(uintptr(nfree) * size) + reduction := int64(nfree) * int64(size) * int64(gcpercent+100) / 100 + if int64(memstats.next_gc)-reduction > int64(heapminimum) { + xadd64(&memstats.next_gc, -reduction) + } else { + atomicstore64(&memstats.next_gc, heapminimum) + } + res = mCentral_FreeSpan(&mheap_.central[cl].mcentral, s, int32(nfree), head, end, preserve) + // MCentral_FreeSpan updates sweepgen + } + if trace.enabled { + traceGCSweepDone() + traceNextGC() + } + return res +} diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go index 13f1b363d0..d082f8e622 100644 --- a/src/runtime/mheap.go +++ b/src/runtime/mheap.go @@ -4,7 +4,72 @@ // Page heap. // -// See malloc.h for overview. +// See malloc.go for overview. + +package runtime + +import "unsafe" + +// Main malloc heap. +// The heap itself is the "free[]" and "large" arrays, +// but all the other global data is here too. +type mheap struct { + lock mutex + free [_MaxMHeapList]mspan // free lists of given length + freelarge mspan // free lists length >= _MaxMHeapList + busy [_MaxMHeapList]mspan // busy lists of large objects of given length + busylarge mspan // busy lists of large objects length >= _MaxMHeapList + allspans **mspan // all spans out there + gcspans **mspan // copy of allspans referenced by gc marker or sweeper + nspan uint32 + sweepgen uint32 // sweep generation, see comment in mspan + sweepdone uint32 // all spans are swept + + // span lookup + spans **mspan + spans_mapped uintptr + + // range of addresses we might see in the heap + bitmap uintptr + bitmap_mapped uintptr + arena_start uintptr + arena_used uintptr + arena_end uintptr + arena_reserved bool + + // write barrier shadow data+heap. + // 64-bit systems only, enabled by GODEBUG=wbshadow=1. + shadow_enabled bool // shadow should be updated and checked + shadow_reserved bool // shadow memory is reserved + shadow_heap uintptr // heap-addr + shadow_heap = shadow heap addr + shadow_data uintptr // data-addr + shadow_data = shadow data addr + data_start uintptr // start of shadowed data addresses + data_end uintptr // end of shadowed data addresses + + // central free lists for small size classes. + // the padding makes sure that the MCentrals are + // spaced CacheLineSize bytes apart, so that each MCentral.lock + // gets its own cache line. + central [_NumSizeClasses]struct { + mcentral mcentral + pad [_CacheLineSize]byte + } + + spanalloc fixalloc // allocator for span* + cachealloc fixalloc // allocator for mcache* + specialfinalizeralloc fixalloc // allocator for specialfinalizer* + specialprofilealloc fixalloc // allocator for specialprofile* + speciallock mutex // lock for sepcial record allocators. + + // Malloc stats. + largefree uint64 // bytes freed for large objects (>maxsmallsize) + nlargefree uint64 // number of frees for large objects (>maxsmallsize) + nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize) +} + +var mheap_ mheap + +// An MSpan is a run of pages. // // When a MSpan is in the heap free list, state == MSpanFree // and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span. @@ -12,9 +77,55 @@ // When a MSpan is allocated, state == MSpanInUse or MSpanStack // and heapmap(i) == span for all s->start <= i < s->start+s->npages. -package runtime - -import "unsafe" +// Every MSpan is in one doubly-linked list, +// either one of the MHeap's free lists or one of the +// MCentral's span lists. We use empty MSpan structures as list heads. + +const ( + _MSpanInUse = iota // allocated for garbage collected heap + _MSpanStack // allocated for use by stack allocator + _MSpanFree + _MSpanListHead + _MSpanDead +) + +type mspan struct { + next *mspan // in a span linked list + prev *mspan // in a span linked list + start pageID // starting page number + npages uintptr // number of pages in span + freelist gclinkptr // list of free objects + // sweep generation: + // if sweepgen == h->sweepgen - 2, the span needs sweeping + // if sweepgen == h->sweepgen - 1, the span is currently being swept + // if sweepgen == h->sweepgen, the span is swept and ready to use + // h->sweepgen is incremented by 2 after every GC + sweepgen uint32 + ref uint16 // capacity - number of objects in freelist + sizeclass uint8 // size class + incache bool // being used by an mcache + state uint8 // mspaninuse etc + needzero uint8 // needs to be zeroed before allocation + elemsize uintptr // computed from sizeclass or from npages + unusedsince int64 // first time spotted by gc in mspanfree state + npreleased uintptr // number of pages released to the os + limit uintptr // end of data in span + speciallock mutex // guards specials list + specials *special // linked list of special records sorted by offset. +} + +func (s *mspan) base() uintptr { + return uintptr(s.start << _PageShift) +} + +func (s *mspan) layout() (size, n, total uintptr) { + total = s.npages << _PageShift + size = s.elemsize + if size > 0 { + n = total / size + } + return +} var h_allspans []*mspan // TODO: make this h.allspans once mheap can be defined in Go var h_spans []*mspan // TODO: make this h.spans once mheap can be defined in Go @@ -50,6 +161,73 @@ func recordspan(vh unsafe.Pointer, p unsafe.Pointer) { h.nspan = uint32(len(h_allspans)) } +// inheap reports whether b is a pointer into a (potentially dead) heap object. +// It returns false for pointers into stack spans. +//go:nowritebarrier +func inheap(b uintptr) bool { + if b == 0 || b < mheap_.arena_start || b >= mheap_.arena_used { + return false + } + // Not a beginning of a block, consult span table to find the block beginning. + k := b >> _PageShift + x := k + x -= mheap_.arena_start >> _PageShift + s := h_spans[x] + if s == nil || pageID(k) < s.start || b >= s.limit || s.state != mSpanInUse { + return false + } + return true +} + +func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 { + _g_ := getg() + + _g_.m.mcache.local_nlookup++ + if ptrSize == 4 && _g_.m.mcache.local_nlookup >= 1<<30 { + // purge cache stats to prevent overflow + lock(&mheap_.lock) + purgecachedstats(_g_.m.mcache) + unlock(&mheap_.lock) + } + + s := mHeap_LookupMaybe(&mheap_, unsafe.Pointer(v)) + if sp != nil { + *sp = s + } + if s == nil { + if base != nil { + *base = 0 + } + if size != nil { + *size = 0 + } + return 0 + } + + p := uintptr(s.start) << _PageShift + if s.sizeclass == 0 { + // Large object. + if base != nil { + *base = p + } + if size != nil { + *size = s.npages << _PageShift + } + return 1 + } + + n := s.elemsize + if base != nil { + i := (uintptr(v) - uintptr(p)) / n + *base = p + i*n + } + if size != nil { + *size = n + } + + return 1 +} + // Initialize the heap. func mHeap_Init(h *mheap, spans_size uintptr) { fixAlloc_Init(&h.spanalloc, unsafe.Sizeof(mspan{}), recordspan, unsafe.Pointer(h), &memstats.mspan_sys) @@ -635,6 +813,21 @@ func mSpanList_InsertBack(list *mspan, span *mspan) { span.prev.next = span } +const ( + _KindSpecialFinalizer = 1 + _KindSpecialProfile = 2 + // Note: The finalizer special must be first because if we're freeing + // an object, a finalizer special will cause the freeing operation + // to abort, and we want to keep the other special records around + // if that happens. +) + +type special struct { + next *special // linked list in span + offset uint16 // span offset of object + kind byte // kind of special +} + // Adds the special record s to the list of special records for // the object p. All fields of s should be filled in except for // offset & next, which this routine will fill in. @@ -723,6 +916,15 @@ func removespecial(p unsafe.Pointer, kind uint8) *special { return nil } +// The described object has a finalizer set for it. +type specialfinalizer struct { + special special + fn *funcval + nret uintptr + fint *_type + ot *ptrtype +} + // Adds a finalizer to the object p. Returns true if it succeeded. func addfinalizer(p unsafe.Pointer, f *funcval, nret uintptr, fint *_type, ot *ptrtype) bool { lock(&mheap_.speciallock) @@ -755,6 +957,12 @@ func removefinalizer(p unsafe.Pointer) { unlock(&mheap_.speciallock) } +// The described object is being heap profiled. +type specialprofile struct { + special special + b *bucket +} + // Set the heap profile bucket associated with addr to b. func setprofilebucket(p unsafe.Pointer, b *bucket) { lock(&mheap_.speciallock) diff --git a/src/runtime/msize.go b/src/runtime/msize.go index a113b0d963..370cae629e 100644 --- a/src/runtime/msize.go +++ b/src/runtime/msize.go @@ -27,8 +27,15 @@ package runtime -//var class_to_size [_NumSizeClasses]int32 -//var class_to_allocnpages [_NumSizeClasses]int32 +// Size classes. Computed and initialized by InitSizes. +// +// SizeToClass(0 <= n <= MaxSmallSize) returns the size class, +// 1 <= sizeclass < NumSizeClasses, for n. +// Size class 0 is reserved to mean "not small". +// +// class_to_size[i] = largest size in class i +// class_to_allocnpages[i] = number of pages to allocate when +// making new objects in class i // The SizeToClass lookup is implemented using two arrays, // one mapping sizes <= 1024 to their class and one mapping @@ -38,8 +45,11 @@ package runtime // are 128-aligned, so the second array is indexed by the // size divided by 128 (rounded up). The arrays are filled in // by InitSizes. -//var size_to_class8 [1024/8 + 1]int8 -//var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8 + +var class_to_size [_NumSizeClasses]int32 +var class_to_allocnpages [_NumSizeClasses]int32 +var size_to_class8 [1024/8 + 1]int8 +var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8 func sizeToClass(size int32) int32 { if size > _MaxSmallSize { diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go new file mode 100644 index 0000000000..19b6833a32 --- /dev/null +++ b/src/runtime/mstats.go @@ -0,0 +1,340 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Memory statistics + +package runtime + +import "unsafe" + +// Statistics. +// Shared with Go: if you edit this structure, also edit type MemStats in mem.go. +type mstats struct { + // General statistics. + alloc uint64 // bytes allocated and still in use + total_alloc uint64 // bytes allocated (even if freed) + sys uint64 // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate) + nlookup uint64 // number of pointer lookups + nmalloc uint64 // number of mallocs + nfree uint64 // number of frees + + // Statistics about malloc heap. + // protected by mheap.lock + heap_alloc uint64 // bytes allocated and still in use + heap_sys uint64 // bytes obtained from system + heap_idle uint64 // bytes in idle spans + heap_inuse uint64 // bytes in non-idle spans + heap_released uint64 // bytes released to the os + heap_objects uint64 // total number of allocated objects + + // Statistics about allocation of low-level fixed-size structures. + // Protected by FixAlloc locks. + stacks_inuse uint64 // this number is included in heap_inuse above + stacks_sys uint64 // always 0 in mstats + mspan_inuse uint64 // mspan structures + mspan_sys uint64 + mcache_inuse uint64 // mcache structures + mcache_sys uint64 + buckhash_sys uint64 // profiling bucket hash table + gc_sys uint64 + other_sys uint64 + + // Statistics about garbage collector. + // Protected by mheap or stopping the world during GC. + next_gc uint64 // next gc (in heap_alloc time) + last_gc uint64 // last gc (in absolute time) + pause_total_ns uint64 + pause_ns [256]uint64 // circular buffer of recent gc pause lengths + pause_end [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970) + numgc uint32 + enablegc bool + debuggc bool + + // Statistics about allocation size classes. + + by_size [_NumSizeClasses]struct { + size uint32 + nmalloc uint64 + nfree uint64 + } + + tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly +} + +var memstats mstats + +// Note: the MemStats struct should be kept in sync with +// struct MStats in malloc.h + +// A MemStats records statistics about the memory allocator. +type MemStats struct { + // General statistics. + Alloc uint64 // bytes allocated and still in use + TotalAlloc uint64 // bytes allocated (even if freed) + Sys uint64 // bytes obtained from system (sum of XxxSys below) + Lookups uint64 // number of pointer lookups + Mallocs uint64 // number of mallocs + Frees uint64 // number of frees + + // Main allocation heap statistics. + HeapAlloc uint64 // bytes allocated and still in use + HeapSys uint64 // bytes obtained from system + HeapIdle uint64 // bytes in idle spans + HeapInuse uint64 // bytes in non-idle span + HeapReleased uint64 // bytes released to the OS + HeapObjects uint64 // total number of allocated objects + + // Low-level fixed-size structure allocator statistics. + // Inuse is bytes used now. + // Sys is bytes obtained from system. + StackInuse uint64 // bytes used by stack allocator + StackSys uint64 + MSpanInuse uint64 // mspan structures + MSpanSys uint64 + MCacheInuse uint64 // mcache structures + MCacheSys uint64 + BuckHashSys uint64 // profiling bucket hash table + GCSys uint64 // GC metadata + OtherSys uint64 // other system allocations + + // Garbage collector statistics. + NextGC uint64 // next collection will happen when HeapAlloc ≥ this amount + LastGC uint64 // end time of last collection (nanoseconds since 1970) + PauseTotalNs uint64 + PauseNs [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256] + PauseEnd [256]uint64 // circular buffer of recent GC pause end times + NumGC uint32 + EnableGC bool + DebugGC bool + + // Per-size allocation statistics. + // 61 is NumSizeClasses in the C code. + BySize [61]struct { + Size uint32 + Mallocs uint64 + Frees uint64 + } +} + +// Size of the trailing by_size array differs between Go and C, +// and all data after by_size is local to runtime, not exported. +// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. +// sizeof_C_MStats is what C thinks about size of Go struct. +var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0]) + +func init() { + var memStats MemStats + if sizeof_C_MStats != unsafe.Sizeof(memStats) { + println(sizeof_C_MStats, unsafe.Sizeof(memStats)) + throw("MStats vs MemStatsType size mismatch") + } +} + +// ReadMemStats populates m with memory allocator statistics. +func ReadMemStats(m *MemStats) { + // Have to acquire worldsema to stop the world, + // because stoptheworld can only be used by + // one goroutine at a time, and there might be + // a pending garbage collection already calling it. + semacquire(&worldsema, false) + gp := getg() + gp.m.preemptoff = "read mem stats" + systemstack(stoptheworld) + + systemstack(func() { + readmemstats_m(m) + }) + + gp.m.preemptoff = "" + gp.m.locks++ + semrelease(&worldsema) + systemstack(starttheworld) + gp.m.locks-- +} + +func readmemstats_m(stats *MemStats) { + updatememstats(nil) + + // Size of the trailing by_size array differs between Go and C, + // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility. + memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats) + + // Stack numbers are part of the heap numbers, separate those out for user consumption + stats.StackSys = stats.StackInuse + stats.HeapInuse -= stats.StackInuse + stats.HeapSys -= stats.StackInuse +} + +//go:linkname readGCStats runtime/debug.readGCStats +func readGCStats(pauses *[]uint64) { + systemstack(func() { + readGCStats_m(pauses) + }) +} + +func readGCStats_m(pauses *[]uint64) { + p := *pauses + // Calling code in runtime/debug should make the slice large enough. + if cap(p) < len(memstats.pause_ns)+3 { + throw("short slice passed to readGCStats") + } + + // Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns. + lock(&mheap_.lock) + + n := memstats.numgc + if n > uint32(len(memstats.pause_ns)) { + n = uint32(len(memstats.pause_ns)) + } + + // The pause buffer is circular. The most recent pause is at + // pause_ns[(numgc-1)%len(pause_ns)], and then backward + // from there to go back farther in time. We deliver the times + // most recent first (in p[0]). + p = p[:cap(p)] + for i := uint32(0); i < n; i++ { + j := (memstats.numgc - 1 - i) % uint32(len(memstats.pause_ns)) + p[i] = memstats.pause_ns[j] + p[n+i] = memstats.pause_end[j] + } + + p[n+n] = memstats.last_gc + p[n+n+1] = uint64(memstats.numgc) + p[n+n+2] = memstats.pause_total_ns + unlock(&mheap_.lock) + *pauses = p[:n+n+3] +} + +//go:nowritebarrier +func updatememstats(stats *gcstats) { + if stats != nil { + *stats = gcstats{} + } + for mp := allm; mp != nil; mp = mp.alllink { + if stats != nil { + src := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(&mp.gcstats)) + dst := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(stats)) + for i, v := range src { + dst[i] += v + } + mp.gcstats = gcstats{} + } + } + + memstats.mcache_inuse = uint64(mheap_.cachealloc.inuse) + memstats.mspan_inuse = uint64(mheap_.spanalloc.inuse) + memstats.sys = memstats.heap_sys + memstats.stacks_sys + memstats.mspan_sys + + memstats.mcache_sys + memstats.buckhash_sys + memstats.gc_sys + memstats.other_sys + + // Calculate memory allocator stats. + // During program execution we only count number of frees and amount of freed memory. + // Current number of alive object in the heap and amount of alive heap memory + // are calculated by scanning all spans. + // Total number of mallocs is calculated as number of frees plus number of alive objects. + // Similarly, total amount of allocated memory is calculated as amount of freed memory + // plus amount of alive heap memory. + memstats.alloc = 0 + memstats.total_alloc = 0 + memstats.nmalloc = 0 + memstats.nfree = 0 + for i := 0; i < len(memstats.by_size); i++ { + memstats.by_size[i].nmalloc = 0 + memstats.by_size[i].nfree = 0 + } + + // Flush MCache's to MCentral. + systemstack(flushallmcaches) + + // Aggregate local stats. + cachestats() + + // Scan all spans and count number of alive objects. + lock(&mheap_.lock) + for i := uint32(0); i < mheap_.nspan; i++ { + s := h_allspans[i] + if s.state != mSpanInUse { + continue + } + if s.sizeclass == 0 { + memstats.nmalloc++ + memstats.alloc += uint64(s.elemsize) + } else { + memstats.nmalloc += uint64(s.ref) + memstats.by_size[s.sizeclass].nmalloc += uint64(s.ref) + memstats.alloc += uint64(s.ref) * uint64(s.elemsize) + } + } + unlock(&mheap_.lock) + + // Aggregate by size class. + smallfree := uint64(0) + memstats.nfree = mheap_.nlargefree + for i := 0; i < len(memstats.by_size); i++ { + memstats.nfree += mheap_.nsmallfree[i] + memstats.by_size[i].nfree = mheap_.nsmallfree[i] + memstats.by_size[i].nmalloc += mheap_.nsmallfree[i] + smallfree += uint64(mheap_.nsmallfree[i]) * uint64(class_to_size[i]) + } + memstats.nfree += memstats.tinyallocs + memstats.nmalloc += memstats.nfree + + // Calculate derived stats. + memstats.total_alloc = uint64(memstats.alloc) + uint64(mheap_.largefree) + smallfree + memstats.heap_alloc = memstats.alloc + memstats.heap_objects = memstats.nmalloc - memstats.nfree +} + +//go:nowritebarrier +func cachestats() { + for i := 0; ; i++ { + p := allp[i] + if p == nil { + break + } + c := p.mcache + if c == nil { + continue + } + purgecachedstats(c) + } +} + +//go:nowritebarrier +func flushallmcaches() { + for i := 0; ; i++ { + p := allp[i] + if p == nil { + break + } + c := p.mcache + if c == nil { + continue + } + mCache_ReleaseAll(c) + stackcache_clear(c) + } +} + +//go:nosplit +func purgecachedstats(c *mcache) { + // Protected by either heap or GC lock. + h := &mheap_ + memstats.heap_alloc += uint64(c.local_cachealloc) + c.local_cachealloc = 0 + if trace.enabled { + traceHeapAlloc() + } + memstats.tinyallocs += uint64(c.local_tinyallocs) + c.local_tinyallocs = 0 + memstats.nlookup += uint64(c.local_nlookup) + c.local_nlookup = 0 + h.largefree += uint64(c.local_largefree) + c.local_largefree = 0 + h.nlargefree += uint64(c.local_nlargefree) + c.local_nlargefree = 0 + for i := 0; i < len(c.local_nsmallfree); i++ { + h.nsmallfree[i] += uint64(c.local_nsmallfree[i]) + c.local_nsmallfree[i] = 0 + } +} diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go index 471ffc83a3..a47df13691 100644 --- a/src/runtime/proc1.go +++ b/src/runtime/proc1.go @@ -528,6 +528,21 @@ func quiesce(mastergp *g) { mcall(mquiesce) } +// Holding worldsema grants an M the right to try to stop the world. +// The procedure is: +// +// semacquire(&worldsema); +// m.preemptoff = "reason"; +// stoptheworld(); +// +// ... do stuff ... +// +// m.preemptoff = ""; +// semrelease(&worldsema); +// starttheworld(); +// +var worldsema uint32 = 1 + // This is used by the GC as well as the routines that do stack dumps. In the case // of GC all the routines can be reliably stopped. This is not always the case // when the system is in panic or being exited. diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 9aa83ef587..00f74f86a3 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -239,3 +239,13 @@ func prefetcht0(addr uintptr) func prefetcht1(addr uintptr) func prefetcht2(addr uintptr) func prefetchnta(addr uintptr) + +func unixnanotime() int64 { + sec, nsec := time_now() + return sec*1e9 + int64(nsec) +} + +// round n up to a multiple of a. a must be a power of 2. +func round(n, a uintptr) uintptr { + return (n + a - 1) &^ (a - 1) +} diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 3e46d428f7..4f3111d551 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -299,3 +299,17 @@ func readvarint(p []byte) (newp []byte, val uint32) { } return p, v } + +type stackmap struct { + n int32 // number of bitmaps + nbit int32 // number of bits in each bitmap + bytedata [1]byte // bitmaps, each starting on a 32-bit boundary +} + +//go:nowritebarrier +func stackmapdata(stkmap *stackmap, n int32) bitvector { + if n < 0 || n >= stkmap.n { + throw("stackmapdata: index out of range") + } + return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))} +} -- cgit v1.2.3-54-g00ecf From 6c4b54f409b537ce60e539e2ec1c56abfe1e145c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 19 Feb 2015 15:45:29 -0500 Subject: runtime: missed change from reorganization CL That is, I accidentally dropped this change of Austin's when preparing my CL. I blame Git. Change-Id: I9dd772c84edefad96c4b16785fdd2dea04a4a0d6 Reviewed-on: https://go-review.googlesource.com/5320 Reviewed-by: Austin Clements --- src/runtime/mgc.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 497695cf18..70661e46d0 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -423,7 +423,9 @@ func gcinstallmarkwb() { // This is the concurrent mark phase. //go:nowritebarrier func gcmark_m() { - gcDrain(nil) + var gcw gcWork + gcDrain(&gcw) + gcw.dispose() // TODO add another harvestwbuf and reset work.nwait=0, work.ndone=0, and work.nproc=1 // and repeat the above gcDrain. } -- cgit v1.2.3-54-g00ecf From 5254b7e9cefb597a9b9ce5137d6e5248a14d8d73 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 19 Feb 2015 16:21:42 -0500 Subject: runtime: do not unmap work.spans until after checkmark phase This is causing crashes. Change-Id: I1832f33d114bc29894e491dd2baac45d7ab3a50d Reviewed-on: https://go-review.googlesource.com/5330 Reviewed-by: Rick Hudson Reviewed-by: Russ Cox --- src/runtime/mgc.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 70661e46d0..75d6b9158e 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -616,24 +616,23 @@ func gc(start_time int64, eagersweep bool) { sweep.npausesweep = 0 } - // See the comment in the beginning of this function as to why we need the following. - // Even if this is still stop-the-world, a concurrent exitsyscall can allocate a stack from heap. - lock(&mheap_.lock) - // Free the old cached mark array if necessary. - if work.spans != nil && &work.spans[0] != &h_allspans[0] { - sysFree(unsafe.Pointer(&work.spans[0]), uintptr(len(work.spans))*unsafe.Sizeof(work.spans[0]), &memstats.other_sys) - } - if debug.gccheckmark > 0 { if !checkmarkphase { // first half of two-pass; don't set up sweep - unlock(&mheap_.lock) return } checkmarkphase = false // done checking marks clearCheckmarks() } + // See the comment in the beginning of this function as to why we need the following. + // Even if this is still stop-the-world, a concurrent exitsyscall can allocate a stack from heap. + lock(&mheap_.lock) + // Free the old cached mark array if necessary. + if work.spans != nil && &work.spans[0] != &h_allspans[0] { + sysFree(unsafe.Pointer(&work.spans[0]), uintptr(len(work.spans))*unsafe.Sizeof(work.spans[0]), &memstats.other_sys) + } + // Cache the current array for sweeping. mheap_.gcspans = mheap_.allspans mheap_.sweepgen += 2 -- cgit v1.2.3-54-g00ecf From 5f8423844463b3b77588e46ea57f44d8b69a1564 Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Fri, 20 Feb 2015 08:34:30 +1100 Subject: cmd/dist: show friendlier error message when building outside a Git repo Fixes #9932 Change-Id: I7943470a1784278a5c6e99c3b66c59d4953734ba Reviewed-on: https://go-review.googlesource.com/5340 Reviewed-by: Brad Fitzpatrick --- src/cmd/dist/build.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 3932c0bc42..141d3c9660 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -296,6 +296,11 @@ func findgoversion() string { return chomp(readfile(path)) } + // Show a nicer error message if this isn't a Git repo. + if !isGitRepo() { + fatal("FAILED: not a Git repo; must put a VERSION file in $GOROOT") + } + // Otherwise, use Git. // What is the current branch? branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD")) @@ -321,6 +326,22 @@ func findgoversion() string { return tag } +// isGitRepo reports whether the working directory is inside a Git repository. +func isGitRepo() bool { + p := ".git" + for { + fi, err := os.Stat(p) + if os.IsNotExist(err) { + p = filepath.Join("..", p) + continue + } + if err != nil || !fi.IsDir() { + return false + } + return true + } +} + /* * Initial tree setup. */ -- cgit v1.2.3-54-g00ecf From ea1306a150bb3ea465dcfad83c1619d9bab943bd Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 19 Feb 2015 20:42:09 -0500 Subject: doc: dummy commit in go1.5.txt Change-Id: I678336daf99f7d7d19f99506f1a604de8e05bf43 Reviewed-on: https://go-review.googlesource.com/5400 Reviewed-by: Russ Cox --- doc/go1.5.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/go1.5.txt b/doc/go1.5.txt index 95db022c74..3ec9395e1c 100644 --- a/doc/go1.5.txt +++ b/doc/go1.5.txt @@ -33,3 +33,4 @@ sort: number of Sort performance optimizations (https://golang.org/cl/2100, http strconv: optimize decimal to string conversion (https://golang.org/cl/2105) math/big: faster assembly kernels for amd64 and 386 (https://golang.org/cl/2503, https://golang.org/cl/2560) math/big: faster "pure Go" kernels for platforms w/o assembly kernels (https://golang.org/cl/2480) + -- cgit v1.2.3-54-g00ecf From 668762c5709b61e0b442b02c81489a7fdf6f9b19 Mon Sep 17 00:00:00 2001 From: Ingo Oeser Date: Thu, 29 Jan 2015 15:37:37 +0100 Subject: cmd/go: simplify/fix handling private github repos Before Go 1.4, the traditional way to work with a private Github repository was to run something similar the following: ``` git config --global url."git@github.com:".insteadOf "https://github.com/" ``` It would allow go get and friends to transparently work as expected, automatically rewriting https URLs to use SSH for auth. This worked both when pushing and pulling. In Go 1.4 this broke, now requiring the use of `go get -f` instead of `go get` in order to fetch private repositories. This seems neither intended nor practical, as it requires changing a lot of tooling. So just use `git config remote.origin.url` instead of `git remote -v` as this reflects the actual substitution intended in the `insteadOf` config directive. Also remove now useless parsing. Also add a check against supported schemes to avoid errors in later commands using this URL and expecting such a scheme. Fixes #9697 Change-Id: I907327f83504302288f913a68f8222a5c2d673ee Reviewed-on: https://go-review.googlesource.com/3504 Reviewed-by: Andrew Gerrand --- src/cmd/go/vcs.go | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index 1cac613388..86f5ea82e8 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -122,32 +122,19 @@ var vcsGit = &vcsCmd{ } func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) { - outb, err := vcsGit.runOutput(rootDir, "remote -v") + cmd := "config remote.origin.url" + errParse := errors.New("unable to parse output of git " + cmd) + outb, err := vcsGit.runOutput(rootDir, cmd) if err != nil { return "", err } - out := string(outb) - - // Expect: - // origin https://github.com/rsc/pdf (fetch) - // origin https://github.com/rsc/pdf (push) - // use first line only. - - if !strings.HasPrefix(out, "origin\t") { - return "", fmt.Errorf("unable to parse output of git remote -v") - } - out = strings.TrimPrefix(out, "origin\t") - i := strings.Index(out, "\n") - if i < 0 { - return "", fmt.Errorf("unable to parse output of git remote -v") - } - out = out[:i] - i = strings.LastIndex(out, " ") - if i < 0 { - return "", fmt.Errorf("unable to parse output of git remote -v") + repoUrl := strings.TrimSpace(string(outb)) + for _, s := range vcsGit.scheme { + if strings.HasPrefix(repoUrl, s) { + return repoUrl, nil + } } - out = out[:i] - return strings.TrimSpace(string(out)), nil + return "", errParse } // vcsBzr describes how to use Bazaar. -- cgit v1.2.3-54-g00ecf From 69275eef5e6dfa837202323223f39bc24f2695ac Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Tue, 10 Feb 2015 12:24:11 +0900 Subject: net, syscall: more accurate parsers for routing messages on BSD variants This changes fixes two issues with regard to handling routing messages as follows: - Misparsing on platforms (such as FreeBSD) supporting multiple architectures in the same kernel (kern.supported_archs="amd64 i386") - Misparsing with unimplemented messages such as route, interface address state notifications To fix those issues, this change implements all the required socket address parsers, adds a processor architecture identifying function to FreeBSD and tests. Fixes #9707. Fixes #8203. Change-Id: I7ed7b4a0b6f10f54b29edc681a2f35603f2d8d45 Reviewed-on: https://go-review.googlesource.com/4330 Reviewed-by: Ian Lance Taylor --- src/net/interface_bsd.go | 81 +++++----- src/net/interface_darwin.go | 37 +++-- src/net/interface_freebsd.go | 37 +++-- src/syscall/route_bsd.go | 303 +++++++++++++++++++++++++------------ src/syscall/route_bsd_test.go | 197 ++++++++++++++++++++++++ src/syscall/route_darwin.go | 46 +++--- src/syscall/route_dragonfly.go | 50 +++--- src/syscall/route_freebsd.go | 70 ++++++--- src/syscall/route_freebsd_32bit.go | 13 +- src/syscall/route_freebsd_64bit.go | 7 +- src/syscall/route_ifma_test.go | 74 +++++++++ src/syscall/route_netbsd.go | 6 +- src/syscall/route_noifma_test.go | 63 ++++++++ src/syscall/route_openbsd.go | 6 +- 14 files changed, 740 insertions(+), 250 deletions(-) create mode 100644 src/syscall/route_bsd_test.go create mode 100644 src/syscall/route_ifma_test.go create mode 100644 src/syscall/route_noifma_test.go diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go index 16775579d0..2f66e4fc31 100644 --- a/src/net/interface_bsd.go +++ b/src/net/interface_bsd.go @@ -54,24 +54,22 @@ func newLink(m *syscall.InterfaceMessage) (*Interface, error) { return nil, os.NewSyscallError("route sockaddr", err) } ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)} - for _, sa := range sas { - switch sa := sa.(type) { - case *syscall.SockaddrDatalink: - // NOTE: SockaddrDatalink.Data is minimum work area, - // can be larger. - m.Data = m.Data[unsafe.Offsetof(sa.Data):] - var name [syscall.IFNAMSIZ]byte - for i := 0; i < int(sa.Nlen); i++ { - name[i] = byte(m.Data[i]) - } - ifi.Name = string(name[:sa.Nlen]) - ifi.MTU = int(m.Header.Data.Mtu) - addr := make([]byte, sa.Alen) - for i := 0; i < int(sa.Alen); i++ { - addr[i] = byte(m.Data[int(sa.Nlen)+i]) - } - ifi.HardwareAddr = addr[:sa.Alen] + sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink) + if sa != nil { + // NOTE: SockaddrDatalink.Data is minimum work area, + // can be larger. + m.Data = m.Data[unsafe.Offsetof(sa.Data):] + var name [syscall.IFNAMSIZ]byte + for i := 0; i < int(sa.Nlen); i++ { + name[i] = byte(m.Data[i]) } + ifi.Name = string(name[:sa.Nlen]) + ifi.MTU = int(m.Header.Data.Mtu) + addr := make([]byte, sa.Alen) + for i := 0; i < int(sa.Alen); i++ { + addr[i] = byte(m.Data[int(sa.Nlen)+i]) + } + ifi.HardwareAddr = addr[:sa.Alen] } return ifi, nil } @@ -144,39 +142,34 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { return ifat, nil } -func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) { +func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) { sas, err := syscall.ParseRoutingSockaddr(m) if err != nil { return nil, os.NewSyscallError("route sockaddr", err) } ifa := &IPNet{} - for i, sa := range sas { - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - switch i { - case 0: - ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) - case 1: - ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) - } - case *syscall.SockaddrInet6: - switch i { - case 0: - ifa.Mask = make(IPMask, IPv6len) - copy(ifa.Mask, sa.Addr[:]) - case 1: - ifa.IP = make(IP, IPv6len) - copy(ifa.IP, sa.Addr[:]) - // NOTE: KAME based IPv6 protcol stack usually embeds - // the interface index in the interface-local or link- - // local address as the kernel-internal form. - if ifa.IP.IsLinkLocalUnicast() { - ifa.IP[2], ifa.IP[3] = 0, 0 - } - } - default: // Sockaddrs contain syscall.SockaddrDatalink on NetBSD - return nil, nil + switch sa := sas[syscall.RTAX_NETMASK].(type) { + case *syscall.SockaddrInet4: + ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) + case *syscall.SockaddrInet6: + ifa.Mask = make(IPMask, IPv6len) + copy(ifa.Mask, sa.Addr[:]) + } + switch sa := sas[syscall.RTAX_IFA].(type) { + case *syscall.SockaddrInet4: + ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) + case *syscall.SockaddrInet6: + ifa.IP = make(IP, IPv6len) + copy(ifa.IP, sa.Addr[:]) + // NOTE: KAME based IPv6 protcol stack usually embeds + // the interface index in the interface-local or + // link-local address as the kernel-internal form. + if ifa.IP.IsLinkLocalUnicast() { + ifa.IP[2], ifa.IP[3] = 0, 0 } } + if ifa.IP == nil || ifa.Mask == nil { + return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD + } return ifa, nil } diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go index ad0937db04..475b8611ce 100644 --- a/src/net/interface_darwin.go +++ b/src/net/interface_darwin.go @@ -29,35 +29,34 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { if err != nil { return nil, err } - ifmat = append(ifmat, ifma...) + if ifma != nil { + ifmat = append(ifmat, ifma) + } } } } return ifmat, nil } -func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) { +func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) { sas, err := syscall.ParseRoutingSockaddr(m) if err != nil { return nil, os.NewSyscallError("route sockaddr", err) } - var ifmat []Addr - for _, sa := range sas { - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])} - ifmat = append(ifmat, ifma.toAddr()) - case *syscall.SockaddrInet6: - ifma := &IPAddr{IP: make(IP, IPv6len)} - copy(ifma.IP, sa.Addr[:]) - // NOTE: KAME based IPv6 protocol stack usually embeds - // the interface index in the interface-local or link- - // local address as the kernel-internal form. - if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { - ifma.IP[2], ifma.IP[3] = 0, 0 - } - ifmat = append(ifmat, ifma.toAddr()) + switch sa := sas[syscall.RTAX_IFA].(type) { + case *syscall.SockaddrInet4: + return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil + case *syscall.SockaddrInet6: + ifma := IPAddr{IP: make(IP, IPv6len)} + copy(ifma.IP, sa.Addr[:]) + // NOTE: KAME based IPv6 protcol stack usually embeds + // the interface index in the interface-local or + // link-local address as the kernel-internal form. + if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { + ifma.IP[2], ifma.IP[3] = 0, 0 } + return &ifma, nil + default: + return nil, nil } - return ifmat, nil } diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go index 5df767910e..13bf438103 100644 --- a/src/net/interface_freebsd.go +++ b/src/net/interface_freebsd.go @@ -29,35 +29,34 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { if err != nil { return nil, err } - ifmat = append(ifmat, ifma...) + if ifma != nil { + ifmat = append(ifmat, ifma) + } } } } return ifmat, nil } -func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) { +func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) { sas, err := syscall.ParseRoutingSockaddr(m) if err != nil { return nil, os.NewSyscallError("route sockaddr", err) } - var ifmat []Addr - for _, sa := range sas { - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])} - ifmat = append(ifmat, ifma.toAddr()) - case *syscall.SockaddrInet6: - ifma := &IPAddr{IP: make(IP, IPv6len)} - copy(ifma.IP, sa.Addr[:]) - // NOTE: KAME based IPv6 protocol stack usually embeds - // the interface index in the interface-local or link- - // local address as the kernel-internal form. - if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { - ifma.IP[2], ifma.IP[3] = 0, 0 - } - ifmat = append(ifmat, ifma.toAddr()) + switch sa := sas[syscall.RTAX_IFA].(type) { + case *syscall.SockaddrInet4: + return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil + case *syscall.SockaddrInet6: + ifma := IPAddr{IP: make(IP, IPv6len)} + copy(ifma.IP, sa.Addr[:]) + // NOTE: KAME based IPv6 protcol stack usually embeds + // the interface index in the interface-local or + // link-local address as the kernel-internal form. + if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { + ifma.IP[2], ifma.IP[3] = 0, 0 } + return &ifma, nil + default: + return nil, nil } - return ifmat, nil } diff --git a/src/syscall/route_bsd.go b/src/syscall/route_bsd.go index 1dabe42531..bc5de69bed 100644 --- a/src/syscall/route_bsd.go +++ b/src/syscall/route_bsd.go @@ -4,23 +4,37 @@ // +build darwin dragonfly freebsd netbsd openbsd -// Routing sockets and messages - package syscall -import "unsafe" +import ( + "runtime" + "unsafe" +) + +var ( + freebsdConfArch string // "machine $arch" line in kern.conftxt on freebsd + minRoutingSockaddrLen = rsaAlignOf(0) +) // Round the length of a raw sockaddr up to align it properly. func rsaAlignOf(salen int) int { salign := sizeofPtr - // NOTE: It seems like 64-bit Darwin kernel still requires - // 32-bit aligned access to BSD subsystem. Also NetBSD 6 - // kernel and beyond require 64-bit aligned access to routing - // facilities. if darwin64Bit { + // Darwin kernels require 32-bit aligned access to + // routing facilities. salign = 4 } else if netbsd32Bit { + // NetBSD 6 and beyond kernels require 64-bit aligned + // access to routing facilities. salign = 8 + } else if runtime.GOOS == "freebsd" { + // In the case of kern.supported_archs="amd64 i386", + // we need to know the underlying kernel's + // architecture because the alignment for routing + // facilities are set at the build time of the kernel. + if freebsdConfArch == "amd64" { + salign = 8 + } } if salen == 0 { return salign @@ -28,6 +42,124 @@ func rsaAlignOf(salen int) int { return (salen + salign - 1) & ^(salign - 1) } +// parseSockaddrLink parses b as a datalink socket address. +func parseSockaddrLink(b []byte) (*SockaddrDatalink, error) { + sa, _, err := parseLinkLayerAddr(b[4:]) + if err != nil { + return nil, err + } + rsa := (*RawSockaddrDatalink)(unsafe.Pointer(&b[0])) + sa.Len = rsa.Len + sa.Family = rsa.Family + sa.Index = rsa.Index + return sa, nil +} + +// parseLinkLayerAddr parses b as a datalink socket address in +// conventional BSD kernel form. +func parseLinkLayerAddr(b []byte) (*SockaddrDatalink, int, error) { + // The encoding looks like the follwoing: + // +----------------------------+ + // | Type (1 octet) | + // +----------------------------+ + // | Name length (1 octet) | + // +----------------------------+ + // | Address length (1 octet) | + // +----------------------------+ + // | Selector length (1 octet) | + // +----------------------------+ + // | Data (variable) | + // +----------------------------+ + type linkLayerAddr struct { + Type byte + Nlen byte + Alen byte + Slen byte + } + lla := (*linkLayerAddr)(unsafe.Pointer(&b[0])) + l := rsaAlignOf(int(4 + lla.Nlen + lla.Alen + lla.Slen)) + if len(b) < l { + return nil, 0, EINVAL + } + b = b[4:] + sa := &SockaddrDatalink{Type: lla.Type, Nlen: lla.Nlen, Alen: lla.Alen, Slen: lla.Slen} + for i := 0; len(sa.Data) > i && i < int(lla.Nlen+lla.Alen+lla.Slen); i++ { + sa.Data[i] = int8(b[i]) + } + return sa, l, nil +} + +// parseSockaddrInet parses b as an internet socket address. +func parseSockaddrInet(b []byte, family byte) (Sockaddr, error) { + switch family { + case AF_INET: + if len(b) < SizeofSockaddrInet4 { + return nil, EINVAL + } + rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0])) + return anyToSockaddr(rsa) + case AF_INET6: + if len(b) < SizeofSockaddrInet6 { + return nil, EINVAL + } + rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0])) + return anyToSockaddr(rsa) + default: + return nil, EINVAL + } +} + +const ( + offsetofInet4 = int(unsafe.Offsetof(RawSockaddrInet4{}.Addr)) + offsetofInet6 = int(unsafe.Offsetof(RawSockaddrInet6{}.Addr)) +) + +// parseNetworkLayerAddr parses b as an internet socket address in +// conventional BSD kernel form. +func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) { + // The encoding looks similar to the NLRI encoding. + // +----------------------------+ + // | Length (1 octet) | + // +----------------------------+ + // | Address prefix (variable) | + // +----------------------------+ + // + // The differences between the kernel form and the NLRI + // encoding are: + // + // - The length field of the kernel form indicates the prefix + // length in bytes, not in bits + // + // - In the kernel form, zero value of the length field + // doesn't mean 0.0.0.0/0 or ::/0 + // + // - The kernel form appends leading bytes to the prefix field + // to make the tuple to be conformed with + // the routing messeage boundary + l := int(rsaAlignOf(int(b[0]))) + if len(b) < l { + return nil, EINVAL + } + switch family { + case AF_INET6: + sa := &SockaddrInet6{} + if l-1 < offsetofInet6 { + copy(sa.Addr[:], b[1:l]) + } else { + copy(sa.Addr[:], b[l-offsetofInet6:l]) + } + return sa, nil + default: // an old fashion, AF_UNSPEC or unknown means AF_INET + sa := &SockaddrInet4{} + if l-1 < offsetofInet4 { + copy(sa.Addr[:], b[1:l]) + } else { + copy(sa.Addr[:], b[l-offsetofInet4:l]) + } + return sa, nil + } +} + // RouteRIB returns routing information base, as known as RIB, // which consists of network facility information, states and // parameters. @@ -50,7 +182,7 @@ func RouteRIB(facility, param int) ([]byte, error) { // RoutingMessage represents a routing message. type RoutingMessage interface { - sockaddr() []Sockaddr + sockaddr() ([]Sockaddr, error) } const anyMessageLen = int(unsafe.Sizeof(anyMessage{})) @@ -68,50 +200,41 @@ type RouteMessage struct { Data []byte } -const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK - -func (m *RouteMessage) sockaddr() []Sockaddr { - var ( - af int - sas [4]Sockaddr - ) +func (m *RouteMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr b := m.Data[:] - for i := uint(0); i < RTAX_MAX; i++ { - if m.Header.Addrs&rtaRtMask&(1<= minRoutingSockaddrLen; i++ { + if m.Header.Addrs&(1< 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ { - sa.Addr[j] = rsa4.Addr[j] - } - sas[i] = sa - case AF_INET6: - rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&b[0])) - sa := new(SockaddrInet6) - for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ { - sa.Addr[j] = rsa6.Addr[j] - } - sas[i] = sa + b = b[rsaAlignOf(int(rsa.Len)):] + family = rsa.Family + default: + sa, err := parseNetworkLayerAddr(b, family) + if err != nil { + return nil, err } + sas[i] = sa + b = b[rsaAlignOf(int(b[0])):] } - b = b[rsaAlignOf(int(rsa.Len)):] } - return sas[:] + return sas[:], nil } // InterfaceMessage represents a routing message containing @@ -121,15 +244,17 @@ type InterfaceMessage struct { Data []byte } -func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) { +func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr if m.Header.Addrs&RTA_IFP == 0 { - return nil + return nil, nil } - sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0]))) + sa, err := parseSockaddrLink(m.Data[:]) if err != nil { - return nil + return nil, err } - return append(sas, sa) + sas[RTAX_IFP] = sa + return sas[:], nil } // InterfaceAddrMessage represents a routing message containing @@ -139,79 +264,63 @@ type InterfaceAddrMessage struct { Data []byte } -const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD - -func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) { - if m.Header.Addrs&rtaIfaMask == 0 { - return nil - } +func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr b := m.Data[:] - // We still see AF_UNSPEC in socket addresses on some - // platforms. To identify each address family correctly, we - // will use the address family of RTAX_NETMASK as a preferred - // one on the 32-bit NetBSD kernel, also use the length of - // RTAX_NETMASK socket address on the FreeBSD kernel. - preferredFamily := uint8(AF_UNSPEC) - for i := uint(0); i < RTAX_MAX; i++ { + family := uint8(AF_UNSPEC) + for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ { if m.Header.Addrs&(1<= anyMessageLen { - msgCount++ + nmsgs++ any := (*anyMessage)(unsafe.Pointer(&b[0])) if any.Version != RTM_VERSION { b = b[any.Msglen:] continue } - msgs = append(msgs, any.toRoutingMessage(b)) + if m := any.toRoutingMessage(b); m == nil { + nskips++ + } else { + msgs = append(msgs, m) + } b = b[any.Msglen:] } // We failed to parse any of the messages - version mismatch? - if msgCount > 0 && len(msgs) == 0 { + if nmsgs != len(msgs)+nskips { return nil, EINVAL } return msgs, nil @@ -219,6 +328,10 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { // ParseRoutingMessage parses msg's payload as raw sockaddrs and // returns the slice containing the Sockaddr interfaces. -func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) { - return append(sas, msg.sockaddr()...), nil +func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { + sas, err := msg.sockaddr() + if err != nil { + return nil, err + } + return sas, nil } diff --git a/src/syscall/route_bsd_test.go b/src/syscall/route_bsd_test.go new file mode 100644 index 0000000000..471f4a25a5 --- /dev/null +++ b/src/syscall/route_bsd_test.go @@ -0,0 +1,197 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package syscall_test + +import ( + "fmt" + "net" + "os" + "syscall" + "testing" + "time" +) + +func TestRouteRIB(t *testing.T) { + for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} { + for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { + b, err := syscall.RouteRIB(facility, param) + if err != nil { + t.Error(facility, param, err) + continue + } + msgs, err := syscall.ParseRoutingMessage(b) + if err != nil { + t.Error(facility, param, err) + continue + } + var ipv4loopback, ipv6loopback bool + for _, m := range msgs { + flags, err := parseRoutingMessageHeader(m) + if err != nil { + t.Error(err) + continue + } + sas, err := parseRoutingSockaddrs(m) + if err != nil { + t.Error(err) + continue + } + if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 { + sa := sas[syscall.RTAX_DST] + if sa == nil { + sa = sas[syscall.RTAX_IFA] + } + switch sa := sa.(type) { + case *syscall.SockaddrInet4: + if net.IP(sa.Addr[:]).IsLoopback() { + ipv4loopback = true + } + case *syscall.SockaddrInet6: + if net.IP(sa.Addr[:]).IsLoopback() { + ipv6loopback = true + } + } + } + t.Log(facility, param, flags, sockaddrs(sas)) + } + if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback { + t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs)) + continue + } + } + } +} + +func TestRouteMonitor(t *testing.T) { + if testing.Short() || os.Getuid() != 0 { + t.Skip("must be root") + } + + s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC) + if err != nil { + t.Fatal(err) + } + defer syscall.Close(s) + + tmo := time.After(30 * time.Second) + go func() { + b := make([]byte, os.Getpagesize()) + for { + n, err := syscall.Read(s, b) + if err != nil { + return + } + msgs, err := syscall.ParseRoutingMessage(b[:n]) + if err != nil { + t.Error(err) + return + } + for _, m := range msgs { + flags, err := parseRoutingMessageHeader(m) + if err != nil { + t.Error(err) + continue + } + sas, err := parseRoutingSockaddrs(m) + if err != nil { + t.Error(err) + continue + } + t.Log(flags, sockaddrs(sas)) + } + } + }() + <-tmo +} + +type addrFamily byte + +func (f addrFamily) String() string { + switch f { + case syscall.AF_UNSPEC: + return "unspec" + case syscall.AF_LINK: + return "link" + case syscall.AF_INET: + return "inet4" + case syscall.AF_INET6: + return "inet6" + default: + return fmt.Sprintf("unknown %d", f) + } +} + +type addrFlags uint32 + +var addrFlagNames = [...]string{ + "dst", + "gateway", + "netmask", + "genmask", + "ifp", + "ifa", + "author", + "brd", + "mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd + "mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd + "mpls3,label", // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd +} + +func (f addrFlags) String() string { + var s string + for i, name := range addrFlagNames { + if f&(1<" + } + return s +} + +type sockaddrs []syscall.Sockaddr + +func (sas sockaddrs) String() string { + var s string + for _, sa := range sas { + if sa == nil { + continue + } + if len(s) > 0 { + s += " " + } + switch sa := sa.(type) { + case *syscall.SockaddrDatalink: + s += fmt.Sprintf("[%v/%v/%v t/n/a/s=%v/%v/%v/%v]", sa.Len, addrFamily(sa.Family), sa.Index, sa.Type, sa.Nlen, sa.Alen, sa.Slen) + case *syscall.SockaddrInet4: + s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4()) + case *syscall.SockaddrInet6: + s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16()) + } + } + if s == "" { + return "" + } + return s +} + +func (sas sockaddrs) match(flags addrFlags) error { + var f addrFlags + for i := range sas { + if sas[i] != nil { + f |= 1 << uint(i) + } + } + if f != flags { + return fmt.Errorf("got %v; want %v", f, flags) + } + return nil +} diff --git a/src/syscall/route_darwin.go b/src/syscall/route_darwin.go index ad27907230..89bca12f3e 100644 --- a/src/syscall/route_darwin.go +++ b/src/syscall/route_darwin.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Routing sockets and messages for Darwin - package syscall import "unsafe" @@ -33,29 +31,37 @@ type InterfaceMulticastAddrMessage struct { Data []byte } -const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA - -func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) { - if m.Header.Addrs&rtaIfmaMask == 0 { - return nil - } +func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr b := m.Data[:] - for i := uint(0); i < RTAX_MAX; i++ { - if m.Header.Addrs&rtaIfmaMask&(1<= minRoutingSockaddrLen; i++ { + if m.Header.Addrs&(1<= minRoutingSockaddrLen; i++ { + if m.Header.Addrs&(1< len("machine") && s[:len("machine")] == "machine" { + s = s[len("machine"):] + for k := 0; k < len(s); k++ { + if s[k] == ' ' || s[k] == '\t' { + s = s[1:] + } + break + } + freebsdConfArch = s + break + } + } } func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { switch any.Type { case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE: - p := (*RouteMessage)(unsafe.Pointer(any)) - return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]} + return any.parseRouteMessage(b) case RTM_IFINFO: return any.parseInterfaceMessage(b) case RTM_IFANNOUNCE: @@ -41,7 +57,7 @@ type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } -func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil } +func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil } // InterfaceMulticastAddrMessage represents a routing message // containing network interface address entries. @@ -50,29 +66,37 @@ type InterfaceMulticastAddrMessage struct { Data []byte } -const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA - -func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) { - if m.Header.Addrs&rtaIfmaMask == 0 { - return nil - } +func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr b := m.Data[:] - for i := uint(0); i < RTAX_MAX; i++ { - if m.Header.Addrs&rtaIfmaMask&(1<= minRoutingSockaddrLen; i++ { + if m.Header.Addrs&(1< Date: Fri, 20 Feb 2015 16:46:48 +1100 Subject: path/filepath: add example for filepath.Split Fixes #9928 Change-Id: Iab37051078755a132f211ad48e756422f7c55a39 Reviewed-on: https://go-review.googlesource.com/5416 Reviewed-by: Minux Ma --- src/path/filepath/example_unix_test.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/path/filepath/example_unix_test.go b/src/path/filepath/example_unix_test.go index f3fe076c3c..27d85d15c6 100644 --- a/src/path/filepath/example_unix_test.go +++ b/src/path/filepath/example_unix_test.go @@ -37,3 +37,31 @@ func ExampleRel() { // "/b/c": "../b/c" // "./b/c": "" Rel: can't make b/c relative to /a } + +func ExampleSplit() { + paths := []string{ + "/home/arnie/amelia.jpg", + "/mnt/photos/", + "rabbit.jpg", + "/usr/local//go", + } + fmt.Println("On Unix:") + for _, p := range paths { + dir, file := filepath.Split(p) + fmt.Printf("input: %q\n\tdir: %q\n\tfile: %q\n", p, dir, file) + } + // Output: + // On Unix: + // input: "/home/arnie/amelia.jpg" + // dir: "/home/arnie/" + // file: "amelia.jpg" + // input: "/mnt/photos/" + // dir: "/mnt/photos/" + // file: "" + // input: "rabbit.jpg" + // dir: "" + // file: "rabbit.jpg" + // input: "/usr/local//go" + // dir: "/usr/local//" + // file: "go" +} -- cgit v1.2.3-54-g00ecf