Add base64 webrtc owned third_party dep

Add base64 webrtc owned third_party dep as copy of base/base64 3pp files
to test posibility to move all 3pp deps to third_party folder

Bug: webrtc:8366
Change-Id: Iac19e3745cbbce6cdb537c65af03e7e19409e741
Reviewed-on: https://webrtc-review.googlesource.com/83720
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23637}
This commit is contained in:
Artem Titov
2018-06-15 01:49:17 +02:00
committed by Commit Bot
parent 5adf07d7b0
commit 5a9ba68300
6 changed files with 1421 additions and 9 deletions

View File

@ -2,10 +2,10 @@ This source tree contains third party source code which is governed by third
party licenses. Paths to the files and associated licenses are collected here.
Files governed by third party licenses:
base/base64.cc
base/base64.h
base/sigslot.cc
base/sigslot.h
rtc_base/base64.cc
rtc_base/base64.h
rtc_base/sigslot.cc
rtc_base/sigslot.h
common_audio/fft4g.c
common_audio/signal_processing/spl_sqrt_floor.c
common_audio/signal_processing/spl_sqrt_floor_arm.S
@ -25,8 +25,8 @@ system_wrappers/source/set_thread_name_win.h
Individual licenses for each file:
-------------------------------------------------------------------------------
Files:
base/base64.cc
base/base64.h
rtc_base/base64.cc
rtc_base/base64.h
License:
//*********************************************************************
@ -45,8 +45,8 @@ License:
//*********************************************************************
-------------------------------------------------------------------------------
Files:
base/sigslot.cc
base/sigslot.h
rtc_base/sigslot.cc
rtc_base/sigslot.h
License:
// sigslot.h: Signal/Slot classes

View File

@ -5,6 +5,7 @@
"THIRD_PARTY_CHROMIUM_DEPS.json)."
],
"dependencies": [
"OWNERS"
"OWNERS",
"base64"
]
}

11
third_party/base64/LICENSE vendored Normal file
View File

@ -0,0 +1,11 @@
Base64 - a simple base64 encoder and decoder.
Copyright (c) 1999, Bob Withers - bwit@pobox.com
This code may be freely used for any purpose, either personal
or commercial, provided the authors copyright notice remains
intact.
Enhancements by Stanley Yamane:
o reverse lookup table for the decode function
o reserve string buffer space in advance

278
third_party/base64/base64.cc vendored Normal file
View File

@ -0,0 +1,278 @@
//*********************************************************************
//* Base64 - a simple base64 encoder and decoder.
//*
//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
//*
//* This code may be freely used for any purpose, either personal
//* or commercial, provided the authors copyright notice remains
//* intact.
//*
//* Enhancements by Stanley Yamane:
//* o reverse lookup table for the decode function
//* o reserve string buffer space in advance
//*
//*********************************************************************
#include "rtc_base/base64.h"
#include <string.h>
#include "rtc_base/checks.h"
using std::vector;
namespace rtc {
static const char kPad = '=';
static const unsigned char pd = 0xFD; // Padding
static const unsigned char sp = 0xFE; // Whitespace
static const unsigned char il = 0xFF; // Illegal base64 character
const char Base64::Base64Table[] =
// 0000000000111111111122222222223333333333444444444455555555556666
// 0123456789012345678901234567890123456789012345678901234567890123
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
// Decode Table gives the index of any valid base64 character in the
// Base64 table
// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == /
const unsigned char Base64::DecodeTable[] = {
// 0 1 2 3 4 5 6 7 8 9
il, il, il, il, il, il, il, il, il, sp, // 0 - 9
sp, sp, sp, sp, il, il, il, il, il, il, // 10 - 19
il, il, il, il, il, il, il, il, il, il, // 20 - 29
il, il, sp, il, il, il, il, il, il, il, // 30 - 39
il, il, il, 62, il, il, il, 63, 52, 53, // 40 - 49
54, 55, 56, 57, 58, 59, 60, 61, il, il, // 50 - 59
il, pd, il, il, il, 0, 1, 2, 3, 4, // 60 - 69
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 70 - 79
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 80 - 89
25, il, il, il, il, il, il, 26, 27, 28, // 90 - 99
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // 100 - 109
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // 110 - 119
49, 50, 51, il, il, il, il, il, il, il, // 120 - 129
il, il, il, il, il, il, il, il, il, il, // 130 - 139
il, il, il, il, il, il, il, il, il, il, // 140 - 149
il, il, il, il, il, il, il, il, il, il, // 150 - 159
il, il, il, il, il, il, il, il, il, il, // 160 - 169
il, il, il, il, il, il, il, il, il, il, // 170 - 179
il, il, il, il, il, il, il, il, il, il, // 180 - 189
il, il, il, il, il, il, il, il, il, il, // 190 - 199
il, il, il, il, il, il, il, il, il, il, // 200 - 209
il, il, il, il, il, il, il, il, il, il, // 210 - 219
il, il, il, il, il, il, il, il, il, il, // 220 - 229
il, il, il, il, il, il, il, il, il, il, // 230 - 239
il, il, il, il, il, il, il, il, il, il, // 240 - 249
il, il, il, il, il, il // 250 - 255
};
bool Base64::IsBase64Char(char ch) {
return (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z')) ||
(('0' <= ch) && (ch <= '9')) || (ch == '+') || (ch == '/');
}
bool Base64::GetNextBase64Char(char ch, char* next_ch) {
if (next_ch == nullptr) {
return false;
}
const char* p = strchr(Base64Table, ch);
if (!p)
return false;
++p;
*next_ch = (*p) ? *p : Base64Table[0];
return true;
}
bool Base64::IsBase64Encoded(const std::string& str) {
for (size_t i = 0; i < str.size(); ++i) {
if (!IsBase64Char(str.at(i)))
return false;
}
return true;
}
void Base64::EncodeFromArray(const void* data,
size_t len,
std::string* result) {
RTC_DCHECK(nullptr != result);
result->clear();
result->resize(((len + 2) / 3) * 4);
const unsigned char* byte_data = static_cast<const unsigned char*>(data);
unsigned char c;
size_t i = 0;
size_t dest_ix = 0;
while (i < len) {
c = (byte_data[i] >> 2) & 0x3f;
(*result)[dest_ix++] = Base64Table[c];
c = (byte_data[i] << 4) & 0x3f;
if (++i < len) {
c |= (byte_data[i] >> 4) & 0x0f;
}
(*result)[dest_ix++] = Base64Table[c];
if (i < len) {
c = (byte_data[i] << 2) & 0x3f;
if (++i < len) {
c |= (byte_data[i] >> 6) & 0x03;
}
(*result)[dest_ix++] = Base64Table[c];
} else {
(*result)[dest_ix++] = kPad;
}
if (i < len) {
c = byte_data[i] & 0x3f;
(*result)[dest_ix++] = Base64Table[c];
++i;
} else {
(*result)[dest_ix++] = kPad;
}
}
}
size_t Base64::GetNextQuantum(DecodeFlags parse_flags,
bool illegal_pads,
const char* data,
size_t len,
size_t* dpos,
unsigned char qbuf[4],
bool* padded) {
size_t byte_len = 0, pad_len = 0, pad_start = 0;
for (; (byte_len < 4) && (*dpos < len); ++*dpos) {
qbuf[byte_len] = DecodeTable[static_cast<unsigned char>(data[*dpos])];
if ((il == qbuf[byte_len]) || (illegal_pads && (pd == qbuf[byte_len]))) {
if (parse_flags != DO_PARSE_ANY)
break;
// Ignore illegal characters
} else if (sp == qbuf[byte_len]) {
if (parse_flags == DO_PARSE_STRICT)
break;
// Ignore spaces
} else if (pd == qbuf[byte_len]) {
if (byte_len < 2) {
if (parse_flags != DO_PARSE_ANY)
break;
// Ignore unexpected padding
} else if (byte_len + pad_len >= 4) {
if (parse_flags != DO_PARSE_ANY)
break;
// Ignore extra pads
} else {
if (1 == ++pad_len) {
pad_start = *dpos;
}
}
} else {
if (pad_len > 0) {
if (parse_flags != DO_PARSE_ANY)
break;
// Ignore pads which are followed by data
pad_len = 0;
}
++byte_len;
}
}
for (size_t i = byte_len; i < 4; ++i) {
qbuf[i] = 0;
}
if (4 == byte_len + pad_len) {
*padded = true;
} else {
*padded = false;
if (pad_len) {
// Roll back illegal padding
*dpos = pad_start;
}
}
return byte_len;
}
bool Base64::DecodeFromArray(const char* data,
size_t len,
DecodeFlags flags,
std::string* result,
size_t* data_used) {
return DecodeFromArrayTemplate<std::string>(data, len, flags, result,
data_used);
}
bool Base64::DecodeFromArray(const char* data,
size_t len,
DecodeFlags flags,
vector<char>* result,
size_t* data_used) {
return DecodeFromArrayTemplate<vector<char>>(data, len, flags, result,
data_used);
}
bool Base64::DecodeFromArray(const char* data,
size_t len,
DecodeFlags flags,
vector<uint8_t>* result,
size_t* data_used) {
return DecodeFromArrayTemplate<vector<uint8_t>>(data, len, flags, result,
data_used);
}
template <typename T>
bool Base64::DecodeFromArrayTemplate(const char* data,
size_t len,
DecodeFlags flags,
T* result,
size_t* data_used) {
RTC_DCHECK(nullptr != result);
RTC_DCHECK(flags <= (DO_PARSE_MASK | DO_PAD_MASK | DO_TERM_MASK));
const DecodeFlags parse_flags = flags & DO_PARSE_MASK;
const DecodeFlags pad_flags = flags & DO_PAD_MASK;
const DecodeFlags term_flags = flags & DO_TERM_MASK;
RTC_DCHECK(0 != parse_flags);
RTC_DCHECK(0 != pad_flags);
RTC_DCHECK(0 != term_flags);
result->clear();
result->reserve(len);
size_t dpos = 0;
bool success = true, padded;
unsigned char c, qbuf[4];
while (dpos < len) {
size_t qlen = GetNextQuantum(parse_flags, (DO_PAD_NO == pad_flags), data,
len, &dpos, qbuf, &padded);
c = (qbuf[0] << 2) | ((qbuf[1] >> 4) & 0x3);
if (qlen >= 2) {
result->push_back(c);
c = ((qbuf[1] << 4) & 0xf0) | ((qbuf[2] >> 2) & 0xf);
if (qlen >= 3) {
result->push_back(c);
c = ((qbuf[2] << 6) & 0xc0) | qbuf[3];
if (qlen >= 4) {
result->push_back(c);
c = 0;
}
}
}
if (qlen < 4) {
if ((DO_TERM_ANY != term_flags) && (0 != c)) {
success = false; // unused bits
}
if ((DO_PAD_YES == pad_flags) && !padded) {
success = false; // expected padding
}
break;
}
}
if ((DO_TERM_BUFFER == term_flags) && (dpos != len)) {
success = false; // unused chars
}
if (data_used) {
*data_used = dpos;
}
return success;
}
} // namespace rtc

123
third_party/base64/base64.h vendored Normal file
View File

@ -0,0 +1,123 @@
//*********************************************************************
//* C_Base64 - a simple base64 encoder and decoder.
//*
//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
//*
//* This code may be freely used for any purpose, either personal
//* or commercial, provided the authors copyright notice remains
//* intact.
//*********************************************************************
#ifndef RTC_BASE_BASE64_H_
#define RTC_BASE_BASE64_H_
#include <string>
#include <vector>
namespace rtc {
class Base64 {
public:
enum DecodeOption {
DO_PARSE_STRICT = 1, // Parse only base64 characters
DO_PARSE_WHITE = 2, // Parse only base64 and whitespace characters
DO_PARSE_ANY = 3, // Parse all characters
DO_PARSE_MASK = 3,
DO_PAD_YES = 4, // Padding is required
DO_PAD_ANY = 8, // Padding is optional
DO_PAD_NO = 12, // Padding is disallowed
DO_PAD_MASK = 12,
DO_TERM_BUFFER = 16, // Must termiante at end of buffer
DO_TERM_CHAR = 32, // May terminate at any character boundary
DO_TERM_ANY = 48, // May terminate at a sub-character bit offset
DO_TERM_MASK = 48,
// Strictest interpretation
DO_STRICT = DO_PARSE_STRICT | DO_PAD_YES | DO_TERM_BUFFER,
DO_LAX = DO_PARSE_ANY | DO_PAD_ANY | DO_TERM_CHAR,
};
typedef int DecodeFlags;
static bool IsBase64Char(char ch);
// Get the char next to the |ch| from the Base64Table.
// If the |ch| is the last one in the Base64Table then returns
// the first one from the table.
// Expects the |ch| be a base64 char.
// The result will be saved in |next_ch|.
// Returns true on success.
static bool GetNextBase64Char(char ch, char* next_ch);
// Determines whether the given string consists entirely of valid base64
// encoded characters.
static bool IsBase64Encoded(const std::string& str);
static void EncodeFromArray(const void* data,
size_t len,
std::string* result);
static bool DecodeFromArray(const char* data,
size_t len,
DecodeFlags flags,
std::string* result,
size_t* data_used);
static bool DecodeFromArray(const char* data,
size_t len,
DecodeFlags flags,
std::vector<char>* result,
size_t* data_used);
static bool DecodeFromArray(const char* data,
size_t len,
DecodeFlags flags,
std::vector<uint8_t>* result,
size_t* data_used);
// Convenience Methods
static inline std::string Encode(const std::string& data) {
std::string result;
EncodeFromArray(data.data(), data.size(), &result);
return result;
}
static inline std::string Decode(const std::string& data, DecodeFlags flags) {
std::string result;
DecodeFromArray(data.data(), data.size(), flags, &result, nullptr);
return result;
}
static inline bool Decode(const std::string& data,
DecodeFlags flags,
std::string* result,
size_t* data_used) {
return DecodeFromArray(data.data(), data.size(), flags, result, data_used);
}
static inline bool Decode(const std::string& data,
DecodeFlags flags,
std::vector<char>* result,
size_t* data_used) {
return DecodeFromArray(data.data(), data.size(), flags, result, data_used);
}
private:
static const char Base64Table[];
static const unsigned char DecodeTable[];
static size_t GetNextQuantum(DecodeFlags parse_flags,
bool illegal_pads,
const char* data,
size_t len,
size_t* dpos,
unsigned char qbuf[4],
bool* padded);
template <typename T>
static bool DecodeFromArrayTemplate(const char* data,
size_t len,
DecodeFlags flags,
T* result,
size_t* data_used);
};
} // namespace rtc
#endif // RTC_BASE_BASE64_H_

999
third_party/base64/base64_unittest.cc vendored Normal file
View File

@ -0,0 +1,999 @@
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/base64.h"
#include "rtc_base/gunit.h"
#include "rtc_base/logging.h"
#include "rtc_base/stringutils.h"
#include "rtc_base/testbase64.h"
using namespace std;
using namespace rtc;
static struct {
size_t plain_length;
const char* plaintext;
const char* cyphertext;
} base64_tests[] = {
// Basic bit patterns;
// values obtained with "echo -n '...' | uuencode -m test"
{ 1, "\000", "AA==" },
{ 1, "\001", "AQ==" },
{ 1, "\002", "Ag==" },
{ 1, "\004", "BA==" },
{ 1, "\010", "CA==" },
{ 1, "\020", "EA==" },
{ 1, "\040", "IA==" },
{ 1, "\100", "QA==" },
{ 1, "\200", "gA==" },
{ 1, "\377", "/w==" },
{ 1, "\376", "/g==" },
{ 1, "\375", "/Q==" },
{ 1, "\373", "+w==" },
{ 1, "\367", "9w==" },
{ 1, "\357", "7w==" },
{ 1, "\337", "3w==" },
{ 1, "\277", "vw==" },
{ 1, "\177", "fw==" },
{ 2, "\000\000", "AAA=" },
{ 2, "\000\001", "AAE=" },
{ 2, "\000\002", "AAI=" },
{ 2, "\000\004", "AAQ=" },
{ 2, "\000\010", "AAg=" },
{ 2, "\000\020", "ABA=" },
{ 2, "\000\040", "ACA=" },
{ 2, "\000\100", "AEA=" },
{ 2, "\000\200", "AIA=" },
{ 2, "\001\000", "AQA=" },
{ 2, "\002\000", "AgA=" },
{ 2, "\004\000", "BAA=" },
{ 2, "\010\000", "CAA=" },
{ 2, "\020\000", "EAA=" },
{ 2, "\040\000", "IAA=" },
{ 2, "\100\000", "QAA=" },
{ 2, "\200\000", "gAA=" },
{ 2, "\377\377", "//8=" },
{ 2, "\377\376", "//4=" },
{ 2, "\377\375", "//0=" },
{ 2, "\377\373", "//s=" },
{ 2, "\377\367", "//c=" },
{ 2, "\377\357", "/+8=" },
{ 2, "\377\337", "/98=" },
{ 2, "\377\277", "/78=" },
{ 2, "\377\177", "/38=" },
{ 2, "\376\377", "/v8=" },
{ 2, "\375\377", "/f8=" },
{ 2, "\373\377", "+/8=" },
{ 2, "\367\377", "9/8=" },
{ 2, "\357\377", "7/8=" },
{ 2, "\337\377", "3/8=" },
{ 2, "\277\377", "v/8=" },
{ 2, "\177\377", "f/8=" },
{ 3, "\000\000\000", "AAAA" },
{ 3, "\000\000\001", "AAAB" },
{ 3, "\000\000\002", "AAAC" },
{ 3, "\000\000\004", "AAAE" },
{ 3, "\000\000\010", "AAAI" },
{ 3, "\000\000\020", "AAAQ" },
{ 3, "\000\000\040", "AAAg" },
{ 3, "\000\000\100", "AABA" },
{ 3, "\000\000\200", "AACA" },
{ 3, "\000\001\000", "AAEA" },
{ 3, "\000\002\000", "AAIA" },
{ 3, "\000\004\000", "AAQA" },
{ 3, "\000\010\000", "AAgA" },
{ 3, "\000\020\000", "ABAA" },
{ 3, "\000\040\000", "ACAA" },
{ 3, "\000\100\000", "AEAA" },
{ 3, "\000\200\000", "AIAA" },
{ 3, "\001\000\000", "AQAA" },
{ 3, "\002\000\000", "AgAA" },
{ 3, "\004\000\000", "BAAA" },
{ 3, "\010\000\000", "CAAA" },
{ 3, "\020\000\000", "EAAA" },
{ 3, "\040\000\000", "IAAA" },
{ 3, "\100\000\000", "QAAA" },
{ 3, "\200\000\000", "gAAA" },
{ 3, "\377\377\377", "////" },
{ 3, "\377\377\376", "///+" },
{ 3, "\377\377\375", "///9" },
{ 3, "\377\377\373", "///7" },
{ 3, "\377\377\367", "///3" },
{ 3, "\377\377\357", "///v" },
{ 3, "\377\377\337", "///f" },
{ 3, "\377\377\277", "//+/" },
{ 3, "\377\377\177", "//9/" },
{ 3, "\377\376\377", "//7/" },
{ 3, "\377\375\377", "//3/" },
{ 3, "\377\373\377", "//v/" },
{ 3, "\377\367\377", "//f/" },
{ 3, "\377\357\377", "/+//" },
{ 3, "\377\337\377", "/9//" },
{ 3, "\377\277\377", "/7//" },
{ 3, "\377\177\377", "/3//" },
{ 3, "\376\377\377", "/v//" },
{ 3, "\375\377\377", "/f//" },
{ 3, "\373\377\377", "+///" },
{ 3, "\367\377\377", "9///" },
{ 3, "\357\377\377", "7///" },
{ 3, "\337\377\377", "3///" },
{ 3, "\277\377\377", "v///" },
{ 3, "\177\377\377", "f///" },
// Random numbers: values obtained with
//
// #! /bin/bash
// dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random
// od -N $1 -t o1 /tmp/bar.random
// uuencode -m test < /tmp/bar.random
//
// where $1 is the number of bytes (2, 3)
{ 2, "\243\361", "o/E=" },
{ 2, "\024\167", "FHc=" },
{ 2, "\313\252", "y6o=" },
{ 2, "\046\041", "JiE=" },
{ 2, "\145\236", "ZZ4=" },
{ 2, "\254\325", "rNU=" },
{ 2, "\061\330", "Mdg=" },
{ 2, "\245\032", "pRo=" },
{ 2, "\006\000", "BgA=" },
{ 2, "\375\131", "/Vk=" },
{ 2, "\303\210", "w4g=" },
{ 2, "\040\037", "IB8=" },
{ 2, "\261\372", "sfo=" },
{ 2, "\335\014", "3Qw=" },
{ 2, "\233\217", "m48=" },
{ 2, "\373\056", "+y4=" },
{ 2, "\247\232", "p5o=" },
{ 2, "\107\053", "Rys=" },
{ 2, "\204\077", "hD8=" },
{ 2, "\276\211", "vok=" },
{ 2, "\313\110", "y0g=" },
{ 2, "\363\376", "8/4=" },
{ 2, "\251\234", "qZw=" },
{ 2, "\103\262", "Q7I=" },
{ 2, "\142\312", "Yso=" },
{ 2, "\067\211", "N4k=" },
{ 2, "\220\001", "kAE=" },
{ 2, "\152\240", "aqA=" },
{ 2, "\367\061", "9zE=" },
{ 2, "\133\255", "W60=" },
{ 2, "\176\035", "fh0=" },
{ 2, "\032\231", "Gpk=" },
{ 3, "\013\007\144", "Cwdk" },
{ 3, "\030\112\106", "GEpG" },
{ 3, "\047\325\046", "J9Um" },
{ 3, "\310\160\022", "yHAS" },
{ 3, "\131\100\237", "WUCf" },
{ 3, "\064\342\134", "NOJc" },
{ 3, "\010\177\004", "CH8E" },
{ 3, "\345\147\205", "5WeF" },
{ 3, "\300\343\360", "wOPw" },
{ 3, "\061\240\201", "MaCB" },
{ 3, "\225\333\044", "ldsk" },
{ 3, "\215\137\352", "jV/q" },
{ 3, "\371\147\160", "+Wdw" },
{ 3, "\030\320\051", "GNAp" },
{ 3, "\044\174\241", "JHyh" },
{ 3, "\260\127\037", "sFcf" },
{ 3, "\111\045\033", "SSUb" },
{ 3, "\202\114\107", "gkxH" },
{ 3, "\057\371\042", "L/ki" },
{ 3, "\223\247\244", "k6ek" },
{ 3, "\047\216\144", "J45k" },
{ 3, "\203\070\327", "gzjX" },
{ 3, "\247\140\072", "p2A6" },
{ 3, "\124\115\116", "VE1O" },
{ 3, "\157\162\050", "b3Io" },
{ 3, "\357\223\004", "75ME" },
{ 3, "\052\117\156", "Kk9u" },
{ 3, "\347\154\000", "52wA" },
{ 3, "\303\012\142", "wwpi" },
{ 3, "\060\035\362", "MB3y" },
{ 3, "\130\226\361", "WJbx" },
{ 3, "\173\013\071", "ews5" },
{ 3, "\336\004\027", "3gQX" },
{ 3, "\357\366\234", "7/ac" },
{ 3, "\353\304\111", "68RJ" },
{ 3, "\024\264\131", "FLRZ" },
{ 3, "\075\114\251", "PUyp" },
{ 3, "\315\031\225", "zRmV" },
{ 3, "\154\201\276", "bIG+" },
{ 3, "\200\066\072", "gDY6" },
{ 3, "\142\350\267", "Yui3" },
{ 3, "\033\000\166", "GwB2" },
{ 3, "\210\055\077", "iC0/" },
{ 3, "\341\037\124", "4R9U" },
{ 3, "\161\103\152", "cUNq" },
{ 3, "\270\142\131", "uGJZ" },
{ 3, "\337\076\074", "3z48" },
{ 3, "\375\106\362", "/Uby" },
{ 3, "\227\301\127", "l8FX" },
{ 3, "\340\002\234", "4AKc" },
{ 3, "\121\064\033", "UTQb" },
{ 3, "\157\134\143", "b1xj" },
{ 3, "\247\055\327", "py3X" },
{ 3, "\340\142\005", "4GIF" },
{ 3, "\060\260\143", "MLBj" },
{ 3, "\075\203\170", "PYN4" },
{ 3, "\143\160\016", "Y3AO" },
{ 3, "\313\013\063", "ywsz" },
{ 3, "\174\236\135", "fJ5d" },
{ 3, "\103\047\026", "QycW" },
{ 3, "\365\005\343", "9QXj" },
{ 3, "\271\160\223", "uXCT" },
{ 3, "\362\255\172", "8q16" },
{ 3, "\113\012\015", "SwoN" },
// various lengths, generated by this python script:
//
// from string import lowercase as lc
// for i in range(27):
// print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i),
// lc[:i].encode('base64').strip())
{ 0, "abcdefghijklmnopqrstuvwxyz", "" },
{ 1, "abcdefghijklmnopqrstuvwxyz", "YQ==" },
{ 2, "abcdefghijklmnopqrstuvwxyz", "YWI=" },
{ 3, "abcdefghijklmnopqrstuvwxyz", "YWJj" },
{ 4, "abcdefghijklmnopqrstuvwxyz", "YWJjZA==" },
{ 5, "abcdefghijklmnopqrstuvwxyz", "YWJjZGU=" },
{ 6, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVm" },
{ 7, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZw==" },
{ 8, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2g=" },
{ 9, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hp" },
{ 10, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpag==" },
{ 11, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpams=" },
{ 12, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamts" },
{ 13, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbQ==" },
{ 14, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW4=" },
{ 15, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5v" },
{ 16, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcA==" },
{ 17, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHE=" },
{ 18, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFy" },
{ 19, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFycw==" },
{ 20, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q=" },
{ 21, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1" },
{ 22, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg==" },
{ 23, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc=" },
{ 24, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4" },
{ 25, "abcdefghijklmnopqrstuvwxy", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ==" },
{ 26, "abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=" },
};
#if 0
static struct {
const char* plaintext;
const char* cyphertext;
} base64_strings[] = {
// The first few Google quotes
// Cyphertext created with "uuencode - GNU sharutils 4.2.1"
{
"Everyone! We're teetering on the brink of disaster."
" - Sergey Brin, 6/24/99, regarding the company's state "
"after the unleashing of Netscape/Google search",
"RXZlcnlvbmUhICBXZSdyZSB0ZWV0ZXJpbmcgb24gdGhlIGJyaW5rIG9mIGRp"
"c2FzdGVyLiAtIFNlcmdleSBCcmluLCA2LzI0Lzk5LCByZWdhcmRpbmcgdGhl"
"IGNvbXBhbnkncyBzdGF0ZSBhZnRlciB0aGUgdW5sZWFzaGluZyBvZiBOZXRz"
"Y2FwZS9Hb29nbGUgc2VhcmNo" },
{
"I'm not sure why we're still alive, but we seem to be."
" - Larry Page, 6/24/99, while hiding in the kitchenette "
"during the Netscape traffic overflow",
"SSdtIG5vdCBzdXJlIHdoeSB3ZSdyZSBzdGlsbCBhbGl2ZSwgYnV0IHdlIHNl"
"ZW0gdG8gYmUuIC0gTGFycnkgUGFnZSwgNi8yNC85OSwgd2hpbGUgaGlkaW5n"
"IGluIHRoZSBraXRjaGVuZXR0ZSBkdXJpbmcgdGhlIE5ldHNjYXBlIHRyYWZm"
"aWMgb3ZlcmZsb3c" },
{
"I think kids want porn."
" - Sergey Brin, 6/99, on why Google shouldn't prioritize a "
"filtered search for children and families",
"SSB0aGluayBraWRzIHdhbnQgcG9ybi4gLSBTZXJnZXkgQnJpbiwgNi85OSwg"
"b24gd2h5IEdvb2dsZSBzaG91bGRuJ3QgcHJpb3JpdGl6ZSBhIGZpbHRlcmVk"
"IHNlYXJjaCBmb3IgY2hpbGRyZW4gYW5kIGZhbWlsaWVz" },
};
#endif
// Compare bytes 0..len-1 of x and y. If not equal, abort with verbose error
// message showing position and numeric value that differed.
// Handles embedded nulls just like any other byte.
// Only added because string.compare() in gcc-3.3.3 seems to misbehave with
// embedded nulls.
// TODO: switch back to string.compare() if/when gcc is fixed
#define EXPECT_EQ_ARRAY(len, x, y, msg) \
for (size_t j = 0; j < len; ++j) { \
if (x[j] != y[j]) { \
RTC_LOG(LS_ERROR) << "" #x << " != " #y << " byte " << j \
<< " msg: " << msg; \
} \
}
size_t Base64Escape(const unsigned char *src, size_t szsrc, char *dest,
size_t szdest) {
std::string escaped;
Base64::EncodeFromArray((const char *)src, szsrc, &escaped);
memcpy(dest, escaped.data(), min(escaped.size(), szdest));
return escaped.size();
}
size_t Base64Unescape(const char *src, size_t szsrc, char *dest,
size_t szdest) {
std::string unescaped;
EXPECT_TRUE(
Base64::DecodeFromArray(src, szsrc, Base64::DO_LAX, &unescaped, nullptr));
memcpy(dest, unescaped.data(), min(unescaped.size(), szdest));
return unescaped.size();
}
size_t Base64Unescape(const char *src, size_t szsrc, std::string *s) {
EXPECT_TRUE(Base64::DecodeFromArray(src, szsrc, Base64::DO_LAX, s, nullptr));
return s->size();
}
TEST(Base64, EncodeDecodeBattery) {
RTC_LOG(LS_VERBOSE) << "Testing base-64";
size_t i;
// Check the short strings; this tests the math (and boundaries)
for( i = 0; i < sizeof(base64_tests) / sizeof(base64_tests[0]); ++i ) {
char encode_buffer[100];
size_t encode_length;
char decode_buffer[100];
size_t decode_length;
size_t cypher_length;
RTC_LOG(LS_VERBOSE) << "B64: " << base64_tests[i].cyphertext;
const unsigned char* unsigned_plaintext =
reinterpret_cast<const unsigned char*>(base64_tests[i].plaintext);
cypher_length = strlen(base64_tests[i].cyphertext);
// The basic escape function:
memset(encode_buffer, 0, sizeof(encode_buffer));
encode_length = Base64Escape(unsigned_plaintext,
base64_tests[i].plain_length,
encode_buffer,
sizeof(encode_buffer));
// Is it of the expected length?
EXPECT_EQ(encode_length, cypher_length);
// Is it the expected encoded value?
EXPECT_STREQ(encode_buffer, base64_tests[i].cyphertext);
// If we encode it into a buffer of exactly the right length...
memset(encode_buffer, 0, sizeof(encode_buffer));
encode_length = Base64Escape(unsigned_plaintext,
base64_tests[i].plain_length,
encode_buffer,
cypher_length);
// Is it still of the expected length?
EXPECT_EQ(encode_length, cypher_length);
// And is the value still correct? (i.e., not losing the last byte)
EXPECT_STREQ(encode_buffer, base64_tests[i].cyphertext);
// If we decode it back:
memset(decode_buffer, 0, sizeof(decode_buffer));
decode_length = Base64Unescape(encode_buffer,
cypher_length,
decode_buffer,
sizeof(decode_buffer));
// Is it of the expected length?
EXPECT_EQ(decode_length, base64_tests[i].plain_length);
// Is it the expected decoded value?
EXPECT_EQ(0, memcmp(decode_buffer, base64_tests[i].plaintext, decode_length));
// Our decoder treats the padding '=' characters at the end as
// optional. If encode_buffer has any, run some additional
// tests that fiddle with them.
char* first_equals = strchr(encode_buffer, '=');
if (first_equals) {
// How many equals signs does the string start with?
int equals = (*(first_equals+1) == '=') ? 2 : 1;
// Try chopping off the equals sign(s) entirely. The decoder
// should still be okay with this.
std::string decoded2("this junk should also be ignored");
*first_equals = '\0';
EXPECT_NE(0U, Base64Unescape(encode_buffer, first_equals-encode_buffer,
&decoded2));
EXPECT_EQ(decoded2.size(), base64_tests[i].plain_length);
EXPECT_EQ_ARRAY(decoded2.size(), decoded2.data(), base64_tests[i].plaintext, i);
size_t len;
// try putting some extra stuff after the equals signs, or in between them
if (equals == 2) {
sprintfn(first_equals, 6, " = = ");
len = first_equals - encode_buffer + 5;
} else {
sprintfn(first_equals, 6, " = ");
len = first_equals - encode_buffer + 3;
}
decoded2.assign("this junk should be ignored");
EXPECT_NE(0U, Base64Unescape(encode_buffer, len, &decoded2));
EXPECT_EQ(decoded2.size(), base64_tests[i].plain_length);
EXPECT_EQ_ARRAY(decoded2.size(), decoded2, base64_tests[i].plaintext, i);
}
}
}
// here's a weird case: a giant base64 encoded stream which broke our base64
// decoding. Let's test it explicitly.
const char SpecificTest[] =
"/9j/4AAQSkZJRgABAgEASABIAAD/4Q0HRXhpZgAATU0AKgAAAAgADAEOAAIAAAAgAAAAngEPAAI\n"
"AAAAFAAAAvgEQAAIAAAAJAAAAwwESAAMAAAABAAEAAAEaAAUAAAABAAAAzAEbAAUAAAABAAAA1A\n"
"EoAAMAAAABAAIAAAExAAIAAAAUAAAA3AEyAAIAAAAUAAAA8AE8AAIAAAAQAAABBAITAAMAAAABA\n"
"AIAAIdpAAQAAAABAAABFAAAAsQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgAFNPTlkA\n"
"RFNDLVAyMDAAAAAASAAAAAEAAABIAAAAAUFkb2JlIFBob3Rvc2hvcCA3LjAAMjAwNzowMTozMCA\n"
"yMzoxMDowNABNYWMgT1MgWCAxMC40LjgAAByCmgAFAAAAAQAAAmqCnQAFAAAAAQAAAnKIIgADAA\n"
"AAAQACAACIJwADAAAAAQBkAACQAAAHAAAABDAyMjCQAwACAAAAFAAAAnqQBAACAAAAFAAAAo6RA\n"
"QAHAAAABAECAwCRAgAFAAAAAQAAAqKSBAAKAAAAAQAAAqqSBQAFAAAAAQAAArKSBwADAAAAAQAF\n"
"AACSCAADAAAAAQAAAACSCQADAAAAAQAPAACSCgAFAAAAAQAAArqgAAAHAAAABDAxMDCgAQADAAA\n"
"AAf//AACgAgAEAAAAAQAAAGSgAwAEAAAAAQAAAGSjAAAHAAAAAQMAAACjAQAHAAAAAQEAAACkAQ\n"
"ADAAAAAQAAAACkAgADAAAAAQAAAACkAwADAAAAAQAAAACkBgADAAAAAQAAAACkCAADAAAAAQAAA\n"
"ACkCQADAAAAAQAAAACkCgADAAAAAQAAAAAAAAAAAAAACgAAAZAAAAAcAAAACjIwMDc6MDE6MjAg\n"
"MjM6MDU6NTIAMjAwNzowMToyMCAyMzowNTo1MgAAAAAIAAAAAQAAAAAAAAAKAAAAMAAAABAAAAB\n"
"PAAAACgAAAAYBAwADAAAAAQAGAAABGgAFAAAAAQAAAxIBGwAFAAAAAQAAAxoBKAADAAAAAQACAA\n"
"ACAQAEAAAAAQAAAyICAgAEAAAAAQAACd0AAAAAAAAASAAAAAEAAABIAAAAAf/Y/+AAEEpGSUYAA\n"
"QIBAEgASAAA/+0ADEFkb2JlX0NNAAL/7gAOQWRvYmUAZIAAAAAB/9sAhAAMCAgICQgMCQkMEQsK\n"
"CxEVDwwMDxUYExMVExMYEQwMDAwMDBEMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQ0LCw0\n"
"ODRAODhAUDg4OFBQODg4OFBEMDAwMDBERDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA\n"
"wMDAz/wAARCABkAGQDASIAAhEBAxEB/90ABAAH/8QBPwAAAQUBAQEBAQEAAAAAAAAAAwABAgQFB\n"
"gcICQoLAQABBQEBAQEBAQAAAAAAAAABAAIDBAUGBwgJCgsQAAEEAQMCBAIFBwYIBQMMMwEAAhED\n"
"BCESMQVBUWETInGBMgYUkaGxQiMkFVLBYjM0coLRQwclklPw4fFjczUWorKDJkSTVGRFwqN0Nhf\n"
"SVeJl8rOEw9N14/NGJ5SkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9xEAAg\n"
"IBAgQEAwQFBgcHBgU1AQACEQMhMRIEQVFhcSITBTKBkRShsUIjwVLR8DMkYuFygpJDUxVjczTxJ\n"
"QYWorKDByY1wtJEk1SjF2RFVTZ0ZeLys4TD03Xj80aUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm\n"
"9ic3R1dnd4eXp7fH/9oADAMBAAIRAxEAPwDy7bKNTUXNLz9EaJPDWMjxH4ozhtpYwaACT8ShaaW\n"
"bW0uEc9/JFfjj0Q4Hk/PRDxwX7y47W9z/AN9Cv4+O3ILK2DcRqT2CaSvEbcl1Jbz37KG1dBldLo\n"
"qaS4l9xGjG9v6yoDAdYIaIjUk+AREgo4y5sapirb8Yl0NHHdKvBNm4yA1o5Pc+SPEFvCWqB3HZF\n"
"Hj2SbWQ/afGFP0bHP8ATY0uc4w1o1JPkkimGiS2KvqlnmBkOZQTyydzgPMM9v8A0lp4v1Nx9gF1\n"
"tpdqJaGtH/S3I0i3lISXW/8AMqnd/O2bfg2eUkqVYf/Q8zuncO4Bj7lZ+n7f5Mj5KsJcY8NUZ4d\n"
"uEDVo1HkeU0rg3Om4H2rabCWUN7DQuK1n5FWKW4uCwG92gDRJBS6exhxmMboQI+Cv4WFTQ42Bs2\n"
"fvnkkqEmy2YxoMMbpVzaz6jt+RbpHZs8lzkHqrasKkYOKP0jgDfZ4N/wDM1tNrcWfSPmRyq9uNV\n"
"DnFg2s97i7UkjxKVrq0eVz3spZsja+ASDzwsh9jnOk/JFzb3XZD3v1c4yT8UACTCniKDUnKz5Nj\n"
"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\n"
"cm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk\n"
"+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1Ib3Jpem9udGFsUmVzPC9rZXk+Cgk8ZGljdD\n"
"4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCTxzdHJpbmc+Y\n"
"29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCTxrZXk+Y29tLmFwcGxlLnByaW50\n"
"LnRpY2tldC5pdGVtQXJyYXk8L2tleT4KCQk8YXJyYXk+CgkJCTxkaWN0PgoJCQkJPGtleT5jb20\n"
"uYXBwbGUucHJpbnQuUGFnZUZvcm1hdC5QTUhvcml6b250YWxSZXM8L2tleT4KCQkJCTxyZWFsPj\n"
"cyPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJC\n"
"QkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJpbmc+CgkJCQk8a2V5PmNv\n"
"bS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGRhdGU+MjAwNy0wMS0zMFQ\n"
"yMjowODo0MVo8L2RhdGU+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuc3RhdGVGbG\n"
"FnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY3Q+CgkJPC9hcnJheT4KC\n"
"TwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwv\n"
"a2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4\n"
"KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS\n"
"5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KC\n"
"QkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1PcmllbnRhdGlvbjwva2V5PgoJ\n"
"CQkJPGludGVnZXI+MTwvaW50ZWdlcj4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5\n"
"jbGllbnQ8L2tleT4KCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW\n"
"5nPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lm1vZERhdGU8L2tleT4KCQkJCTxkY\n"
"XRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQu\n"
"dGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJPGludGVnZXI+MDwvaW50ZWdlcj4KCQkJPC9kaWN\n"
"0PgoJCTwvYXJyYXk+Cgk8L2RpY3Q+Cgk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0Ll\n"
"BNU2NhbGluZzwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZ\n"
"WF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4K\n"
"CQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFycmF5Pgo\n"
"JCQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1TY2FsaW5nPC\n"
"9rZXk+CgkJCQk8cmVhbD4xPC9yZWFsPgoJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0L\n"
"mNsaWVudDwva2V5PgoJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnRpbmdtYW5hZ2VyPC9zdHJp\n"
"bmc+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQkJPGR\n"
"hdGU+MjAwNy0wMS0zMFQyMjowODo0MVo8L2RhdGU+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC\n"
"50aWNrZXQuc3RhdGVGbGFnPC9rZXk+CgkJCQk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJCQk8L2RpY\n"
"3Q+CgkJPC9hcnJheT4KCTwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQu\n"
"UE1WZXJ0aWNhbFJlczwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V\n"
"0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cm\n"
"luZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJPGFyc\n"
"mF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYXQuUE1WZXJ0\n"
"aWNhbFJlczwva2V5PgoJCQkJPHJlYWw+NzI8L3JlYWw+CgkJCQk8a2V5PmNvbS5hcHBsZS5wcml\n"
"udC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbm\n"
"FnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZ\n"
"Xk+CgkJCQk8ZGF0ZT4yMDA3LTAxLTMwVDIyOjA4OjQxWjwvZGF0ZT4KCQkJCTxrZXk+Y29tLmFw\n"
"cGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI\n"
"+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5jb20uYXBwbGUucHJpbnQuUG\n"
"FnZUZvcm1hdC5QTVZlcnRpY2FsU2NhbGluZzwva2V5PgoJPGRpY3Q+CgkJPGtleT5jb20uYXBwb\n"
"GUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGlu\n"
"Z21hbmFnZXI8L3N0cmluZz4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF\n"
"5PC9rZXk+CgkJPGFycmF5PgoJCQk8ZGljdD4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2\n"
"VGb3JtYXQuUE1WZXJ0aWNhbFNjYWxpbmc8L2tleT4KCQkJCTxyZWFsPjE8L3JlYWw+CgkJCQk8a\n"
"2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50PC9rZXk+CgkJCQk8c3RyaW5nPmNvbS5h\n"
"cHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnR\n"
"pY2tldC5tb2REYXRlPC9rZXk+CgkJCQk8ZGF0ZT4yMDA3LTAxLTMwVDIyOjA4OjQxWjwvZGF0ZT\n"
"4KCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCTxpb\n"
"nRlZ2VyPjA8L2ludGVnZXI+CgkJCTwvZGljdD4KCQk8L2FycmF5PgoJPC9kaWN0PgoJPGtleT5j\n"
"b20uYXBwbGUucHJpbnQuc3ViVGlja2V0LnBhcGVyX2luZm9fdGlja2V0PC9rZXk+Cgk8ZGljdD4\n"
"KCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYWdlUmVjdDwva2\n"
"V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY3JlYXRvcjwva2V5P\n"
"goJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJPGtleT5j\n"
"b20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGl\n"
"jdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYWdlRm9ybWF0LlBNQWRqdXN0ZWRQYWdlUm\n"
"VjdDwva2V5PgoJCQkJCTxhcnJheT4KCQkJCQkJPHJlYWw+MC4wPC9yZWFsPgoJCQkJCQk8cmVhb\n"
"D4wLjA8L3JlYWw+CgkJCQkJCTxyZWFsPjczNDwvcmVhbD4KCQkJCQkJPHJlYWw+NTc2PC9yZWFs\n"
"PgoJCQkJCTwvYXJyYXk+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDw\n"
"va2V5PgoJCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQ\n"
"kJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+M\n"
"jAwNy0wMS0zMFQyMjowODo0MVo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlj\n"
"a2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCQk8L2RpY3Q\n"
"+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhZ2VGb3JtYX\n"
"QuUE1BZGp1c3RlZFBhcGVyUmVjdDwva2V5PgoJCTxkaWN0PgoJCQk8a2V5PmNvbS5hcHBsZS5wc\n"
"mludC50aWNrZXQuY3JlYXRvcjwva2V5PgoJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21h\n"
"bmFnZXI8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0Lml0ZW1BcnJheTw\n"
"va2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC5QYW\n"
"dlRm9ybWF0LlBNQWRqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+CgkJCQkJCTxyZ\n"
"WFsPi0xODwvcmVhbD4KCQkJCQkJPHJlYWw+LTE4PC9yZWFsPgoJCQkJCQk8cmVhbD43NzQ8L3Jl\n"
"YWw+CgkJCQkJCTxyZWFsPjU5NDwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+Y29tLmF\n"
"wcGxlLnByaW50LnRpY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcm\n"
"ludGluZ21hbmFnZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQub\n"
"W9kRGF0ZTwva2V5PgoJCQkJCTxkYXRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJ\n"
"CTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWd\n"
"lcj4wPC9pbnRlZ2VyPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5Pm\n"
"NvbS5hcHBsZS5wcmludC5QYXBlckluZm8uUE1QYXBlck5hbWU8L2tleT4KCQk8ZGljdD4KCQkJP\n"
"GtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20u\n"
"YXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcml\n"
"udC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZX\n"
"k+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVBhcGVyTmFtZTwva2V5PgoJCQkJCTxzdHJpb\n"
"mc+bmEtbGV0dGVyPC9zdHJpbmc+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNs\n"
"aWVudDwva2V5PgoJCQkJCTxzdHJpbmc+Y29tLmFwcGxlLnByaW50LnBtLlBvc3RTY3JpcHQ8L3N\n"
"0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5PgoJCQ\n"
"kJCTxkYXRlPjIwMDMtMDctMDFUMTc6NDk6MzZaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFwcGxlL\n"
"nByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4xPC9pbnRlZ2VyPgoJ\n"
"CQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcmludC5\n"
"QYXBlckluZm8uUE1VbmFkanVzdGVkUGFnZVJlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb2\n"
"0uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b3I8L2tleT4KCQkJPHN0cmluZz5jb20uYXBwbGUuc\n"
"HJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5nPgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNr\n"
"ZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJheT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmF\n"
"wcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYWdlUmVjdDwva2V5PgoJCQkJCTxhcn\n"
"JheT4KCQkJCQkJPHJlYWw+MC4wPC9yZWFsPgoJCQkJCQk8cmVhbD4wLjA8L3JlYWw+CgkJCQkJC\n"
"TxyZWFsPjczNDwvcmVhbD4KCQkJCQkJPHJlYWw+NTc2PC9yZWFsPgoJCQkJCTwvYXJyYXk+CgkJ\n"
"CQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNsaWVudDwva2V5PgoJCQkJCTxzdHJpbmc\n"
"+Y29tLmFwcGxlLnByaW50aW5nbWFuYWdlcjwvc3RyaW5nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLn\n"
"ByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPGRhdGU+MjAwNy0wMS0zMFQyMjowODo0M\n"
"Vo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LnN0YXRlRmxhZzwva2V5\n"
"PgoJCQkJCTxpbnRlZ2VyPjA8L2ludGVnZXI+CgkJCQk8L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9\n"
"kaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYWRqdXN0ZWRQYXBlcl\n"
"JlY3Q8L2tleT4KCQk8ZGljdD4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V0LmNyZWF0b\n"
"3I8L2tleT4KCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5n\n"
"PgoJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuaXRlbUFycmF5PC9rZXk+CgkJCTxhcnJ\n"
"heT4KCQkJCTxkaWN0PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LlBhcGVySW5mby5QTVVuYW\n"
"RqdXN0ZWRQYXBlclJlY3Q8L2tleT4KCQkJCQk8YXJyYXk+CgkJCQkJCTxyZWFsPi0xODwvcmVhb\n"
"D4KCQkJCQkJPHJlYWw+LTE4PC9yZWFsPgoJCQkJCQk8cmVhbD43NzQ8L3JlYWw+CgkJCQkJCTxy\n"
"ZWFsPjU5NDwvcmVhbD4KCQkJCQk8L2FycmF5PgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnR\n"
"pY2tldC5jbGllbnQ8L2tleT4KCQkJCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmludGluZ21hbmFnZX\n"
"I8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQubW9kRGF0ZTwva2V5P\n"
"goJCQkJCTxkYXRlPjIwMDctMDEtMzBUMjI6MDg6NDFaPC9kYXRlPgoJCQkJCTxrZXk+Y29tLmFw\n"
"cGxlLnByaW50LnRpY2tldC5zdGF0ZUZsYWc8L2tleT4KCQkJCQk8aW50ZWdlcj4wPC9pbnRlZ2V\n"
"yPgoJCQkJPC9kaWN0PgoJCQk8L2FycmF5PgoJCTwvZGljdD4KCQk8a2V5PmNvbS5hcHBsZS5wcm\n"
"ludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+CgkJPGRpY3Q+CgkJCTxrZXk+Y29tL\n"
"mFwcGxlLnByaW50LnRpY2tldC5jcmVhdG9yPC9rZXk+CgkJCTxzdHJpbmc+Y29tLmFwcGxlLnBy\n"
"aW50LnBtLlBvc3RTY3JpcHQ8L3N0cmluZz4KCQkJPGtleT5jb20uYXBwbGUucHJpbnQudGlja2V\n"
"0Lml0ZW1BcnJheTwva2V5PgoJCQk8YXJyYXk+CgkJCQk8ZGljdD4KCQkJCQk8a2V5PmNvbS5hcH\n"
"BsZS5wcmludC5QYXBlckluZm8ucHBkLlBNUGFwZXJOYW1lPC9rZXk+CgkJCQkJPHN0cmluZz5VU\n"
"yBMZXR0ZXI8L3N0cmluZz4KCQkJCQk8a2V5PmNvbS5hcHBsZS5wcmludC50aWNrZXQuY2xpZW50\n"
"PC9rZXk+CgkJCQkJPHN0cmluZz5jb20uYXBwbGUucHJpbnQucG0uUG9zdFNjcmlwdDwvc3RyaW5\n"
"nPgoJCQkJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2tldC5tb2REYXRlPC9rZXk+CgkJCQkJPG\n"
"RhdGU+MjAwMy0wNy0wMVQxNzo0OTozNlo8L2RhdGU+CgkJCQkJPGtleT5jb20uYXBwbGUucHJpb\n"
"nQudGlja2V0LnN0YXRlRmxhZzwva2V5PgoJCQkJCTxpbnRlZ2VyPjE8L2ludGVnZXI+CgkJCQk8\n"
"L2RpY3Q+CgkJCTwvYXJyYXk+CgkJPC9kaWN0PgoJCTxrZXk+Y29tLmFwcGxlLnByaW50LnRpY2t\n"
"ldC5BUElWZXJzaW9uPC9rZXk+CgkJPHN0cmluZz4wMC4yMDwvc3RyaW5nPgoJCTxrZXk+Y29tLm\n"
"FwcGxlLnByaW50LnRpY2tldC5wcml2YXRlTG9jazwva2V5PgoJCTxmYWxzZS8+CgkJPGtleT5jb\n"
"20uYXBwbGUucHJpbnQudGlja2V0LnR5cGU8L2tleT4KCQk8c3RyaW5nPmNvbS5hcHBsZS5wcmlu\n"
"dC5QYXBlckluZm9UaWNrZXQ8L3N0cmluZz4KCTwvZGljdD4KCTxrZXk+Y29tLmFwcGxlLnByaW5\n"
"0LnRpY2tldC5BUElWZXJzaW9uPC9rZXk+Cgk8c3RyaW5nPjAwLjIwPC9zdHJpbmc+Cgk8a2V5Pm\n"
"NvbS5hcHBsZS5wcmludC50aWNrZXQucHJpdmF0ZUxvY2s8L2tleT4KCTxmYWxzZS8+Cgk8a2V5P\n"
"mNvbS5hcHBsZS5wcmludC50aWNrZXQudHlwZTwva2V5PgoJPHN0cmluZz5jb20uYXBwbGUucHJp\n"
"bnQuUGFnZUZvcm1hdFRpY2tldDwvc3RyaW5nPgo8L2RpY3Q+CjwvcGxpc3Q+CjhCSU0D6QAAAAA\n"
"AeAADAAAASABIAAAAAALeAkD/7v/uAwYCUgNnBSgD/AACAAAASABIAAAAAALYAigAAQAAAGQAAA\n"
"ABAAMDAwAAAAF//wABAAEAAAAAAAAAAAAAAABoCAAZAZAAAAAAACAAAAAAAAAAAAAAAAAAAAAAA\n"
"AAAAAAAAAAAADhCSU0D7QAAAAAAEABIAAAAAQABAEgAAAABAAE4QklNBCYAAAAAAA4AAAAAAAAA\n"
"AAAAP4AAADhCSU0EDQAAAAAABAAAAB44QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAA\n"
"AAAABADhCSU0ECgAAAAAAAQAAOEJJTScQAAAAAAAKAAEAAAAAAAAAAThCSU0D9QAAAAAASAAvZm\n"
"YAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAA\n"
"QAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP//\n"
"//////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA///\n"
"//////////////////////////wPoAAA4QklNBAgAAAAAABAAAAABAAACQAAAAkAAAAAAOEJJTQ\n"
"QeAAAAAAAEAAAAADhCSU0EGgAAAAADRQAAAAYAAAAAAAAAAAAAAGQAAABkAAAACABEAFMAQwAwA\n"
"DIAMwAyADUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAGQAAABkAAAAAAAAAAAA\n"
"AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHN\n"
"PYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAA\n"
"AAQnRvbWxvbmcAAABkAAAAAFJnaHRsb25nAAAAZAAAAAZzbGljZXNWbExzAAAAAU9iamMAAAABA\n"
"AAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAAG\n"
"b3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQA\n"
"AAApFU2xpY2VUeXBlAAAAAEltZyAAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAA\n"
"BUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAAAZAAAAABSZ2h0bG9uZ\n"
"wAAAGQAAAADdXJsVEVYVAAAAAEAAAAAAABudWxsVEVYVAAAAAEAAAAAAABNc2dlVEVYVAAAAAEA\n"
"AAAAAAZhbHRUYWdURVhUAAAAAQAAAAAADmNlbGxUZXh0SXNIVE1MYm9vbAEAAAAIY2VsbFRleHR\n"
"URVhUAAAAAQAAAAAACWhvcnpBbGlnbmVudW0AAAAPRVNsaWNlSG9yekFsaWduAAAAB2RlZmF1bH\n"
"QAAAAJdmVydEFsaWduZW51bQAAAA9FU2xpY2VWZXJ0QWxpZ24AAAAHZGVmYXVsdAAAAAtiZ0Nvb\n"
"G9yVHlwZWVudW0AAAARRVNsaWNlQkdDb2xvclR5cGUAAAAATm9uZQAAAAl0b3BPdXRzZXRsb25n\n"
"AAAAAAAAAApsZWZ0T3V0c2V0bG9uZwAAAAAAAAAMYm90dG9tT3V0c2V0bG9uZwAAAAAAAAALcml\n"
"naHRPdXRzZXRsb25nAAAAAAA4QklNBBEAAAAAAAEBADhCSU0EFAAAAAAABAAAAAE4QklNBAwAAA\n"
"AACfkAAAABAAAAZAAAAGQAAAEsAAB1MAAACd0AGAAB/9j/4AAQSkZJRgABAgEASABIAAD/7QAMQ\n"
"WRvYmVfQ00AAv/uAA5BZG9iZQBkgAAAAAH/2wCEAAwICAgJCAwJCQwRCwoLERUPDAwPFRgTExUT\n"
"ExgRDAwMDAwMEQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDQsLDQ4NEA4OEBQODg4UFA4\n"
"ODg4UEQwMDAwMEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAGQAZA\n"
"MBIgACEQEDEQH/3QAEAAf/xAE/AAABBQEBAQEBAQAAAAAAAAADAAECBAUGBwgJCgsBAAEFAQEBA\n"
"QEBAAAAAAAAAAEAAgMEBQYHCAkKCxAAAQQBAwIEAgUHBggFAwwzAQACEQMEIRIxBUFRYRMicYEy\n"
"BhSRobFCIyQVUsFiMzRygtFDByWSU/Dh8WNzNRaisoMmRJNUZEXCo3Q2F9JV4mXys4TD03Xj80Y\n"
"nlKSFtJXE1OT0pbXF1eX1VmZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3EQACAgECBAQDBAUGBwcGBT\n"
"UBAAIRAyExEgRBUWFxIhMFMoGRFKGxQiPBUtHwMyRi4XKCkkNTFWNzNPElBhaisoMHJjXC0kSTV\n"
"KMXZEVVNnRl4vKzhMPTdePzRpSkhbSVxNTk9KW1xdXl9VZmdoaWprbG1ub2JzdHV2d3h5ent8f/\n"
"2gAMAwEAAhEDEQA/APLtso1NRc0vP0Rok8NYyPEfijOG2ljBoAJPxKFppZtbS4Rz38kV+OPRDge\n"
"T89EPHBfvLjtb3P8A30K/j47cgsrYNxGpPYJpK8RtyXUlvPfsobV0GV0uippLiX3EaMb2/rKgMB\n"
"1ghoiNST4BESCjjLmxqmKtvxiXQ0cd0q8E2bjIDWjk9z5I8QW8JaoHcdkUePZJtZD9p8YU/Rsc/\n"
"wBNjS5zjDWjUk+SSKYaJLYq+qWeYGQ5lBPLJ3OA8wz2/wDSWni/U3H2AXW2l2oloa0f9LcjSLeU\n"
"hJdb/wAyqd387Zt+DZ5SSpVh/9DzO6dw7gGPuVn6ft/kyPkqwlxjw1Rnh24QNWjUeR5TSuDc6bg\n"
"fatpsJZQ3sNC4rWfkVYpbi4LAb3aANEkFLp7GHGYxuhAj4K/hYVNDjYGzZ++eSSoSbLZjGgwxul\n"
"XNrPqO35FukdmzyXOQeqtqwqRg4o/SOAN9ng3/AMzW02txZ9I+ZHKr241UOcWDaz3uLtSSPEpWu\n"
"rR5XPeylmyNr4BIPPCyH2Oc6T8kXNvddkPe/VzjJPxQAJMKeIoNScrPk2MbfddXUNXvcGtPx0Xb\n"
"dJ6NXjOD2Dfdw6w9v5LFW+q/1WLA3Ly9LSJaz91p/wDRjl2lOLWwAMbEJErWjRgESYieVdZhsMF\n"
"wMt08ldrx/vVivHaOdSgCoud9krmElpba93ASTlr/AP/R83ohr97voiJV/Fq9QvsI+mdPgs1thc\n"
"BWO5C38CoOY1g78qOejLiGvknxLAyGtExp5K9uzGt9RrNw7DhRfQKKx6bZIGgPj4rPycLqWVtIs\n"
"JGu5skDyTBRZtQNrb1fU8xrtpBaO4MLQxcx1sNuEjt5rMGJR9noY5hF7Wxa8aAnxVvDb6bgHH2z\n"
"omk0e64ajUUXnev9Idi5rrWAux7SXNd4E/muS+rHSjm9VbPtZjj1CSJBI+g3+0uh69b+iDG/QcD\n"
"u0nQCeFP6l0MZhWX/AJ1xM+QafY1TQlY1a+WABsdXp8Sp27aBH+vZaVbC0ADlVcASwtdOolp8Ct\n"
"BjmtGv0uI8EmJmxkIjWkmPEKLSPiidxIgJKRbDPCSN5pJyH//S87uw/suZ6c72iC13kVs9PdDmk\n"
"KllVziV3cuafc7yP0QjYFh26cqM6hsxAjIj6u6xzbDHh3R663AaceH+5BwdruVp2PqZUA0a9yo6\n"
"DPQajscnXb8YQdzC8H909joiZttoxoBIa4gGOQ3uqh+z1RuD2Ds4j2n+39FNKaFMevS/p5LPpSA\n"
"I8/b/ABW70THZXj11VjaIAIHgFl5VdD8AneDMaec6Lb6QAKmu7x+VSw2a3MdF/rF9YKeh4B9OHZ\n"
"lpAprPH8p7v5DFwrPrV9YDa645toLjMaFo8mtcEvrhkWZHXbg7T0Q2to8o3f8AfkarEitlVTKnY\n"
"ra992QQ2wOfG57H2bg7H2fzbFKA130P6n9dHWemCx5H2mk7LgPH818f8IuhAka6ea8y/wAWrcod\n"
"VyrceRhBsPae5J/Qj+sxq9KDpMuMuKBCEntnny/1CSaWxM6pIKf/0/MvtF3pCrefTBnbOi1elP3\n"
"Et8Vi+Sv9LuNd4HwTSNGSEqkLerwtwn+SYKtOeS4A8Krh2j1D/K1Vu4B5gaDmVDJtAr7zYYGoRB\n"
"QDWQ4c9h/csuyjI3fobnDyJR8fF6ltcTaXRwCkAuAsfMGr1TGFNdTmEwLWS2dIK6npLgK2T4Lle\n"
"pUZxoc9+6K4eR5NO5bPT73NoqIfoILT/JcFJDZr8zGiNXnvrfiur6/Y8tht7WvaexgbXf8AUrFt\n"
"8IExyvRusYDOsYTAIbfWdzHRJ8HN/tLj7OgdRZawmreHP2gt9wEfvtH0f7SkDXe7+o+AOn9DquL\n"
"f0mV+leQPH6H+axafUvrB07ptJtyshtTZDTEudJ7bWS5V6MmyltVLn7ht2hwECQP+isb60/Vqvr\n"
"tbLsa1lObVIJd9Gxv5rXx9F7fzHpIbf/jgfVnd/TLYj6XoOhJcP/zE+sOzd6dW7dt2eo3dH7/9R\n"
"JJWj//U8uiGFx76BFZLQ2xvLeVGAWQrFDJbtKBSHd6blNura4H3BbDXB7InVcZXZdh2bmTt7hbO\n"
"J1dj2gzCjlFnhPod3WLHB+n3o9ZsAkFVMfMrs7orLmgkHUdkyqZQQWWQbLGlrjMjUeSrfV3Ltsw\n"
"30EBzcd5YCedvLETJya66nWOIAaCVnfU/KuZn21CDVa02PngQdHf9LapMfVhzkaAPUUW3M91YaR\n"
"3YDJ+WiBmZGazPo9Kttdt2j63E6s/fft/d/NWjXkMra7KtO2qkE6cErHpvsyMmzPu0dY4Bg/dYP\n"
"otTpyoaMUI2XUya8tzG/pi0NMtICo/bsut21gdcWclkj5OncxaDrw6kM+9QxQzaWRAGii4pDqzC\n"
"MT02aX7WzPU9b7PrG3bvO6P6yStfZm+pHnPySS4590+3jf/V8yb+CsUbp8uyz0kDskbu2dmz9J8\n"
"lSt9Ld+gn1O8cKikmxXydbH+3bhsmfwWj/lONYlcwkhL6L4bfpOxn/tD0/wBN/N944Wh9VJm/b/\n"
"O+347df+/rl0k+O38GLJ83X/CfTOt7v2dV6P8AMbx6njHb/pKuN3pN2+IXnaSjybr8e31fUqd+0\n"
"Sj487DHMryZJMXjq+sfpPX84SXk6SSX/9kAOEJJTQQhAAAAAABVAAAAAQEAAAAPAEEAZABvAGIA\n"
"ZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAA\n"
"gADcALgAwAAAAAQA4QklNBAYAAAAAAAcABQAAAAEBAP/hFWdodHRwOi8vbnMuYWRvYmUuY29tL3\n"
"hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0n77u/JyBpZD0nVzVNME1wQ2VoaUh6cmVTek5UY3prY\n"
"zlkJz8+Cjw/YWRvYmUteGFwLWZpbHRlcnMgZXNjPSJDUiI/Pgo8eDp4YXBtZXRhIHhtbG5zOng9\n"
"J2Fkb2JlOm5zOm1ldGEvJyB4OnhhcHRrPSdYTVAgdG9vbGtpdCAyLjguMi0zMywgZnJhbWV3b3J\n"
"rIDEuNSc+CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi\n"
"1yZGYtc3ludGF4LW5zIycgeG1sbnM6aVg9J2h0dHA6Ly9ucy5hZG9iZS5jb20vaVgvMS4wLyc+C\n"
"gogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXVpZDoyMmQwMmIwYS1iMjQ5LTExZGItOGFmOC05\n"
"MWQ1NDAzZjkyZjknCiAgeG1sbnM6cGRmPSdodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvJz4\n"
"KICA8IS0tIHBkZjpTdWJqZWN0IGlzIGFsaWFzZWQgLS0+CiA8L3JkZjpEZXNjcmlwdGlvbj4KCi\n"
"A8cmRmOkRlc2NyaXB0aW9uIGFib3V0PSd1dWlkOjIyZDAyYjBhLWIyNDktMTFkYi04YWY4LTkxZ\n"
"DU0MDNmOTJmOScKICB4bWxuczpwaG90b3Nob3A9J2h0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9z\n"
"aG9wLzEuMC8nPgogIDwhLS0gcGhvdG9zaG9wOkNhcHRpb24gaXMgYWxpYXNlZCAtLT4KIDwvcmR\n"
"mOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6MjJkMDJiMGEtYj\n"
"I0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5JwogIHhtbG5zOnhhcD0naHR0cDovL25zLmFkb2JlL\n"
"mNvbS94YXAvMS4wLyc+CiAgPCEtLSB4YXA6RGVzY3JpcHRpb24gaXMgYWxpYXNlZCAtLT4KIDwv\n"
"cmRmOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gYWJvdXQ9J3V1aWQ6MjJkMDJiMGE\n"
"tYjI0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5JwogIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuYW\n"
"RvYmUuY29tL3hhcC8xLjAvbW0vJz4KICA8eGFwTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwa\n"
"G90b3Nob3A6MjJkMDJiMDYtYjI0OS0xMWRiLThhZjgtOTFkNTQwM2Y5MmY5PC94YXBNTTpEb2N1\n"
"bWVudElEPgogPC9yZGY6RGVzY3JpcHRpb24+CgogPHJkZjpEZXNjcmlwdGlvbiBhYm91dD0ndXV\n"
"pZDoyMmQwMmIwYS1iMjQ5LTExZGItOGFmOC05MWQ1NDAzZjkyZjknCiAgeG1sbnM6ZGM9J2h0dH\n"
"A6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvJz4KICA8ZGM6ZGVzY3JpcHRpb24+CiAgIDxyZ\n"
"GY6QWx0PgogICAgPHJkZjpsaSB4bWw6bGFuZz0neC1kZWZhdWx0Jz4gICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgIDwvcmRmOkFsdD4KICA8L2RjOmRlc2NyaXB0aW9\n"
"uPgogPC9yZGY6RGVzY3JpcHRpb24+Cgo8L3JkZjpSREY+CjwveDp4YXBtZXRhPgogICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA\n"
"ogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\n"
"ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC\n"
"AgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI\n"
"CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAg\n"
"ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA\n"
"gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgIC\n"
"AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0ndyc/P\n"
"v/uAA5BZG9iZQBkQAAAAAH/2wCEAAQDAwMDAwQDAwQGBAMEBgcFBAQFBwgGBgcGBggKCAkJCQkI\n"
"CgoMDAwMDAoMDAwMDAwMDAwMDAwMDAwMDAwMDAwBBAUFCAcIDwoKDxQODg4UFA4ODg4UEQwMDAw\n"
"MEREMDAwMDAwRDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDP/AABEIAGQAZAMBEQACEQEDEQ\n"
"H/3QAEAA3/xAGiAAAABwEBAQEBAAAAAAAAAAAEBQMCBgEABwgJCgsBAAICAwEBAQEBAAAAAAAAA\n"
"AEAAgMEBQYHCAkKCxAAAgEDAwIEAgYHAwQCBgJzAQIDEQQABSESMUFRBhNhInGBFDKRoQcVsUIj\n"
"wVLR4TMWYvAkcoLxJUM0U5KismNzwjVEJ5OjszYXVGR0w9LiCCaDCQoYGYSURUaktFbTVSga8uP\n"
"zxNTk9GV1hZWltcXV5fVmdoaWprbG1ub2N0dXZ3eHl6e3x9fn9zhIWGh4iJiouMjY6PgpOUlZaX\n"
"mJmam5ydnp+So6SlpqeoqaqrrK2ur6EQACAgECAwUFBAUGBAgDA20BAAIRAwQhEjFBBVETYSIGc\n"
"YGRMqGx8BTB0eEjQhVSYnLxMyQ0Q4IWklMlomOywgdz0jXiRIMXVJMICQoYGSY2RRonZHRVN/Kj\n"
"s8MoKdPj84SUpLTE1OT0ZXWFlaW1xdXl9UZWZnaGlqa2xtbm9kdXZ3eHl6e3x9fn9zhIWGh4iJi\n"
"ouMjY6Pg5SVlpeYmZqbnJ2en5KjpKWmp6ipqqusra6vr/2gAMAwEAAhEDEQA/APBnplwPAdR+GB\n"
"KY6dYtNG1w39yh4+xb+zIksgEfFaRSSoIx8f7RPRRkSWQimM+lRmwWVXFWYigHxUUVoMiJM+Fj0\n"
"tg0RBegLE0Wu+3c+GTBazFCGI7HtSp9slbFYYzyoBsegw2hY1Afl3wqqRqahk+0tDgKpgu4DAUU\n"
"+HY+GRS2ePiMKtUB3G+KGuONq//Q8OzpFbW5WnxMop4k9crG5ZnZNJkEOn21utVRYw7HxZtz+OR\n"
"vdsrZ2lRtci4aVxFEQA0neg/ZXxJpTITNNuOFss0vSotYNvZ2qGRkPKSTqiU8Sdqk5SZU5Ix8XJ\n"
"NNZ8k6bp8TtM73OputUtYq0Unux/hkRkJOzZLCAN2KR+VpbtSkCBaDnIzdlWu59u+XeJTjeASk8\n"
"+juZOESEAVqx8BvU/PJibScTrTy09560hkWOGFd2YgFnPQKD19zhOSkxw2l8Vm6XAiYb8gg+k5O\n"
"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\n"
"fngFN5ulv+l/pL/Lp/scerHo//2Q==\n";
static std::string gCommandLine;
TEST(Base64, LargeSample) {
RTC_LOG(LS_VERBOSE) << "Testing specific base64 file";
char unescaped[64 * 1024];
// unescape that massive blob above
size_t size = Base64Unescape(SpecificTest,
sizeof(SpecificTest),
unescaped,
sizeof(unescaped));
EXPECT_EQ(size, sizeof(testbase64));
EXPECT_EQ(0, memcmp(testbase64, unescaped, sizeof(testbase64)));
}
bool DecodeTest(const char* encoded, size_t expect_unparsed,
const char* decoded, Base64::DecodeFlags flags)
{
std::string result;
size_t consumed = 0, encoded_len = strlen(encoded);
bool success = Base64::DecodeFromArray(encoded, encoded_len, flags,
&result, &consumed);
size_t unparsed = encoded_len - consumed;
EXPECT_EQ(expect_unparsed, unparsed) << "\"" << encoded
<< "\" -> \"" << decoded
<< "\"";
EXPECT_STREQ(decoded, result.c_str());
return success;
}
#define Flags(x,y,z) \
Base64::DO_PARSE_##x | Base64::DO_PAD_##y | Base64::DO_TERM_##z
TEST(Base64, DecodeParseOptions) {
// Trailing whitespace
EXPECT_TRUE (DecodeTest("YWJjZA== ", 1, "abcd", Flags(STRICT, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA== ", 0, "abcd", Flags(WHITE, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA== ", 0, "abcd", Flags(ANY, YES, CHAR)));
// Embedded whitespace
EXPECT_FALSE(DecodeTest("YWJjZA= =", 3, "abcd", Flags(STRICT, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA= =", 0, "abcd", Flags(WHITE, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA= =", 0, "abcd", Flags(ANY, YES, CHAR)));
// Embedded non-base64 characters
EXPECT_FALSE(DecodeTest("YWJjZA=*=", 3, "abcd", Flags(STRICT, YES, CHAR)));
EXPECT_FALSE(DecodeTest("YWJjZA=*=", 3, "abcd", Flags(WHITE, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA=*=", 0, "abcd", Flags(ANY, YES, CHAR)));
// Unexpected padding characters
EXPECT_FALSE(DecodeTest("YW=JjZA==", 7, "a", Flags(STRICT, YES, CHAR)));
EXPECT_FALSE(DecodeTest("YW=JjZA==", 7, "a", Flags(WHITE, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YW=JjZA==", 0, "abcd", Flags(ANY, YES, CHAR)));
}
TEST(Base64, DecodePadOptions) {
// Padding
EXPECT_TRUE (DecodeTest("YWJjZA==", 0, "abcd", Flags(STRICT, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA==", 0, "abcd", Flags(STRICT, ANY, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA==", 2, "abcd", Flags(STRICT, NO, CHAR)));
// Incomplete padding
EXPECT_FALSE(DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, ANY, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA=", 1, "abcd", Flags(STRICT, NO, CHAR)));
// No padding
EXPECT_FALSE(DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, YES, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, ANY, CHAR)));
EXPECT_TRUE (DecodeTest("YWJjZA", 0, "abcd", Flags(STRICT, NO, CHAR)));
}
TEST(Base64, DecodeTerminateOptions) {
// Complete quantum
EXPECT_TRUE (DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, BUFFER)));
EXPECT_TRUE (DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, CHAR)));
EXPECT_TRUE (DecodeTest("YWJj", 0, "abc", Flags(STRICT, NO, ANY)));
// Complete quantum with trailing data
EXPECT_FALSE(DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, BUFFER)));
EXPECT_TRUE (DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, CHAR)));
EXPECT_TRUE (DecodeTest("YWJj*", 1, "abc", Flags(STRICT, NO, ANY)));
// Incomplete quantum
EXPECT_FALSE(DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, BUFFER)));
EXPECT_FALSE(DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, CHAR)));
EXPECT_TRUE (DecodeTest("YWJ", 0, "ab", Flags(STRICT, NO, ANY)));
}
TEST(Base64, GetNextBase64Char) {
// The table looks like this:
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
char next_char;
EXPECT_TRUE(Base64::GetNextBase64Char('A', &next_char));
EXPECT_EQ('B', next_char);
EXPECT_TRUE(Base64::GetNextBase64Char('Z', &next_char));
EXPECT_EQ('a', next_char);
EXPECT_TRUE(Base64::GetNextBase64Char('/', &next_char));
EXPECT_EQ('A', next_char);
EXPECT_FALSE(Base64::GetNextBase64Char('&', &next_char));
EXPECT_FALSE(Base64::GetNextBase64Char('Z', nullptr));
}