diff --git a/.gitignore b/.gitignore index f6b286c..e5df7b9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ captures/ # Intellij *.iml .idea/workspace.xml +.idea/libraries # Keystore files *.jks diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..a042d3c --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +codeview-release \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..3673071 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5d19981 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..e98f7a8 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..889cdfd --- /dev/null +++ b/build.gradle @@ -0,0 +1,25 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.kotlin_version = '1.0.3' + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.1.3' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/codeview/.gitignore b/codeview/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/codeview/.gitignore @@ -0,0 +1 @@ +/build diff --git a/codeview/build.gradle b/codeview/build.gradle new file mode 100644 index 0000000..57383ae --- /dev/null +++ b/codeview/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion 24 + buildToolsVersion "24.0.1" + + defaultConfig { + minSdkVersion 15 + targetSdkVersion 24 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + testCompile 'junit:junit:4.12' + + compile 'com.android.support:appcompat-v7:24.1.1' + compile 'com.android.support:recyclerview-v7:24.1.1' + compile 'com.github.twalcari:java-prettify:1.2.2' + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} +repositories { + mavenCentral() +} diff --git a/codeview/proguard-rules.pro b/codeview/proguard-rules.pro new file mode 100644 index 0000000..531d366 --- /dev/null +++ b/codeview/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/macuser/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/codeview/src/androidTest/java/io/github/kbiakov/codeview/ApplicationTest.java b/codeview/src/androidTest/java/io/github/kbiakov/codeview/ApplicationTest.java new file mode 100644 index 0000000..7d49519 --- /dev/null +++ b/codeview/src/androidTest/java/io/github/kbiakov/codeview/ApplicationTest.java @@ -0,0 +1,13 @@ +package io.github.kbiakov.codeview; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/codeview/src/main/AndroidManifest.xml b/codeview/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c5cd343 --- /dev/null +++ b/codeview/src/main/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/codeview/src/main/assets/fonts/DroidSansMonoSlashed.ttf b/codeview/src/main/assets/fonts/DroidSansMonoSlashed.ttf new file mode 100644 index 0000000..8c44b47 Binary files /dev/null and b/codeview/src/main/assets/fonts/DroidSansMonoSlashed.ttf differ diff --git a/codeview/src/main/assets/training-set/c++/NaClFile.cpp b/codeview/src/main/assets/training-set/c++/NaClFile.cpp new file mode 100755 index 0000000..5a295dd --- /dev/null +++ b/codeview/src/main/assets/training-set/c++/NaClFile.cpp @@ -0,0 +1,143 @@ + +#define NACLFILE_CPP +#include "NaClFile.h" +#include "NaClFileSystem.h" + +//#include +//#define EOF -1 + +FILE * nacl_fopen ( const char * path, const char *mode ) { + + return ( FILE * )NaClFileSystem::Get ()->fopen ( path, mode ); +} + +int nacl_fclose ( FILE *file ) { + + return NaClFileSystem::Get ()->fclose ((NaClFile *) file ); +} + +int nacl_fread ( void *ptr, int size, int count, FILE *file ) { + + return NaClFileSystem::Get ()->fread ( ptr, size, count, (NaClFile *) file ); +} + +int nacl_fwrite ( const void * ptr, int size, int count, FILE *file ) { + + return NaClFileSystem::Get ()->fwrite ( ptr, size, count, (NaClFile *) file ); +} + +int nacl_feof ( FILE * void_file ) { + + NaClFile * file = ( NaClFile * ) void_file; + return ( file->mOffset == file->mSize ); +} + +int nacl_ferror ( FILE * void_file ) { + + //unimplemented + return 0; +} + +void nacl_clearerr ( FILE * void_file ) { + //do nothing +} + +int nacl_fgetc ( FILE * void_file ) { + + NaClFile * file = ( NaClFile * ) void_file; + + if( file && file->mIsHttpLoaded ) { + + int remainingSize = file->mSize - file->mOffset; + + if ( remainingSize ) { + int data = file->mData [ file->mOffset ]; + file->mOffset += 1; + return data; + } + else { + return EOF; + } + } + return 0; +} + +int nacl_ungetc (int c, FILE *void_file) { + + NaClFile * file = ( NaClFile * ) void_file; + + if( file && file->mIsHttpLoaded ) { + + if ( file->mOffset ) { + file->mOffset -= 1; + file->mData [ file->mOffset ] = c; + return file->mData [ file->mOffset ]; + } + else { + return EOF; + } + } + return 0; +} + +int nacl_fseek ( FILE * void_file, long int offset, int origin ) { + + NaClFile * file = ( NaClFile * ) void_file; + + int originPosition; + switch ( origin ) { + case SEEK_SET: + originPosition = 0; + break; + case SEEK_CUR: + originPosition = file->mOffset; + break; + case SEEK_END: + originPosition = file->mSize; + break; + } + int position = originPosition + offset; + if ( position <= file->mSize ) { + + file->mOffset = position; + return 0; + } + + return -1; +} + +long int nacl_ftell ( FILE * void_file ) { + + NaClFile * file = ( NaClFile * ) void_file; + + return file->mOffset; +} + +int nacl_stat ( const char *path, struct stat *s ) { + + //open file with Head + int foundFile = NaClFileSystem::Get ()->stat ( path, s ); + + if ( !foundFile ) { + + s->st_mode = S_IFREG; + s->st_ctime = 0; + s->st_mtime = 0; + s->st_atime = 0; + + return 0; + } + + return -1; +} + +char *nacl_getcwd(char *buf, size_t size) { + + for ( int i = 0; i < size; ++i ) { + buf [ i ] = ( char ) 0; + } + + buf [ 0 ] = '/'; + + return buf; +} diff --git a/codeview/src/main/assets/training-set/c++/c++.cpp b/codeview/src/main/assets/training-set/c++/c++.cpp new file mode 100755 index 0000000..8f71f58 --- /dev/null +++ b/codeview/src/main/assets/training-set/c++/c++.cpp @@ -0,0 +1,1618 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#include "node.h" +#include "node_buffer.h" + +#include "v8.h" +#include "v8-profiler.h" + +#include +#include // malloc, free +#include // memcpy + +#ifdef __POSIX__ +# include // htons, htonl +#endif + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#define BUFFER_CLASS_ID (0xBABE) + +namespace node { + +using namespace v8; + +#define SLICE_ARGS(start_arg, end_arg) \ + if (!start_arg->IsInt32() || !end_arg->IsInt32()) { \ + return ThrowException(Exception::TypeError( \ + String::New("Bad argument."))); \ + } \ + int32_t start = start_arg->Int32Value(); \ + int32_t end = end_arg->Int32Value(); \ + if (start < 0 || end < 0) { \ + return ThrowException(Exception::TypeError( \ + String::New("Bad argument."))); \ + } \ + if (!(start <= end)) { \ + return ThrowException(Exception::Error( \ + String::New("Must have start <= end"))); \ + } \ + if ((size_t)end > parent->length_) { \ + return ThrowException(Exception::Error( \ + String::New("end cannot be longer than parent.length"))); \ + } + + +static Persistent length_symbol; +static Persistent chars_written_sym; +static Persistent write_sym; +Persistent Buffer::constructor_template; + + +static inline size_t base64_decoded_size(const char *src, size_t size) { + const char *const end = src + size; + const int remainder = size % 4; + + size = (size / 4) * 3; + if (remainder) { + if (size == 0 && remainder == 1) { + // special case: 1-byte input cannot be decoded + size = 0; + } else { + // non-padded input, add 1 or 2 extra bytes + size += 1 + (remainder == 3); + } + } + + // check for trailing padding (1 or 2 bytes) + if (size > 0) { + if (end[-1] == '=') size--; + if (end[-2] == '=') size--; + } + + return size; +} + + +static size_t ByteLength (Handle string, enum encoding enc) { + HandleScope scope; + + if (enc == UTF8) { + return string->Utf8Length(); + } else if (enc == BASE64) { + String::Utf8Value v(string); + return base64_decoded_size(*v, v.length()); + } else if (enc == UCS2) { + return string->Length() * 2; + } else if (enc == HEX) { + return string->Length() / 2; + } else { + return string->Length(); + } +} + + +Handle Buffer::New(Handle string) { + HandleScope scope; + + // get Buffer from global scope. + Local global = v8::Context::GetCurrent()->Global(); + Local bv = global->Get(String::NewSymbol("Buffer")); + assert(bv->IsFunction()); + Local b = Local::Cast(bv); + + Local argv[1] = { Local::New(string) }; + Local instance = b->NewInstance(1, argv); + + return scope.Close(instance); +} + + +Buffer* Buffer::New(size_t length) { + HandleScope scope; + + Local arg = Integer::NewFromUnsigned(length); + Local b = constructor_template->GetFunction()->NewInstance(1, &arg); + if (b.IsEmpty()) return NULL; + + return ObjectWrap::Unwrap(b); +} + + +Buffer* Buffer::New(char* data, size_t length) { + HandleScope scope; + + Local arg = Integer::NewFromUnsigned(0); + Local obj = constructor_template->GetFunction()->NewInstance(1, &arg); + + Buffer *buffer = ObjectWrap::Unwrap(obj); + buffer->Replace(data, length, NULL, NULL); + + return buffer; +} + + +Buffer* Buffer::New(char *data, size_t length, + free_callback callback, void *hint) { + HandleScope scope; + + Local arg = Integer::NewFromUnsigned(0); + Local obj = constructor_template->GetFunction()->NewInstance(1, &arg); + + Buffer *buffer = ObjectWrap::Unwrap(obj); + buffer->Replace(data, length, callback, hint); + + return buffer; +} + + +Handle Buffer::New(const Arguments &args) { + if (!args.IsConstructCall()) { + return FromConstructorTemplate(constructor_template, args); + } + + HandleScope scope; + + if (!args[0]->IsUint32()) return ThrowTypeError("Bad argument"); + + size_t length = args[0]->Uint32Value(); + if (length > Buffer::kMaxLength) { + return ThrowRangeError("length > kMaxLength"); + } + new Buffer(args.This(), length); + + return args.This(); +} + + +Buffer::Buffer(Handle wrapper, size_t length) : ObjectWrap() { + Wrap(wrapper); + + length_ = 0; + callback_ = NULL; + handle_.SetWrapperClassId(BUFFER_CLASS_ID); + + Replace(NULL, length, NULL, NULL); +} + + +Buffer::~Buffer() { + Replace(NULL, 0, NULL, NULL); +} + + +void Buffer::Replace(char *data, size_t length, + free_callback callback, void *hint) { + HandleScope scope; + + if (callback_) { + callback_(data_, callback_hint_); + } else if (length_) { + delete [] data_; + V8::AdjustAmountOfExternalAllocatedMemory( + -static_cast(sizeof(Buffer) + length_)); + } + + length_ = length; + callback_ = callback; + callback_hint_ = hint; + + if (callback_) { + data_ = data; + } else if (length_) { + data_ = new char[length_]; + if (data) + memcpy(data_, data, length_); + V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer) + length_); + } else { + data_ = NULL; + } + + handle_->SetIndexedPropertiesToExternalArrayData(data_, + kExternalUnsignedByteArray, + length_); + handle_->Set(length_symbol, Integer::NewFromUnsigned(length_)); +} + + +Handle Buffer::BinarySlice(const Arguments &args) { + HandleScope scope; + Buffer *parent = ObjectWrap::Unwrap(args.This()); + SLICE_ARGS(args[0], args[1]) + + char *data = parent->data_ + start; + //Local string = String::New(data, end - start); + + Local b = Encode(data, end - start, BINARY); + + return scope.Close(b); +} + + +Handle Buffer::AsciiSlice(const Arguments &args) { + HandleScope scope; + Buffer *parent = ObjectWrap::Unwrap(args.This()); + SLICE_ARGS(args[0], args[1]) + + char* data = parent->data_ + start; + Local string = String::New(data, end - start); + + return scope.Close(string); +} + + +Handle Buffer::Utf8Slice(const Arguments &args) { + HandleScope scope; + Buffer *parent = ObjectWrap::Unwrap(args.This()); + SLICE_ARGS(args[0], args[1]) + char *data = parent->data_ + start; + Local string = String::New(data, end - start); + return scope.Close(string); +} + +Handle Buffer::Ucs2Slice(const Arguments &args) { + HandleScope scope; + Buffer *parent = ObjectWrap::Unwrap(args.This()); + SLICE_ARGS(args[0], args[1]) + uint16_t *data = (uint16_t*)(parent->data_ + start); + Local string = String::New(data, (end - start) / 2); + return scope.Close(string); +} + +static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +// supports regular and URL-safe base64 +static const int unbase64_table[] = + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-2,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,62,-1,63 + ,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1 + ,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14 + ,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,63 + ,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 + ,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; +#define unbase64(x) unbase64_table[(uint8_t)(x)] + + +Handle Buffer::Base64Slice(const Arguments &args) { + HandleScope scope; + Buffer *parent = ObjectWrap::Unwrap(args.This()); + SLICE_ARGS(args[0], args[1]) + + int n = end - start; + int out_len = (n + 2 - ((n + 2) % 3)) / 3 * 4; + char *out = new char[out_len]; + + uint8_t bitbuf[3]; + int i = start; // data() index + int j = 0; // out index + char c; + bool b1_oob, b2_oob; + + while (i < end) { + bitbuf[0] = parent->data_[i++]; + + if (i < end) { + bitbuf[1] = parent->data_[i]; + b1_oob = false; + } else { + bitbuf[1] = 0; + b1_oob = true; + } + i++; + + if (i < end) { + bitbuf[2] = parent->data_[i]; + b2_oob = false; + } else { + bitbuf[2] = 0; + b2_oob = true; + } + i++; + + + c = bitbuf[0] >> 2; + assert(c < 64); + out[j++] = base64_table[(int)c]; + assert(j < out_len); + + c = ((bitbuf[0] & 0x03) << 4) | (bitbuf[1] >> 4); + assert(c < 64); + out[j++] = base64_table[(int)c]; + assert(j < out_len); + + if (b1_oob) { + out[j++] = '='; + } else { + c = ((bitbuf[1] & 0x0F) << 2) | (bitbuf[2] >> 6); + assert(c < 64); + out[j++] = base64_table[(int)c]; + } + assert(j < out_len); + + if (b2_oob) { + out[j++] = '='; + } else { + c = bitbuf[2] & 0x3F; + assert(c < 64); + out[j++] = base64_table[(int)c]; + } + assert(j <= out_len); + } + + Local string = String::New(out, out_len); + delete [] out; + return scope.Close(string); +} + + +// buffer.fill(value, start, end); +Handle Buffer::Fill(const Arguments &args) { + HandleScope scope; + + if (!args[0]->IsInt32()) { + return ThrowException(Exception::Error(String::New( + "value is not a number"))); + } + int value = (char)args[0]->Int32Value(); + + Buffer *parent = ObjectWrap::Unwrap(args.This()); + SLICE_ARGS(args[1], args[2]) + + memset( (void*)(parent->data_ + start), + value, + end - start); + + return Undefined(); +} + + +// var bytesCopied = buffer.copy(target, targetStart, sourceStart, sourceEnd); +Handle Buffer::Copy(const Arguments &args) { + HandleScope scope; + + Buffer *source = ObjectWrap::Unwrap(args.This()); + + if (!Buffer::HasInstance(args[0])) { + return ThrowException(Exception::TypeError(String::New( + "First arg should be a Buffer"))); + } + + Local target = args[0]->ToObject(); + char* target_data = Buffer::Data(target); + size_t target_length = Buffer::Length(target); + size_t target_start = args[1]->Uint32Value(); + size_t source_start = args[2]->Uint32Value(); + size_t source_end = args[3]->IsUint32() ? args[3]->Uint32Value() + : source->length_; + + if (source_end < source_start) { + return ThrowException(Exception::Error(String::New( + "sourceEnd < sourceStart"))); + } + + // Copy 0 bytes; we're done + if (source_end == source_start) { + return scope.Close(Integer::New(0)); + } + + if (target_start >= target_length) { + return ThrowException(Exception::Error(String::New( + "targetStart out of bounds"))); + } + + if (source_start >= source->length_) { + return ThrowException(Exception::Error(String::New( + "sourceStart out of bounds"))); + } + + if (source_end > source->length_) { + return ThrowException(Exception::Error(String::New( + "sourceEnd out of bounds"))); + } + + size_t to_copy = MIN(MIN(source_end - source_start, + target_length - target_start), + source->length_ - source_start); + + // need to use slightly slower memmove is the ranges might overlap + memmove((void *)(target_data + target_start), + (const void*)(source->data_ + source_start), + to_copy); + + return scope.Close(Integer::New(to_copy)); +} + + +// var charsWritten = buffer.utf8Write(string, offset, [maxLength]); +Handle Buffer::Utf8Write(const Arguments &args) { + HandleScope scope; + Buffer *buffer = ObjectWrap::Unwrap(args.This()); + + if (!args[0]->IsString()) { + return ThrowException(Exception::TypeError(String::New( + "Argument must be a string"))); + } + + Local s = args[0]->ToString(); + + size_t offset = args[1]->Uint32Value(); + + int length = s->Length(); + + if (length == 0) { + constructor_template->GetFunction()->Set(chars_written_sym, + Integer::New(0)); + return scope.Close(Integer::New(0)); + } + + if (length > 0 && offset >= buffer->length_) { + return ThrowException(Exception::TypeError(String::New( + "Offset is out of bounds"))); + } + + size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset + : args[2]->Uint32Value(); + max_length = MIN(buffer->length_ - offset, max_length); + + char* p = buffer->data_ + offset; + + int char_written; + + int written = s->WriteUtf8(p, + max_length, + &char_written, + (String::HINT_MANY_WRITES_EXPECTED | + String::NO_NULL_TERMINATION)); + + constructor_template->GetFunction()->Set(chars_written_sym, + Integer::New(char_written)); + + return scope.Close(Integer::New(written)); +} + + +// var charsWritten = buffer.ucs2Write(string, offset, [maxLength]); +Handle Buffer::Ucs2Write(const Arguments &args) { + HandleScope scope; + Buffer *buffer = ObjectWrap::Unwrap(args.This()); + + if (!args[0]->IsString()) { + return ThrowException(Exception::TypeError(String::New( + "Argument must be a string"))); + } + + Local s = args[0]->ToString(); + + size_t offset = args[1]->Uint32Value(); + + if (s->Length() > 0 && offset >= buffer->length_) { + return ThrowException(Exception::TypeError(String::New( + "Offset is out of bounds"))); + } + + size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset + : args[2]->Uint32Value(); + max_length = MIN(buffer->length_ - offset, max_length) / 2; + + uint16_t* p = (uint16_t*)(buffer->data_ + offset); + + int written = s->Write(p, + 0, + max_length, + (String::HINT_MANY_WRITES_EXPECTED | + String::NO_NULL_TERMINATION)); + + constructor_template->GetFunction()->Set(chars_written_sym, + Integer::New(written)); + + return scope.Close(Integer::New(written * 2)); +} + + +// var charsWritten = buffer.asciiWrite(string, offset); +Handle Buffer::AsciiWrite(const Arguments &args) { + HandleScope scope; + + Buffer *buffer = ObjectWrap::Unwrap(args.This()); + + if (!args[0]->IsString()) { + return ThrowException(Exception::TypeError(String::New( + "Argument must be a string"))); + } + + Local s = args[0]->ToString(); + size_t length = s->Length(); + size_t offset = args[1]->Int32Value(); + + if (length > 0 && offset >= buffer->length_) { + return ThrowException(Exception::TypeError(String::New( + "Offset is out of bounds"))); + } + + size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset + : args[2]->Uint32Value(); + max_length = MIN(length, MIN(buffer->length_ - offset, max_length)); + + char *p = buffer->data_ + offset; + + int written = s->WriteAscii(p, + 0, + max_length, + (String::HINT_MANY_WRITES_EXPECTED | + String::NO_NULL_TERMINATION)); + + constructor_template->GetFunction()->Set(chars_written_sym, + Integer::New(written)); + + return scope.Close(Integer::New(written)); +} + + +// var bytesWritten = buffer.base64Write(string, offset, [maxLength]); +Handle Buffer::Base64Write(const Arguments &args) { + HandleScope scope; + + Buffer *buffer = ObjectWrap::Unwrap(args.This()); + + if (!args[0]->IsString()) { + return ThrowException(Exception::TypeError(String::New( + "Argument must be a string"))); + } + + String::AsciiValue s(args[0]); + size_t length = s.length(); + size_t offset = args[1]->Int32Value(); + size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset + : args[2]->Uint32Value(); + max_length = MIN(length, MIN(buffer->length_ - offset, max_length)); + + if (max_length && offset >= buffer->length_) { + return ThrowException(Exception::TypeError(String::New( + "Offset is out of bounds"))); + } + + char a, b, c, d; + char* start = buffer->data_ + offset; + char* dst = start; + char* const dstEnd = dst + max_length; + const char* src = *s; + const char* const srcEnd = src + s.length(); + + while (src < srcEnd && dst < dstEnd) { + int remaining = srcEnd - src; + + while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining == 0 || *src == '=') break; + a = unbase64(*src++); + + while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 1 || *src == '=') break; + b = unbase64(*src++); + + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (dst == dstEnd) break; + + while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 2 || *src == '=') break; + c = unbase64(*src++); + + *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); + if (dst == dstEnd) break; + + while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--; + if (remaining <= 3 || *src == '=') break; + d = unbase64(*src++); + + *dst++ = ((c & 0x03) << 6) | (d & 0x3F); + } + + constructor_template->GetFunction()->Set(chars_written_sym, + Integer::New(dst - start)); + + return scope.Close(Integer::New(dst - start)); +} + + +Handle Buffer::BinaryWrite(const Arguments &args) { + HandleScope scope; + + Buffer *buffer = ObjectWrap::Unwrap(args.This()); + + if (!args[0]->IsString()) { + return ThrowException(Exception::TypeError(String::New( + "Argument must be a string"))); + } + + Local s = args[0]->ToString(); + size_t length = s->Length(); + size_t offset = args[1]->Int32Value(); + + if (s->Length() > 0 && offset >= buffer->length_) { + return ThrowException(Exception::TypeError(String::New( + "Offset is out of bounds"))); + } + + char *p = (char*)buffer->data_ + offset; + + size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset + : args[2]->Uint32Value(); + max_length = MIN(length, MIN(buffer->length_ - offset, max_length)); + + int written = DecodeWrite(p, max_length, s, BINARY); + + constructor_template->GetFunction()->Set(chars_written_sym, + Integer::New(written)); + + return scope.Close(Integer::New(written)); +} + + +// var nbytes = Buffer.byteLength("string", "utf8") +Handle Buffer::ByteLength(const Arguments &args) { + HandleScope scope; + + if (!args[0]->IsString()) { + return ThrowException(Exception::TypeError(String::New( + "Argument must be a string"))); + } + + Local s = args[0]->ToString(); + enum encoding e = ParseEncoding(args[1], UTF8); + + return scope.Close(Integer::New(node::ByteLength(s, e))); +} + + +Handle Buffer::MakeFastBuffer(const Arguments &args) { + HandleScope scope; + + if (!Buffer::HasInstance(args[0])) { + return ThrowException(Exception::TypeError(String::New( + "First argument must be a Buffer"))); + } + + Buffer *buffer = ObjectWrap::Unwrap(args[0]->ToObject()); + Local fast_buffer = args[1]->ToObject();; + uint32_t offset = args[2]->Uint32Value(); + uint32_t length = args[3]->Uint32Value(); + + fast_buffer->SetIndexedPropertiesToExternalArrayData(buffer->data_ + offset, + kExternalUnsignedByteArray, + length); + + return Undefined(); +} + + +bool Buffer::HasInstance(v8::Handle val) { + if (!val->IsObject()) return false; + v8::Local obj = val->ToObject(); + + if (obj->GetIndexedPropertiesExternalArrayDataType() == kExternalUnsignedByteArray) + return true; + + // Also check for SlowBuffers that are empty. + if (constructor_template->HasInstance(obj)) + return true; + + return false; +} + + +class RetainedBufferInfo: public v8::RetainedObjectInfo { +public: + RetainedBufferInfo(Buffer* buffer); + virtual void Dispose(); + virtual bool IsEquivalent(RetainedObjectInfo* other); + virtual intptr_t GetHash(); + virtual const char* GetLabel(); + virtual intptr_t GetSizeInBytes(); +private: + Buffer* buffer_; + static const char label[]; +}; + +const char RetainedBufferInfo::label[] = "Buffer"; + + +RetainedBufferInfo::RetainedBufferInfo(Buffer* buffer): buffer_(buffer) { +} + + +void RetainedBufferInfo::Dispose() { + buffer_ = NULL; + delete this; +} + + +bool RetainedBufferInfo::IsEquivalent(RetainedObjectInfo* other) { + return label == other->GetLabel() && + buffer_ == static_cast(other)->buffer_; +} + + +intptr_t RetainedBufferInfo::GetHash() { + return reinterpret_cast(buffer_); +} + + +const char* RetainedBufferInfo::GetLabel() { + return label; +} + + +intptr_t RetainedBufferInfo::GetSizeInBytes() { + return Buffer::Length(buffer_); +} + + +RetainedObjectInfo* WrapperInfo(uint16_t class_id, Handle wrapper) { + assert(class_id == BUFFER_CLASS_ID); + assert(Buffer::HasInstance(wrapper)); + Buffer* buffer = Buffer::Unwrap(wrapper.As()); + return new RetainedBufferInfo(buffer); +} + + +void Buffer::Initialize(Handle target) { + HandleScope scope; + + // sanity checks + assert(unbase64('/') == 63); + assert(unbase64('+') == 62); + assert(unbase64('T') == 19); + assert(unbase64('Z') == 25); + assert(unbase64('t') == 45); + assert(unbase64('z') == 51); + assert(unbase64(' ') == -2); + assert(unbase64('\n') == -2); + assert(unbase64('\r') == -2); + + length_symbol = NODE_PSYMBOL("length"); + chars_written_sym = NODE_PSYMBOL("_charsWritten"); + + Local t = FunctionTemplate::New(Buffer::New); + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("SlowBuffer")); + + // copy free + NODE_SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Slice", Buffer::Base64Slice); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Slice", Buffer::Ucs2Slice); + // TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice); + // copy + NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice); + + NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Write", Buffer::Base64Write); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Write", Buffer::Ucs2Write); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "fill", Buffer::Fill); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy); + + NODE_SET_METHOD(constructor_template->GetFunction(), + "byteLength", + Buffer::ByteLength); + NODE_SET_METHOD(constructor_template->GetFunction(), + "makeFastBuffer", + Buffer::MakeFastBuffer); + + target->Set(String::NewSymbol("SlowBuffer"), constructor_template->GetFunction()); + + HeapProfiler::DefineWrapperClass(BUFFER_CLASS_ID, WrapperInfo); +} + + +} // namespace node + +NODE_MODULE(node_buffer, node::Buffer::Initialize) +// +// Copyright Marshall Clow 2009-2010 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// + +#ifndef _BOOST_MIME_HPP +#define _BOOST_MIME_HPP + +#include +#include +#include +#include + +#include +#include +#include // pulls in all of Phoenix +#include +#include + +#include +#include +#include +#include + + +// #define DUMP_MIME_DATA 1 + + +namespace boost { namespace mime { + +// Errors are reported using this exception class +class mime_parsing_error : public std::runtime_error { +public: + explicit mime_parsing_error ( const std::string & msg ) : std::runtime_error ( msg ) {} + }; + +template class basic_mime; + +namespace detail { + + static const char *k_crlf = "\015\012"; + static const char *k_package_name = "Proposed.Boost.Mime"; + static const char *k_package_version = "0.1"; + static const char *k_content_type_header = "Content-Type"; + static const char *k_mime_version_header = "Mime-Version"; + + struct default_types { + typedef std::string string_type; + // typedef std::pair < std::string, string_type > header_type; + typedef std::vector body_type; + }; + + + template + struct find_mime_header { + find_mime_header ( const char *str ) : searchFor ( str ) {} + bool operator () ( const std::pair &val ) const { return boost::iequals ( val.first, searchFor ); } + private: + const char *searchFor; + }; + + +#ifdef DUMP_MIME_DATA + struct tracer { + tracer ( const char *fn ) : fn_ (fn) { std::cout << "->" << fn_ << std::endl; } + ~tracer () { std::cout << "<-" << fn_ << std::endl; } + const char *fn_; + }; +#else + struct tracer { + tracer ( const char * ) {} + ~tracer () {} + }; +#endif + +// Parsing a Content-Type header + typedef std::pair phrase_t; + typedef std::vector < phrase_t > phrase_container_t; + struct mime_content_type { + std::string type; + std::string sub_type; + phrase_container_t phrases; + }; + + + namespace qi = boost::spirit::qi; + namespace phx = boost::phoenix; + using boost::spirit::_val; + using boost::spirit::_1; + + template + struct mime_header_parser : qi::grammar + { + mime_header_parser() : mime_header_parser::base_type(mime_headerList) + { + mime_headerList = *(mime_header) >> crlf; + mime_header = token >> qi::lit ( ':' ) >> value >> crlf; + token = qi::char_("a-zA-Z") >> *qi::char_("a-zA-Z_0-9\\-"); + + // In Classifieds/000001, a header begins with a CRLF + value = ( valuePart [ _val = _1 ] | qi::eps ) >> *(valueCont [ _val += "\015\012" + _1 ]); + valueCont = crlf >> contWS [ _val += _1 ] >> valuePart [ _val += _1 ]; + valuePart = +qi::char_("\t -~"); + + contWS = +qi::char_( " \t"); + crlf = qi::lit ( k_crlf ); + + /* mime_headerList.name("mime-header-list"); + mime_header.name ("mime-header"); + token.name ("mime-token"); + valuePart.name ("mime-value-part"); + value.name ("mime-value"); + + qi::on_error ( mime_headerList, + std::cout + << phoenix::val("Error! Expecting ") + << qi::labels::_4 + << phoenix::val(" here: \"") + << phoenix::construct(qi::labels::_3, qi::labels::_2) + << phoenix::val("\"") + << std::endl + ); + */ + } + + qi::rule mime_headerList ; + qi::rule mime_header; + qi::rule token, value, valueCont, valuePart, contWS; + qi::rule crlf; + }; + + template + static Container read_headers ( Iterator &begin, Iterator end ) { + tracer t ( __func__ ); + Container retVal; + + mime_header_parser mh_parser; + bool b = qi::parse ( begin, end, mh_parser, retVal ); + if ( !b ) + throw mime_parsing_error ( "Failed to parse headers" ); + +#ifdef DUMP_MIME_DATA + std::cout << "******Headers*******" << std::endl; + for ( typename Container::const_iterator iter = retVal.begin (); iter != retVal.end (); ++iter ) { + std::string val = iter->second; + size_t idx; + while ( std::string::npos != ( idx = val.find ( k_crlf ))) + val.replace ( idx, std::strlen ( k_crlf ), "\n" ); + std::cout << iter->first << ": " << val << std::endl; + } + std::cout << std::endl << "******Headers*******" << std::endl; +#endif + + return retVal; + } + +// The structure of a Content-Type mime header is taken from RFC 2045 +// http://www.ietf.org/rfc/rfc2045.txt, section 5.1 + + template + struct mime_content_type_parser : qi::grammar + { + mime_content_type_parser() : mime_content_type_parser::base_type(content_type_header) + { + content_type_header = *qi::lit(' ') >> part >> '/' >> sub_part >> *phrase ; + + part = token | extension_token; + sub_part = token | extension_token; + + phrase = qi::lit ( ';' ) >> +ws >> attribute >> '=' >> value >> *ws; + ws = qi::char_( " \t") | line_sep | comment; + line_sep = qi::lexeme[ qi::lit ( k_crlf ) ]; + + attribute = token.alias(); + value = token | quoted_string; + + token = +(qi::char_( " -~" ) - qi::char_( " ()<>@,;:\\\"/[]?=" )); + comment = qi::lit ('(') >> +(qi::char_(" -~" ) - ')' ) >> qi::lit(')'); + quoted_string = qi::lit ('"') >> +(qi::char_(" -~" ) - '"' ) >> qi::lit('"'); + extension_token = qi::char_ ( "Xx" ) >> qi::lit ( '-' ) >> token; + } + + qi::rule content_type_header ; + qi::rule phrase ; + qi::rule part, sub_part, token, attribute, value, quoted_string, extension_token; + qi::rule ws, line_sep, comment; + }; + + template + mime_content_type parse_content_type ( const string_type &theHeader ) { + tracer t ( __func__ ); + mime_content_type retVal; + typename string_type::const_iterator first = theHeader.begin (); + mime_content_type_parser ct_parser; + bool b = qi::parse ( first, theHeader.end (), ct_parser, retVal ); + if (!b) + throw mime_parsing_error ( "Failed to parse the 'Content-Type' header" ); + + return retVal; + } + + template + static string_type get_ct_value ( const string_type &ctString, const char *key ) { + tracer t ( __func__ ); + mime_content_type mc = parse_content_type ( ctString ); + for ( phrase_container_t::const_iterator iter = mc.phrases.begin (); iter != mc.phrases.end (); ++iter ) + if ( boost::iequals ( iter->first, key )) + return iter->second; + + throw std::runtime_error ( str ( boost::format ( "Couldn't find Content-Type phrase (%s)" ) % key )); + } + + + // Replace this with a spirit thing later. + // we're looking for '; boundary="".*' + std::string get_boundary ( const std::string &ctString ) { + tracer t ( __func__ ); + return get_ct_value ( ctString, "boundary" ); + } + + + // Read the body of a multipart + // Return a Container of containers, where the first is the actual body, + // and the rest are the sub-parts. + // Note that the body of the multipart can be empty. + // If this is the case, then the first separator need not have a crlf + + // if the marker is "abcde", we could have: + // Note that the separators are really CRLF--abcdeCRLF and CRLF--abcde--CRLF + // + // multipart body + // --abcde + // sub part #1 + // --abcde + // sub part #2 + // --abcde-- + // + // ** or ** + // In this case, the first separator is --abcdeCRLF + // + // --abcde (no multipart body!) + // sub part #1 + // --abcde + // sub part #2 + // --abcde-- + + typedef std::vector sub_part_t; + typedef std::vector sub_parts_t; + + template + struct multipart_body_type { + bool prolog_is_missing; + bodyContainer body_prolog; + sub_parts_t sub_parts; + bodyContainer body_epilog; + }; + + + // Parse a mulitpart body. + // Either "--boundaryCRLF" -- in which case the body is empty + // or "CRLF--boundaryCRLF" -- in which case we return the sequence + // + // I am deliberately not checking for a termination separator here + template + struct multipart_body_parser : qi::grammar { + multipart_body_parser( const std::string &boundary, bool &isMissing ) : multipart_body_parser::base_type(mimeBody), m_is_missing ( isMissing ) { + m_is_missing = false; + // Thanks to Michael Caisse for the hint to get this working + mimeBody %= bareSep [ phx::ref ( m_is_missing ) = true ] | (+(qi::char_ - sep) >> sep ) ; + bareSep = qi::lit("--") >> boundary >> crlf; + sep = crlf >> bareSep; + crlf = qi::lit ( k_crlf ); + } + + bool &m_is_missing; + qi::rule mimeBody; + qi::rule bareSep, sep, crlf; + }; + + + // Break up a multi-part into its' constituent sub parts. + template + struct multipart_part_parser : qi::grammar { + multipart_part_parser( const std::string &boundary ) : multipart_part_parser::base_type(mimeParts) { + mimeParts = (+(qi::char_ - sep) % (sep >> crlf)) > terminator ; + sep = crlf >> qi::lit("--") >> boundary ; + terminator = sep >> qi::lit("--") >> crlf ; + crlf = qi::lit ( k_crlf ); + } + qi::rule mimeParts; + qi::rule sep, terminator, crlf; + }; + + + template + static void read_multipart_body ( Iterator &begin, Iterator end, multipart_body_type &mp_body, const std::string &separator ) { + tracer t ( __func__ ); + typedef bodyContainer innerC; + innerC mpBody; + multipart_body_parser mb_parser (separator, mp_body.prolog_is_missing ); + if ( !qi::parse ( begin, end, mb_parser, mp_body.body_prolog )) + throw mime_parsing_error ("Failed to parse mime body(1)"); + + multipart_part_parser mp_parser ( separator ); + if ( !qi::parse ( begin, end, mp_parser, mp_body.sub_parts )) + throw mime_parsing_error ( "Failed to parse mime body(2)"); + std::copy ( begin, end, std::back_inserter ( mp_body.body_epilog )); + + #ifdef DUMP_MIME_DATA + std::cout << std::endl << ">>****Multipart Body*******" << std::endl; + std::cout << str ( boost::format ( "Body size %d, sub part count = %d, trailer size = %d %s" ) % mp_body.body_prolog.size () % mp_body.sub_parts.size () % mp_body.body_epilog.size () % ( mp_body.prolog_is_missing ? "(missing)" : "" )) << std::endl; + std::cout << std::endl << "****** Multipart Body Prolog *******" << std::endl; + std::copy ( mp_body.body_prolog.begin (), mp_body.body_prolog.end(), std::ostream_iterator ( std::cout )); + std::cout << std::endl << "****** Multipart Body Epilog *******" << std::endl; + std::copy ( mp_body.body_epilog.begin (), mp_body.body_epilog.end(), std::ostream_iterator ( std::cout )); + std::cout << std::endl << "<<****Multipart Body*******" << std::endl; + #endif + } + + + template + static Container read_simplepart_body ( Iterator &begin, Iterator end ) { + tracer t ( __func__ ); + Container retVal; + std::copy ( begin, end, std::back_inserter(retVal)); + +#ifdef DUMP_MIME_DATA + std::cout << std::endl << ">>****SinglePart Body*******" << std::endl; + std::cout << str ( boost::format ( "Body size %d" ) % retVal.size ()) << std::endl; + std::copy ( retVal.begin (), retVal.end(), std::ostream_iterator ( std::cout )); + std::cout << std::endl << "<<****SinglePart Body*******" << std::endl; +#endif + return retVal; + } + +// FIXME: Need to break the headers at 80 chars... + template + void write_headers ( std::ostream &out, const headerList &headers ) { + if ( headers.size () > 0 ) { + for ( typename headerList::const_iterator iter = headers.begin (); iter != headers.end (); ++iter ) + out << iter->first << ':' << iter->second << detail::k_crlf; + } + out << detail::k_crlf; + } + + template + void write_body ( std::ostream &out, const bodyContainer &body ) { + std::copy ( body.begin (), body.end (), std::ostream_iterator ( out )); + } + + inline void write_boundary ( std::ostream &out, std::string boundary, bool isLast, bool leadingCR = true ) { + if ( leadingCR ) + out << detail::k_crlf; + out << "--" << boundary; + if ( isLast ) + out << "--"; + out << detail::k_crlf; + } + + + template + static boost::shared_ptr< basic_mime > parse_mime ( Iterator &begin, Iterator end, const char *default_content_type = "text/plain" ); + } + + +template +class basic_mime { +public: + + typedef enum { simple_part, multi_part, message_part } part_kind; +// Types for headers + typedef typename traits::string_type string_type; + typedef std::pair< std::string, string_type> headerEntry; + typedef std::list headerList; + typedef typename headerList::iterator headerIter; + typedef typename headerList::const_iterator constHeaderIter; + +// Types for the parts + typedef boost::shared_ptr mimePtr; + typedef std::vector partList; + typedef typename partList::iterator partIter; + typedef typename partList::const_iterator constPartIter; + +// Type for the body + typedef typename traits::body_type bodyContainer; + typedef boost::shared_ptr mimeBody; + +// ----------------------------------------------------------- +// Constructors, destructor, assignment, and swap +// ----------------------------------------------------------- + + basic_mime ( const char *type, const char *subtype ) + : m_body_prolog_is_missing ( false ), m_body ( new bodyContainer ), m_body_epilog ( new bodyContainer ) { + if ( NULL == type || NULL == subtype || 0 == std::strlen ( type ) || 0 == std::strlen ( subtype )) + throw std::runtime_error ( "Can't create a mime part w/o a type or subtype" ); + + // We start with just two headers, "Content-Type:" and "Mime-Version" + // Everything else is optional. + m_part_kind = part_kind_from_string_pair ( type, subtype ); + std::string ctString = str ( boost::format ( "%s/%s" ) % type % subtype ); + set_header_value ( detail::k_content_type_header, ctString ); + set_header_value ( detail::k_mime_version_header, str ( boost::format ( "1.0 (%s %s)" ) % detail::k_package_name % detail::k_package_version )); + } + + basic_mime ( const headerList &theHeaders, const string_type &default_content_type ) + : m_body_prolog_is_missing ( false ), m_body ( new bodyContainer ), m_body_epilog ( new bodyContainer ), + m_default_content_type ( default_content_type ) { + string_type ct = m_default_content_type; + + constHeaderIter found = std::find_if ( theHeaders.begin (), theHeaders.end (), + detail::find_mime_header ( detail::k_content_type_header )); + if ( found != theHeaders.end ()) + ct = found->second; + + detail::mime_content_type mct = detail::parse_content_type ( ct ); + m_part_kind = part_kind_from_string_pair ( mct.type, mct.sub_type ); + m_headers = theHeaders; + } + + basic_mime ( const basic_mime &rhs ) + : m_part_kind ( rhs.m_part_kind ), m_headers ( rhs.m_headers ), m_body_prolog_is_missing ( rhs.m_body_prolog_is_missing ), + m_body ( new bodyContainer ( *rhs.m_body )), m_body_epilog ( new bodyContainer ( *rhs.m_body_epilog )), + /* m_subparts ( rhs.m_subparts ), */ m_default_content_type ( rhs.m_default_content_type ) + { + // Copy the parts -- not just the shared pointers + for ( typename partList::const_iterator iter = rhs.subpart_begin (); iter != rhs.subpart_end (); ++iter ) + m_subparts.push_back ( mimePtr ( new basic_mime ( **iter ))); + } + +// Simple, copy constructor-based assignment +// If this is not efficient enough, then I can optimize it later + basic_mime & operator = ( const basic_mime &rhs ) { + basic_mime temp ( rhs ); + this->swap ( temp ); + return *this; + } + + void swap ( basic_mime &rhs ) throw () { + std::swap ( m_part_kind, rhs.m_part_kind ); + std::swap ( m_headers, rhs.m_headers ); + std::swap ( m_body_prolog_is_missing, rhs.m_body_prolog_is_missing ); + std::swap ( m_body, rhs.m_body ); + std::swap ( m_body_epilog, rhs.m_body_epilog ); + std::swap ( m_subparts, rhs.m_subparts ); + std::swap ( m_default_content_type, rhs.m_default_content_type ); + } + + ~basic_mime () {} + + +// What kind of part is this (simple, multi, message) + part_kind get_part_kind () const { return m_part_kind; } + +// Sub-part information +// FIXME: Need some error checking here +// No sub-parts for simple parts, for example. + size_t part_count () const { return m_subparts.size (); } + + boost::shared_ptr operator [] ( std::size_t idx ) const { + check_subpart_index ( idx ); + return m_subparts [ idx ]; + } + + void append_part ( boost::shared_ptr newPart ) { + check_subpart_append (); + m_subparts.push_back ( newPart ); + } + + partIter subpart_begin () { return m_subparts.begin (); } + partIter subpart_end () { return m_subparts.end (); } + constPartIter subpart_begin () const { return m_subparts.begin (); } + constPartIter subpart_end () const { return m_subparts.end (); } + +// Reading the raw headers + headerIter header_begin () { return m_headers.begin (); } + headerIter header_end () { return m_headers.end (); } + constHeaderIter header_begin () const { return m_headers.begin (); } + constHeaderIter header_end () const { return m_headers.end (); } + +// ----------------------------------------------------------- +// Header manipulation +// ----------------------------------------------------------- + +// The 'tag' part of the header is still a std::string + bool header_exists ( const char *key ) const { + return header_end () != find_header ( key ); + } + + string_type header_value ( const char *key ) const { + constHeaderIter found = find_header ( key ); + if ( found == header_end ()) + throw std::runtime_error ( "'header_value' not found" ); + return found->second; + } + + void set_header_value ( const char *key, const string_type &value, bool replace = false ) { + if ( !replace ) + m_headers.push_back ( std::make_pair ( std::string ( key ), value )); + else { + headerIter found = find_header ( key ); + if ( found == m_headers.end ()) + throw std::runtime_error ( "'header_value' not found - can't replace" ); + found->second = value; + } + } + + + string_type get_content_type_header () const { + constHeaderIter found = find_header ( detail::k_content_type_header ); + return found != header_end () ? found->second : m_default_content_type; + } + + + string_type get_content_type () const { + detail::mime_content_type mct = detail::parse_content_type ( get_content_type_header ()); + return string_type ( mct.type ) + '/' + mct.sub_type; + } + + +// Special purpose helper routine + void append_phrase_to_content_type ( const char *key, const string_type &value ) { + headerIter found = find_header ( detail::k_content_type_header ); + + // Create a Content-Type header if there isn't one + if ( m_headers.end () == found ) { + m_headers.push_back ( std::make_pair ( std::string ( detail::k_content_type_header ), m_default_content_type )); + found = find_header ( detail::k_content_type_header ); + } + + detail::mime_content_type mct = detail::parse_content_type ( found->second ); + detail::phrase_container_t::const_iterator p_found = + std::find_if ( mct.phrases.begin (), mct.phrases.end (), + detail::find_mime_header ( key )); + if ( p_found != mct.phrases.end ()) + throw std::runtime_error ( "phrase already exists" ); + found->second += str ( boost::format ( "; %s=\"%s\"" ) % key % value ); + } + + +// Body get/set methods + mimeBody body () const { return m_body; } + mimeBody body_prolog () const { return m_body; } + mimeBody body_epilog () const { return m_body_epilog; } + + std::size_t body_size () const { return m_body->size (); } + + template + void set_body ( Iterator begin, Iterator end ) { + bodyContainer temp; + std::copy ( begin, end, std::back_inserter ( temp )); + m_body->swap ( temp ); + } + + void set_body ( const char *contents, size_t sz ) { set_body ( contents, contents + sz ); } + void set_body ( std::istream &in ) { set_body ( std::istream_iterator ( in ), std::istream_iterator ()); } + void set_body ( const bodyContainer &new_body ) { *m_body = new_body; } + + void set_multipart_prolog_is_missing ( bool isMissing ) { m_body_prolog_is_missing = isMissing; } + void set_body_prolog ( const bodyContainer &new_body_prolog ) { *m_body = new_body_prolog; } + void set_body_epilog ( const bodyContainer &new_body_epilog ) { *m_body_epilog = new_body_epilog; } + +// ----------------------------------------------------------- +// Output +// ----------------------------------------------------------- + void stream_out ( std::ostream &out ) { // called by operator << + if ( m_part_kind == simple_part ) { + detail::write_headers ( out, m_headers ); + detail::write_body ( out, *m_body ); + } + else if ( m_part_kind == message_part ) { + if ( m_subparts.size () != 1 ) + throw std::runtime_error ( "message part w/wrong number of sub-parts - should be 1" ); + + detail::write_headers ( out, m_headers ); + m_subparts [ 0 ]->stream_out ( out ); + } + else { // multi-part + // Find or invent a boundary string + std::string boundary; + try { boundary = detail::get_boundary ( get_content_type_header ()); } + catch ( std::runtime_error & ) { + // FIXME: Make boundary strings (more?) unique + boundary = str ( boost::format ( "------=_NextPart-%s.%08ld" ) % detail::k_package_name % std::clock ()); + append_phrase_to_content_type ( "boundary", boundary ); + } + + // If the body prolog is missing, we don't want a CRLF on the front of the first sub-part. + // Note that there's a (subtle) difference between an zero length body and a missing one. + // See the comments in the parser code for more information. + detail::write_headers ( out, m_headers ); + bool writeCR = body_prolog ()->size () > 0 || !m_body_prolog_is_missing; + detail::write_body ( out, *body_prolog ()); + for ( typename partList::const_iterator iter = m_subparts.begin (); iter != m_subparts.end (); ++iter ) { + detail::write_boundary ( out, boundary, false, writeCR ); + (*iter)->stream_out ( out ); + writeCR = true; + } + detail::write_boundary ( out, boundary, true ); + detail::write_body ( out, *body_epilog ()); + } + // out << detail::k_crlf; + } + +// Build a simple mime part + template + static basic_mime make_simple_part ( const char *type, const char *subtype, Iterator begin, Iterator end ) { + basic_mime retval ( type, subtype ); + retval.set_body ( begin, end ); + return retval; + } + +// Build a mime part from a pair of iterators + template + static boost::shared_ptr< basic_mime > parse_mime ( Iterator &begin, Iterator end ) { + return detail::parse_mime ( begin, end ); + } + +// Build a mime part from a stream + static boost::shared_ptr < basic_mime > parse_mime ( std::istream &in ) { + boost::spirit::istream_iterator first (in); + boost::spirit::istream_iterator last; + return parse_mime ( first, last ); + } + + +private: + basic_mime (); // Can't create a part w/o a type + + headerIter find_header ( const char *key ) { + return std::find_if ( header_begin (), header_end (), detail::find_mime_header ( key )); + } + + constHeaderIter find_header ( const char *key ) const { + return std::find_if ( header_begin (), header_end (), detail::find_mime_header ( key )); + } + + static part_kind part_kind_from_string_pair ( const std::string &type, const std::string &sub_type ) { + if ( boost::iequals ( type, "multipart" )) + return multi_part; + + part_kind retVal = simple_part; + // I expect that this will get more complicated as time goes on.... + // + // message/delivery-status is a simple type. + // RFC 3464 defines message/delivery-status + // The body of a message/delivery-status consists of one or more + // "fields" formatted according to the ABNF of RFC 822 header "fields" + // (see [RFC822]). + if ( boost::iequals ( type, "message" )) + if ( !boost::iequals ( sub_type, "delivery-status" )) + retVal = message_part; + return retVal; + } + + void check_subpart_index ( size_t idx ) const { + if ( get_part_kind () == simple_part ) + throw std::runtime_error ( "Simple Mime parts don't have sub-parts" ); + else if ( get_part_kind () == multi_part ) { + if ( idx >= m_subparts.size ()) + throw std::runtime_error ( + str ( boost::format ( "Trying to access part %d (of %d) sub-part to a multipart/xxx mime part" ) % idx % m_subparts.size ())); + } + else { // message-part + if ( get_part_kind () == message_part ) + if ( m_subparts.size () > 1 ) + throw std::runtime_error ( "How did a message/xxx mime parts get more than one sub-part?" ); + + if ( idx >= m_subparts.size ()) + throw std::runtime_error ( + str ( boost::format ( "Trying to access part %d (of %d) sub-part to a message/xxx mime part" ) % idx % m_subparts.size ())); + } + } + + void check_subpart_append () const { + if ( get_part_kind () == simple_part ) + throw std::runtime_error ( "Simple Mime parts don't have sub-parts" ); + else if ( get_part_kind () == message_part ) { + if ( m_subparts.size () > 0 ) + throw std::runtime_error ( "Can't add a second sub-part to a message/xxx mime part" ); + } + // else { /* Multi-part */ } // We can always add to a multi-part + } + + part_kind m_part_kind; + headerList m_headers; + bool m_body_prolog_is_missing; // only for multiparts + mimeBody m_body; + mimeBody m_body_epilog; // only for multiparts + partList m_subparts; // only for multiparts or message + string_type m_default_content_type; + }; + + +namespace detail { + + template + static boost::shared_ptr< basic_mime > parse_mime ( Iterator &begin, Iterator end, const char *default_content_type ) { + tracer t ( __func__ ); + typedef typename boost::mime::basic_mime mime_part; + + shared_ptr < mime_part > retVal ( + new mime_part ( detail::read_headers ( begin, end ), default_content_type )); + + std::string content_type = retVal->get_content_type (); + +#ifdef DUMP_MIME_DATA + std::cout << "Content-Type: " << content_type << std::endl; + std::cout << str ( boost::format ( "retVal->get_part_kind () = %d" ) % ((int) retVal->get_part_kind ())) << std::endl; +#endif + + if ( retVal->get_part_kind () == mime_part::simple_part ) + retVal->set_body ( detail::read_simplepart_body ( begin, end )); + else if ( retVal->get_part_kind () == mime_part::message_part ) { + // If we've got a message/xxxx, then there is no body, and we have a single + // embedded mime_part (which, of course, could be a multipart) + retVal->append_part ( parse_mime ( begin, end )); + } + else /* multi_part */ { + // Find or invent a boundary string + std::string part_separator = detail::get_boundary ( retVal->get_content_type_header ()); + const char *cont_type = boost::iequals ( content_type, "multipart/digest" ) ? "message/rfc822" : "text/plain"; + + detail::multipart_body_type body_and_subParts; + detail::read_multipart_body ( begin, end, body_and_subParts, part_separator ); + + retVal->set_body_prolog ( body_and_subParts.body_prolog ); + retVal->set_multipart_prolog_is_missing ( body_and_subParts.prolog_is_missing ); + for ( typename sub_parts_t::const_iterator iter = body_and_subParts.sub_parts.begin (); + iter != body_and_subParts.sub_parts.end (); ++iter ) { + typedef typename sub_part_t::const_iterator iter_type; + iter_type b = iter->begin (); + iter_type e = iter->end (); + retVal->append_part ( parse_mime ( b, e, cont_type )); + } + retVal->set_body_epilog ( body_and_subParts.body_epilog ); + } + + return retVal; + } + + } + + +// ----------------------------------------------------------- +// +// Streaming +// +// ----------------------------------------------------------- + +template +inline std::ostream & operator << ( std::ostream &stream, basic_mime &part ) { + part.stream_out ( stream ); + return stream; + } + +template +inline std::ostream & operator << ( std::ostream &stream, boost::shared_ptr > part ) { + return stream << *part; + } + + + +}} + +BOOST_FUSION_ADAPT_STRUCT( + boost::mime::detail::mime_content_type, + (std::string, type) + (std::string, sub_type) + (boost::mime::detail::phrase_container_t, phrases) +) + +#endif // _BOOST_MIME_HPP diff --git a/codeview/src/main/assets/training-set/c++/hstest.cpp b/codeview/src/main/assets/training-set/c++/hstest.cpp new file mode 100755 index 0000000..eeb4bd5 --- /dev/null +++ b/codeview/src/main/assets/training-set/c++/hstest.cpp @@ -0,0 +1,1532 @@ + +// vim:sw=2:ai + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.hpp" +#include "auto_ptrcontainer.hpp" +#include "socket.hpp" +#include "thread.hpp" +#include "hstcpcli.hpp" + +#if __GNUC__ >= 4 +long atomic_exchange_and_add(volatile long *valp, long c) +{ + return __sync_fetch_and_add(valp, c); +} +#else +#include +using namespace __gnu_cxx; +long atomic_exchange_and_add(volatile long *valp, long c) +{ + return __exchange_and_add((volatile _Atomic_word *)valp, c); +} +#endif + +namespace dena { + +struct auto_mysql : private noncopyable { + auto_mysql() : db(0) { + reset(); + } + ~auto_mysql() { + if (db) { + mysql_close(db); + } + } + void reset() { + if (db) { + mysql_close(db); + } + if ((db = mysql_init(0)) == 0) { + fatal_abort("failed to initialize mysql client"); + } + } + operator MYSQL *() const { return db; } + private: + MYSQL *db; +}; + +struct auto_mysql_res : private noncopyable { + auto_mysql_res(MYSQL *db) { + res = mysql_store_result(db); + } + ~auto_mysql_res() { + if (res) { + mysql_free_result(res); + } + } + operator MYSQL_RES *() const { return res; } + private: + MYSQL_RES *res; +}; + +struct auto_mysql_stmt : private noncopyable { + auto_mysql_stmt(MYSQL *db) { + stmt = mysql_stmt_init(db); + } + ~auto_mysql_stmt() { + if (stmt) { + mysql_stmt_close(stmt); + } + } + operator MYSQL_STMT *() const { return stmt; } + private: + MYSQL_STMT *stmt; +}; + +namespace { + +double +gettimeofday_double() +{ + struct timeval tv = { }; + if (gettimeofday(&tv, 0) != 0) { + fatal_abort("gettimeofday"); + } + return static_cast(tv.tv_usec) / 1000000 + tv.tv_sec; +} + +// unused +void +wait_close(int fd) +{ + char buf[1024]; + while (true) { + int r = read(fd, buf, sizeof(buf)); + if (r <= 0) { + break; + } + } +} + +// unused +void +gentle_close(int fd) +{ + int r = shutdown(fd, SHUT_WR); + if (r != 0) { + return; + } + wait_close(fd); +} + +}; + +struct hstest_shared { + config conf; + socket_args arg; + int verbose; + size_t loop; + size_t pipe; + char op; + long num_threads; + mutable volatile long count; + mutable volatile long conn_count; + long wait_conn; + volatile char *keygen; + long keygen_size; + mutable volatile int enable_timing; + int usleep; + int dump; + hstest_shared() : verbose(0), loop(0), pipe(0), op('G'), num_threads(0), + count(0), conn_count(0), wait_conn(0), keygen(0), keygen_size(0), + enable_timing(0), usleep(0), dump(0) { } + void increment_count(unsigned int c = 1) const volatile { + atomic_exchange_and_add(&count, c); + } + void increment_conn(unsigned int c) const volatile { + atomic_exchange_and_add(&conn_count, c); + while (wait_conn != 0 && conn_count < wait_conn) { + sleep(1); + } + // fprintf(stderr, "wait_conn=%ld done\n", wait_conn); + } +}; + +struct hstest_thread { + struct arg_type { + size_t id; + const hstest_shared& sh; + bool watch_flag; + arg_type(size_t i, const hstest_shared& s, bool w) + : id(i), sh(s), watch_flag(w) { } + }; + hstest_thread(const arg_type& a) : arg(a), io_success_count(0), + op_success_count(0), response_min(99999), response_max(0), + response_sum(0), response_avg(0) { } + void operator ()(); + void test_1(); + void test_2_3(int test_num); + void test_4_5(int test_num); + void test_6(int test_num); + void test_7(int test_num); + void test_8(int test_num); + void test_9(int test_num); + void test_10(int test_num); + void test_11(int test_num); + void test_12(int test_num); + void test_21(int test_num); + void test_22(int test_num); + void test_watch(); + void sleep_if(); + void set_timing(double time_spent); + arg_type arg; + auto_file fd; + size_t io_success_count; + size_t op_success_count; + double response_min, response_max, response_sum, response_avg; +}; + +void +hstest_thread::test_1() +{ + char buf[1024]; + unsigned int seed = arg.id; + seed ^= arg.sh.conf.get_int("seed_xor", 0); + std::string err; + if (socket_connect(fd, arg.sh.arg, err) != 0) { + fprintf(stderr, "connect: %d %s\n", errno, strerror(errno)); + return; + } + const char op = arg.sh.op; + const int tablesize = arg.sh.conf.get_int("tablesize", 0); + for (size_t i = 0; i < arg.sh.loop; ++i) { + for (size_t j = 0; j < arg.sh.pipe; ++j) { + int k = 0, v = 0, len = 0; + if (op == 'G') { + k = rand_r(&seed); + v = rand_r(&seed); /* unused */ + if (tablesize != 0) { + k &= tablesize; + } + len = snprintf(buf, sizeof(buf), "%c\tk%d\n", op, k); + } else { + k = rand_r(&seed); + v = rand_r(&seed); + if (tablesize != 0) { + k &= tablesize; + } + len = snprintf(buf, sizeof(buf), "%c\tk%d\tv%d\n", op, k, v); + } + const int wlen = write(fd.get(), buf, len); + if (wlen != len) { + return; + } + } + size_t read_cnt = 0; + size_t read_pos = 0; + while (read_cnt < arg.sh.pipe) { + const int rlen = read(fd.get(), buf + read_pos, sizeof(buf) - read_pos); + if (rlen <= 0) { + return; + } + read_pos += rlen; + while (true) { + const char *const p = static_cast(memchr(buf, '\n', + read_pos)); + if (p == 0) { + break; + } + ++read_cnt; + ++io_success_count; + arg.sh.increment_count(); + if (p != buf && buf[0] == '=') { + ++op_success_count; + } + const size_t rest_size = buf + read_pos - (p + 1); + if (rest_size != 0) { + memmove(buf, p + 1, rest_size); + } + read_pos = rest_size; + } + } + } +} + +void +hstest_thread::test_2_3(int test_num) +{ +#if 0 + char buf_k[128], buf_v[128]; + unsigned int seed = arg.id; + op_base_t op = static_cast(arg.sh.op); + micli_ptr hnd; + if (test_num == 2) { + hnd = micli_i::create_remote(arg.sh.conf); + } else if (test_num == 3) { + // hnd = micli_i::create_inproc(arg.sh.localdb); + } + if (hnd.get() == 0) { + return; + } + for (size_t i = 0; i < arg.sh.loop; ++i) { + for (size_t j = 0; j < arg.sh.pipe; ++j) { + int k = 0, v = 0, klen = 0, vlen = 0; + k = rand_r(&seed); + klen = snprintf(buf_k, sizeof(buf_k), "k%d", k); + v = rand_r(&seed); /* unused */ + vlen = snprintf(buf_v, sizeof(buf_v), "v%d", v); + string_ref arr[2]; + arr[0] = string_ref(buf_k, klen); + arr[1] = string_ref(buf_v, vlen); + pstrarr_ptr rec(arr, 2); + if (hnd->execute(op, 0, 0, rec.get_const())) { + ++io_success_count; + arg.sh.increment_count(); + const dataset& res = hnd->get_result_ref(); + if (res.size() == 1) { + ++op_success_count; + } + } + } + } +#endif +} + +void +hstest_thread::test_4_5(int test_num) +{ +#if 0 + char buf_k[128], buf_v[8192]; + memset(buf_v, ' ', sizeof(buf_v)); + unsigned int seed = arg.id; + op_base_t op = static_cast(arg.sh.op); + micli_ptr hnd; + if (test_num == 4) { + hnd = micli_i::create_remote(arg.sh.conf); + } else if (test_num == 5) { + hnd = micli_i::create_inproc(arg.sh.localdb); + } + if (hnd.get() == 0) { + return; + } + for (size_t i = 0; i < arg.sh.loop; ++i) { + for (size_t j = 0; j < arg.sh.pipe; ++j) { + int k = 0, klen = 0, vlen = 0; + k = i & 0x0000ffffUL; + if (k == 0) { + fprintf(stderr, "k=0\n"); + } + klen = snprintf(buf_k, sizeof(buf_k), "k%d", k); + vlen = rand_r(&seed) % 8192; + string_ref arr[2]; + arr[0] = string_ref(buf_k, klen); + arr[1] = string_ref(buf_v, vlen); + pstrarr_ptr rec(arr, 2); + if (hnd->execute(op, 0, 0, rec.get_const())) { + ++io_success_count; + const dataset& res = hnd->get_result_ref(); + if (res.size() == 1) { + ++op_success_count; + } + } + } + } +#endif +} + +void +hstest_thread::test_6(int test_num) +{ + int count = arg.sh.conf.get_int("count", 1); + auto_file fds[count]; + for (int i = 0; i < count; ++i) { + const double t1 = gettimeofday_double(); + std::string err; + if (socket_connect(fds[i], arg.sh.arg, err) != 0) { + fprintf(stderr, "id=%zu i=%d err=%s\n", arg.id, i, err.c_str()); + } + const double t2 = gettimeofday_double(); + if (t2 - t1 > 1) { + fprintf(stderr, "id=%zu i=%d time %f\n", arg.id, i, t2 - t1); + } + } +} + +void +hstest_thread::test_7(int num) +{ + /* + set foo 0 0 10 + 0123456789 + STORED + get foo + VALUE foo 0 10 + 0123456789 + END + get var + END + */ + char buf[1024]; + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); + unsigned int seed = arg.id; + seed ^= arg.sh.conf.get_int("seed_xor", 0); + const int tablesize = arg.sh.conf.get_int("tablesize", 0); + const char op = arg.sh.op; + for (size_t i = 0; i < arg.sh.loop; ++i) { + const double tm1 = gettimeofday_double(); + std::string err; + if (fd.get() < 0 && socket_connect(fd, arg.sh.arg, err) != 0) { + fprintf(stderr, "connect: %d %s\n", errno, strerror(errno)); + return; + } + for (size_t j = 0; j < arg.sh.pipe; ++j) { + int k = 0, v = 0, len = 0; + if (op == 'G') { + k = rand_r(&seed); + v = rand_r(&seed); /* unused */ + if (tablesize != 0) { + k &= tablesize; + } + len = snprintf(buf, sizeof(buf), "get k%d\r\n", k); + } else { + k = rand_r(&seed); + v = rand_r(&seed); + if (tablesize != 0) { + k &= tablesize; + } + char vbuf[1024]; + int vlen = snprintf(vbuf, sizeof(vbuf), + "v%d" + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + , v); + len = snprintf(buf, sizeof(buf), "set k%d 0 0 %d\r\n%s\r\n", + k, vlen, vbuf); + } + const int wlen = write(fd.get(), buf, len); + if (wlen != len) { + return; + } + } + size_t read_cnt = 0; + size_t read_pos = 0; + bool read_response_done = false; + bool expect_value = false; + while (!read_response_done) { + const int rlen = read(fd.get(), buf + read_pos, sizeof(buf) - read_pos); + if (rlen <= 0) { + return; + } + read_pos += rlen; + while (true) { + const char *const p = static_cast(memchr(buf, '\n', + read_pos)); + if (p == 0) { + break; + } + ++read_cnt; + if (expect_value) { + expect_value = false; + } else if (p >= buf + 6 && memcmp(buf, "VALUE ", 6) == 0) { + expect_value = true; + ++op_success_count; + } else { + if (p == buf + 7 && memcmp(buf, "STORED\r", 7) == 0) { + ++op_success_count; + } + read_response_done = true; + } + const size_t rest_size = buf + read_pos - (p + 1); + if (rest_size != 0) { + memmove(buf, p + 1, rest_size); + } + read_pos = rest_size; + } + ++io_success_count; + } + arg.sh.increment_count(); + if (!keep_connection) { + fd.close(); + } + const double tm2 = gettimeofday_double(); + set_timing(tm2 - tm1); + sleep_if(); + } +} + +struct rec { + std::string key; + std::string value; +}; + +void +hstest_thread::test_8(int test_num) +{ +#if 0 + char buf_k[128], buf_v[128]; + unsigned int seed = arg.id; + // op_base_t op = static_cast(arg.sh.op); + using namespace boost::multi_index; + typedef member rec_get_key; + typedef ordered_unique oui; + typedef multi_index_container< rec, indexed_by > mic; + #if 0 + typedef std::map m_type; + m_type m; + #endif + mic m; + for (size_t i = 0; i < arg.sh.loop; ++i) { + for (size_t j = 0; j < arg.sh.pipe; ++j) { + int k = 0, v = 0, klen = 0, vlen = 0; + k = rand_r(&seed); + klen = snprintf(buf_k, sizeof(buf_k), "k%d", k); + v = rand_r(&seed); /* unused */ + vlen = snprintf(buf_v, sizeof(buf_v), "v%d", v); + const std::string ks(buf_k, klen); + const std::string vs(buf_v, vlen); + rec r; + r.key = ks; + r.value = vs; + m.insert(r); + // m.insert(std::make_pair(ks, vs)); + ++io_success_count; + ++op_success_count; + arg.sh.increment_count(); + } + } +#endif +} + +struct mysqltest_thread_initobj : private noncopyable { + mysqltest_thread_initobj() { + mysql_thread_init(); + } + ~mysqltest_thread_initobj() { + mysql_thread_end(); + } +}; + +void +hstest_thread::test_9(int test_num) +{ + /* create table hstest + * ( k varchar(255) not null, v varchar(255) not null, primary key(k)) + * engine = innodb; */ + auto_mysql db; + // mysqltest_thread_initobj initobj; + std::string err; + const char op = arg.sh.op; + const std::string suffix = arg.sh.conf.get_str("value_suffix", "upd"); + unsigned long long err_cnt = 0; + unsigned long long query_cnt = 0; + #if 0 + my_bool reconnect = 0; + if (mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect) != 0) { + err = "mysql_options() failed"; + ++err_cnt; + return; + } + #endif + unsigned int seed = time(0) + arg.id + 1; + seed ^= arg.sh.conf.get_int("seed_xor", 0); + drand48_data randbuf; + srand48_r(seed, &randbuf); + const std::string mysql_host = arg.sh.conf.get_str("host", "localhost"); + const int mysql_port = arg.sh.conf.get_int("mysqlport", 3306); + const int num = arg.sh.loop; + const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root"); + const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", ""); + const std::string mysql_dbname = arg.sh.conf.get_str("dbname", "hstest"); + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); + const int verbose = arg.sh.conf.get_int("verbose", 1); + const int tablesize = arg.sh.conf.get_int("tablesize", 10000); + const int moreflds = arg.sh.conf.get_int("moreflds", 0); + const std::string moreflds_prefix = arg.sh.conf.get_str( + "moreflds_prefix", "column0123456789_"); + const int use_handler = arg.sh.conf.get_int("handler", 0); + const int sched_flag = arg.sh.conf.get_int("sched", 0); + const int use_in = arg.sh.conf.get_int("in", 0); + const int ssps = use_in ? 0 : arg.sh.conf.get_int("ssps", 0); + std::string flds = "v"; + for (int i = 0; i < moreflds; ++i) { + char buf[1024]; + snprintf(buf, sizeof(buf), ",%s%d", moreflds_prefix.c_str(), i); + flds += std::string(buf); + } + int connected = 0; + std::auto_ptr stmt; + string_buffer wbuf; + for (int i = 0; i < num; ++i) { + const double tm1 = gettimeofday_double(); + const int flags = 0; + if (connected == 0) { + if (!mysql_real_connect(db, mysql_host.c_str(), + mysql_user.c_str(), mysql_user.empty() ? 0 : mysql_passwd.c_str(), + mysql_dbname.c_str(), mysql_port, 0, flags)) { + err = "failed to connect: " + std::string(mysql_error(db)); + if (verbose >= 1) { + fprintf(stderr, "e=[%s]\n", err.c_str()); + } + ++err_cnt; + return; + } + arg.sh.increment_conn(1); + } + int r = 0; + if (connected == 0 && use_handler) { + const char *const q = "handler hstest_table1 open"; + r = mysql_real_query(db, q, strlen(q)); + if (r != 0) { + err = 1; + } + } + if (connected == 0 && ssps) { + stmt.reset(new auto_mysql_stmt(db)); + const char *const q = "select v from hstest_table1 where k = ?"; + r = mysql_stmt_prepare(*stmt, q, strlen(q)); + if (r != 0) { + fprintf(stderr, "ssps err\n"); + ++err_cnt; + return; + } + } + connected = 1; + std::string result_str; + unsigned int err = 0; + unsigned int num_flds = 0, num_affected_rows = 0; + int got_data = 0; + char buf_query[16384]; + int buf_query_len = 0; + int k = 0, v = 0; + { + double kf = 0, vf = 0; + drand48_r(&randbuf, &kf); + drand48_r(&randbuf, &vf); + k = int(kf * tablesize); + v = int(vf * tablesize); + #if 0 + k = rand_r(&seed); + v = rand_r(&seed); + if (tablesize != 0) { + k %= tablesize; + } + #endif + if (op == 'G') { + if (use_handler) { + buf_query_len = snprintf(buf_query, sizeof(buf_query), + "handler hstest_table1 read `primary` = ( '%d' )", k); + // TODO: moreflds + } else if (ssps) { + // + } else if (use_in) { + wbuf.clear(); + char *p = wbuf.make_space(1024); + int len = snprintf(p, 1024, "select %s from hstest_table1 where k in ('%d'", flds.c_str(), k); + wbuf.space_wrote(len); + for (int j = 1; j < use_in; ++j) { + /* generate more key */ + drand48_r(&randbuf, &kf); + k = int(kf * tablesize); + p = wbuf.make_space(1024); + int len = snprintf(p, 1024, ", '%d'", k); + wbuf.space_wrote(len); + } + wbuf.append_literal(")"); + } else { + buf_query_len = snprintf(buf_query, sizeof(buf_query), + "select %s from hstest_table1 where k = '%d'", flds.c_str(), k); + } + } else if (op == 'U') { + buf_query_len = snprintf(buf_query, sizeof(buf_query), + "update hstest_table1 set v = '%d_%d%s' where k = '%d'", + v, k, suffix.c_str(), k); + } else if (op == 'R') { + buf_query_len = snprintf(buf_query, sizeof(buf_query), + "replace into hstest_table1 values ('%d', 'v%d')", k, v); + // TODO: moreflds + } + } + if (r == 0) { + if (ssps) { + MYSQL_BIND bind[1] = { }; + bind[0].buffer_type = MYSQL_TYPE_LONG; + bind[0].buffer = (char *)&k; + bind[0].is_null = 0; + bind[0].length = 0; + if (mysql_stmt_bind_param(*stmt, bind)) { + fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt)); + ++err_cnt; + return; + } + r = mysql_stmt_execute(*stmt); + // fprintf(stderr, "stmt exec\n"); + } else if (use_in) { + r = mysql_real_query(db, wbuf.begin(), wbuf.size()); + } else { + r = mysql_real_query(db, buf_query, buf_query_len); + // fprintf(stderr, "real query\n"); + } + ++query_cnt; + } + if (r != 0) { + err = 1; + } else if (ssps) { + if (verbose >= 0) { + char resbuf[1024]; + unsigned long res_len = 0; + MYSQL_BIND bind[1] = { }; + bind[0].buffer_type = MYSQL_TYPE_STRING; + bind[0].buffer = resbuf; + bind[0].buffer_length = sizeof(resbuf); + bind[0].length = &res_len; + if (mysql_stmt_bind_result(*stmt, bind)) { + fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt)); + ++err_cnt; + return; + } + if (mysql_stmt_fetch(*stmt)) { + fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt)); + ++err_cnt; + return; + } + if (!result_str.empty()) { + result_str += " "; + } + result_str += std::string(resbuf, res_len); + // fprintf(stderr, "SSPS RES: %s\n", result_str.c_str()); + got_data = 1; + } else { + got_data = 1; + } + } else { + auto_mysql_res res(db); + if (res != 0) { + if (verbose >= 0) { + num_flds = mysql_num_fields(res); + MYSQL_ROW row = 0; + while ((row = mysql_fetch_row(res)) != 0) { + got_data += 1; + unsigned long *const lengths = mysql_fetch_lengths(res); + if (verbose >= 2) { + for (unsigned int i = 0; i < num_flds; ++i) { + if (!result_str.empty()) { + result_str += " "; + } + result_str += std::string(row[i], lengths[i]); + } + } + } + } else { + MYSQL_ROW row = 0; + while ((row = mysql_fetch_row(res)) != 0) { + got_data += 1; + } + } + } else { + if (mysql_field_count(db) == 0) { + num_affected_rows = mysql_affected_rows(db); + } else { + err = 1; + } + } + } + if (verbose >= 2 || (verbose >= 1 && err != 0)) { + if (err) { + ++err_cnt; + const char *const errstr = mysql_error(db); + fprintf(stderr, "e=[%s] a=%u q=[%s]\n", errstr, + num_affected_rows, buf_query); + } else { + fprintf(stderr, "a=%u q=[%s] r=[%s]\n", num_affected_rows, buf_query, + result_str.c_str()); + } + } + if (err == 0) { + ++io_success_count; + if (num_affected_rows > 0 || got_data > 0) { + op_success_count += got_data; + } else { + if (verbose >= 1) { + fprintf(stderr, "k=%d numaff=%u gotdata=%d\n", + k, num_affected_rows, got_data); + } + } + arg.sh.increment_count(); + } + if (!keep_connection) { + if (stmt.get() != 0) { + stmt.reset(); + } + db.reset(); + connected = 0; + } + const double tm2 = gettimeofday_double(); + set_timing(tm2 - tm1); + sleep_if(); + if (sched_flag) { + sched_yield(); + } + } + if (verbose >= 1) { + fprintf(stderr, "thread finished (error_count=%llu)\n", err_cnt); + } +} + +void +hstest_thread::test_10(int test_num) +{ + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); + unsigned int seed = time(0) + arg.id + 1; + seed ^= arg.sh.conf.get_int("seed_xor", 0); + drand48_data randbuf; + srand48_r(seed, &randbuf); + std::string err; + int keepconn_count = 0; + const char op = arg.sh.op; + const int verbose = arg.sh.conf.get_int("verbose", 1); + const std::string suffix = arg.sh.conf.get_str("value_suffix", "upd"); + const int tablesize = arg.sh.conf.get_int("tablesize", 10000); + const int firstkey = arg.sh.conf.get_int("firstkey", 0); + const int sched_flag = arg.sh.conf.get_int("sched", 0); + const int moreflds = arg.sh.conf.get_int("moreflds", 0); + const std::string dbname = arg.sh.conf.get_str("dbname", "hstest"); + const std::string table = arg.sh.conf.get_str("table", "hstest_table1"); + const std::string index = arg.sh.conf.get_str("index", "PRIMARY"); + const std::string field = arg.sh.conf.get_str("field", "v"); + const int use_in = arg.sh.conf.get_int("in", 0); + const std::string moreflds_prefix = arg.sh.conf.get_str( + "moreflds_prefix", "column0123456789_"); + const int dump = arg.sh.dump; + const int nodup = arg.sh.conf.get_int("nodup", 0); + std::string moreflds_str; + for (int i = 0; i < moreflds; ++i) { + char sbuf[1024]; + snprintf(sbuf, sizeof(sbuf), ",%s%d", moreflds_prefix.c_str(), i); + moreflds_str += std::string(sbuf); + } + string_buffer wbuf; + char rbuf[16384]; + for (size_t i = 0; i < arg.sh.loop; ++i) { + int len = 0, rlen = 0, wlen = 0; + #if 0 + const double tm1 = gettimeofday_double(); + #endif + if (fd.get() < 0) { + if (socket_connect(fd, arg.sh.arg, err) != 0) { + fprintf(stderr, "connect: %d %s\n", errno, strerror(errno)); + return; + } + char *wp = wbuf.make_space(1024); + len = snprintf(wp, 1024, + "P\t1\t%s\t%s\tPRIMARY\t%s%s\n", dbname.c_str(), table.c_str(), + field.c_str(), moreflds_str.c_str()); + /* pst_num, db, table, index, retflds */ + wbuf.space_wrote(len); + wlen = write(fd.get(), wbuf.begin(), len); + if (len != wlen) { + fprintf(stderr, "write: %d %d\n", len, wlen); + return; + } + wbuf.clear(); + rlen = read(fd.get(), rbuf, sizeof(rbuf)); + if (rlen <= 0 || rbuf[rlen - 1] != '\n') { + fprintf(stderr, "read: rlen=%d errno=%d\n", rlen, errno); + return; + } + if (rbuf[0] != '0') { + fprintf(stderr, "failed to open table\n"); + return; + } + arg.sh.increment_conn(1); + } + const double tm1 = gettimeofday_double(); + for (size_t j = 0; j < arg.sh.pipe; ++j) { + int k = 0, v = 0; + { + while (true) { + double kf = 0, vf = 0; + drand48_r(&randbuf, &kf); + drand48_r(&randbuf, &vf); + k = int(kf * tablesize) + firstkey; + v = int(vf * tablesize) + firstkey; + if (k - firstkey < arg.sh.keygen_size) { + volatile char *const ptr = arg.sh.keygen + (k - firstkey); + // int oldv = __sync_fetch_and_or(ptr, 1); + int oldv = *ptr; + *ptr += 1; + if (nodup && oldv != 0) { + if (dump) { + fprintf(stderr, "retry\n"); + } + continue; + } + } else { + if (nodup) { + if (dump) { + fprintf(stderr, "retry2\n"); + } + continue; + } + } + size_t len = 0; + if (op == 'G') { + if (use_in) { + char *wp = wbuf.make_space(1024); + len = snprintf(wp, 1024, "1\t=\t1\t\t%d\t0\t@\t0\t%d\t%d", + use_in, use_in, k); + wbuf.space_wrote(len); + for (int j = 1; j < use_in; ++j) { + drand48_r(&randbuf, &kf); + k = int(kf * tablesize) + firstkey; + char *wp = wbuf.make_space(1024); + len = snprintf(wp, 1024, "\t%d", k); + wbuf.space_wrote(len); + } + wbuf.append_literal("\n"); + } else { + char *wp = wbuf.make_space(1024); + len = snprintf(wp, 1024, "1\t=\t1\t%d\n", k); + wbuf.space_wrote(len); + } + } else if (op == 'U') { + char *wp = wbuf.make_space(1024); + len = snprintf(wp, 1024, + "1\t=\t1\t%d\t1\t0\tU\t%d_%d%s\n", k, v, k, suffix.c_str()); + wbuf.space_wrote(len); + } + break; + } + } + } + wlen = write(fd.get(), wbuf.begin(), wbuf.size()); + if (wlen != wbuf.size()) { + fprintf(stderr, "write: %d %d\n", (int)wbuf.size(), wlen); + return; + } + wbuf.clear(); + size_t read_cnt = 0; + size_t read_pos = 0; + while (read_cnt < arg.sh.pipe) { + rlen = read(fd.get(), rbuf + read_pos, sizeof(rbuf) - read_pos); + if (rlen <= 0) { + fprintf(stderr, "read: %d\n", rlen); + return; + } + read_pos += rlen; + while (true) { + const char *const nl = static_cast(memchr(rbuf, '\n', + read_pos)); + if (nl == 0) { + break; + } + ++read_cnt; + ++io_success_count; + const char *t1 = static_cast(memchr(rbuf, '\t', + nl - rbuf)); + if (t1 == 0) { + fprintf(stderr, "error \n"); + break; + } + ++t1; + const char *t2 = static_cast(memchr(t1, '\t', + nl - t1)); + if (t2 == 0) { + if (verbose > 1) { + fprintf(stderr, "key: notfound \n"); + } + break; + } + ++t2; + if (t1 == rbuf + 2 && rbuf[0] == '0') { + if (op == 'G') { + ++op_success_count; + arg.sh.increment_count(); + } else if (op == 'U') { + const char *t3 = t2; + while (t3 != nl && t3[0] >= 0x10) { + ++t3; + } + if (t3 != t2 + 1 || t2[0] != '1') { + const std::string mess(t2, t3); + fprintf(stderr, "mod: %s\n", mess.c_str()); + } else { + ++op_success_count; + arg.sh.increment_count(); + if (arg.sh.dump && arg.sh.pipe == 1) { + fwrite(wbuf.begin(), wbuf.size(), 1, stderr); + } + } + } + } else { + const char *t3 = t2; + while (t3 != nl && t3[0] >= 0x10) { + ++t3; + } + const std::string mess(t2, t3); + fprintf(stderr, "err: %s\n", mess.c_str()); + } + const size_t rest_size = rbuf + read_pos - (nl + 1); + if (rest_size != 0) { + memmove(rbuf, nl + 1, rest_size); + } + read_pos = rest_size; + } + } + if (!keep_connection) { + fd.reset(); + arg.sh.increment_conn(-1); + } else if (keep_connection > 1 && ++keepconn_count > keep_connection) { + keepconn_count = 0; + fd.reset(); + arg.sh.increment_conn(-1); + } + const double tm2 = gettimeofday_double(); + set_timing(tm2 - tm1); + sleep_if(); + if (sched_flag) { + sched_yield(); + } + } + if (dump) { + fprintf(stderr, "done\n"); + } +} + +void +hstest_thread::sleep_if() +{ + if (arg.sh.usleep) { + struct timespec ts = { + arg.sh.usleep / 1000000, + (arg.sh.usleep % 1000000) * 1000 + }; + nanosleep(&ts, 0); + } +} + +void +hstest_thread::set_timing(double time_spent) +{ + response_min = std::min(response_min, time_spent); + response_max = std::max(response_max, time_spent); + response_sum += time_spent; + if (op_success_count != 0) { + response_avg = response_sum / op_success_count; + } +} + +void +hstest_thread::test_11(int test_num) +{ + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); + const int tablesize = arg.sh.conf.get_int("tablesize", 0); + unsigned int seed = arg.id; + seed ^= arg.sh.conf.get_int("seed_xor", 0); + std::string err; + hstcpcli_ptr cli; + for (size_t i = 0; i < arg.sh.loop; ++i) { + if (cli.get() == 0) { + cli = hstcpcli_i::create(arg.sh.arg); + cli->request_buf_open_index(0, "hstest", "hstest_table1", "", "v"); + /* pst_num, db, table, index, retflds */ + if (cli->request_send() != 0) { + fprintf(stderr, "reuqest_send: %s\n", cli->get_error().c_str()); + return; + } + size_t num_flds = 0; + if (cli->response_recv(num_flds) != 0) { + fprintf(stderr, "reuqest_recv: %s\n", cli->get_error().c_str()); + return; + } + cli->response_buf_remove(); + } + for (size_t j = 0; j < arg.sh.pipe; ++j) { + char buf[256]; + int k = 0, v = 0, len = 0; + { + k = rand_r(&seed); + v = rand_r(&seed); /* unused */ + if (tablesize != 0) { + k &= tablesize; + } + len = snprintf(buf, sizeof(buf), "%d", k); + } + const string_ref key(buf, len); + const string_ref op("=", 1); + cli->request_buf_exec_generic(0, op, &key, 1, 1, 0, string_ref(), 0, 0); + } + if (cli->request_send() != 0) { + fprintf(stderr, "reuqest_send: %s\n", cli->get_error().c_str()); + return; + } + size_t read_cnt = 0; + for (size_t j = 0; j < arg.sh.pipe; ++j) { + size_t num_flds = 0; + if (cli->response_recv(num_flds) != 0) { + fprintf(stderr, "reuqest_recv: %s\n", cli->get_error().c_str()); + return; + } + { + ++read_cnt; + ++io_success_count; + arg.sh.increment_count(); + { + ++op_success_count; + } + } + cli->response_buf_remove(); + } + if (!keep_connection) { + cli.reset(); + } + } +} + +void +hstest_thread::test_watch() +{ + const int timelimit = arg.sh.conf.get_int("timelimit", 0); + const int timelimit_offset = timelimit / 2; + int loop = 0; + double t1 = 0, t2 = 0; + size_t cnt_t1 = 0, cnt_t2 = 0; + size_t prev_cnt = 0; + double now_f = 0; + while (true) { + sleep(1); + const size_t cnt = arg.sh.count; + const size_t df = cnt - prev_cnt; + prev_cnt = cnt; + const double now_prev = now_f; + now_f = gettimeofday_double(); + if (now_prev != 0) { + const double rps = static_cast(df) / (now_f - now_prev); + fprintf(stderr, "now: %zu cntdiff: %zu tdiff: %f rps: %f\n", + static_cast(now_f), df, now_f - now_prev, rps); + } + if (timelimit != 0) { + if (arg.sh.wait_conn == 0 || arg.sh.conn_count >= arg.sh.wait_conn) { + ++loop; + } + if (loop == timelimit_offset) { + t1 = gettimeofday_double(); + cnt_t1 = cnt; + arg.sh.enable_timing = 1; + fprintf(stderr, "start timing\n"); + } else if (loop == timelimit_offset + timelimit) { + t2 = gettimeofday_double(); + cnt_t2 = cnt; + const size_t cnt_diff = cnt_t2 - cnt_t1; + const double tdiff = t2 - t1; + const double qps = cnt_diff / (tdiff != 0 ? tdiff : 1); + fprintf(stderr, "(%f: %zu, %f: %zu), %10.5f qps\n", + t1, cnt_t1, t2, cnt_t2, qps); + size_t keycnt = 0; + for (int i = 0; i < arg.sh.keygen_size; ++i) { + if (arg.sh.keygen[i]) { + ++keycnt; + } + } + fprintf(stderr, "keygen=%zu\n", keycnt); + break; + } + } + } +#if 0 + int loop = 0; + double t1 = 0, t2 = 0; + size_t cnt_t1 = 0, cnt_t2 = 0; + size_t prev_cnt = 0; + while (true) { + sleep(1); + const size_t cnt = arg.sh.count; + const size_t df = cnt - prev_cnt; + prev_cnt = cnt; + const size_t now = time(0); + fprintf(stderr, "%zu %zu\n", now, df); + if (timelimit != 0) { + ++loop; + if (loop == timelimit_offset) { + t1 = gettimeofday_double(); + cnt_t1 = cnt; + } else if (loop == timelimit_offset + timelimit) { + t2 = gettimeofday_double(); + cnt_t2 = cnt; + const size_t cnt_diff = cnt_t2 - cnt_t1; + const double tdiff = t2 - t1; + const double qps = cnt_diff / (tdiff != 0 ? tdiff : 1); + fprintf(stderr, "(%f: %zu, %f: %zu), %10.5f qps\n", + t1, cnt_t1, t2, cnt_t2, qps); + size_t keycnt = 0; + for (int i = 0; i < arg.sh.keygen_size; ++i) { + if (arg.sh.keygen[i]) { + ++keycnt; + } + } + fprintf(stderr, "keygen=%zu\n", keycnt); + _exit(0); + } + } + } +#endif +} + +void +hstest_thread::test_12(int test_num) +{ + /* NOTE: num_threads should be 1 */ + /* create table hstest + * ( k varchar(255) not null, v varchar(255) not null, primary key(k)) + * engine = innodb; */ + mysqltest_thread_initobj initobj; + auto_mysql db; + std::string err; + unsigned long long err_cnt = 0; + unsigned long long query_cnt = 0; + #if 0 + my_bool reconnect = 0; + if (mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect) != 0) { + err = "mysql_options() failed"; + ++err_cnt; + return; + } + #endif + const std::string mysql_host = arg.sh.conf.get_str("host", "localhost"); + const int mysql_port = arg.sh.conf.get_int("mysqlport", 3306); + const unsigned int num = arg.sh.loop; + const size_t pipe = arg.sh.pipe; + const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root"); + const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", ""); + const std::string mysql_dbname = arg.sh.conf.get_str("db", "hstest"); + const int keep_connection = arg.sh.conf.get_int("keep_connection", 1); + const int verbose = arg.sh.conf.get_int("verbose", 1); + const int use_handler = arg.sh.conf.get_int("handler", 0); + int connected = 0; + unsigned int k = 0; + string_buffer buf; + for (unsigned int i = 0; i < num; ++i) { + const int flags = 0; + if (connected == 0 && !mysql_real_connect(db, mysql_host.c_str(), + mysql_user.c_str(), mysql_user.empty() ? 0 : mysql_passwd.c_str(), + mysql_dbname.c_str(), mysql_port, 0, flags)) { + err = "failed to connect: " + std::string(mysql_error(db)); + if (verbose >= 1) { + fprintf(stderr, "e=[%s]\n", err.c_str()); + } + ++err_cnt; + return; + } + int r = 0; + if (connected == 0 && use_handler) { + const char *const q = "handler hstest open"; + r = mysql_real_query(db, q, strlen(q)); + if (r != 0) { + err = 1; + } + } + connected = 1; + std::string result_str; + unsigned int err = 0; + unsigned int num_flds = 0, num_affected_rows = 0; + int got_data = 0; + buf.clear(); + buf.append_literal("insert into hstest values "); + for (size_t j = 0; j < pipe; ++j) { + const unsigned int v = ~k; + if (j != 0) { + buf.append_literal(","); + } + char *wp = buf.make_space(64); + int buf_query_len = snprintf(wp, 64, "('k%u', 'v%u')", k, v); + buf.space_wrote(buf_query_len); + ++k; + } + if (r == 0) { + r = mysql_real_query(db, buf.begin(), buf.size()); + ++query_cnt; + } + if (r != 0) { + err = 1; + } else { + auto_mysql_res res(db); + if (res != 0) { + if (verbose >= 0) { + num_flds = mysql_num_fields(res); + MYSQL_ROW row = 0; + while ((row = mysql_fetch_row(res)) != 0) { + got_data = 1; + unsigned long *const lengths = mysql_fetch_lengths(res); + if (verbose >= 2) { + for (unsigned int i = 0; i < num_flds; ++i) { + if (!result_str.empty()) { + result_str += " "; + } + result_str += std::string(row[i], lengths[i]); + } + } + } + } + } else { + if (mysql_field_count(db) == 0) { + num_affected_rows = mysql_affected_rows(db); + } else { + err = 1; + } + } + } + if (verbose >= 2 || (verbose >= 1 && err != 0)) { + if (err) { + ++err_cnt; + const char *const errstr = mysql_error(db); + fprintf(stderr, "e=[%s] a=%u q=[%s]\n", errstr, + num_affected_rows, std::string(buf.begin(), buf.size()).c_str()); + } else { + fprintf(stderr, "a=%u q=[%s] r=[%s]\n", num_affected_rows, + std::string(buf.begin(), buf.size()).c_str(), + result_str.c_str()); + } + } + if (err == 0) { + ++io_success_count; + if (num_affected_rows > 0 || got_data > 0) { + ++op_success_count; + } + arg.sh.increment_count(pipe); + } + if (!keep_connection) { + db.reset(); + connected = 0; + } + } + if (verbose >= 1) { + fprintf(stderr, "thread finished (error_count=%llu)\n", err_cnt); + } +} + +void +hstest_thread::test_21(int num) +{ + /* fsync test */ + unsigned int id = arg.id; + std::string err; + #if 0 + if (socket_connect(fd, arg.sh.arg, err) != 0) { + fprintf(stderr, "connect: %d %s\n", errno, strerror(errno)); + return; + } + #endif + auto_file logfd; + char fname[1024]; + snprintf(fname, sizeof(fname), "synctest_%u", id); + int open_flags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND; + logfd.reset(open(fname, open_flags, 0644)); + if (logfd.get() < 0) { + fprintf(stderr, "open: %s: %d %s\n", fname, errno, strerror(errno)); + return; + } + char buf[1024]; + unsigned long long count = 0; + while (true) { + snprintf(buf, sizeof(buf), "%u %llu\n", id, count); + const size_t len = strlen(buf); + if (write(logfd.get(), buf, len) != (ssize_t)len) { + fprintf(stderr, "write: %s: %d %s\n", fname, errno, strerror(errno)); + return; + } + #if 0 + if (write(fd.get(), buf, len) != (ssize_t)len) { + fprintf(stderr, "write(sock): %d %s\n", errno, strerror(errno)); + return; + } + #endif + if (fdatasync(logfd.get()) != 0) { + fprintf(stderr, "fsync: %s: %d %s\n", fname, errno, strerror(errno)); + return; + } + ++count; + ++op_success_count; + arg.sh.increment_count(); + } +} + +void +hstest_thread::test_22(int num) +{ + /* dd if=/dev/zero of=dummy.dat bs=1024M count=100 */ + unsigned int id = arg.id; + std::string err; + auto_file filefd; + char fname[1024]; + snprintf(fname, sizeof(fname), "dummy.dat"); + int open_flags = O_RDONLY | O_DIRECT; + filefd.reset(open(fname, open_flags, 0644)); + if (filefd.get() < 0) { + fprintf(stderr, "open: %s: %d %s\n", fname, errno, strerror(errno)); + return; + } + char buf_x[4096 * 2]; + char *const buf = (char *)(size_t(buf_x + 4096) / 4096 * 4096); + unsigned long long count = 0; + drand48_data randbuf; + unsigned long long seed = time(0); + seed *= 10; + seed += id; + srand48_r(seed, &randbuf); + for (unsigned int i = 0; i < arg.sh.loop; ++i) { + double kf = 0; + drand48_r(&randbuf, &kf); + kf *= (209715200 / 1); + // fprintf(stderr, "v=%f\n", kf); + off_t v = static_cast(kf); + v %= (209715200 / 1); + v *= (512 * 1); + const double tm1 = gettimeofday_double(); + const ssize_t r = pread(filefd.get(), buf, (512 * 1), v); + const double tm2 = gettimeofday_double(); + if (r < 0) { + fprintf(stderr, "pread: %s: %d %s\n", fname, errno, strerror(errno)); + return; + } + ++count; + ++op_success_count; + arg.sh.increment_count(); + set_timing(tm2 - tm1); + } +} + +void +hstest_thread::operator ()() +{ + if (arg.watch_flag) { + return test_watch(); + } + int test_num = arg.sh.conf.get_int("test", 1); + if (test_num == 1) { + test_1(); + } else if (test_num == 2 || test_num == 3) { + test_2_3(test_num); + } else if (test_num == 4 || test_num == 5) { + test_4_5(test_num); + } else if (test_num == 6) { + test_6(test_num); + } else if (test_num == 7) { + test_7(test_num); + } else if (test_num == 8) { + test_8(test_num); + } else if (test_num == 9) { + test_9(test_num); + } else if (test_num == 10) { + test_10(test_num); + } else if (test_num == 11) { + test_11(test_num); + } else if (test_num == 12) { + test_12(test_num); + } else if (test_num == 21) { + test_21(test_num); + } else if (test_num == 22) { + test_22(test_num); + } + const int halt = arg.sh.conf.get_int("halt", 0); + if (halt) { + fprintf(stderr, "thread halted\n"); + while (true) { + sleep(100000); + } + } + fprintf(stderr, "thread finished\n"); +} + +int +hstest_main(int argc, char **argv) +{ + ignore_sigpipe(); + hstest_shared shared; + parse_args(argc, argv, shared.conf); + shared.conf["port"] = shared.conf["hsport"]; + shared.arg.set(shared.conf); + shared.loop = shared.conf.get_int("num", 1000); + shared.pipe = shared.conf.get_int("pipe", 1); + shared.verbose = shared.conf.get_int("verbose", 1); + const int tablesize = shared.conf.get_int("tablesize", 0); + std::vector keygen(tablesize); + shared.keygen = &keygen[0]; + shared.keygen_size = tablesize; + shared.usleep = shared.conf.get_int("usleep", 0); + shared.dump = shared.conf.get_int("dump", 0); + shared.num_threads = shared.conf.get_int("num_threads", 10); + shared.wait_conn = shared.conf.get_int("wait_conn", 0); + const std::string op = shared.conf.get_str("op", "G"); + if (op.size() > 0) { + shared.op = op[0]; + } + #if 0 + const int localdb_flag = shared.conf.get_int("local", 0); + if (localdb_flag) { + shared.localdb = database_i::create(shared.conf); + } + #endif + const int num_thrs = shared.num_threads; + typedef thread thread_type; + typedef std::auto_ptr thread_ptr; + typedef auto_ptrcontainer< std::vector > thrs_type; + thrs_type thrs; + for (int i = 0; i < num_thrs; ++i) { + const hstest_thread::arg_type arg(i, shared, false); + thread_ptr thr(new thread(arg)); + thrs.push_back_ptr(thr); + } + for (size_t i = 0; i < thrs.size(); ++i) { + thrs[i]->start(); + } + thread_ptr watch_thread; + const int timelimit = shared.conf.get_int("timelimit", 0); + { + const hstest_thread::arg_type arg(0, shared, true); + watch_thread = thread_ptr(new thread(arg)); + watch_thread->start(); + } + size_t iocnt = 0, opcnt = 0; + double respmin = 999999, respmax = 0; + double respsum = 0; + if (timelimit != 0) { + watch_thread->join(); + } + for (size_t i = 0; i < thrs.size(); ++i) { + if (timelimit == 0) { + thrs[i]->join(); + } + iocnt += (*thrs[i])->io_success_count; + opcnt += (*thrs[i])->op_success_count; + respmin = std::min(respmin, (*thrs[i])->response_min); + respmax = std::max(respmax, (*thrs[i])->response_max); + respsum += (*thrs[i])->response_sum; + } + fprintf(stderr, "io_success_count=%zu op_success_count=%zu\n", iocnt, opcnt); + fprintf(stderr, "respmin=%f respmax=%f respsum=%f respavg=%f\n", + respmin, respmax, respsum, respsum / opcnt); + size_t keycnt = 0; + for (size_t i = 0; i < keygen.size(); ++i) { + if (keygen[i]) { + ++keycnt; + } + } + fprintf(stderr, "keycnt=%zu\n", keycnt); + _exit(0); + return 0; +} + +}; + +int +main(int argc, char **argv) +{ + return dena::hstest_main(argc, argv); +} + diff --git a/codeview/src/main/assets/training-set/c/adlist.c b/codeview/src/main/assets/training-set/c/adlist.c new file mode 100755 index 0000000..b4cc785 --- /dev/null +++ b/codeview/src/main/assets/training-set/c/adlist.c @@ -0,0 +1,341 @@ +/* adlist.c - A generic doubly linked list implementation + * + * Copyright (c) 2006-2010, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include "adlist.h" +#include "zmalloc.h" + +/* Create a new list. The created list can be freed with + * AlFreeList(), but private value of every node need to be freed + * by the user before to call AlFreeList(). + * + * On error, NULL is returned. Otherwise the pointer to the new list. */ +list *listCreate(void) +{ + struct list *list; + + if ((list = zmalloc(sizeof(*list))) == NULL) + return NULL; + list->head = list->tail = NULL; + list->len = 0; + list->dup = NULL; + list->free = NULL; + list->match = NULL; + return list; +} + +/* Free the whole list. + * + * This function can't fail. */ +void listRelease(list *list) +{ + unsigned long len; + listNode *current, *next; + + current = list->head; + len = list->len; + while(len--) { + next = current->next; + if (list->free) list->free(current->value); + zfree(current); + current = next; + } + zfree(list); +} + +/* Add a new node to the list, to head, containing the specified 'value' + * pointer as value. + * + * On error, NULL is returned and no operation is performed (i.e. the + * list remains unaltered). + * On success the 'list' pointer you pass to the function is returned. */ +list *listAddNodeHead(list *list, void *value) +{ + listNode *node; + + if ((node = zmalloc(sizeof(*node))) == NULL) + return NULL; + node->value = value; + if (list->len == 0) { + list->head = list->tail = node; + node->prev = node->next = NULL; + } else { + node->prev = NULL; + node->next = list->head; + list->head->prev = node; + list->head = node; + } + list->len++; + return list; +} + +/* Add a new node to the list, to tail, containing the specified 'value' + * pointer as value. + * + * On error, NULL is returned and no operation is performed (i.e. the + * list remains unaltered). + * On success the 'list' pointer you pass to the function is returned. */ +list *listAddNodeTail(list *list, void *value) +{ + listNode *node; + + if ((node = zmalloc(sizeof(*node))) == NULL) + return NULL; + node->value = value; + if (list->len == 0) { + list->head = list->tail = node; + node->prev = node->next = NULL; + } else { + node->prev = list->tail; + node->next = NULL; + list->tail->next = node; + list->tail = node; + } + list->len++; + return list; +} + +list *listInsertNode(list *list, listNode *old_node, void *value, int after) { + listNode *node; + + if ((node = zmalloc(sizeof(*node))) == NULL) + return NULL; + node->value = value; + if (after) { + node->prev = old_node; + node->next = old_node->next; + if (list->tail == old_node) { + list->tail = node; + } + } else { + node->next = old_node; + node->prev = old_node->prev; + if (list->head == old_node) { + list->head = node; + } + } + if (node->prev != NULL) { + node->prev->next = node; + } + if (node->next != NULL) { + node->next->prev = node; + } + list->len++; + return list; +} + +/* Remove the specified node from the specified list. + * It's up to the caller to free the private value of the node. + * + * This function can't fail. */ +void listDelNode(list *list, listNode *node) +{ + if (node->prev) + node->prev->next = node->next; + else + list->head = node->next; + if (node->next) + node->next->prev = node->prev; + else + list->tail = node->prev; + if (list->free) list->free(node->value); + zfree(node); + list->len--; +} + +/* Returns a list iterator 'iter'. After the initialization every + * call to listNext() will return the next element of the list. + * + * This function can't fail. */ +listIter *listGetIterator(list *list, int direction) +{ + listIter *iter; + + if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL; + if (direction == AL_START_HEAD) + iter->next = list->head; + else + iter->next = list->tail; + iter->direction = direction; + return iter; +} + +/* Release the iterator memory */ +void listReleaseIterator(listIter *iter) { + zfree(iter); +} + +/* Create an iterator in the list private iterator structure */ +void listRewind(list *list, listIter *li) { + li->next = list->head; + li->direction = AL_START_HEAD; +} + +void listRewindTail(list *list, listIter *li) { + li->next = list->tail; + li->direction = AL_START_TAIL; +} + +/* Return the next element of an iterator. + * It's valid to remove the currently returned element using + * listDelNode(), but not to remove other elements. + * + * The function returns a pointer to the next element of the list, + * or NULL if there are no more elements, so the classical usage patter + * is: + * + * iter = listGetIterator(list,); + * while ((node = listNext(iter)) != NULL) { + * doSomethingWith(listNodeValue(node)); + * } + * + * */ +listNode *listNext(listIter *iter) +{ + listNode *current = iter->next; + + if (current != NULL) { + if (iter->direction == AL_START_HEAD) + iter->next = current->next; + else + iter->next = current->prev; + } + return current; +} + +/* Duplicate the whole list. On out of memory NULL is returned. + * On success a copy of the original list is returned. + * + * The 'Dup' method set with listSetDupMethod() function is used + * to copy the node value. Otherwise the same pointer value of + * the original node is used as value of the copied node. + * + * The original list both on success or error is never modified. */ +list *listDup(list *orig) +{ + list *copy; + listIter *iter; + listNode *node; + + if ((copy = listCreate()) == NULL) + return NULL; + copy->dup = orig->dup; + copy->free = orig->free; + copy->match = orig->match; + iter = listGetIterator(orig, AL_START_HEAD); + while((node = listNext(iter)) != NULL) { + void *value; + + if (copy->dup) { + value = copy->dup(node->value); + if (value == NULL) { + listRelease(copy); + listReleaseIterator(iter); + return NULL; + } + } else + value = node->value; + if (listAddNodeTail(copy, value) == NULL) { + listRelease(copy); + listReleaseIterator(iter); + return NULL; + } + } + listReleaseIterator(iter); + return copy; +} + +/* Search the list for a node matching a given key. + * The match is performed using the 'match' method + * set with listSetMatchMethod(). If no 'match' method + * is set, the 'value' pointer of every node is directly + * compared with the 'key' pointer. + * + * On success the first matching node pointer is returned + * (search starts from head). If no matching node exists + * NULL is returned. */ +listNode *listSearchKey(list *list, void *key) +{ + listIter *iter; + listNode *node; + + iter = listGetIterator(list, AL_START_HEAD); + while((node = listNext(iter)) != NULL) { + if (list->match) { + if (list->match(node->value, key)) { + listReleaseIterator(iter); + return node; + } + } else { + if (key == node->value) { + listReleaseIterator(iter); + return node; + } + } + } + listReleaseIterator(iter); + return NULL; +} + +/* Return the element at the specified zero-based index + * where 0 is the head, 1 is the element next to head + * and so on. Negative integers are used in order to count + * from the tail, -1 is the last element, -2 the penultimate + * and so on. If the index is out of range NULL is returned. */ +listNode *listIndex(list *list, long index) { + listNode *n; + + if (index < 0) { + index = (-index)-1; + n = list->tail; + while(index-- && n) n = n->prev; + } else { + n = list->head; + while(index-- && n) n = n->next; + } + return n; +} + +/* Rotate the list removing the tail node and inserting it to the head. */ +void listRotate(list *list) { + listNode *tail = list->tail; + + if (listLength(list) <= 1) return; + + /* Detach current tail */ + list->tail = tail->prev; + list->tail->next = NULL; + /* Move it as head */ + list->head->prev = tail; + tail->prev = NULL; + tail->next = list->head; + list->head = tail; +} diff --git a/codeview/src/main/assets/training-set/c/async.c b/codeview/src/main/assets/training-set/c/async.c new file mode 100755 index 0000000..4c3773c --- /dev/null +++ b/codeview/src/main/assets/training-set/c/async.c @@ -0,0 +1,328 @@ +/* + * async.c: Asynchronous function calls for boot performance + * + * (C) Copyright 2009 Intel Corporation + * Author: Arjan van de Ven + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + + +/* + +Goals and Theory of Operation + +The primary goal of this feature is to reduce the kernel boot time, +by doing various independent hardware delays and discovery operations +decoupled and not strictly serialized. + +More specifically, the asynchronous function call concept allows +certain operations (primarily during system boot) to happen +asynchronously, out of order, while these operations still +have their externally visible parts happen sequentially and in-order. +(not unlike how out-of-order CPUs retire their instructions in order) + +Key to the asynchronous function call implementation is the concept of +a "sequence cookie" (which, although it has an abstracted type, can be +thought of as a monotonically incrementing number). + +The async core will assign each scheduled event such a sequence cookie and +pass this to the called functions. + +The asynchronously called function should before doing a globally visible +operation, such as registering device numbers, call the +async_synchronize_cookie() function and pass in its own cookie. The +async_synchronize_cookie() function will make sure that all asynchronous +operations that were scheduled prior to the operation corresponding with the +cookie have completed. + +Subsystem/driver initialization code that scheduled asynchronous probe +functions, but which shares global resources with other drivers/subsystems +that do not use the asynchronous call feature, need to do a full +synchronization with the async_synchronize_full() function, before returning +from their init function. This is to maintain strict ordering between the +asynchronous and synchronous parts of the kernel. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "workqueue_internal.h" + +static async_cookie_t next_cookie = 1; + +#define MAX_WORK 32768 +#define ASYNC_COOKIE_MAX ULLONG_MAX /* infinity cookie */ + +static LIST_HEAD(async_global_pending); /* pending from all registered doms */ +static ASYNC_DOMAIN(async_dfl_domain); +static DEFINE_SPINLOCK(async_lock); + +struct async_entry { + struct list_head domain_list; + struct list_head global_list; + struct work_struct work; + async_cookie_t cookie; + async_func_t func; + void *data; + struct async_domain *domain; +}; + +static DECLARE_WAIT_QUEUE_HEAD(async_done); + +static atomic_t entry_count; + +static async_cookie_t lowest_in_progress(struct async_domain *domain) +{ + struct list_head *pending; + async_cookie_t ret = ASYNC_COOKIE_MAX; + unsigned long flags; + + spin_lock_irqsave(&async_lock, flags); + + if (domain) + pending = &domain->pending; + else + pending = &async_global_pending; + + if (!list_empty(pending)) + ret = list_first_entry(pending, struct async_entry, + domain_list)->cookie; + + spin_unlock_irqrestore(&async_lock, flags); + return ret; +} + +/* + * pick the first pending entry and run it + */ +static void async_run_entry_fn(struct work_struct *work) +{ + struct async_entry *entry = + container_of(work, struct async_entry, work); + unsigned long flags; + ktime_t uninitialized_var(calltime), delta, rettime; + + /* 1) run (and print duration) */ + if (initcall_debug && system_state == SYSTEM_BOOTING) { + pr_debug("calling %lli_%pF @ %i\n", + (long long)entry->cookie, + entry->func, task_pid_nr(current)); + calltime = ktime_get(); + } + entry->func(entry->data, entry->cookie); + if (initcall_debug && system_state == SYSTEM_BOOTING) { + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + pr_debug("initcall %lli_%pF returned 0 after %lld usecs\n", + (long long)entry->cookie, + entry->func, + (long long)ktime_to_ns(delta) >> 10); + } + + /* 2) remove self from the pending queues */ + spin_lock_irqsave(&async_lock, flags); + list_del_init(&entry->domain_list); + list_del_init(&entry->global_list); + + /* 3) free the entry */ + kfree(entry); + atomic_dec(&entry_count); + + spin_unlock_irqrestore(&async_lock, flags); + + /* 4) wake up any waiters */ + wake_up(&async_done); +} + +static async_cookie_t __async_schedule(async_func_t func, void *data, struct async_domain *domain) +{ + struct async_entry *entry; + unsigned long flags; + async_cookie_t newcookie; + + /* allow irq-off callers */ + entry = kzalloc(sizeof(struct async_entry), GFP_ATOMIC); + + /* + * If we're out of memory or if there's too much work + * pending already, we execute synchronously. + */ + if (!entry || atomic_read(&entry_count) > MAX_WORK) { + kfree(entry); + spin_lock_irqsave(&async_lock, flags); + newcookie = next_cookie++; + spin_unlock_irqrestore(&async_lock, flags); + + /* low on memory.. run synchronously */ + func(data, newcookie); + return newcookie; + } + INIT_LIST_HEAD(&entry->domain_list); + INIT_LIST_HEAD(&entry->global_list); + INIT_WORK(&entry->work, async_run_entry_fn); + entry->func = func; + entry->data = data; + entry->domain = domain; + + spin_lock_irqsave(&async_lock, flags); + + /* allocate cookie and queue */ + newcookie = entry->cookie = next_cookie++; + + list_add_tail(&entry->domain_list, &domain->pending); + if (domain->registered) + list_add_tail(&entry->global_list, &async_global_pending); + + atomic_inc(&entry_count); + spin_unlock_irqrestore(&async_lock, flags); + + /* mark that this task has queued an async job, used by module init */ + current->flags |= PF_USED_ASYNC; + + /* schedule for execution */ + queue_work(system_unbound_wq, &entry->work); + + return newcookie; +} + +/** + * async_schedule - schedule a function for asynchronous execution + * @func: function to execute asynchronously + * @data: data pointer to pass to the function + * + * Returns an async_cookie_t that may be used for checkpointing later. + * Note: This function may be called from atomic or non-atomic contexts. + */ +async_cookie_t async_schedule(async_func_t func, void *data) +{ + return __async_schedule(func, data, &async_dfl_domain); +} +EXPORT_SYMBOL_GPL(async_schedule); + +/** + * async_schedule_domain - schedule a function for asynchronous execution within a certain domain + * @func: function to execute asynchronously + * @data: data pointer to pass to the function + * @domain: the domain + * + * Returns an async_cookie_t that may be used for checkpointing later. + * @domain may be used in the async_synchronize_*_domain() functions to + * wait within a certain synchronization domain rather than globally. A + * synchronization domain is specified via @domain. Note: This function + * may be called from atomic or non-atomic contexts. + */ +async_cookie_t async_schedule_domain(async_func_t func, void *data, + struct async_domain *domain) +{ + return __async_schedule(func, data, domain); +} +EXPORT_SYMBOL_GPL(async_schedule_domain); + +/** + * async_synchronize_full - synchronize all asynchronous function calls + * + * This function waits until all asynchronous function calls have been done. + */ +void async_synchronize_full(void) +{ + async_synchronize_full_domain(NULL); +} +EXPORT_SYMBOL_GPL(async_synchronize_full); + +/** + * async_unregister_domain - ensure no more anonymous waiters on this domain + * @domain: idle domain to flush out of any async_synchronize_full instances + * + * async_synchronize_{cookie|full}_domain() are not flushed since callers + * of these routines should know the lifetime of @domain + * + * Prefer ASYNC_DOMAIN_EXCLUSIVE() declarations over flushing + */ +void async_unregister_domain(struct async_domain *domain) +{ + spin_lock_irq(&async_lock); + WARN_ON(!domain->registered || !list_empty(&domain->pending)); + domain->registered = 0; + spin_unlock_irq(&async_lock); +} +EXPORT_SYMBOL_GPL(async_unregister_domain); + +/** + * async_synchronize_full_domain - synchronize all asynchronous function within a certain domain + * @domain: the domain to synchronize + * + * This function waits until all asynchronous function calls for the + * synchronization domain specified by @domain have been done. + */ +void async_synchronize_full_domain(struct async_domain *domain) +{ + async_synchronize_cookie_domain(ASYNC_COOKIE_MAX, domain); +} +EXPORT_SYMBOL_GPL(async_synchronize_full_domain); + +/** + * async_synchronize_cookie_domain - synchronize asynchronous function calls within a certain domain with cookie checkpointing + * @cookie: async_cookie_t to use as checkpoint + * @domain: the domain to synchronize (%NULL for all registered domains) + * + * This function waits until all asynchronous function calls for the + * synchronization domain specified by @domain submitted prior to @cookie + * have been done. + */ +void async_synchronize_cookie_domain(async_cookie_t cookie, struct async_domain *domain) +{ + ktime_t uninitialized_var(starttime), delta, endtime; + + if (initcall_debug && system_state == SYSTEM_BOOTING) { + pr_debug("async_waiting @ %i\n", task_pid_nr(current)); + starttime = ktime_get(); + } + + wait_event(async_done, lowest_in_progress(domain) >= cookie); + + if (initcall_debug && system_state == SYSTEM_BOOTING) { + endtime = ktime_get(); + delta = ktime_sub(endtime, starttime); + + pr_debug("async_continuing @ %i after %lli usec\n", + task_pid_nr(current), + (long long)ktime_to_ns(delta) >> 10); + } +} +EXPORT_SYMBOL_GPL(async_synchronize_cookie_domain); + +/** + * async_synchronize_cookie - synchronize asynchronous function calls with cookie checkpointing + * @cookie: async_cookie_t to use as checkpoint + * + * This function waits until all asynchronous function calls prior to @cookie + * have been done. + */ +void async_synchronize_cookie(async_cookie_t cookie) +{ + async_synchronize_cookie_domain(cookie, &async_dfl_domain); +} +EXPORT_SYMBOL_GPL(async_synchronize_cookie); + +/** + * current_is_async - is %current an async worker task? + * + * Returns %true if %current is an async worker task. + */ +bool current_is_async(void) +{ + struct worker *worker = current_wq_worker(); + + return worker && worker->current_func == async_run_entry_fn; +} diff --git a/codeview/src/main/assets/training-set/c/c.c b/codeview/src/main/assets/training-set/c/c.c new file mode 100755 index 0000000..be34952 --- /dev/null +++ b/codeview/src/main/assets/training-set/c/c.c @@ -0,0 +1,884 @@ + +// +// mon.c +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "commander.h" +#include "ms.h" + +/* + * Program version. + */ + +#define VERSION "1.1.1" + +/* + * Log prefix. + */ + +static const char *prefix = NULL; + +/* + * Monitor. + */ + +typedef struct { + const char *pidfile; + const char *mon_pidfile; + const char *logfile; + const char *on_error; + const char *on_restart; + int64_t last_restart_at; + int64_t clock; + int daemon; + int sleepsec; + int max_attempts; + int attempts; +} monitor_t; + +/* + * Logger. + */ + +#define log(fmt, args...) \ + do { \ + if (prefix) { \ + printf("mon : %s : " fmt "\n", prefix, ##args); \ + } else { \ + printf("mon : " fmt "\n", ##args); \ + } \ + } while(0) + +/* + * Output error `msg`. + */ + +void +error(char *msg) { + fprintf(stderr, "Error: %s\n", msg); + exit(1); +} + +/* + * Check if process of `pid` is alive. + */ + +int +alive(pid_t pid) { + return 0 == kill(pid, 0); +} + +/* + * Graceful exit, signal process group. + */ + +void +graceful_exit(int sig) { + pid_t pid = getpid(); + log("shutting down"); + log("kill(-%d, %d)", pid, sig); + kill(-pid, sig); + log("bye :)"); + exit(0); +} + +/* + * Return a timestamp in milliseconds. + */ + +int64_t +timestamp() { + struct timeval tv; + int ret = gettimeofday(&tv, NULL); + if (-1 == ret) return -1; + return (int64_t) ((int64_t) tv.tv_sec * 1000 + (int64_t) tv.tv_usec / 1000); +} + +/* + * Write `pid` to `file`. + */ + +void +write_pidfile(const char *file, pid_t pid) { + char buf[32] = { 0 }; + snprintf(buf, 32, "%d", pid); + int fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) perror("open()"); + write(fd, buf, 32); + close(fd); +} + +/* + * Output status of `pidfile`. + */ + +void +show_status_of(const char *pidfile) { + off_t size; + struct stat s; + + // stat + if (stat(pidfile, &s) < 0) { + perror("stat()"); + exit(1); + } + + size = s.st_size; + + // opens + int fd = open(pidfile, O_RDONLY, 0); + if (fd < 0) { + perror("open()"); + exit(1); + } + + // read + char buf[size]; + if (size != read(fd, buf, size)) { + perror("read()"); + exit(1); + } + + // uptime + time_t modified = s.st_mtime; + + struct timeval t; + gettimeofday(&t, NULL); + time_t now = t.tv_sec; + time_t secs = now - modified; + + // status + pid_t pid = atoi(buf); + + if (alive(pid)) { + char *str = milliseconds_to_long_string(secs * 1000); + printf("\e[90m%d\e[0m : \e[32malive\e[0m : uptime %s\e[m\n", pid, str); + free(str); + } + else { + printf("\e[90m%d\e[0m : \e[31mdead\e[0m\n", pid); + } + + close(fd); +} + +/* + * Redirect stdio to `file`. + */ + +void +redirect_stdio_to(const char *file) { + int logfd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0755); + int nullfd = open("/dev/null", O_RDONLY, 0); + + if (-1 == logfd) { + perror("open()"); + exit(1); + } + + if (-1 == nullfd) { + perror("open()"); + exit(1); + } + + dup2(nullfd, 0); + dup2(logfd, 1); + dup2(logfd, 2); +} + +/* + * Daemonize the program. + */ + +void +daemonize() { + if (fork()) exit(0); + + if (setsid() < 0) { + perror("setsid()"); + exit(1); + } +} + +/* + * Invoke the --on-restart command. + */ + +void +exec_restart_command(monitor_t *monitor) { + log("on restart `%s`", monitor->on_restart); + int status = system(monitor->on_restart); + if (status) log("exit(%d)", status); +} + +/* + * Invoke the --on-error command. + */ + +void +exec_error_command(monitor_t *monitor) { + log("on error `%s`", monitor->on_error); + int status = system(monitor->on_error); + if (status) log("exit(%d)", status); +} + +/* + * Return the ms since the last restart. + */ + +int64_t +ms_since_last_restart(monitor_t *monitor) { + if (0 == monitor->last_restart_at) return 0; + int64_t now = timestamp(); + return now - monitor->last_restart_at; +} + +/* + * Check if the maximum restarts within 60 seconds + * have been exceeded and return 1, 0 otherwise. + */ + +int +attempts_exceeded(monitor_t *monitor, int64_t ms) { + monitor->attempts++; + monitor->clock -= ms; + + // reset + if (monitor->clock <= 0) { + monitor->clock = 60000; + monitor->attempts = 0; + return 0; + } + + // all good + if (monitor->attempts < monitor->max_attempts) return 0; + + return 1; +} + +/* + * Monitor the given `cmd`. + */ + +void +start(const char *cmd, monitor_t *monitor) { +exec: { + pid_t pid = fork(); + int status; + + switch (pid) { + case -1: + perror("fork()"); + exit(1); + case 0: + signal(SIGTERM, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + log("sh -c \"%s\"", cmd); + execl("/bin/sh", "sh", "-c", cmd, 0); + perror("execl()"); + exit(1); + default: + log("child %d", pid); + + // write pidfile + if (monitor->pidfile) { + log("write pid to %s", monitor->pidfile); + write_pidfile(monitor->pidfile, pid); + } + + // wait for exit + waitpid(pid, &status, 0); + + // signalled + if (WIFSIGNALED(status)) { + log("signal(%s)", strsignal(WTERMSIG(status))); + log("sleep(%d)", monitor->sleepsec); + sleep(monitor->sleepsec); + goto error; + } + + // check status + if (WEXITSTATUS(status)) { + log("exit(%d)", WEXITSTATUS(status)); + log("sleep(%d)", monitor->sleepsec); + sleep(monitor->sleepsec); + goto error; + } + + // restart + error: { + if (monitor->on_restart) exec_restart_command(monitor); + int64_t ms = ms_since_last_restart(monitor); + monitor->last_restart_at = timestamp(); + log("last restart %s ago", milliseconds_to_long_string(ms)); + log("%d attempts remaining", monitor->max_attempts - monitor->attempts); + + if (attempts_exceeded(monitor, ms)) { + char *time = milliseconds_to_long_string(60000 - monitor->clock); + log("%d restarts within %s, bailing", monitor->max_attempts, time); + exec_error_command(monitor); + log("bye :)"); + exit(2); + } + + goto exec; + } + } +} +} + +/* + * --log + */ + +static void +on_log(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + monitor->logfile = self->arg; +} + +/* + * --sleep + */ + +static void +on_sleep(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + monitor->sleepsec = atoi(self->arg); +} + +/* + * --daemonize + */ + +static void +on_daemonize(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + monitor->daemon = 1; +} + +/* + * --pidfile + */ + +static void +on_pidfile(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + monitor->pidfile = self->arg; +} + +/* + * --mon-pidfile + */ + +static void +on_mon_pidfile(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + monitor->mon_pidfile = self->arg; +} + +/* + * --status + */ + +static void +on_status(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + if (!monitor->pidfile) error("--pidfile required"); + show_status_of(monitor->pidfile); + exit(0); +} + +/* + * --prefix + */ + +static void +on_prefix(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + prefix = self->arg; +} + +/* + * --on-restart + */ + +static void +on_restart(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + monitor->on_restart = self->arg; +} + +/* + * --on-error + */ + +static void +on_error(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + monitor->on_error = self->arg; +} + +/* + * --attempts + */ + +static void +on_attempts(command_t *self) { + monitor_t *monitor = (monitor_t *) self->data; + monitor->max_attempts = atoi(self->arg); +} + +/* + * [options] + */ + +int +main(int argc, char **argv){ + monitor_t monitor; + monitor.pidfile = NULL; + monitor.mon_pidfile = NULL; + monitor.on_restart = NULL; + monitor.on_error = NULL; + monitor.logfile = "mon.log"; + monitor.daemon = 0; + monitor.sleepsec = 1; + monitor.max_attempts = 10; + monitor.attempts = 0; + monitor.last_restart_at = 0; + monitor.clock = 60000; + + command_t program; + command_init(&program, "mon", VERSION); + program.data = &monitor; + program.usage = "[options] "; + command_option(&program, "-l", "--log ", "specify logfile [mon.log]", on_log); + command_option(&program, "-s", "--sleep ", "sleep seconds before re-executing [1]", on_sleep); + command_option(&program, "-S", "--status", "check status of --pidfile", on_status); + command_option(&program, "-p", "--pidfile ", "write pid to ", on_pidfile); + command_option(&program, "-m", "--mon-pidfile ", "write mon(1) pid to ", on_mon_pidfile); + command_option(&program, "-P", "--prefix ", "add a log prefix", on_prefix); + command_option(&program, "-d", "--daemonize", "daemonize the program", on_daemonize); + command_option(&program, "-a", "--attempts ", "retry attempts within 60 seconds [10]", on_attempts); + command_option(&program, "-R", "--on-restart ", "execute on restarts", on_restart); + command_option(&program, "-E", "--on-error ", "execute on error", on_error); + command_parse(&program, argc, argv); + + // command required + if (!program.argc) error(" required"); + const char *cmd = program.argv[0]; + + // signals + signal(SIGTERM, graceful_exit); + signal(SIGQUIT, graceful_exit); + + // daemonize + if (monitor.daemon) { + daemonize(); + redirect_stdio_to(monitor.logfile); + } + + // write mon pidfile + if (monitor.mon_pidfile) { + log("write mon pid to %s", monitor.mon_pidfile); + write_pidfile(monitor.mon_pidfile, getpid()); + } + + start(cmd, &monitor); + + return 0; +} + + + +// +// term.c +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#include +#include +#include +#include "term.h" + +/* + * X pos. + */ + +static int _x = 0; + +/* + * Y pos. + */ + +static int _y = 0; + +/* + * Move to `(x, y)`. + */ + +void +term_move_to(int x, int y) { + _x = x; + _y = y; + printf("\e[%d;%d;f", y, x); +} + +/* + * Move by `(x, y)`. + */ + +void +term_move_by(int x, int y) { + term_move_to(_x + x, _y + y); +} + +/* + * Set `w` and `h` to the terminal dimensions. + */ + +int +term_size(int *w, int *h) { + struct winsize ws; + int ret = ioctl(0, TIOCGWINSZ, &ws); + if (ret < 0) return ret; + *w = ws.ws_col; + *h = ws.ws_row; +} + +/* + * Return the erase code for `name` or -1. + */ + +const char * +term_erase_from_name(const char *name) { + if (!strcmp("end", name)) return "K"; + if (!strcmp("start", name)) return "1K"; + if (!strcmp("line", name)) return "2K"; + if (!strcmp("up", name)) return "1J"; + if (!strcmp("down", name)) return "J"; + if (!strcmp("screen", name)) return "1J"; + return NULL; +} + +/* + * Erase with `name`: + * + * - "end" + * - "start" + * - "line" + * - "up" + * - "down" + * - "screen" + * + */ + +int +term_erase(const char *name) { + const char *s = term_erase_from_name(name); + if (!s) return -1; + printf("\e[%s", s); + return 0; +} + +/* + * Return the color code for `name` or -1. + */ + +int +term_color_from_name(const char *name) { + if (!strcmp("black", name)) return 0; + if (!strcmp("red", name)) return 1; + if (!strcmp("green", name)) return 2; + if (!strcmp("yellow", name)) return 3; + if (!strcmp("blue", name)) return 4; + if (!strcmp("magenta", name)) return 5; + if (!strcmp("cyan", name)) return 6; + if (!strcmp("white", name)) return 7; + return -1; +} + +/* + * Set color by `name` or return -1. + */ + +int +term_color(const char *name) { + // TODO: refactor term_color_from_name() + if (!strcmp("gray", name) || !strcmp("grey", name)) { + printf("\e[90m"); + return 0; + } + + int n = term_color_from_name(name); + if (-1 == n) return n; + printf("\e[3%dm", n); + return 0; +} + +/* + * Set background color by `name` or return -1. + */ + +int +term_background(const char *name) { + int n = term_color_from_name(name); + if (-1 == n) return n; + printf("\e[4%dm", n); + return 0; +} + +// +// ms.c +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#include +#include +#include +#include "ms.h" + +// microseconds + +#define US_SEC 1000000 +#define US_MIN 60 * US_SEC +#define US_HOUR 60 * US_MIN +#define US_DAY 24 * US_HOUR +#define US_WEEK 7 * US_HOUR +#define US_YEAR 52 * US_WEEK + +// milliseconds + +#define MS_SEC 1000 +#define MS_MIN 60000 +#define MS_HOUR 3600000 +#define MS_DAY 86400000 +#define MS_WEEK 604800000 +#define MS_YEAR 31557600000 + +/* + * Convert the given `str` representation to microseconds, + * for example "10ms", "5s", "2m", "1h" etc. + */ + +long long +string_to_microseconds(const char *str) { + size_t len = strlen(str); + long long val = strtoll(str, NULL, 10); + if (!val) return -1; + switch (str[len - 1]) { + case 's': return 'm' == str[len - 2] ? val * 1000 : val * US_SEC; + case 'm': return val * US_MIN; + case 'h': return val * US_HOUR; + case 'd': return val * US_DAY; + case 'w': return val * US_WEEK; + case 'y': return val * US_YEAR; + default: return val; + } +} + +/* + * Convert the given `str` representation to milliseconds, + * for example "10ms", "5s", "2m", "1h" etc. + */ + +long long +string_to_milliseconds(const char *str) { + size_t len = strlen(str); + long long val = strtoll(str, NULL, 10); + if (!val) return -1; + switch (str[len - 1]) { + case 's': return 'm' == str[len - 2] ? val : val * 1000; + case 'm': return val * MS_MIN; + case 'h': return val * MS_HOUR; + case 'd': return val * MS_DAY; + case 'w': return val * MS_WEEK; + case 'y': return val * MS_YEAR; + default: return val; + } +} + +/* + * Convert the given `str` representation to seconds. + */ + +long long +string_to_seconds(const char *str) { + long long ret = string_to_milliseconds(str); + if (-1 == ret) return ret; + return ret / 1000; +} + +/* + * Convert the given `ms` to a string. This + * value must be `free()`d by the developer. + */ + +char * +milliseconds_to_string(long long ms) { + char *str = malloc(MS_MAX); + if (!str) return NULL; + long div = 1; + char *fmt; + + if (ms < MS_SEC) fmt = "%lldms"; + else if (ms < MS_MIN) { fmt = "%llds"; div = MS_SEC; } + else if (ms < MS_HOUR) { fmt = "%lldm"; div = MS_MIN; } + else if (ms < MS_DAY) { fmt = "%lldh"; div = MS_HOUR; } + else if (ms < MS_WEEK) { fmt = "%lldd"; div = MS_DAY; } + else if (ms < MS_YEAR) { fmt = "%lldw"; div = MS_WEEK; } + else { fmt = "%lldy"; div = MS_YEAR; } + snprintf(str, MS_MAX, fmt, ms / div); + + return str; +} + +/* + * Convert the given `ms` to a long string. This + * value must be `free()`d by the developer. + */ + +char * +milliseconds_to_long_string(long long ms) { + long div; + char *name; + + char *str = malloc(MS_MAX); + if (!str) return NULL; + + if (ms < MS_SEC) { + sprintf(str, "less than one second"); + return str; + } + + if (ms < MS_MIN) { name = "second"; div = MS_SEC; } + else if (ms < MS_HOUR) { name = "minute"; div = MS_MIN; } + else if (ms < MS_DAY) { name = "hour"; div = MS_HOUR; } + else if (ms < MS_WEEK) { name = "day"; div = MS_DAY; } + else if (ms < MS_YEAR) { name = "week"; div = MS_WEEK; } + else { name = "year"; div = MS_YEAR; } + + long long val = ms / div; + char *fmt = 1 == val + ? "%lld %s" + : "%lld %ss"; + + snprintf(str, MS_MAX, fmt, val, name); + return str; +} + +// tests + +#ifdef TEST_MS + +#include + +void +equal(char *a, char *b) { + if (strcmp(a, b)) { + printf("expected: %s\n", a); + printf("actual: %s\n", b); + exit(1); + } +} + +void +test_string_to_microseconds() { + assert(string_to_microseconds("") == -1); + assert(string_to_microseconds("s") == -1); + assert(string_to_microseconds("hey") == -1); + assert(string_to_microseconds("5000") == 5000); + assert(string_to_microseconds("1ms") == 1000); + assert(string_to_microseconds("5ms") == 5000); + assert(string_to_microseconds("1s") == 1000000); + assert(string_to_microseconds("5s") == 5000000); + assert(string_to_microseconds("1m") == 60000000); + assert(string_to_microseconds("1h") == 3600000000); + assert(string_to_microseconds("2d") == 2 * 24 * 3600000000); +} + +void +test_string_to_milliseconds() { + assert(string_to_milliseconds("") == -1); + assert(string_to_milliseconds("s") == -1); + assert(string_to_milliseconds("hey") == -1); + assert(string_to_milliseconds("5000") == 5000); + assert(string_to_milliseconds("1ms") == 1); + assert(string_to_milliseconds("5ms") == 5); + assert(string_to_milliseconds("1s") == 1000); + assert(string_to_milliseconds("5s") == 5000); + assert(string_to_milliseconds("1m") == 60 * 1000); + assert(string_to_milliseconds("1h") == 60 * 60 * 1000); + assert(string_to_milliseconds("1d") == 24 * 60 * 60 * 1000); +} + +void +test_string_to_seconds() { + assert(string_to_seconds("") == -1); + assert(string_to_seconds("s") == -1); + assert(string_to_seconds("hey") == -1); + assert(string_to_seconds("5000") == 5); + assert(string_to_seconds("1ms") == 0); + assert(string_to_seconds("5ms") == 0); + assert(string_to_seconds("1s") == 1); + assert(string_to_seconds("5s") == 5); + assert(string_to_seconds("1m") == 60); + assert(string_to_seconds("1h") == 60 * 60); + assert(string_to_seconds("1d") == 24 * 60 * 60); +} + +void +test_milliseconds_to_string() { + equal("500ms", milliseconds_to_string(500)); + equal("5s", milliseconds_to_string(5000)); + equal("2s", milliseconds_to_string(2500)); + equal("1m", milliseconds_to_string(MS_MIN)); + equal("5m", milliseconds_to_string(5 * MS_MIN)); + equal("1h", milliseconds_to_string(MS_HOUR)); + equal("2d", milliseconds_to_string(2 * MS_DAY)); + equal("2w", milliseconds_to_string(15 * MS_DAY)); + equal("3y", milliseconds_to_string(3 * MS_YEAR)); +} + +void +test_milliseconds_to_long_string() { + equal("less than one second", milliseconds_to_long_string(500)); + equal("5 seconds", milliseconds_to_long_string(5000)); + equal("2 seconds", milliseconds_to_long_string(2500)); + equal("1 minute", milliseconds_to_long_string(MS_MIN)); + equal("5 minutes", milliseconds_to_long_string(5 * MS_MIN)); + equal("1 hour", milliseconds_to_long_string(MS_HOUR)); + equal("2 days", milliseconds_to_long_string(2 * MS_DAY)); + equal("2 weeks", milliseconds_to_long_string(15 * MS_DAY)); + equal("1 year", milliseconds_to_long_string(MS_YEAR)); + equal("3 years", milliseconds_to_long_string(3 * MS_YEAR)); +} + +int +main(){ + test_string_to_microseconds(); + test_string_to_milliseconds(); + test_string_to_seconds(); + test_milliseconds_to_string(); + test_milliseconds_to_long_string(); + printf("\n \e[32m\u2713 \e[90mok\e[0m\n\n"); + return 0; +} + +#endif diff --git a/codeview/src/main/assets/training-set/c/cluster.c b/codeview/src/main/assets/training-set/c/cluster.c new file mode 100755 index 0000000..fb45bd0 --- /dev/null +++ b/codeview/src/main/assets/training-set/c/cluster.c @@ -0,0 +1,5007 @@ +/* Redis Cluster implementation. + * + * Copyright (c) 2009-2012, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "redis.h" +#include "cluster.h" +#include "endianconv.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* A global reference to myself is handy to make code more clear. + * Myself always points to server.cluster->myself, that is, the clusterNode + * that represents this node. */ +clusterNode *myself = NULL; + +clusterNode *createClusterNode(char *nodename, int flags); +int clusterAddNode(clusterNode *node); +void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask); +void clusterReadHandler(aeEventLoop *el, int fd, void *privdata, int mask); +void clusterSendPing(clusterLink *link, int type); +void clusterSendFail(char *nodename); +void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request); +void clusterUpdateState(void); +int clusterNodeGetSlotBit(clusterNode *n, int slot); +sds clusterGenNodesDescription(int filter); +clusterNode *clusterLookupNode(char *name); +int clusterNodeAddSlave(clusterNode *master, clusterNode *slave); +int clusterAddSlot(clusterNode *n, int slot); +int clusterDelSlot(int slot); +int clusterDelNodeSlots(clusterNode *node); +int clusterNodeSetSlotBit(clusterNode *n, int slot); +void clusterSetMaster(clusterNode *n); +void clusterHandleSlaveFailover(void); +void clusterHandleSlaveMigration(int max_slaves); +int bitmapTestBit(unsigned char *bitmap, int pos); +void clusterDoBeforeSleep(int flags); +void clusterSendUpdate(clusterLink *link, clusterNode *node); +void resetManualFailover(void); +void clusterCloseAllSlots(void); +void clusterSetNodeAsMaster(clusterNode *n); +void clusterDelNode(clusterNode *delnode); +sds representRedisNodeFlags(sds ci, uint16_t flags); +uint64_t clusterGetMaxEpoch(void); +int clusterBumpConfigEpochWithoutConsensus(void); + +/* ----------------------------------------------------------------------------- + * Initialization + * -------------------------------------------------------------------------- */ + +/* Load the cluster config from 'filename'. + * + * If the file does not exist or is zero-length (this may happen because + * when we lock the nodes.conf file, we create a zero-length one for the + * sake of locking if it does not already exist), REDIS_ERR is returned. + * If the configuration was loaded from the file, REDIS_OK is returned. */ +int clusterLoadConfig(char *filename) { + FILE *fp = fopen(filename,"r"); + struct stat sb; + char *line; + int maxline, j; + + if (fp == NULL) { + if (errno == ENOENT) { + return REDIS_ERR; + } else { + redisLog(REDIS_WARNING, + "Loading the cluster node config from %s: %s", + filename, strerror(errno)); + exit(1); + } + } + + /* Check if the file is zero-length: if so return REDIS_ERR to signal + * we have to write the config. */ + if (fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) { + fclose(fp); + return REDIS_ERR; + } + + /* Parse the file. Note that single lines of the cluster config file can + * be really long as they include all the hash slots of the node. + * This means in the worst possible case, half of the Redis slots will be + * present in a single line, possibly in importing or migrating state, so + * together with the node ID of the sender/receiver. + * + * To simplify we allocate 1024+REDIS_CLUSTER_SLOTS*128 bytes per line. */ + maxline = 1024+REDIS_CLUSTER_SLOTS*128; + line = zmalloc(maxline); + while(fgets(line,maxline,fp) != NULL) { + int argc; + sds *argv; + clusterNode *n, *master; + char *p, *s; + + /* Skip blank lines, they can be created either by users manually + * editing nodes.conf or by the config writing process if stopped + * before the truncate() call. */ + if (line[0] == '\n') continue; + + /* Split the line into arguments for processing. */ + argv = sdssplitargs(line,&argc); + if (argv == NULL) goto fmterr; + + /* Handle the special "vars" line. Don't pretend it is the last + * line even if it actually is when generated by Redis. */ + if (strcasecmp(argv[0],"vars") == 0) { + for (j = 1; j < argc; j += 2) { + if (strcasecmp(argv[j],"currentEpoch") == 0) { + server.cluster->currentEpoch = + strtoull(argv[j+1],NULL,10); + } else if (strcasecmp(argv[j],"lastVoteEpoch") == 0) { + server.cluster->lastVoteEpoch = + strtoull(argv[j+1],NULL,10); + } else { + redisLog(REDIS_WARNING, + "Skipping unknown cluster config variable '%s'", + argv[j]); + } + } + sdsfreesplitres(argv,argc); + continue; + } + + /* Regular config lines have at least eight fields */ + if (argc < 8) goto fmterr; + + /* Create this node if it does not exist */ + n = clusterLookupNode(argv[0]); + if (!n) { + n = createClusterNode(argv[0],0); + clusterAddNode(n); + } + /* Address and port */ + if ((p = strrchr(argv[1],':')) == NULL) goto fmterr; + *p = '\0'; + memcpy(n->ip,argv[1],strlen(argv[1])+1); + n->port = atoi(p+1); + + /* Parse flags */ + p = s = argv[2]; + while(p) { + p = strchr(s,','); + if (p) *p = '\0'; + if (!strcasecmp(s,"myself")) { + redisAssert(server.cluster->myself == NULL); + myself = server.cluster->myself = n; + n->flags |= REDIS_NODE_MYSELF; + } else if (!strcasecmp(s,"master")) { + n->flags |= REDIS_NODE_MASTER; + } else if (!strcasecmp(s,"slave")) { + n->flags |= REDIS_NODE_SLAVE; + } else if (!strcasecmp(s,"fail?")) { + n->flags |= REDIS_NODE_PFAIL; + } else if (!strcasecmp(s,"fail")) { + n->flags |= REDIS_NODE_FAIL; + n->fail_time = mstime(); + } else if (!strcasecmp(s,"handshake")) { + n->flags |= REDIS_NODE_HANDSHAKE; + } else if (!strcasecmp(s,"noaddr")) { + n->flags |= REDIS_NODE_NOADDR; + } else if (!strcasecmp(s,"noflags")) { + /* nothing to do */ + } else { + redisPanic("Unknown flag in redis cluster config file"); + } + if (p) s = p+1; + } + + /* Get master if any. Set the master and populate master's + * slave list. */ + if (argv[3][0] != '-') { + master = clusterLookupNode(argv[3]); + if (!master) { + master = createClusterNode(argv[3],0); + clusterAddNode(master); + } + n->slaveof = master; + clusterNodeAddSlave(master,n); + } + + /* Set ping sent / pong received timestamps */ + if (atoi(argv[4])) n->ping_sent = mstime(); + if (atoi(argv[5])) n->pong_received = mstime(); + + /* Set configEpoch for this node. */ + n->configEpoch = strtoull(argv[6],NULL,10); + + /* Populate hash slots served by this instance. */ + for (j = 8; j < argc; j++) { + int start, stop; + + if (argv[j][0] == '[') { + /* Here we handle migrating / importing slots */ + int slot; + char direction; + clusterNode *cn; + + p = strchr(argv[j],'-'); + redisAssert(p != NULL); + *p = '\0'; + direction = p[1]; /* Either '>' or '<' */ + slot = atoi(argv[j]+1); + p += 3; + cn = clusterLookupNode(p); + if (!cn) { + cn = createClusterNode(p,0); + clusterAddNode(cn); + } + if (direction == '>') { + server.cluster->migrating_slots_to[slot] = cn; + } else { + server.cluster->importing_slots_from[slot] = cn; + } + continue; + } else if ((p = strchr(argv[j],'-')) != NULL) { + *p = '\0'; + start = atoi(argv[j]); + stop = atoi(p+1); + } else { + start = stop = atoi(argv[j]); + } + while(start <= stop) clusterAddSlot(n, start++); + } + + sdsfreesplitres(argv,argc); + } + /* Config sanity check */ + if (server.cluster->myself == NULL) goto fmterr; + + zfree(line); + fclose(fp); + + redisLog(REDIS_NOTICE,"Node configuration loaded, I'm %.40s", myself->name); + + /* Something that should never happen: currentEpoch smaller than + * the max epoch found in the nodes configuration. However we handle this + * as some form of protection against manual editing of critical files. */ + if (clusterGetMaxEpoch() > server.cluster->currentEpoch) { + server.cluster->currentEpoch = clusterGetMaxEpoch(); + } + return REDIS_OK; + +fmterr: + redisLog(REDIS_WARNING, + "Unrecoverable error: corrupted cluster config file."); + zfree(line); + if (fp) fclose(fp); + exit(1); +} + +/* Cluster node configuration is exactly the same as CLUSTER NODES output. + * + * This function writes the node config and returns 0, on error -1 + * is returned. + * + * Note: we need to write the file in an atomic way from the point of view + * of the POSIX filesystem semantics, so that if the server is stopped + * or crashes during the write, we'll end with either the old file or the + * new one. Since we have the full payload to write available we can use + * a single write to write the whole file. If the pre-existing file was + * bigger we pad our payload with newlines that are anyway ignored and truncate + * the file afterward. */ +int clusterSaveConfig(int do_fsync) { + sds ci; + size_t content_size; + struct stat sb; + int fd; + + server.cluster->todo_before_sleep &= ~CLUSTER_TODO_SAVE_CONFIG; + + /* Get the nodes description and concatenate our "vars" directive to + * save currentEpoch and lastVoteEpoch. */ + ci = clusterGenNodesDescription(REDIS_NODE_HANDSHAKE); + ci = sdscatprintf(ci,"vars currentEpoch %llu lastVoteEpoch %llu\n", + (unsigned long long) server.cluster->currentEpoch, + (unsigned long long) server.cluster->lastVoteEpoch); + content_size = sdslen(ci); + + if ((fd = open(server.cluster_configfile,O_WRONLY|O_CREAT,0644)) + == -1) goto err; + + /* Pad the new payload if the existing file length is greater. */ + if (fstat(fd,&sb) != -1) { + if (sb.st_size > (off_t)content_size) { + ci = sdsgrowzero(ci,sb.st_size); + memset(ci+content_size,'\n',sb.st_size-content_size); + } + } + if (write(fd,ci,sdslen(ci)) != (ssize_t)sdslen(ci)) goto err; + if (do_fsync) { + server.cluster->todo_before_sleep &= ~CLUSTER_TODO_FSYNC_CONFIG; + fsync(fd); + } + + /* Truncate the file if needed to remove the final \n padding that + * is just garbage. */ + if (content_size != sdslen(ci) && ftruncate(fd,content_size) == -1) { + /* ftruncate() failing is not a critical error. */ + } + close(fd); + sdsfree(ci); + return 0; + +err: + if (fd != -1) close(fd); + sdsfree(ci); + return -1; +} + +void clusterSaveConfigOrDie(int do_fsync) { + if (clusterSaveConfig(do_fsync) == -1) { + redisLog(REDIS_WARNING,"Fatal: can't update cluster config file."); + exit(1); + } +} + +/* Lock the cluster config using flock(), and leaks the file descritor used to + * acquire the lock so that the file will be locked forever. + * + * This works because we always update nodes.conf with a new version + * in-place, reopening the file, and writing to it in place (later adjusting + * the length with ftruncate()). + * + * On success REDIS_OK is returned, otherwise an error is logged and + * the function returns REDIS_ERR to signal a lock was not acquired. */ +int clusterLockConfig(char *filename) { + /* To lock it, we need to open the file in a way it is created if + * it does not exist, otherwise there is a race condition with other + * processes. */ + int fd = open(filename,O_WRONLY|O_CREAT,0644); + if (fd == -1) { + redisLog(REDIS_WARNING, + "Can't open %s in order to acquire a lock: %s", + filename, strerror(errno)); + return REDIS_ERR; + } + + if (flock(fd,LOCK_EX|LOCK_NB) == -1) { + if (errno == EWOULDBLOCK) { + redisLog(REDIS_WARNING, + "Sorry, the cluster configuration file %s is already used " + "by a different Redis Cluster node. Please make sure that " + "different nodes use different cluster configuration " + "files.", filename); + } else { + redisLog(REDIS_WARNING, + "Impossible to lock %s: %s", filename, strerror(errno)); + } + close(fd); + return REDIS_ERR; + } + /* Lock acquired: leak the 'fd' by not closing it, so that we'll retain the + * lock to the file as long as the process exists. */ + return REDIS_OK; +} + +void clusterInit(void) { + int saveconf = 0; + + server.cluster = zmalloc(sizeof(clusterState)); + server.cluster->myself = NULL; + server.cluster->currentEpoch = 0; + server.cluster->state = REDIS_CLUSTER_FAIL; + server.cluster->size = 1; + server.cluster->todo_before_sleep = 0; + server.cluster->nodes = dictCreate(&clusterNodesDictType,NULL); + server.cluster->nodes_black_list = + dictCreate(&clusterNodesBlackListDictType,NULL); + server.cluster->failover_auth_time = 0; + server.cluster->failover_auth_count = 0; + server.cluster->failover_auth_rank = 0; + server.cluster->failover_auth_epoch = 0; + server.cluster->cant_failover_reason = REDIS_CLUSTER_CANT_FAILOVER_NONE; + server.cluster->lastVoteEpoch = 0; + server.cluster->stats_bus_messages_sent = 0; + server.cluster->stats_bus_messages_received = 0; + memset(server.cluster->slots,0, sizeof(server.cluster->slots)); + clusterCloseAllSlots(); + + /* Lock the cluster config file to make sure every node uses + * its own nodes.conf. */ + if (clusterLockConfig(server.cluster_configfile) == REDIS_ERR) + exit(1); + + /* Load or create a new nodes configuration. */ + if (clusterLoadConfig(server.cluster_configfile) == REDIS_ERR) { + /* No configuration found. We will just use the random name provided + * by the createClusterNode() function. */ + myself = server.cluster->myself = + createClusterNode(NULL,REDIS_NODE_MYSELF|REDIS_NODE_MASTER); + redisLog(REDIS_NOTICE,"No cluster configuration found, I'm %.40s", + myself->name); + clusterAddNode(myself); + saveconf = 1; + } + if (saveconf) clusterSaveConfigOrDie(1); + + /* We need a listening TCP port for our cluster messaging needs. */ + server.cfd_count = 0; + + /* Port sanity check II + * The other handshake port check is triggered too late to stop + * us from trying to use a too-high cluster port number. */ + if (server.port > (65535-REDIS_CLUSTER_PORT_INCR)) { + redisLog(REDIS_WARNING, "Redis port number too high. " + "Cluster communication port is 10,000 port " + "numbers higher than your Redis port. " + "Your Redis port number must be " + "lower than 55535."); + exit(1); + } + + if (listenToPort(server.port+REDIS_CLUSTER_PORT_INCR, + server.cfd,&server.cfd_count) == REDIS_ERR) + { + exit(1); + } else { + int j; + + for (j = 0; j < server.cfd_count; j++) { + if (aeCreateFileEvent(server.el, server.cfd[j], AE_READABLE, + clusterAcceptHandler, NULL) == AE_ERR) + redisPanic("Unrecoverable error creating Redis Cluster " + "file event."); + } + } + + /* The slots -> keys map is a sorted set. Init it. */ + server.cluster->slots_to_keys = zslCreate(); + + /* Set myself->port to my listening port, we'll just need to discover + * the IP address via MEET messages. */ + myself->port = server.port; + + server.cluster->mf_end = 0; + resetManualFailover(); +} + +/* Reset a node performing a soft or hard reset: + * + * 1) All other nodes are forget. + * 2) All the assigned / open slots are released. + * 3) If the node is a slave, it turns into a master. + * 5) Only for hard reset: a new Node ID is generated. + * 6) Only for hard reset: currentEpoch and configEpoch are set to 0. + * 7) The new configuration is saved and the cluster state updated. + * 8) If the node was a slave, the whole data set is flushed away. */ +void clusterReset(int hard) { + dictIterator *di; + dictEntry *de; + int j; + + /* Turn into master. */ + if (nodeIsSlave(myself)) { + clusterSetNodeAsMaster(myself); + replicationUnsetMaster(); + emptyDb(NULL); + } + + /* Close slots, reset manual failover state. */ + clusterCloseAllSlots(); + resetManualFailover(); + + /* Unassign all the slots. */ + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) clusterDelSlot(j); + + /* Forget all the nodes, but myself. */ + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + + if (node == myself) continue; + clusterDelNode(node); + } + dictReleaseIterator(di); + + /* Hard reset only: set epochs to 0, change node ID. */ + if (hard) { + sds oldname; + + server.cluster->currentEpoch = 0; + server.cluster->lastVoteEpoch = 0; + myself->configEpoch = 0; + redisLog(REDIS_WARNING, "configEpoch set to 0 via CLUSTER RESET HARD"); + + /* To change the Node ID we need to remove the old name from the + * nodes table, change the ID, and re-add back with new name. */ + oldname = sdsnewlen(myself->name, REDIS_CLUSTER_NAMELEN); + dictDelete(server.cluster->nodes,oldname); + sdsfree(oldname); + getRandomHexChars(myself->name, REDIS_CLUSTER_NAMELEN); + clusterAddNode(myself); + } + + /* Make sure to persist the new config and update the state. */ + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE| + CLUSTER_TODO_FSYNC_CONFIG); +} + +/* ----------------------------------------------------------------------------- + * CLUSTER communication link + * -------------------------------------------------------------------------- */ + +clusterLink *createClusterLink(clusterNode *node) { + clusterLink *link = zmalloc(sizeof(*link)); + link->ctime = mstime(); + link->sndbuf = sdsempty(); + link->rcvbuf = sdsempty(); + link->node = node; + link->fd = -1; + return link; +} + +/* Free a cluster link, but does not free the associated node of course. + * This function will just make sure that the original node associated + * with this link will have the 'link' field set to NULL. */ +void freeClusterLink(clusterLink *link) { + if (link->fd != -1) { + aeDeleteFileEvent(server.el, link->fd, AE_WRITABLE); + aeDeleteFileEvent(server.el, link->fd, AE_READABLE); + } + sdsfree(link->sndbuf); + sdsfree(link->rcvbuf); + if (link->node) + link->node->link = NULL; + close(link->fd); + zfree(link); +} + +#define MAX_CLUSTER_ACCEPTS_PER_CALL 1000 +void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) { + int cport, cfd; + int max = MAX_CLUSTER_ACCEPTS_PER_CALL; + char cip[REDIS_IP_STR_LEN]; + clusterLink *link; + REDIS_NOTUSED(el); + REDIS_NOTUSED(mask); + REDIS_NOTUSED(privdata); + + /* If the server is starting up, don't accept cluster connections: + * UPDATE messages may interact with the database content. */ + if (server.masterhost == NULL && server.loading) return; + + while(max--) { + cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport); + if (cfd == ANET_ERR) { + if (errno != EWOULDBLOCK) + redisLog(REDIS_VERBOSE, + "Error accepting cluster node: %s", server.neterr); + return; + } + anetNonBlock(NULL,cfd); + anetEnableTcpNoDelay(NULL,cfd); + + /* Use non-blocking I/O for cluster messages. */ + redisLog(REDIS_VERBOSE,"Accepted cluster node %s:%d", cip, cport); + /* Create a link object we use to handle the connection. + * It gets passed to the readable handler when data is available. + * Initiallly the link->node pointer is set to NULL as we don't know + * which node is, but the right node is references once we know the + * node identity. */ + link = createClusterLink(NULL); + link->fd = cfd; + aeCreateFileEvent(server.el,cfd,AE_READABLE,clusterReadHandler,link); + } +} + +/* ----------------------------------------------------------------------------- + * Key space handling + * -------------------------------------------------------------------------- */ + +/* We have 16384 hash slots. The hash slot of a given key is obtained + * as the least significant 14 bits of the crc16 of the key. + * + * However if the key contains the {...} pattern, only the part between + * { and } is hashed. This may be useful in the future to force certain + * keys to be in the same node (assuming no resharding is in progress). */ +unsigned int keyHashSlot(char *key, int keylen) { + int s, e; /* start-end indexes of { and } */ + + for (s = 0; s < keylen; s++) + if (key[s] == '{') break; + + /* No '{' ? Hash the whole key. This is the base case. */ + if (s == keylen) return crc16(key,keylen) & 0x3FFF; + + /* '{' found? Check if we have the corresponding '}'. */ + for (e = s+1; e < keylen; e++) + if (key[e] == '}') break; + + /* No '}' or nothing betweeen {} ? Hash the whole key. */ + if (e == keylen || e == s+1) return crc16(key,keylen) & 0x3FFF; + + /* If we are here there is both a { and a } on its right. Hash + * what is in the middle between { and }. */ + return crc16(key+s+1,e-s-1) & 0x3FFF; +} + +/* ----------------------------------------------------------------------------- + * CLUSTER node API + * -------------------------------------------------------------------------- */ + +/* Create a new cluster node, with the specified flags. + * If "nodename" is NULL this is considered a first handshake and a random + * node name is assigned to this node (it will be fixed later when we'll + * receive the first pong). + * + * The node is created and returned to the user, but it is not automatically + * added to the nodes hash table. */ +clusterNode *createClusterNode(char *nodename, int flags) { + clusterNode *node = zmalloc(sizeof(*node)); + + if (nodename) + memcpy(node->name, nodename, REDIS_CLUSTER_NAMELEN); + else + getRandomHexChars(node->name, REDIS_CLUSTER_NAMELEN); + node->ctime = mstime(); + node->configEpoch = 0; + node->flags = flags; + memset(node->slots,0,sizeof(node->slots)); + node->numslots = 0; + node->numslaves = 0; + node->slaves = NULL; + node->slaveof = NULL; + node->ping_sent = node->pong_received = 0; + node->fail_time = 0; + node->link = NULL; + memset(node->ip,0,sizeof(node->ip)); + node->port = 0; + node->fail_reports = listCreate(); + node->voted_time = 0; + node->repl_offset_time = 0; + node->repl_offset = 0; + listSetFreeMethod(node->fail_reports,zfree); + return node; +} + +/* This function is called every time we get a failure report from a node. + * The side effect is to populate the fail_reports list (or to update + * the timestamp of an existing report). + * + * 'failing' is the node that is in failure state according to the + * 'sender' node. + * + * The function returns 0 if it just updates a timestamp of an existing + * failure report from the same sender. 1 is returned if a new failure + * report is created. */ +int clusterNodeAddFailureReport(clusterNode *failing, clusterNode *sender) { + list *l = failing->fail_reports; + listNode *ln; + listIter li; + clusterNodeFailReport *fr; + + /* If a failure report from the same sender already exists, just update + * the timestamp. */ + listRewind(l,&li); + while ((ln = listNext(&li)) != NULL) { + fr = ln->value; + if (fr->node == sender) { + fr->time = mstime(); + return 0; + } + } + + /* Otherwise create a new report. */ + fr = zmalloc(sizeof(*fr)); + fr->node = sender; + fr->time = mstime(); + listAddNodeTail(l,fr); + return 1; +} + +/* Remove failure reports that are too old, where too old means reasonably + * older than the global node timeout. Note that anyway for a node to be + * flagged as FAIL we need to have a local PFAIL state that is at least + * older than the global node timeout, so we don't just trust the number + * of failure reports from other nodes. */ +void clusterNodeCleanupFailureReports(clusterNode *node) { + list *l = node->fail_reports; + listNode *ln; + listIter li; + clusterNodeFailReport *fr; + mstime_t maxtime = server.cluster_node_timeout * + REDIS_CLUSTER_FAIL_REPORT_VALIDITY_MULT; + mstime_t now = mstime(); + + listRewind(l,&li); + while ((ln = listNext(&li)) != NULL) { + fr = ln->value; + if (now - fr->time > maxtime) listDelNode(l,ln); + } +} + +/* Remove the failing report for 'node' if it was previously considered + * failing by 'sender'. This function is called when a node informs us via + * gossip that a node is OK from its point of view (no FAIL or PFAIL flags). + * + * Note that this function is called relatively often as it gets called even + * when there are no nodes failing, and is O(N), however when the cluster is + * fine the failure reports list is empty so the function runs in constant + * time. + * + * The function returns 1 if the failure report was found and removed. + * Otherwise 0 is returned. */ +int clusterNodeDelFailureReport(clusterNode *node, clusterNode *sender) { + list *l = node->fail_reports; + listNode *ln; + listIter li; + clusterNodeFailReport *fr; + + /* Search for a failure report from this sender. */ + listRewind(l,&li); + while ((ln = listNext(&li)) != NULL) { + fr = ln->value; + if (fr->node == sender) break; + } + if (!ln) return 0; /* No failure report from this sender. */ + + /* Remove the failure report. */ + listDelNode(l,ln); + clusterNodeCleanupFailureReports(node); + return 1; +} + +/* Return the number of external nodes that believe 'node' is failing, + * not including this node, that may have a PFAIL or FAIL state for this + * node as well. */ +int clusterNodeFailureReportsCount(clusterNode *node) { + clusterNodeCleanupFailureReports(node); + return listLength(node->fail_reports); +} + +int clusterNodeRemoveSlave(clusterNode *master, clusterNode *slave) { + int j; + + for (j = 0; j < master->numslaves; j++) { + if (master->slaves[j] == slave) { + if ((j+1) < master->numslaves) { + int remaining_slaves = (master->numslaves - j) - 1; + memmove(master->slaves+j,master->slaves+(j+1), + (sizeof(*master->slaves) * remaining_slaves)); + } + master->numslaves--; + return REDIS_OK; + } + } + return REDIS_ERR; +} + +int clusterNodeAddSlave(clusterNode *master, clusterNode *slave) { + int j; + + /* If it's already a slave, don't add it again. */ + for (j = 0; j < master->numslaves; j++) + if (master->slaves[j] == slave) return REDIS_ERR; + master->slaves = zrealloc(master->slaves, + sizeof(clusterNode*)*(master->numslaves+1)); + master->slaves[master->numslaves] = slave; + master->numslaves++; + return REDIS_OK; +} + +void clusterNodeResetSlaves(clusterNode *n) { + zfree(n->slaves); + n->numslaves = 0; + n->slaves = NULL; +} + +int clusterCountNonFailingSlaves(clusterNode *n) { + int j, okslaves = 0; + + for (j = 0; j < n->numslaves; j++) + if (!nodeFailed(n->slaves[j])) okslaves++; + return okslaves; +} + +/* Low level cleanup of the node structure. Only called by clusterDelNode(). */ +void freeClusterNode(clusterNode *n) { + sds nodename; + int j; + + /* If the node is a master with associated slaves, we have to set + * all the slaves->slaveof fields to NULL (unknown). */ + if (nodeIsMaster(n)) { + for (j = 0; j < n->numslaves; j++) + n->slaves[j]->slaveof = NULL; + } + + /* Remove this node from the list of slaves of its master. */ + if (nodeIsSlave(n) && n->slaveof) clusterNodeRemoveSlave(n->slaveof,n); + + /* Unlink from the set of nodes. */ + nodename = sdsnewlen(n->name, REDIS_CLUSTER_NAMELEN); + redisAssert(dictDelete(server.cluster->nodes,nodename) == DICT_OK); + sdsfree(nodename); + + /* Release link and associated data structures. */ + if (n->link) freeClusterLink(n->link); + listRelease(n->fail_reports); + zfree(n->slaves); + zfree(n); +} + +/* Add a node to the nodes hash table */ +int clusterAddNode(clusterNode *node) { + int retval; + + retval = dictAdd(server.cluster->nodes, + sdsnewlen(node->name,REDIS_CLUSTER_NAMELEN), node); + return (retval == DICT_OK) ? REDIS_OK : REDIS_ERR; +} + +/* Remove a node from the cluster. The functio performs the high level + * cleanup, calling freeClusterNode() for the low level cleanup. + * Here we do the following: + * + * 1) Mark all the slots handled by it as unassigned. + * 2) Remove all the failure reports sent by this node and referenced by + * other nodes. + * 3) Free the node with freeClusterNode() that will in turn remove it + * from the hash table and from the list of slaves of its master, if + * it is a slave node. + */ +void clusterDelNode(clusterNode *delnode) { + int j; + dictIterator *di; + dictEntry *de; + + /* 1) Mark slots as unassigned. */ + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (server.cluster->importing_slots_from[j] == delnode) + server.cluster->importing_slots_from[j] = NULL; + if (server.cluster->migrating_slots_to[j] == delnode) + server.cluster->migrating_slots_to[j] = NULL; + if (server.cluster->slots[j] == delnode) + clusterDelSlot(j); + } + + /* 2) Remove failure reports. */ + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + + if (node == delnode) continue; + clusterNodeDelFailureReport(node,delnode); + } + dictReleaseIterator(di); + + /* 3) Free the node, unlinking it from the cluster. */ + freeClusterNode(delnode); +} + +/* Node lookup by name */ +clusterNode *clusterLookupNode(char *name) { + sds s = sdsnewlen(name, REDIS_CLUSTER_NAMELEN); + dictEntry *de; + + de = dictFind(server.cluster->nodes,s); + sdsfree(s); + if (de == NULL) return NULL; + return dictGetVal(de); +} + +/* This is only used after the handshake. When we connect a given IP/PORT + * as a result of CLUSTER MEET we don't have the node name yet, so we + * pick a random one, and will fix it when we receive the PONG request using + * this function. */ +void clusterRenameNode(clusterNode *node, char *newname) { + int retval; + sds s = sdsnewlen(node->name, REDIS_CLUSTER_NAMELEN); + + redisLog(REDIS_DEBUG,"Renaming node %.40s into %.40s", + node->name, newname); + retval = dictDelete(server.cluster->nodes, s); + sdsfree(s); + redisAssert(retval == DICT_OK); + memcpy(node->name, newname, REDIS_CLUSTER_NAMELEN); + clusterAddNode(node); +} + +/* ----------------------------------------------------------------------------- + * CLUSTER config epoch handling + * -------------------------------------------------------------------------- */ + +/* Return the greatest configEpoch found in the cluster, or the current + * epoch if greater than any node configEpoch. */ +uint64_t clusterGetMaxEpoch(void) { + uint64_t max = 0; + dictIterator *di; + dictEntry *de; + + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + if (node->configEpoch > max) max = node->configEpoch; + } + dictReleaseIterator(di); + if (max < server.cluster->currentEpoch) max = server.cluster->currentEpoch; + return max; +} + +/* If this node epoch is zero or is not already the greatest across the + * cluster (from the POV of the local configuration), this function will: + * + * 1) Generate a new config epoch increment the current epoch. + * 2) Assign the new epoch to this node, WITHOUT any consensus. + * 3) Persist the configuration on disk before sending packets with the + * new configuration. + * + * If the new config epoch is generated and assigend, REDIS_OK is returned, + * otherwise REDIS_ERR is returned (since the node has already the greatest + * configuration around) and no operation is performed. + * + * Important note: this function violates the principle that config epochs + * should be generated with consensus and should be unique across the cluster. + * However Redis Cluster uses this auto-generated new config epochs in two + * cases: + * + * 1) When slots are closed after importing. Otherwise resharding would be + * too exansive. + * 2) When CLUSTER FAILOVER is called with options that force a slave to + * failover its master even if there is not master majority able to + * create a new configuration epoch. + * + * Redis Cluster does not explode using this function, even in the case of + * a collision between this node and another node, generating the same + * configuration epoch unilaterally, because the config epoch conflict + * resolution algorithm will eventually move colliding nodes to different + * config epochs. However usign this function may violate the "last failover + * wins" rule, so should only be used with care. */ +int clusterBumpConfigEpochWithoutConsensus(void) { + uint64_t maxEpoch = clusterGetMaxEpoch(); + + if (myself->configEpoch == 0 || + myself->configEpoch != maxEpoch) + { + server.cluster->currentEpoch++; + myself->configEpoch = server.cluster->currentEpoch; + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_FSYNC_CONFIG); + redisLog(REDIS_WARNING, + "New configEpoch set to %llu", + (unsigned long long) myself->configEpoch); + return REDIS_OK; + } else { + return REDIS_ERR; + } +} + +/* This function is called when this node is a master, and we receive from + * another master a configuration epoch that is equal to our configuration + * epoch. + * + * BACKGROUND + * + * It is not possible that different slaves get the same config + * epoch during a failover election, because the slaves need to get voted + * by a majority. However when we perform a manual resharding of the cluster + * the node will assign a configuration epoch to itself without to ask + * for agreement. Usually resharding happens when the cluster is working well + * and is supervised by the sysadmin, however it is possible for a failover + * to happen exactly while the node we are resharding a slot to assigns itself + * a new configuration epoch, but before it is able to propagate it. + * + * So technically it is possible in this condition that two nodes end with + * the same configuration epoch. + * + * Another possibility is that there are bugs in the implementation causing + * this to happen. + * + * Moreover when a new cluster is created, all the nodes start with the same + * configEpoch. This collision resolution code allows nodes to automatically + * end with a different configEpoch at startup automatically. + * + * In all the cases, we want a mechanism that resolves this issue automatically + * as a safeguard. The same configuration epoch for masters serving different + * set of slots is not harmful, but it is if the nodes end serving the same + * slots for some reason (manual errors or software bugs) without a proper + * failover procedure. + * + * In general we want a system that eventually always ends with different + * masters having different configuration epochs whatever happened, since + * nothign is worse than a split-brain condition in a distributed system. + * + * BEHAVIOR + * + * When this function gets called, what happens is that if this node + * has the lexicographically smaller Node ID compared to the other node + * with the conflicting epoch (the 'sender' node), it will assign itself + * the greatest configuration epoch currently detected among nodes plus 1. + * + * This means that even if there are multiple nodes colliding, the node + * with the greatest Node ID never moves forward, so eventually all the nodes + * end with a different configuration epoch. + */ +void clusterHandleConfigEpochCollision(clusterNode *sender) { + /* Prerequisites: nodes have the same configEpoch and are both masters. */ + if (sender->configEpoch != myself->configEpoch || + !nodeIsMaster(sender) || !nodeIsMaster(myself)) return; + /* Don't act if the colliding node has a smaller Node ID. */ + if (memcmp(sender->name,myself->name,REDIS_CLUSTER_NAMELEN) <= 0) return; + /* Get the next ID available at the best of this node knowledge. */ + server.cluster->currentEpoch++; + myself->configEpoch = server.cluster->currentEpoch; + clusterSaveConfigOrDie(1); + redisLog(REDIS_VERBOSE, + "WARNING: configEpoch collision with node %.40s." + " configEpoch set to %llu", + sender->name, + (unsigned long long) myself->configEpoch); +} + +/* ----------------------------------------------------------------------------- + * CLUSTER nodes blacklist + * + * The nodes blacklist is just a way to ensure that a given node with a given + * Node ID is not readded before some time elapsed (this time is specified + * in seconds in REDIS_CLUSTER_BLACKLIST_TTL). + * + * This is useful when we want to remove a node from the cluster completely: + * when CLUSTER FORGET is called, it also puts the node into the blacklist so + * that even if we receive gossip messages from other nodes that still remember + * about the node we want to remove, we don't re-add it before some time. + * + * Currently the REDIS_CLUSTER_BLACKLIST_TTL is set to 1 minute, this means + * that redis-trib has 60 seconds to send CLUSTER FORGET messages to nodes + * in the cluster without dealing with the problem of other nodes re-adding + * back the node to nodes we already sent the FORGET command to. + * + * The data structure used is a hash table with an sds string representing + * the node ID as key, and the time when it is ok to re-add the node as + * value. + * -------------------------------------------------------------------------- */ + +#define REDIS_CLUSTER_BLACKLIST_TTL 60 /* 1 minute. */ + + +/* Before of the addNode() or Exists() operations we always remove expired + * entries from the black list. This is an O(N) operation but it is not a + * problem since add / exists operations are called very infrequently and + * the hash table is supposed to contain very little elements at max. + * However without the cleanup during long uptimes and with some automated + * node add/removal procedures, entries could accumulate. */ +void clusterBlacklistCleanup(void) { + dictIterator *di; + dictEntry *de; + + di = dictGetSafeIterator(server.cluster->nodes_black_list); + while((de = dictNext(di)) != NULL) { + int64_t expire = dictGetUnsignedIntegerVal(de); + + if (expire < server.unixtime) + dictDelete(server.cluster->nodes_black_list,dictGetKey(de)); + } + dictReleaseIterator(di); +} + +/* Cleanup the blacklist and add a new node ID to the black list. */ +void clusterBlacklistAddNode(clusterNode *node) { + dictEntry *de; + sds id = sdsnewlen(node->name,REDIS_CLUSTER_NAMELEN); + + clusterBlacklistCleanup(); + if (dictAdd(server.cluster->nodes_black_list,id,NULL) == DICT_OK) { + /* If the key was added, duplicate the sds string representation of + * the key for the next lookup. We'll free it at the end. */ + id = sdsdup(id); + } + de = dictFind(server.cluster->nodes_black_list,id); + dictSetUnsignedIntegerVal(de,time(NULL)+REDIS_CLUSTER_BLACKLIST_TTL); + sdsfree(id); +} + +/* Return non-zero if the specified node ID exists in the blacklist. + * You don't need to pass an sds string here, any pointer to 40 bytes + * will work. */ +int clusterBlacklistExists(char *nodeid) { + sds id = sdsnewlen(nodeid,REDIS_CLUSTER_NAMELEN); + int retval; + + clusterBlacklistCleanup(); + retval = dictFind(server.cluster->nodes_black_list,id) != NULL; + sdsfree(id); + return retval; +} + +/* ----------------------------------------------------------------------------- + * CLUSTER messages exchange - PING/PONG and gossip + * -------------------------------------------------------------------------- */ + +/* This function checks if a given node should be marked as FAIL. + * It happens if the following conditions are met: + * + * 1) We received enough failure reports from other master nodes via gossip. + * Enough means that the majority of the masters signaled the node is + * down recently. + * 2) We believe this node is in PFAIL state. + * + * If a failure is detected we also inform the whole cluster about this + * event trying to force every other node to set the FAIL flag for the node. + * + * Note that the form of agreement used here is weak, as we collect the majority + * of masters state during some time, and even if we force agreement by + * propagating the FAIL message, because of partitions we may not reach every + * node. However: + * + * 1) Either we reach the majority and eventually the FAIL state will propagate + * to all the cluster. + * 2) Or there is no majority so no slave promotion will be authorized and the + * FAIL flag will be cleared after some time. + */ +void markNodeAsFailingIfNeeded(clusterNode *node) { + int failures; + int needed_quorum = (server.cluster->size / 2) + 1; + + if (!nodeTimedOut(node)) return; /* We can reach it. */ + if (nodeFailed(node)) return; /* Already FAILing. */ + + failures = clusterNodeFailureReportsCount(node); + /* Also count myself as a voter if I'm a master. */ + if (nodeIsMaster(myself)) failures++; + if (failures < needed_quorum) return; /* No weak agreement from masters. */ + + redisLog(REDIS_NOTICE, + "Marking node %.40s as failing (quorum reached).", node->name); + + /* Mark the node as failing. */ + node->flags &= ~REDIS_NODE_PFAIL; + node->flags |= REDIS_NODE_FAIL; + node->fail_time = mstime(); + + /* Broadcast the failing node name to everybody, forcing all the other + * reachable nodes to flag the node as FAIL. */ + if (nodeIsMaster(myself)) clusterSendFail(node->name); + clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG); +} + +/* This function is called only if a node is marked as FAIL, but we are able + * to reach it again. It checks if there are the conditions to undo the FAIL + * state. */ +void clearNodeFailureIfNeeded(clusterNode *node) { + mstime_t now = mstime(); + + redisAssert(nodeFailed(node)); + + /* For slaves we always clear the FAIL flag if we can contact the + * node again. */ + if (nodeIsSlave(node) || node->numslots == 0) { + redisLog(REDIS_NOTICE, + "Clear FAIL state for node %.40s: %s is reachable again.", + node->name, + nodeIsSlave(node) ? "slave" : "master without slots"); + node->flags &= ~REDIS_NODE_FAIL; + clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG); + } + + /* If it is a master and... + * 1) The FAIL state is old enough. + * 2) It is yet serving slots from our point of view (not failed over). + * Apparently no one is going to fix these slots, clear the FAIL flag. */ + if (nodeIsMaster(node) && node->numslots > 0 && + (now - node->fail_time) > + (server.cluster_node_timeout * REDIS_CLUSTER_FAIL_UNDO_TIME_MULT)) + { + redisLog(REDIS_NOTICE, + "Clear FAIL state for node %.40s: is reachable again and nobody is serving its slots after some time.", + node->name); + node->flags &= ~REDIS_NODE_FAIL; + clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG); + } +} + +/* Return true if we already have a node in HANDSHAKE state matching the + * specified ip address and port number. This function is used in order to + * avoid adding a new handshake node for the same address multiple times. */ +int clusterHandshakeInProgress(char *ip, int port) { + dictIterator *di; + dictEntry *de; + + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + + if (!nodeInHandshake(node)) continue; + if (!strcasecmp(node->ip,ip) && node->port == port) break; + } + dictReleaseIterator(di); + return de != NULL; +} + +/* Start an handshake with the specified address if there is not one + * already in progress. Returns non-zero if the handshake was actually + * started. On error zero is returned and errno is set to one of the + * following values: + * + * EAGAIN - There is already an handshake in progress for this address. + * EINVAL - IP or port are not valid. */ +int clusterStartHandshake(char *ip, int port) { + clusterNode *n; + char norm_ip[REDIS_IP_STR_LEN]; + struct sockaddr_storage sa; + + /* IP sanity check */ + if (inet_pton(AF_INET,ip, + &(((struct sockaddr_in *)&sa)->sin_addr))) + { + sa.ss_family = AF_INET; + } else if (inet_pton(AF_INET6,ip, + &(((struct sockaddr_in6 *)&sa)->sin6_addr))) + { + sa.ss_family = AF_INET6; + } else { + errno = EINVAL; + return 0; + } + + /* Port sanity check */ + if (port <= 0 || port > (65535-REDIS_CLUSTER_PORT_INCR)) { + errno = EINVAL; + return 0; + } + + /* Set norm_ip as the normalized string representation of the node + * IP address. */ + memset(norm_ip,0,REDIS_IP_STR_LEN); + if (sa.ss_family == AF_INET) + inet_ntop(AF_INET, + (void*)&(((struct sockaddr_in *)&sa)->sin_addr), + norm_ip,REDIS_IP_STR_LEN); + else + inet_ntop(AF_INET6, + (void*)&(((struct sockaddr_in6 *)&sa)->sin6_addr), + norm_ip,REDIS_IP_STR_LEN); + + if (clusterHandshakeInProgress(norm_ip,port)) { + errno = EAGAIN; + return 0; + } + + /* Add the node with a random address (NULL as first argument to + * createClusterNode()). Everything will be fixed during the + * handshake. */ + n = createClusterNode(NULL,REDIS_NODE_HANDSHAKE|REDIS_NODE_MEET); + memcpy(n->ip,norm_ip,sizeof(n->ip)); + n->port = port; + clusterAddNode(n); + return 1; +} + +/* Process the gossip section of PING or PONG packets. + * Note that this function assumes that the packet is already sanity-checked + * by the caller, not in the content of the gossip section, but in the + * length. */ +void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) { + uint16_t count = ntohs(hdr->count); + clusterMsgDataGossip *g = (clusterMsgDataGossip*) hdr->data.ping.gossip; + clusterNode *sender = link->node ? link->node : clusterLookupNode(hdr->sender); + + while(count--) { + uint16_t flags = ntohs(g->flags); + clusterNode *node; + sds ci; + + ci = representRedisNodeFlags(sdsempty(), flags); + redisLog(REDIS_DEBUG,"GOSSIP %.40s %s:%d %s", + g->nodename, + g->ip, + ntohs(g->port), + ci); + sdsfree(ci); + + /* Update our state accordingly to the gossip sections */ + node = clusterLookupNode(g->nodename); + if (node) { + /* We already know this node. + Handle failure reports, only when the sender is a master. */ + if (sender && nodeIsMaster(sender) && node != myself) { + if (flags & (REDIS_NODE_FAIL|REDIS_NODE_PFAIL)) { + if (clusterNodeAddFailureReport(node,sender)) { + redisLog(REDIS_VERBOSE, + "Node %.40s reported node %.40s as not reachable.", + sender->name, node->name); + } + markNodeAsFailingIfNeeded(node); + } else { + if (clusterNodeDelFailureReport(node,sender)) { + redisLog(REDIS_VERBOSE, + "Node %.40s reported node %.40s is back online.", + sender->name, node->name); + } + } + } + + /* If we already know this node, but it is not reachable, and + * we see a different address in the gossip section, start an + * handshake with the (possibly) new address: this will result + * into a node address update if the handshake will be + * successful. */ + if (node->flags & (REDIS_NODE_FAIL|REDIS_NODE_PFAIL) && + (strcasecmp(node->ip,g->ip) || node->port != ntohs(g->port))) + { + clusterStartHandshake(g->ip,ntohs(g->port)); + } + } else { + /* If it's not in NOADDR state and we don't have it, we + * start a handshake process against this IP/PORT pairs. + * + * Note that we require that the sender of this gossip message + * is a well known node in our cluster, otherwise we risk + * joining another cluster. */ + if (sender && + !(flags & REDIS_NODE_NOADDR) && + !clusterBlacklistExists(g->nodename)) + { + clusterStartHandshake(g->ip,ntohs(g->port)); + } + } + + /* Next node */ + g++; + } +} + +/* IP -> string conversion. 'buf' is supposed to at least be 46 bytes. */ +void nodeIp2String(char *buf, clusterLink *link) { + anetPeerToString(link->fd, buf, REDIS_IP_STR_LEN, NULL); +} + +/* Update the node address to the IP address that can be extracted + * from link->fd, and at the specified port. + * Also disconnect the node link so that we'll connect again to the new + * address. + * + * If the ip/port pair are already correct no operation is performed at + * all. + * + * The function returns 0 if the node address is still the same, + * otherwise 1 is returned. */ +int nodeUpdateAddressIfNeeded(clusterNode *node, clusterLink *link, int port) { + char ip[REDIS_IP_STR_LEN] = {0}; + + /* We don't proceed if the link is the same as the sender link, as this + * function is designed to see if the node link is consistent with the + * symmetric link that is used to receive PINGs from the node. + * + * As a side effect this function never frees the passed 'link', so + * it is safe to call during packet processing. */ + if (link == node->link) return 0; + + nodeIp2String(ip,link); + if (node->port == port && strcmp(ip,node->ip) == 0) return 0; + + /* IP / port is different, update it. */ + memcpy(node->ip,ip,sizeof(ip)); + node->port = port; + if (node->link) freeClusterLink(node->link); + node->flags &= ~REDIS_NODE_NOADDR; + redisLog(REDIS_WARNING,"Address updated for node %.40s, now %s:%d", + node->name, node->ip, node->port); + + /* Check if this is our master and we have to change the + * replication target as well. */ + if (nodeIsSlave(myself) && myself->slaveof == node) + replicationSetMaster(node->ip, node->port); + return 1; +} + +/* Reconfigure the specified node 'n' as a master. This function is called when + * a node that we believed to be a slave is now acting as master in order to + * update the state of the node. */ +void clusterSetNodeAsMaster(clusterNode *n) { + if (nodeIsMaster(n)) return; + + if (n->slaveof) clusterNodeRemoveSlave(n->slaveof,n); + n->flags &= ~REDIS_NODE_SLAVE; + n->flags |= REDIS_NODE_MASTER; + n->slaveof = NULL; + + /* Update config and state. */ + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE); +} + +/* This function is called when we receive a master configuration via a + * PING, PONG or UPDATE packet. What we receive is a node, a configEpoch of the + * node, and the set of slots claimed under this configEpoch. + * + * What we do is to rebind the slots with newer configuration compared to our + * local configuration, and if needed, we turn ourself into a replica of the + * node (see the function comments for more info). + * + * The 'sender' is the node for which we received a configuration update. + * Sometimes it is not actually the "Sender" of the information, like in the case + * we receive the info via an UPDATE packet. */ +void clusterUpdateSlotsConfigWith(clusterNode *sender, uint64_t senderConfigEpoch, unsigned char *slots) { + int j; + clusterNode *curmaster, *newmaster = NULL; + /* The dirty slots list is a list of slots for which we lose the ownership + * while having still keys inside. This usually happens after a failover + * or after a manual cluster reconfiguration operated by the admin. + * + * If the update message is not able to demote a master to slave (in this + * case we'll resync with the master updating the whole key space), we + * need to delete all the keys in the slots we lost ownership. */ + uint16_t dirty_slots[REDIS_CLUSTER_SLOTS]; + int dirty_slots_count = 0; + + /* Here we set curmaster to this node or the node this node + * replicates to if it's a slave. In the for loop we are + * interested to check if slots are taken away from curmaster. */ + curmaster = nodeIsMaster(myself) ? myself : myself->slaveof; + + if (sender == myself) { + redisLog(REDIS_WARNING,"Discarding UPDATE message about myself."); + return; + } + + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (bitmapTestBit(slots,j)) { + /* The slot is already bound to the sender of this message. */ + if (server.cluster->slots[j] == sender) continue; + + /* The slot is in importing state, it should be modified only + * manually via redis-trib (example: a resharding is in progress + * and the migrating side slot was already closed and is advertising + * a new config. We still want the slot to be closed manually). */ + if (server.cluster->importing_slots_from[j]) continue; + + /* We rebind the slot to the new node claiming it if: + * 1) The slot was unassigned or the new node claims it with a + * greater configEpoch. + * 2) We are not currently importing the slot. */ + if (server.cluster->slots[j] == NULL || + server.cluster->slots[j]->configEpoch < senderConfigEpoch) + { + /* Was this slot mine, and still contains keys? Mark it as + * a dirty slot. */ + if (server.cluster->slots[j] == myself && + countKeysInSlot(j) && + sender != myself) + { + dirty_slots[dirty_slots_count] = j; + dirty_slots_count++; + } + + if (server.cluster->slots[j] == curmaster) + newmaster = sender; + clusterDelSlot(j); + clusterAddSlot(sender,j); + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE| + CLUSTER_TODO_FSYNC_CONFIG); + } + } + } + + /* If at least one slot was reassigned from a node to another node + * with a greater configEpoch, it is possible that: + * 1) We are a master left without slots. This means that we were + * failed over and we should turn into a replica of the new + * master. + * 2) We are a slave and our master is left without slots. We need + * to replicate to the new slots owner. */ + if (newmaster && curmaster->numslots == 0) { + redisLog(REDIS_WARNING, + "Configuration change detected. Reconfiguring myself " + "as a replica of %.40s", sender->name); + clusterSetMaster(sender); + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE| + CLUSTER_TODO_FSYNC_CONFIG); + } else if (dirty_slots_count) { + /* If we are here, we received an update message which removed + * ownership for certain slots we still have keys about, but still + * we are serving some slots, so this master node was not demoted to + * a slave. + * + * In order to maintain a consistent state between keys and slots + * we need to remove all the keys from the slots we lost. */ + for (j = 0; j < dirty_slots_count; j++) + delKeysInSlot(dirty_slots[j]); + } +} + +/* When this function is called, there is a packet to process starting + * at node->rcvbuf. Releasing the buffer is up to the caller, so this + * function should just handle the higher level stuff of processing the + * packet, modifying the cluster state if needed. + * + * The function returns 1 if the link is still valid after the packet + * was processed, otherwise 0 if the link was freed since the packet + * processing lead to some inconsistency error (for instance a PONG + * received from the wrong sender ID). */ +int clusterProcessPacket(clusterLink *link) { + clusterMsg *hdr = (clusterMsg*) link->rcvbuf; + uint32_t totlen = ntohl(hdr->totlen); + uint16_t type = ntohs(hdr->type); + uint16_t flags = ntohs(hdr->flags); + uint64_t senderCurrentEpoch = 0, senderConfigEpoch = 0; + clusterNode *sender; + + server.cluster->stats_bus_messages_received++; + redisLog(REDIS_DEBUG,"--- Processing packet of type %d, %lu bytes", + type, (unsigned long) totlen); + + /* Perform sanity checks */ + if (totlen < 16) return 1; /* At least signature, version, totlen, count. */ + if (ntohs(hdr->ver) != CLUSTER_PROTO_VER) + return 1; /* Can't handle versions other than the current one.*/ + if (totlen > sdslen(link->rcvbuf)) return 1; + if (type == CLUSTERMSG_TYPE_PING || type == CLUSTERMSG_TYPE_PONG || + type == CLUSTERMSG_TYPE_MEET) + { + uint16_t count = ntohs(hdr->count); + uint32_t explen; /* expected length of this packet */ + + explen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + explen += (sizeof(clusterMsgDataGossip)*count); + if (totlen != explen) return 1; + } else if (type == CLUSTERMSG_TYPE_FAIL) { + uint32_t explen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + + explen += sizeof(clusterMsgDataFail); + if (totlen != explen) return 1; + } else if (type == CLUSTERMSG_TYPE_PUBLISH) { + uint32_t explen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + + explen += sizeof(clusterMsgDataPublish) - + 8 + + ntohl(hdr->data.publish.msg.channel_len) + + ntohl(hdr->data.publish.msg.message_len); + if (totlen != explen) return 1; + } else if (type == CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST || + type == CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK || + type == CLUSTERMSG_TYPE_MFSTART) + { + uint32_t explen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + + if (totlen != explen) return 1; + } else if (type == CLUSTERMSG_TYPE_UPDATE) { + uint32_t explen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + + explen += sizeof(clusterMsgDataUpdate); + if (totlen != explen) return 1; + } + + /* Check if the sender is a known node. */ + sender = clusterLookupNode(hdr->sender); + if (sender && !nodeInHandshake(sender)) { + /* Update our curretEpoch if we see a newer epoch in the cluster. */ + senderCurrentEpoch = ntohu64(hdr->currentEpoch); + senderConfigEpoch = ntohu64(hdr->configEpoch); + if (senderCurrentEpoch > server.cluster->currentEpoch) + server.cluster->currentEpoch = senderCurrentEpoch; + /* Update the sender configEpoch if it is publishing a newer one. */ + if (senderConfigEpoch > sender->configEpoch) { + sender->configEpoch = senderConfigEpoch; + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_FSYNC_CONFIG); + } + /* Update the replication offset info for this node. */ + sender->repl_offset = ntohu64(hdr->offset); + sender->repl_offset_time = mstime(); + /* If we are a slave performing a manual failover and our master + * sent its offset while already paused, populate the MF state. */ + if (server.cluster->mf_end && + nodeIsSlave(myself) && + myself->slaveof == sender && + hdr->mflags[0] & CLUSTERMSG_FLAG0_PAUSED && + server.cluster->mf_master_offset == 0) + { + server.cluster->mf_master_offset = sender->repl_offset; + redisLog(REDIS_WARNING, + "Received replication offset for paused " + "master manual failover: %lld", + server.cluster->mf_master_offset); + } + } + + /* Initial processing of PING and MEET requests replying with a PONG. */ + if (type == CLUSTERMSG_TYPE_PING || type == CLUSTERMSG_TYPE_MEET) { + redisLog(REDIS_DEBUG,"Ping packet received: %p", (void*)link->node); + + /* We use incoming MEET messages in order to set the address + * for 'myself', since only other cluster nodes will send us + * MEET messagses on handshakes, when the cluster joins, or + * later if we changed address, and those nodes will use our + * official address to connect to us. So by obtaining this address + * from the socket is a simple way to discover / update our own + * address in the cluster without it being hardcoded in the config. + * + * However if we don't have an address at all, we update the address + * even with a normal PING packet. If it's wrong it will be fixed + * by MEET later. */ + if (type == CLUSTERMSG_TYPE_MEET || myself->ip[0] == '\0') { + char ip[REDIS_IP_STR_LEN]; + + if (anetSockName(link->fd,ip,sizeof(ip),NULL) != -1 && + strcmp(ip,myself->ip)) + { + memcpy(myself->ip,ip,REDIS_IP_STR_LEN); + redisLog(REDIS_WARNING,"IP address for this node updated to %s", + myself->ip); + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG); + } + } + + /* Add this node if it is new for us and the msg type is MEET. + * In this stage we don't try to add the node with the right + * flags, slaveof pointer, and so forth, as this details will be + * resolved when we'll receive PONGs from the node. */ + if (!sender && type == CLUSTERMSG_TYPE_MEET) { + clusterNode *node; + + node = createClusterNode(NULL,REDIS_NODE_HANDSHAKE); + nodeIp2String(node->ip,link); + node->port = ntohs(hdr->port); + clusterAddNode(node); + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG); + } + + /* If this is a MEET packet from an unknown node, we still process + * the gossip section here since we have to trust the sender because + * of the message type. */ + if (!sender && type == CLUSTERMSG_TYPE_MEET) + clusterProcessGossipSection(hdr,link); + + /* Anyway reply with a PONG */ + clusterSendPing(link,CLUSTERMSG_TYPE_PONG); + } + + /* PING, PONG, MEET: process config information. */ + if (type == CLUSTERMSG_TYPE_PING || type == CLUSTERMSG_TYPE_PONG || + type == CLUSTERMSG_TYPE_MEET) + { + redisLog(REDIS_DEBUG,"%s packet received: %p", + type == CLUSTERMSG_TYPE_PING ? "ping" : "pong", + (void*)link->node); + if (link->node) { + if (nodeInHandshake(link->node)) { + /* If we already have this node, try to change the + * IP/port of the node with the new one. */ + if (sender) { + redisLog(REDIS_VERBOSE, + "Handshake: we already know node %.40s, " + "updating the address if needed.", sender->name); + if (nodeUpdateAddressIfNeeded(sender,link,ntohs(hdr->port))) + { + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE); + } + /* Free this node as we already have it. This will + * cause the link to be freed as well. */ + clusterDelNode(link->node); + return 0; + } + + /* First thing to do is replacing the random name with the + * right node name if this was a handshake stage. */ + clusterRenameNode(link->node, hdr->sender); + redisLog(REDIS_DEBUG,"Handshake with node %.40s completed.", + link->node->name); + link->node->flags &= ~REDIS_NODE_HANDSHAKE; + link->node->flags |= flags&(REDIS_NODE_MASTER|REDIS_NODE_SLAVE); + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG); + } else if (memcmp(link->node->name,hdr->sender, + REDIS_CLUSTER_NAMELEN) != 0) + { + /* If the reply has a non matching node ID we + * disconnect this node and set it as not having an associated + * address. */ + redisLog(REDIS_DEBUG,"PONG contains mismatching sender ID"); + link->node->flags |= REDIS_NODE_NOADDR; + link->node->ip[0] = '\0'; + link->node->port = 0; + freeClusterLink(link); + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG); + return 0; + } + } + + /* Update the node address if it changed. */ + if (sender && type == CLUSTERMSG_TYPE_PING && + !nodeInHandshake(sender) && + nodeUpdateAddressIfNeeded(sender,link,ntohs(hdr->port))) + { + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE); + } + + /* Update our info about the node */ + if (link->node && type == CLUSTERMSG_TYPE_PONG) { + link->node->pong_received = mstime(); + link->node->ping_sent = 0; + + /* The PFAIL condition can be reversed without external + * help if it is momentary (that is, if it does not + * turn into a FAIL state). + * + * The FAIL condition is also reversible under specific + * conditions detected by clearNodeFailureIfNeeded(). */ + if (nodeTimedOut(link->node)) { + link->node->flags &= ~REDIS_NODE_PFAIL; + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE); + } else if (nodeFailed(link->node)) { + clearNodeFailureIfNeeded(link->node); + } + } + + /* Check for role switch: slave -> master or master -> slave. */ + if (sender) { + if (!memcmp(hdr->slaveof,REDIS_NODE_NULL_NAME, + sizeof(hdr->slaveof))) + { + /* Node is a master. */ + clusterSetNodeAsMaster(sender); + } else { + /* Node is a slave. */ + clusterNode *master = clusterLookupNode(hdr->slaveof); + + if (nodeIsMaster(sender)) { + /* Master turned into a slave! Reconfigure the node. */ + clusterDelNodeSlots(sender); + sender->flags &= ~REDIS_NODE_MASTER; + sender->flags |= REDIS_NODE_SLAVE; + + /* Remove the list of slaves from the node. */ + if (sender->numslaves) clusterNodeResetSlaves(sender); + + /* Update config and state. */ + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE); + } + + /* Master node changed for this slave? */ + if (master && sender->slaveof != master) { + if (sender->slaveof) + clusterNodeRemoveSlave(sender->slaveof,sender); + clusterNodeAddSlave(master,sender); + sender->slaveof = master; + + /* Update config. */ + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG); + } + } + } + + /* Update our info about served slots. + * + * Note: this MUST happen after we update the master/slave state + * so that REDIS_NODE_MASTER flag will be set. */ + + /* Many checks are only needed if the set of served slots this + * instance claims is different compared to the set of slots we have + * for it. Check this ASAP to avoid other computational expansive + * checks later. */ + clusterNode *sender_master = NULL; /* Sender or its master if slave. */ + int dirty_slots = 0; /* Sender claimed slots don't match my view? */ + + if (sender) { + sender_master = nodeIsMaster(sender) ? sender : sender->slaveof; + if (sender_master) { + dirty_slots = memcmp(sender_master->slots, + hdr->myslots,sizeof(hdr->myslots)) != 0; + } + } + + /* 1) If the sender of the message is a master, and we detected that + * the set of slots it claims changed, scan the slots to see if we + * need to update our configuration. */ + if (sender && nodeIsMaster(sender) && dirty_slots) + clusterUpdateSlotsConfigWith(sender,senderConfigEpoch,hdr->myslots); + + /* 2) We also check for the reverse condition, that is, the sender + * claims to serve slots we know are served by a master with a + * greater configEpoch. If this happens we inform the sender. + * + * This is useful because sometimes after a partition heals, a + * reappearing master may be the last one to claim a given set of + * hash slots, but with a configuration that other instances know to + * be deprecated. Example: + * + * A and B are master and slave for slots 1,2,3. + * A is partitioned away, B gets promoted. + * B is partitioned away, and A returns available. + * + * Usually B would PING A publishing its set of served slots and its + * configEpoch, but because of the partition B can't inform A of the + * new configuration, so other nodes that have an updated table must + * do it. In this way A will stop to act as a master (or can try to + * failover if there are the conditions to win the election). */ + if (sender && dirty_slots) { + int j; + + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (bitmapTestBit(hdr->myslots,j)) { + if (server.cluster->slots[j] == sender || + server.cluster->slots[j] == NULL) continue; + if (server.cluster->slots[j]->configEpoch > + senderConfigEpoch) + { + redisLog(REDIS_VERBOSE, + "Node %.40s has old slots configuration, sending " + "an UPDATE message about %.40s", + sender->name, server.cluster->slots[j]->name); + clusterSendUpdate(sender->link, + server.cluster->slots[j]); + + /* TODO: instead of exiting the loop send every other + * UPDATE packet for other nodes that are the new owner + * of sender's slots. */ + break; + } + } + } + } + + /* If our config epoch collides with the sender's try to fix + * the problem. */ + if (sender && + nodeIsMaster(myself) && nodeIsMaster(sender) && + senderConfigEpoch == myself->configEpoch) + { + clusterHandleConfigEpochCollision(sender); + } + + /* Get info from the gossip section */ + if (sender) clusterProcessGossipSection(hdr,link); + } else if (type == CLUSTERMSG_TYPE_FAIL) { + clusterNode *failing; + + if (sender) { + failing = clusterLookupNode(hdr->data.fail.about.nodename); + if (failing && + !(failing->flags & (REDIS_NODE_FAIL|REDIS_NODE_MYSELF))) + { + redisLog(REDIS_NOTICE, + "FAIL message received from %.40s about %.40s", + hdr->sender, hdr->data.fail.about.nodename); + failing->flags |= REDIS_NODE_FAIL; + failing->fail_time = mstime(); + failing->flags &= ~REDIS_NODE_PFAIL; + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE); + } + } else { + redisLog(REDIS_NOTICE, + "Ignoring FAIL message from unknown node %.40s about %.40s", + hdr->sender, hdr->data.fail.about.nodename); + } + } else if (type == CLUSTERMSG_TYPE_PUBLISH) { + robj *channel, *message; + uint32_t channel_len, message_len; + + /* Don't bother creating useless objects if there are no + * Pub/Sub subscribers. */ + if (dictSize(server.pubsub_channels) || + listLength(server.pubsub_patterns)) + { + channel_len = ntohl(hdr->data.publish.msg.channel_len); + message_len = ntohl(hdr->data.publish.msg.message_len); + channel = createStringObject( + (char*)hdr->data.publish.msg.bulk_data,channel_len); + message = createStringObject( + (char*)hdr->data.publish.msg.bulk_data+channel_len, + message_len); + pubsubPublishMessage(channel,message); + decrRefCount(channel); + decrRefCount(message); + } + } else if (type == CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST) { + if (!sender) return 1; /* We don't know that node. */ + clusterSendFailoverAuthIfNeeded(sender,hdr); + } else if (type == CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK) { + if (!sender) return 1; /* We don't know that node. */ + /* We consider this vote only if the sender is a master serving + * a non zero number of slots, and its currentEpoch is greater or + * equal to epoch where this node started the election. */ + if (nodeIsMaster(sender) && sender->numslots > 0 && + senderCurrentEpoch >= server.cluster->failover_auth_epoch) + { + server.cluster->failover_auth_count++; + /* Maybe we reached a quorum here, set a flag to make sure + * we check ASAP. */ + clusterDoBeforeSleep(CLUSTER_TODO_HANDLE_FAILOVER); + } + } else if (type == CLUSTERMSG_TYPE_MFSTART) { + /* This message is acceptable only if I'm a master and the sender + * is one of my slaves. */ + if (!sender || sender->slaveof != myself) return 1; + /* Manual failover requested from slaves. Initialize the state + * accordingly. */ + resetManualFailover(); + server.cluster->mf_end = mstime() + REDIS_CLUSTER_MF_TIMEOUT; + server.cluster->mf_slave = sender; + pauseClients(mstime()+(REDIS_CLUSTER_MF_TIMEOUT*2)); + redisLog(REDIS_WARNING,"Manual failover requested by slave %.40s.", + sender->name); + } else if (type == CLUSTERMSG_TYPE_UPDATE) { + clusterNode *n; /* The node the update is about. */ + uint64_t reportedConfigEpoch = + ntohu64(hdr->data.update.nodecfg.configEpoch); + + if (!sender) return 1; /* We don't know the sender. */ + n = clusterLookupNode(hdr->data.update.nodecfg.nodename); + if (!n) return 1; /* We don't know the reported node. */ + if (n->configEpoch >= reportedConfigEpoch) return 1; /* Nothing new. */ + + /* If in our current config the node is a slave, set it as a master. */ + if (nodeIsSlave(n)) clusterSetNodeAsMaster(n); + + /* Update the node's configEpoch. */ + n->configEpoch = reportedConfigEpoch; + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_FSYNC_CONFIG); + + /* Check the bitmap of served slots and update our + * config accordingly. */ + clusterUpdateSlotsConfigWith(n,reportedConfigEpoch, + hdr->data.update.nodecfg.slots); + } else { + redisLog(REDIS_WARNING,"Received unknown packet type: %d", type); + } + return 1; +} + +/* This function is called when we detect the link with this node is lost. + We set the node as no longer connected. The Cluster Cron will detect + this connection and will try to get it connected again. + + Instead if the node is a temporary node used to accept a query, we + completely free the node on error. */ +void handleLinkIOError(clusterLink *link) { + freeClusterLink(link); +} + +/* Send data. This is handled using a trivial send buffer that gets + * consumed by write(). We don't try to optimize this for speed too much + * as this is a very low traffic channel. */ +void clusterWriteHandler(aeEventLoop *el, int fd, void *privdata, int mask) { + clusterLink *link = (clusterLink*) privdata; + ssize_t nwritten; + REDIS_NOTUSED(el); + REDIS_NOTUSED(mask); + + nwritten = write(fd, link->sndbuf, sdslen(link->sndbuf)); + if (nwritten <= 0) { + redisLog(REDIS_DEBUG,"I/O error writing to node link: %s", + strerror(errno)); + handleLinkIOError(link); + return; + } + sdsrange(link->sndbuf,nwritten,-1); + if (sdslen(link->sndbuf) == 0) + aeDeleteFileEvent(server.el, link->fd, AE_WRITABLE); +} + +/* Read data. Try to read the first field of the header first to check the + * full length of the packet. When a whole packet is in memory this function + * will call the function to process the packet. And so forth. */ +void clusterReadHandler(aeEventLoop *el, int fd, void *privdata, int mask) { + char buf[sizeof(clusterMsg)]; + ssize_t nread; + clusterMsg *hdr; + clusterLink *link = (clusterLink*) privdata; + unsigned int readlen, rcvbuflen; + REDIS_NOTUSED(el); + REDIS_NOTUSED(mask); + + while(1) { /* Read as long as there is data to read. */ + rcvbuflen = sdslen(link->rcvbuf); + if (rcvbuflen < 8) { + /* First, obtain the first 8 bytes to get the full message + * length. */ + readlen = 8 - rcvbuflen; + } else { + /* Finally read the full message. */ + hdr = (clusterMsg*) link->rcvbuf; + if (rcvbuflen == 8) { + /* Perform some sanity check on the message signature + * and length. */ + if (memcmp(hdr->sig,"RCmb",4) != 0 || + ntohl(hdr->totlen) < CLUSTERMSG_MIN_LEN) + { + redisLog(REDIS_WARNING, + "Bad message length or signature received " + "from Cluster bus."); + handleLinkIOError(link); + return; + } + } + readlen = ntohl(hdr->totlen) - rcvbuflen; + if (readlen > sizeof(buf)) readlen = sizeof(buf); + } + + nread = read(fd,buf,readlen); + if (nread == -1 && errno == EAGAIN) return; /* No more data ready. */ + + if (nread <= 0) { + /* I/O error... */ + redisLog(REDIS_DEBUG,"I/O error reading from node link: %s", + (nread == 0) ? "connection closed" : strerror(errno)); + handleLinkIOError(link); + return; + } else { + /* Read data and recast the pointer to the new buffer. */ + link->rcvbuf = sdscatlen(link->rcvbuf,buf,nread); + hdr = (clusterMsg*) link->rcvbuf; + rcvbuflen += nread; + } + + /* Total length obtained? Process this packet. */ + if (rcvbuflen >= 8 && rcvbuflen == ntohl(hdr->totlen)) { + if (clusterProcessPacket(link)) { + sdsfree(link->rcvbuf); + link->rcvbuf = sdsempty(); + } else { + return; /* Link no longer valid. */ + } + } + } +} + +/* Put stuff into the send buffer. + * + * It is guaranteed that this function will never have as a side effect + * the link to be invalidated, so it is safe to call this function + * from event handlers that will do stuff with the same link later. */ +void clusterSendMessage(clusterLink *link, unsigned char *msg, size_t msglen) { + if (sdslen(link->sndbuf) == 0 && msglen != 0) + aeCreateFileEvent(server.el,link->fd,AE_WRITABLE, + clusterWriteHandler,link); + + link->sndbuf = sdscatlen(link->sndbuf, msg, msglen); + server.cluster->stats_bus_messages_sent++; +} + +/* Send a message to all the nodes that are part of the cluster having + * a connected link. + * + * It is guaranteed that this function will never have as a side effect + * some node->link to be invalidated, so it is safe to call this function + * from event handlers that will do stuff with node links later. */ +void clusterBroadcastMessage(void *buf, size_t len) { + dictIterator *di; + dictEntry *de; + + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + + if (!node->link) continue; + if (node->flags & (REDIS_NODE_MYSELF|REDIS_NODE_HANDSHAKE)) + continue; + clusterSendMessage(node->link,buf,len); + } + dictReleaseIterator(di); +} + +/* Build the message header. hdr must point to a buffer at least + * sizeof(clusterMsg) in bytes. */ +void clusterBuildMessageHdr(clusterMsg *hdr, int type) { + int totlen = 0; + uint64_t offset; + clusterNode *master; + + /* If this node is a master, we send its slots bitmap and configEpoch. + * If this node is a slave we send the master's information instead (the + * node is flagged as slave so the receiver knows that it is NOT really + * in charge for this slots. */ + master = (nodeIsSlave(myself) && myself->slaveof) ? + myself->slaveof : myself; + + memset(hdr,0,sizeof(*hdr)); + hdr->ver = htons(CLUSTER_PROTO_VER); + hdr->sig[0] = 'R'; + hdr->sig[1] = 'C'; + hdr->sig[2] = 'm'; + hdr->sig[3] = 'b'; + hdr->type = htons(type); + memcpy(hdr->sender,myself->name,REDIS_CLUSTER_NAMELEN); + + memcpy(hdr->myslots,master->slots,sizeof(hdr->myslots)); + memset(hdr->slaveof,0,REDIS_CLUSTER_NAMELEN); + if (myself->slaveof != NULL) + memcpy(hdr->slaveof,myself->slaveof->name, REDIS_CLUSTER_NAMELEN); + hdr->port = htons(server.port); + hdr->flags = htons(myself->flags); + hdr->state = server.cluster->state; + + /* Set the currentEpoch and configEpochs. */ + hdr->currentEpoch = htonu64(server.cluster->currentEpoch); + hdr->configEpoch = htonu64(master->configEpoch); + + /* Set the replication offset. */ + if (nodeIsSlave(myself)) + offset = replicationGetSlaveOffset(); + else + offset = server.master_repl_offset; + hdr->offset = htonu64(offset); + + /* Set the message flags. */ + if (nodeIsMaster(myself) && server.cluster->mf_end) + hdr->mflags[0] |= CLUSTERMSG_FLAG0_PAUSED; + + /* Compute the message length for certain messages. For other messages + * this is up to the caller. */ + if (type == CLUSTERMSG_TYPE_FAIL) { + totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + totlen += sizeof(clusterMsgDataFail); + } else if (type == CLUSTERMSG_TYPE_UPDATE) { + totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + totlen += sizeof(clusterMsgDataUpdate); + } + hdr->totlen = htonl(totlen); + /* For PING, PONG, and MEET, fixing the totlen field is up to the caller. */ +} + +/* Send a PING or PONG packet to the specified node, making sure to add enough + * gossip informations. */ +void clusterSendPing(clusterLink *link, int type) { + unsigned char *buf; + clusterMsg *hdr; + int gossipcount = 0; /* Number of gossip sections added so far. */ + int wanted; /* Number of gossip sections we want to append if possible. */ + int totlen; /* Total packet length. */ + /* freshnodes is the max number of nodes we can hope to append at all: + * nodes available minus two (ourself and the node we are sending the + * message to). However practically there may be less valid nodes since + * nodes in handshake state, disconnected, are not considered. */ + int freshnodes = dictSize(server.cluster->nodes)-2; + + /* How many gossip sections we want to add? 1/10 of the number of nodes + * and anyway at least 3. Why 1/10? + * + * If we have N masters, with N/10 entries, and we consider that in + * node_timeout we exchange with each other node at least 4 packets + * (we ping in the worst case in node_timeout/2 time, and we also + * receive two pings from the host), we have a total of 8 packets + * in the node_timeout*2 falure reports validity time. So we have + * that, for a single PFAIL node, we can expect to receive the following + * number of failure reports (in the specified window of time): + * + * PROB * GOSSIP_ENTRIES_PER_PACKET * TOTAL_PACKETS: + * + * PROB = probability of being featured in a single gossip entry, + * which is 1 / NUM_OF_NODES. + * ENTRIES = 10. + * TOTAL_PACKETS = 2 * 4 * NUM_OF_MASTERS. + * + * If we assume we have just masters (so num of nodes and num of masters + * is the same), with 1/10 we always get over the majority, and specifically + * 80% of the number of nodes, to account for many masters failing at the + * same time. + * + * Since we have non-voting slaves that lower the probability of an entry + * to feature our node, we set the number of entires per packet as + * 10% of the total nodes we have. */ + wanted = floor(dictSize(server.cluster->nodes)/10); + if (wanted < 3) wanted = 3; + if (wanted > freshnodes) wanted = freshnodes; + + /* Compute the maxium totlen to allocate our buffer. We'll fix the totlen + * later according to the number of gossip sections we really were able + * to put inside the packet. */ + totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + totlen += (sizeof(clusterMsgDataGossip)*wanted); + /* Note: clusterBuildMessageHdr() expects the buffer to be always at least + * sizeof(clusterMsg) or more. */ + if (totlen < (int)sizeof(clusterMsg)) totlen = sizeof(clusterMsg); + buf = zcalloc(totlen); + hdr = (clusterMsg*) buf; + + /* Populate the header. */ + if (link->node && type == CLUSTERMSG_TYPE_PING) + link->node->ping_sent = mstime(); + clusterBuildMessageHdr(hdr,type); + + /* Populate the gossip fields */ + int maxiterations = wanted*3; + while(freshnodes > 0 && gossipcount < wanted && maxiterations--) { + dictEntry *de = dictGetRandomKey(server.cluster->nodes); + clusterNode *this = dictGetVal(de); + clusterMsgDataGossip *gossip; + int j; + + /* Don't include this node: the whole packet header is about us + * already, so we just gossip about other nodes. */ + if (this == myself) continue; + + /* Give a bias to FAIL/PFAIL nodes. */ + if (maxiterations > wanted*2 && + !(this->flags & (REDIS_NODE_PFAIL|REDIS_NODE_FAIL))) + continue; + + /* In the gossip section don't include: + * 1) Nodes in HANDSHAKE state. + * 3) Nodes with the NOADDR flag set. + * 4) Disconnected nodes if they don't have configured slots. + */ + if (this->flags & (REDIS_NODE_HANDSHAKE|REDIS_NODE_NOADDR) || + (this->link == NULL && this->numslots == 0)) + { + freshnodes--; /* Tecnically not correct, but saves CPU. */ + continue; + } + + /* Check if we already added this node */ + for (j = 0; j < gossipcount; j++) { + if (memcmp(hdr->data.ping.gossip[j].nodename,this->name, + REDIS_CLUSTER_NAMELEN) == 0) break; + } + if (j != gossipcount) continue; + + /* Add it */ + freshnodes--; + gossip = &(hdr->data.ping.gossip[gossipcount]); + memcpy(gossip->nodename,this->name,REDIS_CLUSTER_NAMELEN); + gossip->ping_sent = htonl(this->ping_sent); + gossip->pong_received = htonl(this->pong_received); + memcpy(gossip->ip,this->ip,sizeof(this->ip)); + gossip->port = htons(this->port); + gossip->flags = htons(this->flags); + gossip->notused1 = 0; + gossip->notused2 = 0; + gossipcount++; + } + + /* Ready to send... fix the totlen fiend and queue the message in the + * output buffer. */ + totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + totlen += (sizeof(clusterMsgDataGossip)*gossipcount); + hdr->count = htons(gossipcount); + hdr->totlen = htonl(totlen); + clusterSendMessage(link,buf,totlen); + zfree(buf); +} + +/* Send a PONG packet to every connected node that's not in handshake state + * and for which we have a valid link. + * + * In Redis Cluster pongs are not used just for failure detection, but also + * to carry important configuration information. So broadcasting a pong is + * useful when something changes in the configuration and we want to make + * the cluster aware ASAP (for instance after a slave promotion). + * + * The 'target' argument specifies the receiving instances using the + * defines below: + * + * CLUSTER_BROADCAST_ALL -> All known instances. + * CLUSTER_BROADCAST_LOCAL_SLAVES -> All slaves in my master-slaves ring. + */ +#define CLUSTER_BROADCAST_ALL 0 +#define CLUSTER_BROADCAST_LOCAL_SLAVES 1 +void clusterBroadcastPong(int target) { + dictIterator *di; + dictEntry *de; + + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + + if (!node->link) continue; + if (node == myself || nodeInHandshake(node)) continue; + if (target == CLUSTER_BROADCAST_LOCAL_SLAVES) { + int local_slave = + nodeIsSlave(node) && node->slaveof && + (node->slaveof == myself || node->slaveof == myself->slaveof); + if (!local_slave) continue; + } + clusterSendPing(node->link,CLUSTERMSG_TYPE_PONG); + } + dictReleaseIterator(di); +} + +/* Send a PUBLISH message. + * + * If link is NULL, then the message is broadcasted to the whole cluster. */ +void clusterSendPublish(clusterLink *link, robj *channel, robj *message) { + unsigned char buf[sizeof(clusterMsg)], *payload; + clusterMsg *hdr = (clusterMsg*) buf; + uint32_t totlen; + uint32_t channel_len, message_len; + + channel = getDecodedObject(channel); + message = getDecodedObject(message); + channel_len = sdslen(channel->ptr); + message_len = sdslen(message->ptr); + + clusterBuildMessageHdr(hdr,CLUSTERMSG_TYPE_PUBLISH); + totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + totlen += sizeof(clusterMsgDataPublish) - 8 + channel_len + message_len; + + hdr->data.publish.msg.channel_len = htonl(channel_len); + hdr->data.publish.msg.message_len = htonl(message_len); + hdr->totlen = htonl(totlen); + + /* Try to use the local buffer if possible */ + if (totlen < sizeof(buf)) { + payload = buf; + } else { + payload = zmalloc(totlen); + memcpy(payload,hdr,sizeof(*hdr)); + hdr = (clusterMsg*) payload; + } + memcpy(hdr->data.publish.msg.bulk_data,channel->ptr,sdslen(channel->ptr)); + memcpy(hdr->data.publish.msg.bulk_data+sdslen(channel->ptr), + message->ptr,sdslen(message->ptr)); + + if (link) + clusterSendMessage(link,payload,totlen); + else + clusterBroadcastMessage(payload,totlen); + + decrRefCount(channel); + decrRefCount(message); + if (payload != buf) zfree(payload); +} + +/* Send a FAIL message to all the nodes we are able to contact. + * The FAIL message is sent when we detect that a node is failing + * (REDIS_NODE_PFAIL) and we also receive a gossip confirmation of this: + * we switch the node state to REDIS_NODE_FAIL and ask all the other + * nodes to do the same ASAP. */ +void clusterSendFail(char *nodename) { + unsigned char buf[sizeof(clusterMsg)]; + clusterMsg *hdr = (clusterMsg*) buf; + + clusterBuildMessageHdr(hdr,CLUSTERMSG_TYPE_FAIL); + memcpy(hdr->data.fail.about.nodename,nodename,REDIS_CLUSTER_NAMELEN); + clusterBroadcastMessage(buf,ntohl(hdr->totlen)); +} + +/* Send an UPDATE message to the specified link carrying the specified 'node' + * slots configuration. The node name, slots bitmap, and configEpoch info + * are included. */ +void clusterSendUpdate(clusterLink *link, clusterNode *node) { + unsigned char buf[sizeof(clusterMsg)]; + clusterMsg *hdr = (clusterMsg*) buf; + + if (link == NULL) return; + clusterBuildMessageHdr(hdr,CLUSTERMSG_TYPE_UPDATE); + memcpy(hdr->data.update.nodecfg.nodename,node->name,REDIS_CLUSTER_NAMELEN); + hdr->data.update.nodecfg.configEpoch = htonu64(node->configEpoch); + memcpy(hdr->data.update.nodecfg.slots,node->slots,sizeof(node->slots)); + clusterSendMessage(link,buf,ntohl(hdr->totlen)); +} + +/* ----------------------------------------------------------------------------- + * CLUSTER Pub/Sub support + * + * For now we do very little, just propagating PUBLISH messages across the whole + * cluster. In the future we'll try to get smarter and avoiding propagating those + * messages to hosts without receives for a given channel. + * -------------------------------------------------------------------------- */ +void clusterPropagatePublish(robj *channel, robj *message) { + clusterSendPublish(NULL, channel, message); +} + +/* ----------------------------------------------------------------------------- + * SLAVE node specific functions + * -------------------------------------------------------------------------- */ + +/* This function sends a FAILOVE_AUTH_REQUEST message to every node in order to + * see if there is the quorum for this slave instance to failover its failing + * master. + * + * Note that we send the failover request to everybody, master and slave nodes, + * but only the masters are supposed to reply to our query. */ +void clusterRequestFailoverAuth(void) { + unsigned char buf[sizeof(clusterMsg)]; + clusterMsg *hdr = (clusterMsg*) buf; + uint32_t totlen; + + clusterBuildMessageHdr(hdr,CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST); + /* If this is a manual failover, set the CLUSTERMSG_FLAG0_FORCEACK bit + * in the header to communicate the nodes receiving the message that + * they should authorized the failover even if the master is working. */ + if (server.cluster->mf_end) hdr->mflags[0] |= CLUSTERMSG_FLAG0_FORCEACK; + totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + hdr->totlen = htonl(totlen); + clusterBroadcastMessage(buf,totlen); +} + +/* Send a FAILOVER_AUTH_ACK message to the specified node. */ +void clusterSendFailoverAuth(clusterNode *node) { + unsigned char buf[sizeof(clusterMsg)]; + clusterMsg *hdr = (clusterMsg*) buf; + uint32_t totlen; + + if (!node->link) return; + clusterBuildMessageHdr(hdr,CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK); + totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + hdr->totlen = htonl(totlen); + clusterSendMessage(node->link,buf,totlen); +} + +/* Send a MFSTART message to the specified node. */ +void clusterSendMFStart(clusterNode *node) { + unsigned char buf[sizeof(clusterMsg)]; + clusterMsg *hdr = (clusterMsg*) buf; + uint32_t totlen; + + if (!node->link) return; + clusterBuildMessageHdr(hdr,CLUSTERMSG_TYPE_MFSTART); + totlen = sizeof(clusterMsg)-sizeof(union clusterMsgData); + hdr->totlen = htonl(totlen); + clusterSendMessage(node->link,buf,totlen); +} + +/* Vote for the node asking for our vote if there are the conditions. */ +void clusterSendFailoverAuthIfNeeded(clusterNode *node, clusterMsg *request) { + clusterNode *master = node->slaveof; + uint64_t requestCurrentEpoch = ntohu64(request->currentEpoch); + uint64_t requestConfigEpoch = ntohu64(request->configEpoch); + unsigned char *claimed_slots = request->myslots; + int force_ack = request->mflags[0] & CLUSTERMSG_FLAG0_FORCEACK; + int j; + + /* IF we are not a master serving at least 1 slot, we don't have the + * right to vote, as the cluster size in Redis Cluster is the number + * of masters serving at least one slot, and quorum is the cluster + * size + 1 */ + if (nodeIsSlave(myself) || myself->numslots == 0) return; + + /* Request epoch must be >= our currentEpoch. + * Note that it is impossible for it to actually be greater since + * our currentEpoch was updated as a side effect of receiving this + * request, if the request epoch was greater. */ + if (requestCurrentEpoch < server.cluster->currentEpoch) { + redisLog(REDIS_WARNING, + "Failover auth denied to %.40s: reqEpoch (%llu) < curEpoch(%llu)", + node->name, + (unsigned long long) requestCurrentEpoch, + (unsigned long long) server.cluster->currentEpoch); + return; + } + + /* I already voted for this epoch? Return ASAP. */ + if (server.cluster->lastVoteEpoch == server.cluster->currentEpoch) { + redisLog(REDIS_WARNING, + "Failover auth denied to %.40s: already voted for epoch %llu", + node->name, + (unsigned long long) server.cluster->currentEpoch); + return; + } + + /* Node must be a slave and its master down. + * The master can be non failing if the request is flagged + * with CLUSTERMSG_FLAG0_FORCEACK (manual failover). */ + if (nodeIsMaster(node) || master == NULL || + (!nodeFailed(master) && !force_ack)) + { + if (nodeIsMaster(node)) { + redisLog(REDIS_WARNING, + "Failover auth denied to %.40s: it is a master node", + node->name); + } else if (master == NULL) { + redisLog(REDIS_WARNING, + "Failover auth denied to %.40s: I don't know its master", + node->name); + } else if (!nodeFailed(master)) { + redisLog(REDIS_WARNING, + "Failover auth denied to %.40s: its master is up", + node->name); + } + return; + } + + /* We did not voted for a slave about this master for two + * times the node timeout. This is not strictly needed for correctness + * of the algorithm but makes the base case more linear. */ + if (mstime() - node->slaveof->voted_time < server.cluster_node_timeout * 2) + { + redisLog(REDIS_WARNING, + "Failover auth denied to %.40s: " + "can't vote about this master before %lld milliseconds", + node->name, + (long long) ((server.cluster_node_timeout*2)- + (mstime() - node->slaveof->voted_time))); + return; + } + + /* The slave requesting the vote must have a configEpoch for the claimed + * slots that is >= the one of the masters currently serving the same + * slots in the current configuration. */ + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (bitmapTestBit(claimed_slots, j) == 0) continue; + if (server.cluster->slots[j] == NULL || + server.cluster->slots[j]->configEpoch <= requestConfigEpoch) + { + continue; + } + /* If we reached this point we found a slot that in our current slots + * is served by a master with a greater configEpoch than the one claimed + * by the slave requesting our vote. Refuse to vote for this slave. */ + redisLog(REDIS_WARNING, + "Failover auth denied to %.40s: " + "slot %d epoch (%llu) > reqEpoch (%llu)", + node->name, j, + (unsigned long long) server.cluster->slots[j]->configEpoch, + (unsigned long long) requestConfigEpoch); + return; + } + + /* We can vote for this slave. */ + clusterSendFailoverAuth(node); + server.cluster->lastVoteEpoch = server.cluster->currentEpoch; + node->slaveof->voted_time = mstime(); + redisLog(REDIS_WARNING, "Failover auth granted to %.40s for epoch %llu", + node->name, (unsigned long long) server.cluster->currentEpoch); +} + +/* This function returns the "rank" of this instance, a slave, in the context + * of its master-slaves ring. The rank of the slave is given by the number of + * other slaves for the same master that have a better replication offset + * compared to the local one (better means, greater, so they claim more data). + * + * A slave with rank 0 is the one with the greatest (most up to date) + * replication offset, and so forth. Note that because how the rank is computed + * multiple slaves may have the same rank, in case they have the same offset. + * + * The slave rank is used to add a delay to start an election in order to + * get voted and replace a failing master. Slaves with better replication + * offsets are more likely to win. */ +int clusterGetSlaveRank(void) { + long long myoffset; + int j, rank = 0; + clusterNode *master; + + redisAssert(nodeIsSlave(myself)); + master = myself->slaveof; + if (master == NULL) return 0; /* Never called by slaves without master. */ + + myoffset = replicationGetSlaveOffset(); + for (j = 0; j < master->numslaves; j++) + if (master->slaves[j] != myself && + master->slaves[j]->repl_offset > myoffset) rank++; + return rank; +} + +/* This function is called by clusterHandleSlaveFailover() in order to + * let the slave log why it is not able to failover. Sometimes there are + * not the conditions, but since the failover function is called again and + * again, we can't log the same things continuously. + * + * This function works by logging only if a given set of conditions are + * true: + * + * 1) The reason for which the failover can't be initiated changed. + * The reasons also include a NONE reason we reset the state to + * when the slave finds that its master is fine (no FAIL flag). + * 2) Also, the log is emitted again if the master is still down and + * the reason for not failing over is still the same, but more than + * REDIS_CLUSTER_CANT_FAILOVER_RELOG_PERIOD seconds elapsed. + * 3) Finally, the function only logs if the slave is down for more than + * five seconds + NODE_TIMEOUT. This way nothing is logged when a + * failover starts in a reasonable time. + * + * The function is called with the reason why the slave can't failover + * which is one of the integer macros REDIS_CLUSTER_CANT_FAILOVER_*. + * + * The function is guaranteed to be called only if 'myself' is a slave. */ +void clusterLogCantFailover(int reason) { + char *msg; + static time_t lastlog_time = 0; + mstime_t nolog_fail_time = server.cluster_node_timeout + 5000; + + /* Don't log if we have the same reason for some time. */ + if (reason == server.cluster->cant_failover_reason && + time(NULL)-lastlog_time < REDIS_CLUSTER_CANT_FAILOVER_RELOG_PERIOD) + return; + + server.cluster->cant_failover_reason = reason; + + /* We also don't emit any log if the master failed no long ago, the + * goal of this function is to log slaves in a stalled condition for + * a long time. */ + if (myself->slaveof && + nodeFailed(myself->slaveof) && + (mstime() - myself->slaveof->fail_time) < nolog_fail_time) return; + + switch(reason) { + case REDIS_CLUSTER_CANT_FAILOVER_DATA_AGE: + msg = "Disconnected from master for longer than allowed."; + break; + case REDIS_CLUSTER_CANT_FAILOVER_WAITING_DELAY: + msg = "Waiting the delay before I can start a new failover."; + break; + case REDIS_CLUSTER_CANT_FAILOVER_EXPIRED: + msg = "Failover attempt expired."; + break; + case REDIS_CLUSTER_CANT_FAILOVER_WAITING_VOTES: + msg = "Waiting for votes, but majority still not reached."; + break; + default: + msg = "Unknown reason code."; + break; + } + lastlog_time = time(NULL); + redisLog(REDIS_WARNING,"Currently unable to failover: %s", msg); +} + +/* This function implements the final part of automatic and manual failovers, + * where the slave grabs its master's hash slots, and propagates the new + * configuration. + * + * Note that it's up to the caller to be sure that the node got a new + * configuration epoch already. */ +void clusterFailoverReplaceYourMaster(void) { + int j; + clusterNode *oldmaster = myself->slaveof; + + if (nodeIsMaster(myself) || oldmaster == NULL) return; + + /* 1) Turn this node into a master. */ + clusterSetNodeAsMaster(myself); + replicationUnsetMaster(); + + /* 2) Claim all the slots assigned to our master. */ + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (clusterNodeGetSlotBit(oldmaster,j)) { + clusterDelSlot(j); + clusterAddSlot(myself,j); + } + } + + /* 3) Update state and save config. */ + clusterUpdateState(); + clusterSaveConfigOrDie(1); + + /* 4) Pong all the other nodes so that they can update the state + * accordingly and detect that we switched to master role. */ + clusterBroadcastPong(CLUSTER_BROADCAST_ALL); + + /* 5) If there was a manual failover in progress, clear the state. */ + resetManualFailover(); +} + +/* This function is called if we are a slave node and our master serving + * a non-zero amount of hash slots is in FAIL state. + * + * The gaol of this function is: + * 1) To check if we are able to perform a failover, is our data updated? + * 2) Try to get elected by masters. + * 3) Perform the failover informing all the other nodes. + */ +void clusterHandleSlaveFailover(void) { + mstime_t data_age; + mstime_t auth_age = mstime() - server.cluster->failover_auth_time; + int needed_quorum = (server.cluster->size / 2) + 1; + int manual_failover = server.cluster->mf_end != 0 && + server.cluster->mf_can_start; + mstime_t auth_timeout, auth_retry_time; + + server.cluster->todo_before_sleep &= ~CLUSTER_TODO_HANDLE_FAILOVER; + + /* Compute the failover timeout (the max time we have to send votes + * and wait for replies), and the failover retry time (the time to wait + * before trying to get voted again). + * + * Timeout is MIN(NODE_TIMEOUT*2,2000) milliseconds. + * Retry is two times the Timeout. + */ + auth_timeout = server.cluster_node_timeout*2; + if (auth_timeout < 2000) auth_timeout = 2000; + auth_retry_time = auth_timeout*2; + + /* Pre conditions to run the function, that must be met both in case + * of an automatic or manual failover: + * 1) We are a slave. + * 2) Our master is flagged as FAIL, or this is a manual failover. + * 3) It is serving slots. */ + if (nodeIsMaster(myself) || + myself->slaveof == NULL || + (!nodeFailed(myself->slaveof) && !manual_failover) || + myself->slaveof->numslots == 0) + { + /* There are no reasons to failover, so we set the reason why we + * are returning without failing over to NONE. */ + server.cluster->cant_failover_reason = REDIS_CLUSTER_CANT_FAILOVER_NONE; + return; + } + + /* Set data_age to the number of seconds we are disconnected from + * the master. */ + if (server.repl_state == REDIS_REPL_CONNECTED) { + data_age = (mstime_t)(server.unixtime - server.master->lastinteraction) + * 1000; + } else { + data_age = (mstime_t)(server.unixtime - server.repl_down_since) * 1000; + } + + /* Remove the node timeout from the data age as it is fine that we are + * disconnected from our master at least for the time it was down to be + * flagged as FAIL, that's the baseline. */ + if (data_age > server.cluster_node_timeout) + data_age -= server.cluster_node_timeout; + + /* Check if our data is recent enough according to the slave validity + * factor configured by the user. + * + * Check bypassed for manual failovers. */ + if (server.cluster_slave_validity_factor && + data_age > + (((mstime_t)server.repl_ping_slave_period * 1000) + + (server.cluster_node_timeout * server.cluster_slave_validity_factor))) + { + if (!manual_failover) { + clusterLogCantFailover(REDIS_CLUSTER_CANT_FAILOVER_DATA_AGE); + return; + } + } + + /* If the previous failover attempt timedout and the retry time has + * elapsed, we can setup a new one. */ + if (auth_age > auth_retry_time) { + server.cluster->failover_auth_time = mstime() + + 500 + /* Fixed delay of 500 milliseconds, let FAIL msg propagate. */ + random() % 500; /* Random delay between 0 and 500 milliseconds. */ + server.cluster->failover_auth_count = 0; + server.cluster->failover_auth_sent = 0; + server.cluster->failover_auth_rank = clusterGetSlaveRank(); + /* We add another delay that is proportional to the slave rank. + * Specifically 1 second * rank. This way slaves that have a probably + * less updated replication offset, are penalized. */ + server.cluster->failover_auth_time += + server.cluster->failover_auth_rank * 1000; + /* However if this is a manual failover, no delay is needed. */ + if (server.cluster->mf_end) { + server.cluster->failover_auth_time = mstime(); + server.cluster->failover_auth_rank = 0; + } + redisLog(REDIS_WARNING, + "Start of election delayed for %lld milliseconds " + "(rank #%d, offset %lld).", + server.cluster->failover_auth_time - mstime(), + server.cluster->failover_auth_rank, + replicationGetSlaveOffset()); + /* Now that we have a scheduled election, broadcast our offset + * to all the other slaves so that they'll updated their offsets + * if our offset is better. */ + clusterBroadcastPong(CLUSTER_BROADCAST_LOCAL_SLAVES); + return; + } + + /* It is possible that we received more updated offsets from other + * slaves for the same master since we computed our election delay. + * Update the delay if our rank changed. + * + * Not performed if this is a manual failover. */ + if (server.cluster->failover_auth_sent == 0 && + server.cluster->mf_end == 0) + { + int newrank = clusterGetSlaveRank(); + if (newrank > server.cluster->failover_auth_rank) { + long long added_delay = + (newrank - server.cluster->failover_auth_rank) * 1000; + server.cluster->failover_auth_time += added_delay; + server.cluster->failover_auth_rank = newrank; + redisLog(REDIS_WARNING, + "Slave rank updated to #%d, added %lld milliseconds of delay.", + newrank, added_delay); + } + } + + /* Return ASAP if we can't still start the election. */ + if (mstime() < server.cluster->failover_auth_time) { + clusterLogCantFailover(REDIS_CLUSTER_CANT_FAILOVER_WAITING_DELAY); + return; + } + + /* Return ASAP if the election is too old to be valid. */ + if (auth_age > auth_timeout) { + clusterLogCantFailover(REDIS_CLUSTER_CANT_FAILOVER_EXPIRED); + return; + } + + /* Ask for votes if needed. */ + if (server.cluster->failover_auth_sent == 0) { + server.cluster->currentEpoch++; + server.cluster->failover_auth_epoch = server.cluster->currentEpoch; + redisLog(REDIS_WARNING,"Starting a failover election for epoch %llu.", + (unsigned long long) server.cluster->currentEpoch); + clusterRequestFailoverAuth(); + server.cluster->failover_auth_sent = 1; + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG| + CLUSTER_TODO_UPDATE_STATE| + CLUSTER_TODO_FSYNC_CONFIG); + return; /* Wait for replies. */ + } + + /* Check if we reached the quorum. */ + if (server.cluster->failover_auth_count >= needed_quorum) { + /* We have the quorum, we can finally failover the master. */ + + redisLog(REDIS_WARNING, + "Failover election won: I'm the new master."); + + /* Update my configEpoch to the epoch of the election. */ + if (myself->configEpoch < server.cluster->failover_auth_epoch) { + myself->configEpoch = server.cluster->failover_auth_epoch; + redisLog(REDIS_WARNING, + "configEpoch set to %llu after successful failover", + (unsigned long long) myself->configEpoch); + } + + /* Take responsability for the cluster slots. */ + clusterFailoverReplaceYourMaster(); + } else { + clusterLogCantFailover(REDIS_CLUSTER_CANT_FAILOVER_WAITING_VOTES); + } +} + +/* ----------------------------------------------------------------------------- + * CLUSTER slave migration + * + * Slave migration is the process that allows a slave of a master that is + * already covered by at least another slave, to "migrate" to a master that + * is orpaned, that is, left with no working slaves. + * -------------------------------------------------------------------------- */ + +/* This function is responsible to decide if this replica should be migrated + * to a different (orphaned) master. It is called by the clusterCron() function + * only if: + * + * 1) We are a slave node. + * 2) It was detected that there is at least one orphaned master in + * the cluster. + * 3) We are a slave of one of the masters with the greatest number of + * slaves. + * + * This checks are performed by the caller since it requires to iterate + * the nodes anyway, so we spend time into clusterHandleSlaveMigration() + * if definitely needed. + * + * The fuction is called with a pre-computed max_slaves, that is the max + * number of working (not in FAIL state) slaves for a single master. + * + * Additional conditions for migration are examined inside the function. + */ +void clusterHandleSlaveMigration(int max_slaves) { + int j, okslaves = 0; + clusterNode *mymaster = myself->slaveof, *target = NULL, *candidate = NULL; + dictIterator *di; + dictEntry *de; + + /* Step 1: Don't migrate if the cluster state is not ok. */ + if (server.cluster->state != REDIS_CLUSTER_OK) return; + + /* Step 2: Don't migrate if my master will not be left with at least + * 'migration-barrier' slaves after my migration. */ + if (mymaster == NULL) return; + for (j = 0; j < mymaster->numslaves; j++) + if (!nodeFailed(mymaster->slaves[j]) && + !nodeTimedOut(mymaster->slaves[j])) okslaves++; + if (okslaves <= server.cluster_migration_barrier) return; + + /* Step 3: Idenitfy a candidate for migration, and check if among the + * masters with the greatest number of ok slaves, I'm the one with the + * smaller node ID. + * + * Note that this means that eventually a replica migration will occurr + * since slaves that are reachable again always have their FAIL flag + * cleared. At the same time this does not mean that there are no + * race conditions possible (two slaves migrating at the same time), but + * this is extremely unlikely to happen, and harmless. */ + candidate = myself; + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + int okslaves; + + /* Only iterate over working masters. */ + if (nodeIsSlave(node) || nodeFailed(node)) continue; + /* If this master never had slaves so far, don't migrate. We want + * to migrate to a master that remained orphaned, not masters that + * were never configured to have slaves. */ + if (node->numslaves == 0) continue; + okslaves = clusterCountNonFailingSlaves(node); + + if (okslaves == 0 && target == NULL && node->numslots > 0) + target = node; + + if (okslaves == max_slaves) { + for (j = 0; j < node->numslaves; j++) { + if (memcmp(node->slaves[j]->name, + candidate->name, + REDIS_CLUSTER_NAMELEN) < 0) + { + candidate = node->slaves[j]; + } + } + } + } + dictReleaseIterator(di); + + /* Step 4: perform the migration if there is a target, and if I'm the + * candidate. */ + if (target && candidate == myself) { + redisLog(REDIS_WARNING,"Migrating to orphaned master %.40s", + target->name); + clusterSetMaster(target); + } +} + +/* ----------------------------------------------------------------------------- + * CLUSTER manual failover + * + * This are the important steps performed by slaves during a manual failover: + * 1) User send CLUSTER FAILOVER command. The failover state is initialized + * setting mf_end to the millisecond unix time at which we'll abort the + * attempt. + * 2) Slave sends a MFSTART message to the master requesting to pause clients + * for two times the manual failover timeout REDIS_CLUSTER_MF_TIMEOUT. + * When master is paused for manual failover, it also starts to flag + * packets with CLUSTERMSG_FLAG0_PAUSED. + * 3) Slave waits for master to send its replication offset flagged as PAUSED. + * 4) If slave received the offset from the master, and its offset matches, + * mf_can_start is set to 1, and clusterHandleSlaveFailover() will perform + * the failover as usually, with the difference that the vote request + * will be modified to force masters to vote for a slave that has a + * working master. + * + * From the point of view of the master things are simpler: when a + * PAUSE_CLIENTS packet is received the master sets mf_end as well and + * the sender in mf_slave. During the time limit for the manual failover + * the master will just send PINGs more often to this slave, flagged with + * the PAUSED flag, so that the slave will set mf_master_offset when receiving + * a packet from the master with this flag set. + * + * The gaol of the manual failover is to perform a fast failover without + * data loss due to the asynchronous master-slave replication. + * -------------------------------------------------------------------------- */ + +/* Reset the manual failover state. This works for both masters and slavesa + * as all the state about manual failover is cleared. + * + * The function can be used both to initialize the manual failover state at + * startup or to abort a manual failover in progress. */ +void resetManualFailover(void) { + if (server.cluster->mf_end && clientsArePaused()) { + server.clients_pause_end_time = 0; + clientsArePaused(); /* Just use the side effect of the function. */ + } + server.cluster->mf_end = 0; /* No manual failover in progress. */ + server.cluster->mf_can_start = 0; + server.cluster->mf_slave = NULL; + server.cluster->mf_master_offset = 0; +} + +/* If a manual failover timed out, abort it. */ +void manualFailoverCheckTimeout(void) { + if (server.cluster->mf_end && server.cluster->mf_end < mstime()) { + redisLog(REDIS_WARNING,"Manual failover timed out."); + resetManualFailover(); + } +} + +/* This function is called from the cluster cron function in order to go + * forward with a manual failover state machine. */ +void clusterHandleManualFailover(void) { + /* Return ASAP if no manual failover is in progress. */ + if (server.cluster->mf_end == 0) return; + + /* If mf_can_start is non-zero, the failover was already triggered so the + * next steps are performed by clusterHandleSlaveFailover(). */ + if (server.cluster->mf_can_start) return; + + if (server.cluster->mf_master_offset == 0) return; /* Wait for offset... */ + + if (server.cluster->mf_master_offset == replicationGetSlaveOffset()) { + /* Our replication offset matches the master replication offset + * announced after clients were paused. We can start the failover. */ + server.cluster->mf_can_start = 1; + redisLog(REDIS_WARNING, + "All master replication stream processed, " + "manual failover can start."); + } +} + +/* ----------------------------------------------------------------------------- + * CLUSTER cron job + * -------------------------------------------------------------------------- */ + +/* This is executed 10 times every second */ +void clusterCron(void) { + dictIterator *di; + dictEntry *de; + int update_state = 0; + int orphaned_masters; /* How many masters there are without ok slaves. */ + int max_slaves; /* Max number of ok slaves for a single master. */ + int this_slaves; /* Number of ok slaves for our master (if we are slave). */ + mstime_t min_pong = 0, now = mstime(); + clusterNode *min_pong_node = NULL; + static unsigned long long iteration = 0; + mstime_t handshake_timeout; + + iteration++; /* Number of times this function was called so far. */ + + /* The handshake timeout is the time after which a handshake node that was + * not turned into a normal node is removed from the nodes. Usually it is + * just the NODE_TIMEOUT value, but when NODE_TIMEOUT is too small we use + * the value of 1 second. */ + handshake_timeout = server.cluster_node_timeout; + if (handshake_timeout < 1000) handshake_timeout = 1000; + + /* Check if we have disconnected nodes and re-establish the connection. */ + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + + if (node->flags & (REDIS_NODE_MYSELF|REDIS_NODE_NOADDR)) continue; + + /* A Node in HANDSHAKE state has a limited lifespan equal to the + * configured node timeout. */ + if (nodeInHandshake(node) && now - node->ctime > handshake_timeout) { + clusterDelNode(node); + continue; + } + + if (node->link == NULL) { + int fd; + mstime_t old_ping_sent; + clusterLink *link; + + fd = anetTcpNonBlockBindConnect(server.neterr, node->ip, + node->port+REDIS_CLUSTER_PORT_INCR, REDIS_BIND_ADDR); + if (fd == -1) { + /* We got a synchronous error from connect before + * clusterSendPing() had a chance to be called. + * If node->ping_sent is zero, failure detection can't work, + * so we claim we actually sent a ping now (that will + * be really sent as soon as the link is obtained). */ + if (node->ping_sent == 0) node->ping_sent = mstime(); + redisLog(REDIS_DEBUG, "Unable to connect to " + "Cluster Node [%s]:%d -> %s", node->ip, + node->port+REDIS_CLUSTER_PORT_INCR, + server.neterr); + continue; + } + link = createClusterLink(node); + link->fd = fd; + node->link = link; + aeCreateFileEvent(server.el,link->fd,AE_READABLE, + clusterReadHandler,link); + /* Queue a PING in the new connection ASAP: this is crucial + * to avoid false positives in failure detection. + * + * If the node is flagged as MEET, we send a MEET message instead + * of a PING one, to force the receiver to add us in its node + * table. */ + old_ping_sent = node->ping_sent; + clusterSendPing(link, node->flags & REDIS_NODE_MEET ? + CLUSTERMSG_TYPE_MEET : CLUSTERMSG_TYPE_PING); + if (old_ping_sent) { + /* If there was an active ping before the link was + * disconnected, we want to restore the ping time, otherwise + * replaced by the clusterSendPing() call. */ + node->ping_sent = old_ping_sent; + } + /* We can clear the flag after the first packet is sent. + * If we'll never receive a PONG, we'll never send new packets + * to this node. Instead after the PONG is received and we + * are no longer in meet/handshake status, we want to send + * normal PING packets. */ + node->flags &= ~REDIS_NODE_MEET; + + redisLog(REDIS_DEBUG,"Connecting with Node %.40s at %s:%d", + node->name, node->ip, node->port+REDIS_CLUSTER_PORT_INCR); + } + } + dictReleaseIterator(di); + + /* Ping some random node 1 time every 10 iterations, so that we usually ping + * one random node every second. */ + if (!(iteration % 10)) { + int j; + + /* Check a few random nodes and ping the one with the oldest + * pong_received time. */ + for (j = 0; j < 5; j++) { + de = dictGetRandomKey(server.cluster->nodes); + clusterNode *this = dictGetVal(de); + + /* Don't ping nodes disconnected or with a ping currently active. */ + if (this->link == NULL || this->ping_sent != 0) continue; + if (this->flags & (REDIS_NODE_MYSELF|REDIS_NODE_HANDSHAKE)) + continue; + if (min_pong_node == NULL || min_pong > this->pong_received) { + min_pong_node = this; + min_pong = this->pong_received; + } + } + if (min_pong_node) { + redisLog(REDIS_DEBUG,"Pinging node %.40s", min_pong_node->name); + clusterSendPing(min_pong_node->link, CLUSTERMSG_TYPE_PING); + } + } + + /* Iterate nodes to check if we need to flag something as failing. + * This loop is also responsible to: + * 1) Check if there are orphaned masters (masters without non failing + * slaves). + * 2) Count the max number of non failing slaves for a single master. + * 3) Count the number of slaves for our master, if we are a slave. */ + orphaned_masters = 0; + max_slaves = 0; + this_slaves = 0; + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + now = mstime(); /* Use an updated time at every iteration. */ + mstime_t delay; + + if (node->flags & + (REDIS_NODE_MYSELF|REDIS_NODE_NOADDR|REDIS_NODE_HANDSHAKE)) + continue; + + /* Orphaned master check, useful only if the current instance + * is a slave that may migrate to another master. */ + if (nodeIsSlave(myself) && nodeIsMaster(node) && !nodeFailed(node)) { + int okslaves = clusterCountNonFailingSlaves(node); + + /* A master is orphaned if it is serving a non-zero number of + * slots, have no working slaves, but used to have at least one + * slave. */ + if (okslaves == 0 && node->numslots > 0 && node->numslaves) + orphaned_masters++; + if (okslaves > max_slaves) max_slaves = okslaves; + if (nodeIsSlave(myself) && myself->slaveof == node) + this_slaves = okslaves; + } + + /* If we are waiting for the PONG more than half the cluster + * timeout, reconnect the link: maybe there is a connection + * issue even if the node is alive. */ + if (node->link && /* is connected */ + now - node->link->ctime > + server.cluster_node_timeout && /* was not already reconnected */ + node->ping_sent && /* we already sent a ping */ + node->pong_received < node->ping_sent && /* still waiting pong */ + /* and we are waiting for the pong more than timeout/2 */ + now - node->ping_sent > server.cluster_node_timeout/2) + { + /* Disconnect the link, it will be reconnected automatically. */ + freeClusterLink(node->link); + } + + /* If we have currently no active ping in this instance, and the + * received PONG is older than half the cluster timeout, send + * a new ping now, to ensure all the nodes are pinged without + * a too big delay. */ + if (node->link && + node->ping_sent == 0 && + (now - node->pong_received) > server.cluster_node_timeout/2) + { + clusterSendPing(node->link, CLUSTERMSG_TYPE_PING); + continue; + } + + /* If we are a master and one of the slaves requested a manual + * failover, ping it continuously. */ + if (server.cluster->mf_end && + nodeIsMaster(myself) && + server.cluster->mf_slave == node && + node->link) + { + clusterSendPing(node->link, CLUSTERMSG_TYPE_PING); + continue; + } + + /* Check only if we have an active ping for this instance. */ + if (node->ping_sent == 0) continue; + + /* Compute the delay of the PONG. Note that if we already received + * the PONG, then node->ping_sent is zero, so can't reach this + * code at all. */ + delay = now - node->ping_sent; + + if (delay > server.cluster_node_timeout) { + /* Timeout reached. Set the node as possibly failing if it is + * not already in this state. */ + if (!(node->flags & (REDIS_NODE_PFAIL|REDIS_NODE_FAIL))) { + redisLog(REDIS_DEBUG,"*** NODE %.40s possibly failing", + node->name); + node->flags |= REDIS_NODE_PFAIL; + update_state = 1; + } + } + } + dictReleaseIterator(di); + + /* If we are a slave node but the replication is still turned off, + * enable it if we know the address of our master and it appears to + * be up. */ + if (nodeIsSlave(myself) && + server.masterhost == NULL && + myself->slaveof && + nodeHasAddr(myself->slaveof)) + { + replicationSetMaster(myself->slaveof->ip, myself->slaveof->port); + } + + /* Abourt a manual failover if the timeout is reached. */ + manualFailoverCheckTimeout(); + + if (nodeIsSlave(myself)) { + clusterHandleManualFailover(); + clusterHandleSlaveFailover(); + /* If there are orphaned slaves, and we are a slave among the masters + * with the max number of non-failing slaves, consider migrating to + * the orphaned masters. Note that it does not make sense to try + * a migration if there is no master with at least *two* working + * slaves. */ + if (orphaned_masters && max_slaves >= 2 && this_slaves == max_slaves) + clusterHandleSlaveMigration(max_slaves); + } + + if (update_state || server.cluster->state == REDIS_CLUSTER_FAIL) + clusterUpdateState(); +} + +/* This function is called before the event handler returns to sleep for + * events. It is useful to perform operations that must be done ASAP in + * reaction to events fired but that are not safe to perform inside event + * handlers, or to perform potentially expansive tasks that we need to do + * a single time before replying to clients. */ +void clusterBeforeSleep(void) { + /* Handle failover, this is needed when it is likely that there is already + * the quorum from masters in order to react fast. */ + if (server.cluster->todo_before_sleep & CLUSTER_TODO_HANDLE_FAILOVER) + clusterHandleSlaveFailover(); + + /* Update the cluster state. */ + if (server.cluster->todo_before_sleep & CLUSTER_TODO_UPDATE_STATE) + clusterUpdateState(); + + /* Save the config, possibly using fsync. */ + if (server.cluster->todo_before_sleep & CLUSTER_TODO_SAVE_CONFIG) { + int fsync = server.cluster->todo_before_sleep & + CLUSTER_TODO_FSYNC_CONFIG; + clusterSaveConfigOrDie(fsync); + } + + /* Reset our flags (not strictly needed since every single function + * called for flags set should be able to clear its flag). */ + server.cluster->todo_before_sleep = 0; +} + +void clusterDoBeforeSleep(int flags) { + server.cluster->todo_before_sleep |= flags; +} + +/* ----------------------------------------------------------------------------- + * Slots management + * -------------------------------------------------------------------------- */ + +/* Test bit 'pos' in a generic bitmap. Return 1 if the bit is set, + * otherwise 0. */ +int bitmapTestBit(unsigned char *bitmap, int pos) { + off_t byte = pos/8; + int bit = pos&7; + return (bitmap[byte] & (1<slots,slot); + bitmapSetBit(n->slots,slot); + if (!old) n->numslots++; + return old; +} + +/* Clear the slot bit and return the old value. */ +int clusterNodeClearSlotBit(clusterNode *n, int slot) { + int old = bitmapTestBit(n->slots,slot); + bitmapClearBit(n->slots,slot); + if (old) n->numslots--; + return old; +} + +/* Return the slot bit from the cluster node structure. */ +int clusterNodeGetSlotBit(clusterNode *n, int slot) { + return bitmapTestBit(n->slots,slot); +} + +/* Add the specified slot to the list of slots that node 'n' will + * serve. Return REDIS_OK if the operation ended with success. + * If the slot is already assigned to another instance this is considered + * an error and REDIS_ERR is returned. */ +int clusterAddSlot(clusterNode *n, int slot) { + if (server.cluster->slots[slot]) return REDIS_ERR; + clusterNodeSetSlotBit(n,slot); + server.cluster->slots[slot] = n; + return REDIS_OK; +} + +/* Delete the specified slot marking it as unassigned. + * Returns REDIS_OK if the slot was assigned, otherwise if the slot was + * already unassigned REDIS_ERR is returned. */ +int clusterDelSlot(int slot) { + clusterNode *n = server.cluster->slots[slot]; + + if (!n) return REDIS_ERR; + redisAssert(clusterNodeClearSlotBit(n,slot) == 1); + server.cluster->slots[slot] = NULL; + return REDIS_OK; +} + +/* Delete all the slots associated with the specified node. + * The number of deleted slots is returned. */ +int clusterDelNodeSlots(clusterNode *node) { + int deleted = 0, j; + + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (clusterNodeGetSlotBit(node,j)) clusterDelSlot(j); + deleted++; + } + return deleted; +} + +/* Clear the migrating / importing state for all the slots. + * This is useful at initialization and when turning a master into slave. */ +void clusterCloseAllSlots(void) { + memset(server.cluster->migrating_slots_to,0, + sizeof(server.cluster->migrating_slots_to)); + memset(server.cluster->importing_slots_from,0, + sizeof(server.cluster->importing_slots_from)); +} + +/* ----------------------------------------------------------------------------- + * Cluster state evaluation function + * -------------------------------------------------------------------------- */ + +/* The following are defines that are only used in the evaluation function + * and are based on heuristics. Actaully the main point about the rejoin and + * writable delay is that they should be a few orders of magnitude larger + * than the network latency. */ +#define REDIS_CLUSTER_MAX_REJOIN_DELAY 5000 +#define REDIS_CLUSTER_MIN_REJOIN_DELAY 500 +#define REDIS_CLUSTER_WRITABLE_DELAY 2000 + +void clusterUpdateState(void) { + int j, new_state; + int reachable_masters = 0; + static mstime_t among_minority_time; + static mstime_t first_call_time = 0; + + server.cluster->todo_before_sleep &= ~CLUSTER_TODO_UPDATE_STATE; + + /* If this is a master node, wait some time before turning the state + * into OK, since it is not a good idea to rejoin the cluster as a writable + * master, after a reboot, without giving the cluster a chance to + * reconfigure this node. Note that the delay is calculated starting from + * the first call to this function and not since the server start, in order + * to don't count the DB loading time. */ + if (first_call_time == 0) first_call_time = mstime(); + if (nodeIsMaster(myself) && + server.cluster->state == REDIS_CLUSTER_FAIL && + mstime() - first_call_time < REDIS_CLUSTER_WRITABLE_DELAY) return; + + /* Start assuming the state is OK. We'll turn it into FAIL if there + * are the right conditions. */ + new_state = REDIS_CLUSTER_OK; + + /* Check if all the slots are covered. */ + if (server.cluster_require_full_coverage) { + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (server.cluster->slots[j] == NULL || + server.cluster->slots[j]->flags & (REDIS_NODE_FAIL)) + { + new_state = REDIS_CLUSTER_FAIL; + break; + } + } + } + + /* Compute the cluster size, that is the number of master nodes + * serving at least a single slot. + * + * At the same time count the number of reachable masters having + * at least one slot. */ + { + dictIterator *di; + dictEntry *de; + + server.cluster->size = 0; + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + + if (nodeIsMaster(node) && node->numslots) { + server.cluster->size++; + if ((node->flags & (REDIS_NODE_FAIL|REDIS_NODE_PFAIL)) == 0) + reachable_masters++; + } + } + dictReleaseIterator(di); + } + + /* If we are in a minority partition, change the cluster state + * to FAIL. */ + { + int needed_quorum = (server.cluster->size / 2) + 1; + + if (reachable_masters < needed_quorum) { + new_state = REDIS_CLUSTER_FAIL; + among_minority_time = mstime(); + } + } + + /* Log a state change */ + if (new_state != server.cluster->state) { + mstime_t rejoin_delay = server.cluster_node_timeout; + + /* If the instance is a master and was partitioned away with the + * minority, don't let it accept queries for some time after the + * partition heals, to make sure there is enough time to receive + * a configuration update. */ + if (rejoin_delay > REDIS_CLUSTER_MAX_REJOIN_DELAY) + rejoin_delay = REDIS_CLUSTER_MAX_REJOIN_DELAY; + if (rejoin_delay < REDIS_CLUSTER_MIN_REJOIN_DELAY) + rejoin_delay = REDIS_CLUSTER_MIN_REJOIN_DELAY; + + if (new_state == REDIS_CLUSTER_OK && + nodeIsMaster(myself) && + mstime() - among_minority_time < rejoin_delay) + { + return; + } + + /* Change the state and log the event. */ + redisLog(REDIS_WARNING,"Cluster state changed: %s", + new_state == REDIS_CLUSTER_OK ? "ok" : "fail"); + server.cluster->state = new_state; + } +} + +/* This function is called after the node startup in order to verify that data + * loaded from disk is in agreement with the cluster configuration: + * + * 1) If we find keys about hash slots we have no responsibility for, the + * following happens: + * A) If no other node is in charge according to the current cluster + * configuration, we add these slots to our node. + * B) If according to our config other nodes are already in charge for + * this lots, we set the slots as IMPORTING from our point of view + * in order to justify we have those slots, and in order to make + * redis-trib aware of the issue, so that it can try to fix it. + * 2) If we find data in a DB different than DB0 we return REDIS_ERR to + * signal the caller it should quit the server with an error message + * or take other actions. + * + * The function always returns REDIS_OK even if it will try to correct + * the error described in "1". However if data is found in DB different + * from DB0, REDIS_ERR is returned. + * + * The function also uses the logging facility in order to warn the user + * about desynchronizations between the data we have in memory and the + * cluster configuration. */ +int verifyClusterConfigWithData(void) { + int j; + int update_config = 0; + + /* If this node is a slave, don't perform the check at all as we + * completely depend on the replication stream. */ + if (nodeIsSlave(myself)) return REDIS_OK; + + /* Make sure we only have keys in DB0. */ + for (j = 1; j < server.dbnum; j++) { + if (dictSize(server.db[j].dict)) return REDIS_ERR; + } + + /* Check that all the slots we see populated memory have a corresponding + * entry in the cluster table. Otherwise fix the table. */ + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (!countKeysInSlot(j)) continue; /* No keys in this slot. */ + /* Check if we are assigned to this slot or if we are importing it. + * In both cases check the next slot as the configuration makes + * sense. */ + if (server.cluster->slots[j] == myself || + server.cluster->importing_slots_from[j] != NULL) continue; + + /* If we are here data and cluster config don't agree, and we have + * slot 'j' populated even if we are not importing it, nor we are + * assigned to this slot. Fix this condition. */ + + update_config++; + /* Case A: slot is unassigned. Take responsibility for it. */ + if (server.cluster->slots[j] == NULL) { + redisLog(REDIS_WARNING, "I have keys for unassigned slot %d. " + "Taking responsibility for it.",j); + clusterAddSlot(myself,j); + } else { + redisLog(REDIS_WARNING, "I have keys for slot %d, but the slot is " + "assigned to another node. " + "Setting it to importing state.",j); + server.cluster->importing_slots_from[j] = server.cluster->slots[j]; + } + } + if (update_config) clusterSaveConfigOrDie(1); + return REDIS_OK; +} + +/* ----------------------------------------------------------------------------- + * SLAVE nodes handling + * -------------------------------------------------------------------------- */ + +/* Set the specified node 'n' as master for this node. + * If this node is currently a master, it is turned into a slave. */ +void clusterSetMaster(clusterNode *n) { + redisAssert(n != myself); + redisAssert(myself->numslots == 0); + + if (nodeIsMaster(myself)) { + myself->flags &= ~REDIS_NODE_MASTER; + myself->flags |= REDIS_NODE_SLAVE; + clusterCloseAllSlots(); + } else { + if (myself->slaveof) + clusterNodeRemoveSlave(myself->slaveof,myself); + } + myself->slaveof = n; + clusterNodeAddSlave(n,myself); + replicationSetMaster(n->ip, n->port); + resetManualFailover(); +} + +/* ----------------------------------------------------------------------------- + * Nodes to string representation functions. + * -------------------------------------------------------------------------- */ + +struct redisNodeFlags { + uint16_t flag; + char *name; +}; + +static struct redisNodeFlags redisNodeFlagsTable[] = { + {REDIS_NODE_MYSELF, "myself,"}, + {REDIS_NODE_MASTER, "master,"}, + {REDIS_NODE_SLAVE, "slave,"}, + {REDIS_NODE_PFAIL, "fail?,"}, + {REDIS_NODE_FAIL, "fail,"}, + {REDIS_NODE_HANDSHAKE, "handshake,"}, + {REDIS_NODE_NOADDR, "noaddr,"} +}; + +/* Concatenate the comma separated list of node flags to the given SDS + * string 'ci'. */ +sds representRedisNodeFlags(sds ci, uint16_t flags) { + if (flags == 0) { + ci = sdscat(ci,"noflags,"); + } else { + int i, size = sizeof(redisNodeFlagsTable)/sizeof(struct redisNodeFlags); + for (i = 0; i < size; i++) { + struct redisNodeFlags *nodeflag = redisNodeFlagsTable + i; + if (flags & nodeflag->flag) ci = sdscat(ci, nodeflag->name); + } + } + sdsIncrLen(ci,-1); /* Remove trailing comma. */ + return ci; +} + +/* Generate a csv-alike representation of the specified cluster node. + * See clusterGenNodesDescription() top comment for more information. + * + * The function returns the string representation as an SDS string. */ +sds clusterGenNodeDescription(clusterNode *node) { + int j, start; + sds ci; + + /* Node coordinates */ + ci = sdscatprintf(sdsempty(),"%.40s %s:%d ", + node->name, + node->ip, + node->port); + + /* Flags */ + ci = representRedisNodeFlags(ci, node->flags); + + /* Slave of... or just "-" */ + if (node->slaveof) + ci = sdscatprintf(ci," %.40s ",node->slaveof->name); + else + ci = sdscatlen(ci," - ",3); + + /* Latency from the POV of this node, config epoch, link status */ + ci = sdscatprintf(ci,"%lld %lld %llu %s", + (long long) node->ping_sent, + (long long) node->pong_received, + (unsigned long long) node->configEpoch, + (node->link || node->flags & REDIS_NODE_MYSELF) ? + "connected" : "disconnected"); + + /* Slots served by this instance */ + start = -1; + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + int bit; + + if ((bit = clusterNodeGetSlotBit(node,j)) != 0) { + if (start == -1) start = j; + } + if (start != -1 && (!bit || j == REDIS_CLUSTER_SLOTS-1)) { + if (bit && j == REDIS_CLUSTER_SLOTS-1) j++; + + if (start == j-1) { + ci = sdscatprintf(ci," %d",start); + } else { + ci = sdscatprintf(ci," %d-%d",start,j-1); + } + start = -1; + } + } + + /* Just for MYSELF node we also dump info about slots that + * we are migrating to other instances or importing from other + * instances. */ + if (node->flags & REDIS_NODE_MYSELF) { + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (server.cluster->migrating_slots_to[j]) { + ci = sdscatprintf(ci," [%d->-%.40s]",j, + server.cluster->migrating_slots_to[j]->name); + } else if (server.cluster->importing_slots_from[j]) { + ci = sdscatprintf(ci," [%d-<-%.40s]",j, + server.cluster->importing_slots_from[j]->name); + } + } + } + return ci; +} + +/* Generate a csv-alike representation of the nodes we are aware of, + * including the "myself" node, and return an SDS string containing the + * representation (it is up to the caller to free it). + * + * All the nodes matching at least one of the node flags specified in + * "filter" are excluded from the output, so using zero as a filter will + * include all the known nodes in the representation, including nodes in + * the HANDSHAKE state. + * + * The representation obtained using this function is used for the output + * of the CLUSTER NODES function, and as format for the cluster + * configuration file (nodes.conf) for a given node. */ +sds clusterGenNodesDescription(int filter) { + sds ci = sdsempty(), ni; + dictIterator *di; + dictEntry *de; + + di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + + if (node->flags & filter) continue; + ni = clusterGenNodeDescription(node); + ci = sdscatsds(ci,ni); + sdsfree(ni); + ci = sdscatlen(ci,"\n",1); + } + dictReleaseIterator(di); + return ci; +} + +/* ----------------------------------------------------------------------------- + * CLUSTER command + * -------------------------------------------------------------------------- */ + +int getSlotOrReply(redisClient *c, robj *o) { + long long slot; + + if (getLongLongFromObject(o,&slot) != REDIS_OK || + slot < 0 || slot >= REDIS_CLUSTER_SLOTS) + { + addReplyError(c,"Invalid or out of range slot"); + return -1; + } + return (int) slot; +} + +void clusterReplyMultiBulkSlots(redisClient *c) { + /* Format: 1) 1) start slot + * 2) end slot + * 3) 1) master IP + * 2) master port + * 4) 1) replica IP + * 2) replica port + * ... continued until done + */ + + int num_masters = 0; + void *slot_replylen = addDeferredMultiBulkLength(c); + + dictEntry *de; + dictIterator *di = dictGetSafeIterator(server.cluster->nodes); + while((de = dictNext(di)) != NULL) { + clusterNode *node = dictGetVal(de); + int j = 0, start = -1; + + /* Skip slaves (that are iterated when producing the output of their + * master) and masters not serving any slot. */ + if (!nodeIsMaster(node) || node->numslots == 0) continue; + + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + int bit, i; + + if ((bit = clusterNodeGetSlotBit(node,j)) != 0) { + if (start == -1) start = j; + } + if (start != -1 && (!bit || j == REDIS_CLUSTER_SLOTS-1)) { + int nested_elements = 3; /* slots (2) + master addr (1). */ + void *nested_replylen = addDeferredMultiBulkLength(c); + + if (bit && j == REDIS_CLUSTER_SLOTS-1) j++; + + /* If slot exists in output map, add to it's list. + * else, create a new output map for this slot */ + if (start == j-1) { + addReplyLongLong(c, start); /* only one slot; low==high */ + addReplyLongLong(c, start); + } else { + addReplyLongLong(c, start); /* low */ + addReplyLongLong(c, j-1); /* high */ + } + start = -1; + + /* First node reply position is always the master */ + addReplyMultiBulkLen(c, 2); + addReplyBulkCString(c, node->ip); + addReplyLongLong(c, node->port); + + /* Remaining nodes in reply are replicas for slot range */ + for (i = 0; i < node->numslaves; i++) { + /* This loop is copy/pasted from clusterGenNodeDescription() + * with modifications for per-slot node aggregation */ + if (nodeFailed(node->slaves[i])) continue; + addReplyMultiBulkLen(c, 2); + addReplyBulkCString(c, node->slaves[i]->ip); + addReplyLongLong(c, node->slaves[i]->port); + nested_elements++; + } + setDeferredMultiBulkLength(c, nested_replylen, nested_elements); + num_masters++; + } + } + } + dictReleaseIterator(di); + setDeferredMultiBulkLength(c, slot_replylen, num_masters); +} + +void clusterCommand(redisClient *c) { + if (server.cluster_enabled == 0) { + addReplyError(c,"This instance has cluster support disabled"); + return; + } + + if (!strcasecmp(c->argv[1]->ptr,"meet") && c->argc == 4) { + long long port; + + if (getLongLongFromObject(c->argv[3], &port) != REDIS_OK) { + addReplyErrorFormat(c,"Invalid TCP port specified: %s", + (char*)c->argv[3]->ptr); + return; + } + + if (clusterStartHandshake(c->argv[2]->ptr,port) == 0 && + errno == EINVAL) + { + addReplyErrorFormat(c,"Invalid node address specified: %s:%s", + (char*)c->argv[2]->ptr, (char*)c->argv[3]->ptr); + } else { + addReply(c,shared.ok); + } + } else if (!strcasecmp(c->argv[1]->ptr,"nodes") && c->argc == 2) { + /* CLUSTER NODES */ + robj *o; + sds ci = clusterGenNodesDescription(0); + + o = createObject(REDIS_STRING,ci); + addReplyBulk(c,o); + decrRefCount(o); + } else if (!strcasecmp(c->argv[1]->ptr,"myid") && c->argc == 2) { + /* CLUSTER MYID */ + addReplyBulkCBuffer(c,myself->name, REDIS_CLUSTER_NAMELEN); + } else if (!strcasecmp(c->argv[1]->ptr,"slots") && c->argc == 2) { + /* CLUSTER SLOTS */ + clusterReplyMultiBulkSlots(c); + } else if (!strcasecmp(c->argv[1]->ptr,"flushslots") && c->argc == 2) { + /* CLUSTER FLUSHSLOTS */ + if (dictSize(server.db[0].dict) != 0) { + addReplyError(c,"DB must be empty to perform CLUSTER FLUSHSLOTS."); + return; + } + clusterDelNodeSlots(myself); + clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG); + addReply(c,shared.ok); + } else if ((!strcasecmp(c->argv[1]->ptr,"addslots") || + !strcasecmp(c->argv[1]->ptr,"delslots")) && c->argc >= 3) + { + /* CLUSTER ADDSLOTS [slot] ... */ + /* CLUSTER DELSLOTS [slot] ... */ + int j, slot; + unsigned char *slots = zmalloc(REDIS_CLUSTER_SLOTS); + int del = !strcasecmp(c->argv[1]->ptr,"delslots"); + + memset(slots,0,REDIS_CLUSTER_SLOTS); + /* Check that all the arguments are parseable and that all the + * slots are not already busy. */ + for (j = 2; j < c->argc; j++) { + if ((slot = getSlotOrReply(c,c->argv[j])) == -1) { + zfree(slots); + return; + } + if (del && server.cluster->slots[slot] == NULL) { + addReplyErrorFormat(c,"Slot %d is already unassigned", slot); + zfree(slots); + return; + } else if (!del && server.cluster->slots[slot]) { + addReplyErrorFormat(c,"Slot %d is already busy", slot); + zfree(slots); + return; + } + if (slots[slot]++ == 1) { + addReplyErrorFormat(c,"Slot %d specified multiple times", + (int)slot); + zfree(slots); + return; + } + } + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + if (slots[j]) { + int retval; + + /* If this slot was set as importing we can clear this + * state as now we are the real owner of the slot. */ + if (server.cluster->importing_slots_from[j]) + server.cluster->importing_slots_from[j] = NULL; + + retval = del ? clusterDelSlot(j) : + clusterAddSlot(myself,j); + redisAssertWithInfo(c,NULL,retval == REDIS_OK); + } + } + zfree(slots); + clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG); + addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"setslot") && c->argc >= 4) { + /* SETSLOT 10 MIGRATING */ + /* SETSLOT 10 IMPORTING */ + /* SETSLOT 10 STABLE */ + /* SETSLOT 10 NODE */ + int slot; + clusterNode *n; + + if ((slot = getSlotOrReply(c,c->argv[2])) == -1) return; + + if (!strcasecmp(c->argv[3]->ptr,"migrating") && c->argc == 5) { + if (server.cluster->slots[slot] != myself) { + addReplyErrorFormat(c,"I'm not the owner of hash slot %u",slot); + return; + } + if ((n = clusterLookupNode(c->argv[4]->ptr)) == NULL) { + addReplyErrorFormat(c,"I don't know about node %s", + (char*)c->argv[4]->ptr); + return; + } + server.cluster->migrating_slots_to[slot] = n; + } else if (!strcasecmp(c->argv[3]->ptr,"importing") && c->argc == 5) { + if (server.cluster->slots[slot] == myself) { + addReplyErrorFormat(c, + "I'm already the owner of hash slot %u",slot); + return; + } + if ((n = clusterLookupNode(c->argv[4]->ptr)) == NULL) { + addReplyErrorFormat(c,"I don't know about node %s", + (char*)c->argv[3]->ptr); + return; + } + server.cluster->importing_slots_from[slot] = n; + } else if (!strcasecmp(c->argv[3]->ptr,"stable") && c->argc == 4) { + /* CLUSTER SETSLOT STABLE */ + server.cluster->importing_slots_from[slot] = NULL; + server.cluster->migrating_slots_to[slot] = NULL; + } else if (!strcasecmp(c->argv[3]->ptr,"node") && c->argc == 5) { + /* CLUSTER SETSLOT NODE */ + clusterNode *n = clusterLookupNode(c->argv[4]->ptr); + + if (!n) { + addReplyErrorFormat(c,"Unknown node %s", + (char*)c->argv[4]->ptr); + return; + } + /* If this hash slot was served by 'myself' before to switch + * make sure there are no longer local keys for this hash slot. */ + if (server.cluster->slots[slot] == myself && n != myself) { + if (countKeysInSlot(slot) != 0) { + addReplyErrorFormat(c, + "Can't assign hashslot %d to a different node " + "while I still hold keys for this hash slot.", slot); + return; + } + } + /* If this slot is in migrating status but we have no keys + * for it assigning the slot to another node will clear + * the migratig status. */ + if (countKeysInSlot(slot) == 0 && + server.cluster->migrating_slots_to[slot]) + server.cluster->migrating_slots_to[slot] = NULL; + + /* If this node was importing this slot, assigning the slot to + * itself also clears the importing status. */ + if (n == myself && + server.cluster->importing_slots_from[slot]) + { + /* This slot was manually migrated, set this node configEpoch + * to a new epoch so that the new version can be propagated + * by the cluster. + * + * Note that if this ever results in a collision with another + * node getting the same configEpoch, for example because a + * failover happens at the same time we close the slot, the + * configEpoch collision resolution will fix it assigning + * a different epoch to each node. */ + if (clusterBumpConfigEpochWithoutConsensus() == REDIS_OK) { + redisLog(REDIS_WARNING, + "configEpoch updated after importing slot %d", slot); + } + server.cluster->importing_slots_from[slot] = NULL; + } + clusterDelSlot(slot); + clusterAddSlot(n,slot); + } else { + addReplyError(c, + "Invalid CLUSTER SETSLOT action or number of arguments"); + return; + } + clusterDoBeforeSleep(CLUSTER_TODO_SAVE_CONFIG|CLUSTER_TODO_UPDATE_STATE); + addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"info") && c->argc == 2) { + /* CLUSTER INFO */ + char *statestr[] = {"ok","fail","needhelp"}; + int slots_assigned = 0, slots_ok = 0, slots_pfail = 0, slots_fail = 0; + uint64_t myepoch; + int j; + + for (j = 0; j < REDIS_CLUSTER_SLOTS; j++) { + clusterNode *n = server.cluster->slots[j]; + + if (n == NULL) continue; + slots_assigned++; + if (nodeFailed(n)) { + slots_fail++; + } else if (nodeTimedOut(n)) { + slots_pfail++; + } else { + slots_ok++; + } + } + + myepoch = (nodeIsSlave(myself) && myself->slaveof) ? + myself->slaveof->configEpoch : myself->configEpoch; + + sds info = sdscatprintf(sdsempty(), + "cluster_state:%s\r\n" + "cluster_slots_assigned:%d\r\n" + "cluster_slots_ok:%d\r\n" + "cluster_slots_pfail:%d\r\n" + "cluster_slots_fail:%d\r\n" + "cluster_known_nodes:%lu\r\n" + "cluster_size:%d\r\n" + "cluster_current_epoch:%llu\r\n" + "cluster_my_epoch:%llu\r\n" + "cluster_stats_messages_sent:%lld\r\n" + "cluster_stats_messages_received:%lld\r\n" + , statestr[server.cluster->state], + slots_assigned, + slots_ok, + slots_pfail, + slots_fail, + dictSize(server.cluster->nodes), + server.cluster->size, + (unsigned long long) server.cluster->currentEpoch, + (unsigned long long) myepoch, + server.cluster->stats_bus_messages_sent, + server.cluster->stats_bus_messages_received + ); + addReplySds(c,sdscatprintf(sdsempty(),"$%lu\r\n", + (unsigned long)sdslen(info))); + addReplySds(c,info); + addReply(c,shared.crlf); + } else if (!strcasecmp(c->argv[1]->ptr,"saveconfig") && c->argc == 2) { + int retval = clusterSaveConfig(1); + + if (retval == 0) + addReply(c,shared.ok); + else + addReplyErrorFormat(c,"error saving the cluster node config: %s", + strerror(errno)); + } else if (!strcasecmp(c->argv[1]->ptr,"keyslot") && c->argc == 3) { + /* CLUSTER KEYSLOT */ + sds key = c->argv[2]->ptr; + + addReplyLongLong(c,keyHashSlot(key,sdslen(key))); + } else if (!strcasecmp(c->argv[1]->ptr,"countkeysinslot") && c->argc == 3) { + /* CLUSTER COUNTKEYSINSLOT */ + long long slot; + + if (getLongLongFromObjectOrReply(c,c->argv[2],&slot,NULL) != REDIS_OK) + return; + if (slot < 0 || slot >= REDIS_CLUSTER_SLOTS) { + addReplyError(c,"Invalid slot"); + return; + } + addReplyLongLong(c,countKeysInSlot(slot)); + } else if (!strcasecmp(c->argv[1]->ptr,"getkeysinslot") && c->argc == 4) { + /* CLUSTER GETKEYSINSLOT */ + long long maxkeys, slot; + unsigned int numkeys, j; + robj **keys; + + if (getLongLongFromObjectOrReply(c,c->argv[2],&slot,NULL) != REDIS_OK) + return; + if (getLongLongFromObjectOrReply(c,c->argv[3],&maxkeys,NULL) + != REDIS_OK) + return; + if (slot < 0 || slot >= REDIS_CLUSTER_SLOTS || maxkeys < 0) { + addReplyError(c,"Invalid slot or number of keys"); + return; + } + + keys = zmalloc(sizeof(robj*)*maxkeys); + numkeys = getKeysInSlot(slot, keys, maxkeys); + addReplyMultiBulkLen(c,numkeys); + for (j = 0; j < numkeys; j++) addReplyBulk(c,keys[j]); + zfree(keys); + } else if (!strcasecmp(c->argv[1]->ptr,"forget") && c->argc == 3) { + /* CLUSTER FORGET */ + clusterNode *n = clusterLookupNode(c->argv[2]->ptr); + + if (!n) { + addReplyErrorFormat(c,"Unknown node %s", (char*)c->argv[2]->ptr); + return; + } else if (n == myself) { + addReplyError(c,"I tried hard but I can't forget myself..."); + return; + } else if (nodeIsSlave(myself) && myself->slaveof == n) { + addReplyError(c,"Can't forget my master!"); + return; + } + clusterBlacklistAddNode(n); + clusterDelNode(n); + clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE| + CLUSTER_TODO_SAVE_CONFIG); + addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"replicate") && c->argc == 3) { + /* CLUSTER REPLICATE */ + clusterNode *n = clusterLookupNode(c->argv[2]->ptr); + + /* Lookup the specified node in our table. */ + if (!n) { + addReplyErrorFormat(c,"Unknown node %s", (char*)c->argv[2]->ptr); + return; + } + + /* I can't replicate myself. */ + if (n == myself) { + addReplyError(c,"Can't replicate myself"); + return; + } + + /* Can't replicate a slave. */ + if (nodeIsSlave(n)) { + addReplyError(c,"I can only replicate a master, not a slave."); + return; + } + + /* If the instance is currently a master, it should have no assigned + * slots nor keys to accept to replicate some other node. + * Slaves can switch to another master without issues. */ + if (nodeIsMaster(myself) && + (myself->numslots != 0 || dictSize(server.db[0].dict) != 0)) { + addReplyError(c, + "To set a master the node must be empty and " + "without assigned slots."); + return; + } + + /* Set the master. */ + clusterSetMaster(n); + clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE|CLUSTER_TODO_SAVE_CONFIG); + addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"slaves") && c->argc == 3) { + /* CLUSTER SLAVES */ + clusterNode *n = clusterLookupNode(c->argv[2]->ptr); + int j; + + /* Lookup the specified node in our table. */ + if (!n) { + addReplyErrorFormat(c,"Unknown node %s", (char*)c->argv[2]->ptr); + return; + } + + if (nodeIsSlave(n)) { + addReplyError(c,"The specified node is not a master"); + return; + } + + addReplyMultiBulkLen(c,n->numslaves); + for (j = 0; j < n->numslaves; j++) { + sds ni = clusterGenNodeDescription(n->slaves[j]); + addReplyBulkCString(c,ni); + sdsfree(ni); + } + } else if (!strcasecmp(c->argv[1]->ptr,"count-failure-reports") && + c->argc == 3) + { + /* CLUSTER COUNT-FAILURE-REPORTS */ + clusterNode *n = clusterLookupNode(c->argv[2]->ptr); + + if (!n) { + addReplyErrorFormat(c,"Unknown node %s", (char*)c->argv[2]->ptr); + return; + } else { + addReplyLongLong(c,clusterNodeFailureReportsCount(n)); + } + } else if (!strcasecmp(c->argv[1]->ptr,"failover") && + (c->argc == 2 || c->argc == 3)) + { + /* CLUSTER FAILOVER [FORCE|TAKEOVER] */ + int force = 0, takeover = 0; + + if (c->argc == 3) { + if (!strcasecmp(c->argv[2]->ptr,"force")) { + force = 1; + } else if (!strcasecmp(c->argv[2]->ptr,"takeover")) { + takeover = 1; + force = 1; /* Takeover also implies force. */ + } else { + addReply(c,shared.syntaxerr); + return; + } + } + + /* Check preconditions. */ + if (nodeIsMaster(myself)) { + addReplyError(c,"You should send CLUSTER FAILOVER to a slave"); + return; + } else if (myself->slaveof == NULL) { + addReplyError(c,"I'm a slave but my master is unknown to me"); + return; + } else if (!force && + (nodeFailed(myself->slaveof) || + myself->slaveof->link == NULL)) + { + addReplyError(c,"Master is down or failed, " + "please use CLUSTER FAILOVER FORCE"); + return; + } + resetManualFailover(); + server.cluster->mf_end = mstime() + REDIS_CLUSTER_MF_TIMEOUT; + + if (takeover) { + /* A takeover does not perform any initial check. It just + * generates a new configuration epoch for this node without + * consensus, claims the master's slots, and broadcast the new + * configuration. */ + redisLog(REDIS_WARNING,"Taking over the master (user request)."); + clusterBumpConfigEpochWithoutConsensus(); + clusterFailoverReplaceYourMaster(); + } else if (force) { + /* If this is a forced failover, we don't need to talk with our + * master to agree about the offset. We just failover taking over + * it without coordination. */ + redisLog(REDIS_WARNING,"Forced failover user request accepted."); + server.cluster->mf_can_start = 1; + } else { + redisLog(REDIS_WARNING,"Manual failover user request accepted."); + clusterSendMFStart(myself->slaveof); + } + addReply(c,shared.ok); + } else if (!strcasecmp(c->argv[1]->ptr,"set-config-epoch") && c->argc == 3) + { + /* CLUSTER SET-CONFIG-EPOCH + * + * The user is allowed to set the config epoch only when a node is + * totally fresh: no config epoch, no other known node, and so forth. + * This happens at cluster creation time to start with a cluster where + * every node has a different node ID, without to rely on the conflicts + * resolution system which is too slow when a big cluster is created. */ + long long epoch; + + if (getLongLongFromObjectOrReply(c,c->argv[2],&epoch,NULL) != REDIS_OK) + return; + + if (epoch < 0) { + addReplyErrorFormat(c,"Invalid config epoch specified: %lld",epoch); + } else if (dictSize(server.cluster->nodes) > 1) { + addReplyError(c,"The user can assign a config epoch only when the " + "node does not know any other node."); + } else if (myself->configEpoch != 0) { + addReplyError(c,"Node config epoch is already non-zero"); + } else { + myself->configEpoch = epoch; + redisLog(REDIS_WARNING, + "configEpoch set to %llu via CLUSTER SET-CONFIG-EPOCH", + (unsigned long long) myself->configEpoch); + + if (server.cluster->currentEpoch < (uint64_t)epoch) + server.cluster->currentEpoch = epoch; + /* No need to fsync the config here since in the unlucky event + * of a failure to persist the config, the conflict resolution code + * will assign an unique config to this node. */ + clusterDoBeforeSleep(CLUSTER_TODO_UPDATE_STATE| + CLUSTER_TODO_SAVE_CONFIG); + addReply(c,shared.ok); + } + } else if (!strcasecmp(c->argv[1]->ptr,"reset") && + (c->argc == 2 || c->argc == 3)) + { + /* CLUSTER RESET [SOFT|HARD] */ + int hard = 0; + + /* Parse soft/hard argument. Default is soft. */ + if (c->argc == 3) { + if (!strcasecmp(c->argv[2]->ptr,"hard")) { + hard = 1; + } else if (!strcasecmp(c->argv[2]->ptr,"soft")) { + hard = 0; + } else { + addReply(c,shared.syntaxerr); + return; + } + } + + /* Slaves can be reset while containing data, but not master nodes + * that must be empty. */ + if (nodeIsMaster(myself) && dictSize(c->db->dict) != 0) { + addReplyError(c,"CLUSTER RESET can't be called with " + "master nodes containing keys"); + return; + } + clusterReset(hard); + addReply(c,shared.ok); + } else { + addReplyError(c,"Wrong CLUSTER subcommand or number of arguments"); + } +} + +/* ----------------------------------------------------------------------------- + * DUMP, RESTORE and MIGRATE commands + * -------------------------------------------------------------------------- */ + +/* Generates a DUMP-format representation of the object 'o', adding it to the + * io stream pointed by 'rio'. This function can't fail. */ +void createDumpPayload(rio *payload, robj *o) { + unsigned char buf[2]; + uint64_t crc; + + /* Serialize the object in a RDB-like format. It consist of an object type + * byte followed by the serialized object. This is understood by RESTORE. */ + rioInitWithBuffer(payload,sdsempty()); + redisAssert(rdbSaveObjectType(payload,o)); + redisAssert(rdbSaveObject(payload,o)); + + /* Write the footer, this is how it looks like: + * ----------------+---------------------+---------------+ + * ... RDB payload | 2 bytes RDB version | 8 bytes CRC64 | + * ----------------+---------------------+---------------+ + * RDB version and CRC are both in little endian. + */ + + /* RDB version */ + buf[0] = REDIS_RDB_VERSION & 0xff; + buf[1] = (REDIS_RDB_VERSION >> 8) & 0xff; + payload->io.buffer.ptr = sdscatlen(payload->io.buffer.ptr,buf,2); + + /* CRC64 */ + crc = crc64(0,(unsigned char*)payload->io.buffer.ptr, + sdslen(payload->io.buffer.ptr)); + memrev64ifbe(&crc); + payload->io.buffer.ptr = sdscatlen(payload->io.buffer.ptr,&crc,8); +} + +/* Verify that the RDB version of the dump payload matches the one of this Redis + * instance and that the checksum is ok. + * If the DUMP payload looks valid REDIS_OK is returned, otherwise REDIS_ERR + * is returned. */ +int verifyDumpPayload(unsigned char *p, size_t len) { + unsigned char *footer; + uint16_t rdbver; + uint64_t crc; + + /* At least 2 bytes of RDB version and 8 of CRC64 should be present. */ + if (len < 10) return REDIS_ERR; + footer = p+(len-10); + + /* Verify RDB version */ + rdbver = (footer[1] << 8) | footer[0]; + if (rdbver != REDIS_RDB_VERSION) return REDIS_ERR; + + /* Verify CRC64 */ + crc = crc64(0,p,len-8); + memrev64ifbe(&crc); + return (memcmp(&crc,footer+2,8) == 0) ? REDIS_OK : REDIS_ERR; +} + +/* DUMP keyname + * DUMP is actually not used by Redis Cluster but it is the obvious + * complement of RESTORE and can be useful for different applications. */ +void dumpCommand(redisClient *c) { + robj *o, *dumpobj; + rio payload; + + /* Check if the key is here. */ + if ((o = lookupKeyRead(c->db,c->argv[1])) == NULL) { + addReply(c,shared.nullbulk); + return; + } + + /* Create the DUMP encoded representation. */ + createDumpPayload(&payload,o); + + /* Transfer to the client */ + dumpobj = createObject(REDIS_STRING,payload.io.buffer.ptr); + addReplyBulk(c,dumpobj); + decrRefCount(dumpobj); + return; +} + +/* RESTORE key ttl serialized-value [REPLACE] */ +void restoreCommand(redisClient *c) { + long long ttl; + rio payload; + int j, type, replace = 0; + robj *obj; + + /* Parse additional options */ + for (j = 4; j < c->argc; j++) { + if (!strcasecmp(c->argv[j]->ptr,"replace")) { + replace = 1; + } else { + addReply(c,shared.syntaxerr); + return; + } + } + + /* Make sure this key does not already exist here... */ + if (!replace && lookupKeyWrite(c->db,c->argv[1]) != NULL) { + addReply(c,shared.busykeyerr); + return; + } + + /* Check if the TTL value makes sense */ + if (getLongLongFromObjectOrReply(c,c->argv[2],&ttl,NULL) != REDIS_OK) { + return; + } else if (ttl < 0) { + addReplyError(c,"Invalid TTL value, must be >= 0"); + return; + } + + /* Verify RDB version and data checksum. */ + if (verifyDumpPayload(c->argv[3]->ptr,sdslen(c->argv[3]->ptr)) == REDIS_ERR) + { + addReplyError(c,"DUMP payload version or checksum are wrong"); + return; + } + + rioInitWithBuffer(&payload,c->argv[3]->ptr); + if (((type = rdbLoadObjectType(&payload)) == -1) || + ((obj = rdbLoadObject(type,&payload)) == NULL)) + { + addReplyError(c,"Bad data format"); + return; + } + + /* Remove the old key if needed. */ + if (replace) dbDelete(c->db,c->argv[1]); + + /* Create the key and set the TTL if any */ + dbAdd(c->db,c->argv[1],obj); + if (ttl) setExpire(c->db,c->argv[1],mstime()+ttl); + signalModifiedKey(c->db,c->argv[1]); + addReply(c,shared.ok); + server.dirty++; +} + +/* MIGRATE socket cache implementation. + * + * We take a map between host:ip and a TCP socket that we used to connect + * to this instance in recent time. + * This sockets are closed when the max number we cache is reached, and also + * in serverCron() when they are around for more than a few seconds. */ +#define MIGRATE_SOCKET_CACHE_ITEMS 64 /* max num of items in the cache. */ +#define MIGRATE_SOCKET_CACHE_TTL 10 /* close cached sockets after 10 sec. */ + +typedef struct migrateCachedSocket { + int fd; + long last_dbid; + time_t last_use_time; +} migrateCachedSocket; + +/* Return a migrateCachedSocket containing a TCP socket connected with the + * target instance, possibly returning a cached one. + * + * This function is responsible of sending errors to the client if a + * connection can't be established. In this case -1 is returned. + * Otherwise on success the socket is returned, and the caller should not + * attempt to free it after usage. + * + * If the caller detects an error while using the socket, migrateCloseSocket() + * should be called so that the connection will be created from scratch + * the next time. */ +migrateCachedSocket* migrateGetSocket(redisClient *c, robj *host, robj *port, long timeout) { + int fd; + sds name = sdsempty(); + migrateCachedSocket *cs; + + /* Check if we have an already cached socket for this ip:port pair. */ + name = sdscatlen(name,host->ptr,sdslen(host->ptr)); + name = sdscatlen(name,":",1); + name = sdscatlen(name,port->ptr,sdslen(port->ptr)); + cs = dictFetchValue(server.migrate_cached_sockets,name); + if (cs) { + sdsfree(name); + cs->last_use_time = server.unixtime; + return cs; + } + + /* No cached socket, create one. */ + if (dictSize(server.migrate_cached_sockets) == MIGRATE_SOCKET_CACHE_ITEMS) { + /* Too many items, drop one at random. */ + dictEntry *de = dictGetRandomKey(server.migrate_cached_sockets); + cs = dictGetVal(de); + close(cs->fd); + zfree(cs); + dictDelete(server.migrate_cached_sockets,dictGetKey(de)); + } + + /* Create the socket */ + fd = anetTcpNonBlockConnect(server.neterr,c->argv[1]->ptr, + atoi(c->argv[2]->ptr)); + if (fd == -1) { + sdsfree(name); + addReplyErrorFormat(c,"Can't connect to target node: %s", + server.neterr); + return NULL; + } + anetEnableTcpNoDelay(server.neterr,fd); + + /* Check if it connects within the specified timeout. */ + if ((aeWait(fd,AE_WRITABLE,timeout) & AE_WRITABLE) == 0) { + sdsfree(name); + addReplySds(c, + sdsnew("-IOERR error or timeout connecting to the client\r\n")); + close(fd); + return NULL; + } + + /* Add to the cache and return it to the caller. */ + cs = zmalloc(sizeof(*cs)); + cs->fd = fd; + cs->last_dbid = -1; + cs->last_use_time = server.unixtime; + dictAdd(server.migrate_cached_sockets,name,cs); + return cs; +} + +/* Free a migrate cached connection. */ +void migrateCloseSocket(robj *host, robj *port) { + sds name = sdsempty(); + migrateCachedSocket *cs; + + name = sdscatlen(name,host->ptr,sdslen(host->ptr)); + name = sdscatlen(name,":",1); + name = sdscatlen(name,port->ptr,sdslen(port->ptr)); + cs = dictFetchValue(server.migrate_cached_sockets,name); + if (!cs) { + sdsfree(name); + return; + } + + close(cs->fd); + zfree(cs); + dictDelete(server.migrate_cached_sockets,name); + sdsfree(name); +} + +void migrateCloseTimedoutSockets(void) { + dictIterator *di = dictGetSafeIterator(server.migrate_cached_sockets); + dictEntry *de; + + while((de = dictNext(di)) != NULL) { + migrateCachedSocket *cs = dictGetVal(de); + + if ((server.unixtime - cs->last_use_time) > MIGRATE_SOCKET_CACHE_TTL) { + close(cs->fd); + zfree(cs); + dictDelete(server.migrate_cached_sockets,dictGetKey(de)); + } + } + dictReleaseIterator(di); +} + +/* MIGRATE host port key dbid timeout [COPY | REPLACE] */ +void migrateCommand(redisClient *c) { + migrateCachedSocket *cs; + int copy, replace, j; + long timeout; + long dbid; + long long ttl, expireat; + robj *o; + rio cmd, payload; + int retry_num = 0; + +try_again: + /* Initialization */ + copy = 0; + replace = 0; + ttl = 0; + + /* Parse additional options */ + for (j = 6; j < c->argc; j++) { + if (!strcasecmp(c->argv[j]->ptr,"copy")) { + copy = 1; + } else if (!strcasecmp(c->argv[j]->ptr,"replace")) { + replace = 1; + } else { + addReply(c,shared.syntaxerr); + return; + } + } + + /* Sanity check */ + if (getLongFromObjectOrReply(c,c->argv[5],&timeout,NULL) != REDIS_OK) + return; + if (getLongFromObjectOrReply(c,c->argv[4],&dbid,NULL) != REDIS_OK) + return; + if (timeout <= 0) timeout = 1000; + + /* Check if the key is here. If not we reply with success as there is + * nothing to migrate (for instance the key expired in the meantime), but + * we include such information in the reply string. */ + if ((o = lookupKeyRead(c->db,c->argv[3])) == NULL) { + addReplySds(c,sdsnew("+NOKEY\r\n")); + return; + } + + /* Connect */ + cs = migrateGetSocket(c,c->argv[1],c->argv[2],timeout); + if (cs == NULL) return; /* error sent to the client by migrateGetSocket() */ + + rioInitWithBuffer(&cmd,sdsempty()); + + /* Send the SELECT command if the current DB is not already selected. */ + int select = cs->last_dbid != dbid; /* Should we emit SELECT? */ + if (select) { + redisAssertWithInfo(c,NULL,rioWriteBulkCount(&cmd,'*',2)); + redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"SELECT",6)); + redisAssertWithInfo(c,NULL,rioWriteBulkLongLong(&cmd,dbid)); + } + + /* Create RESTORE payload and generate the protocol to call the command. */ + expireat = getExpire(c->db,c->argv[3]); + if (expireat != -1) { + ttl = expireat-mstime(); + if (ttl < 1) ttl = 1; + } + redisAssertWithInfo(c,NULL,rioWriteBulkCount(&cmd,'*',replace ? 5 : 4)); + if (server.cluster_enabled) + redisAssertWithInfo(c,NULL, + rioWriteBulkString(&cmd,"RESTORE-ASKING",14)); + else + redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"RESTORE",7)); + redisAssertWithInfo(c,NULL,sdsEncodedObject(c->argv[3])); + redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,c->argv[3]->ptr, + sdslen(c->argv[3]->ptr))); + redisAssertWithInfo(c,NULL,rioWriteBulkLongLong(&cmd,ttl)); + + /* Emit the payload argument, that is the serialized object using + * the DUMP format. */ + createDumpPayload(&payload,o); + redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,payload.io.buffer.ptr, + sdslen(payload.io.buffer.ptr))); + sdsfree(payload.io.buffer.ptr); + + /* Add the REPLACE option to the RESTORE command if it was specified + * as a MIGRATE option. */ + if (replace) + redisAssertWithInfo(c,NULL,rioWriteBulkString(&cmd,"REPLACE",7)); + + /* Transfer the query to the other node in 64K chunks. */ + errno = 0; + { + sds buf = cmd.io.buffer.ptr; + size_t pos = 0, towrite; + int nwritten = 0; + + while ((towrite = sdslen(buf)-pos) > 0) { + towrite = (towrite > (64*1024) ? (64*1024) : towrite); + nwritten = syncWrite(cs->fd,buf+pos,towrite,timeout); + if (nwritten != (signed)towrite) goto socket_wr_err; + pos += nwritten; + } + } + + /* Read back the reply. */ + { + char buf1[1024]; + char buf2[1024]; + + /* Read the two replies */ + if (select && syncReadLine(cs->fd, buf1, sizeof(buf1), timeout) <= 0) + goto socket_rd_err; + if (syncReadLine(cs->fd, buf2, sizeof(buf2), timeout) <= 0) + goto socket_rd_err; + if ((select && buf1[0] == '-') || buf2[0] == '-') { + /* On error assume that last_dbid is no longer valid. */ + cs->last_dbid = -1; + addReplyErrorFormat(c,"Target instance replied with error: %s", + (select && buf1[0] == '-') ? buf1+1 : buf2+1); + } else { + /* Update the last_dbid in migrateCachedSocket */ + cs->last_dbid = dbid; + robj *aux; + + addReply(c,shared.ok); + + if (!copy) { + /* No COPY option: remove the local key, signal the change. */ + dbDelete(c->db,c->argv[3]); + signalModifiedKey(c->db,c->argv[3]); + server.dirty++; + + /* Translate MIGRATE as DEL for replication/AOF. */ + aux = createStringObject("DEL",3); + rewriteClientCommandVector(c,2,aux,c->argv[3]); + decrRefCount(aux); + } + } + } + + sdsfree(cmd.io.buffer.ptr); + return; + +socket_wr_err: + sdsfree(cmd.io.buffer.ptr); + migrateCloseSocket(c->argv[1],c->argv[2]); + if (errno != ETIMEDOUT && retry_num++ == 0) goto try_again; + addReplySds(c, + sdsnew("-IOERR error or timeout writing to target instance\r\n")); + return; + +socket_rd_err: + sdsfree(cmd.io.buffer.ptr); + migrateCloseSocket(c->argv[1],c->argv[2]); + if (errno != ETIMEDOUT && retry_num++ == 0) goto try_again; + addReplySds(c, + sdsnew("-IOERR error or timeout reading from target node\r\n")); + return; +} + +/* ----------------------------------------------------------------------------- + * Cluster functions related to serving / redirecting clients + * -------------------------------------------------------------------------- */ + +/* The ASKING command is required after a -ASK redirection. + * The client should issue ASKING before to actually send the command to + * the target instance. See the Redis Cluster specification for more + * information. */ +void askingCommand(redisClient *c) { + if (server.cluster_enabled == 0) { + addReplyError(c,"This instance has cluster support disabled"); + return; + } + c->flags |= REDIS_ASKING; + addReply(c,shared.ok); +} + +/* The READONLY command is used by clients to enter the read-only mode. + * In this mode slaves will not redirect clients as long as clients access + * with read-only commands to keys that are served by the slave's master. */ +void readonlyCommand(redisClient *c) { + if (server.cluster_enabled == 0) { + addReplyError(c,"This instance has cluster support disabled"); + return; + } + c->flags |= REDIS_READONLY; + addReply(c,shared.ok); +} + +/* The READWRITE command just clears the READONLY command state. */ +void readwriteCommand(redisClient *c) { + c->flags &= ~REDIS_READONLY; + addReply(c,shared.ok); +} + +/* Return the pointer to the cluster node that is able to serve the command. + * For the function to succeed the command should only target either: + * + * 1) A single key (even multiple times like LPOPRPUSH mylist mylist). + * 2) Multiple keys in the same hash slot, while the slot is stable (no + * resharding in progress). + * + * On success the function returns the node that is able to serve the request. + * If the node is not 'myself' a redirection must be perfomed. The kind of + * redirection is specified setting the integer passed by reference + * 'error_code', which will be set to REDIS_CLUSTER_REDIR_ASK or + * REDIS_CLUSTER_REDIR_MOVED. + * + * When the node is 'myself' 'error_code' is set to REDIS_CLUSTER_REDIR_NONE. + * + * If the command fails NULL is returned, and the reason of the failure is + * provided via 'error_code', which will be set to: + * + * REDIS_CLUSTER_REDIR_CROSS_SLOT if the request contains multiple keys that + * don't belong to the same hash slot. + * + * REDIS_CLUSTER_REDIR_UNSTABLE if the request contains mutliple keys + * belonging to the same slot, but the slot is not stable (in migration or + * importing state, likely because a resharding is in progress). + * + * REDIS_CLUSTER_REDIR_DOWN_UNBOUND if the request addresses a slot which is + * not bound to any node. In this case the cluster global state should be + * already "down" but it is fragile to rely on the update of the global state, + * so we also handle it here. */ +clusterNode *getNodeByQuery(redisClient *c, struct redisCommand *cmd, robj **argv, int argc, int *hashslot, int *error_code) { + clusterNode *n = NULL; + robj *firstkey = NULL; + int multiple_keys = 0; + multiState *ms, _ms; + multiCmd mc; + int i, slot = 0, migrating_slot = 0, importing_slot = 0, missing_keys = 0; + + /* Set error code optimistically for the base case. */ + if (error_code) *error_code = REDIS_CLUSTER_REDIR_NONE; + + /* We handle all the cases as if they were EXEC commands, so we have + * a common code path for everything */ + if (cmd->proc == execCommand) { + /* If REDIS_MULTI flag is not set EXEC is just going to return an + * error. */ + if (!(c->flags & REDIS_MULTI)) return myself; + ms = &c->mstate; + } else { + /* In order to have a single codepath create a fake Multi State + * structure if the client is not in MULTI/EXEC state, this way + * we have a single codepath below. */ + ms = &_ms; + _ms.commands = &mc; + _ms.count = 1; + mc.argv = argv; + mc.argc = argc; + mc.cmd = cmd; + } + + /* Check that all the keys are in the same hash slot, and obtain this + * slot and the node associated. */ + for (i = 0; i < ms->count; i++) { + struct redisCommand *mcmd; + robj **margv; + int margc, *keyindex, numkeys, j; + + mcmd = ms->commands[i].cmd; + margc = ms->commands[i].argc; + margv = ms->commands[i].argv; + + keyindex = getKeysFromCommand(mcmd,margv,margc,&numkeys); + for (j = 0; j < numkeys; j++) { + robj *thiskey = margv[keyindex[j]]; + int thisslot = keyHashSlot((char*)thiskey->ptr, + sdslen(thiskey->ptr)); + + if (firstkey == NULL) { + /* This is the first key we see. Check what is the slot + * and node. */ + firstkey = thiskey; + slot = thisslot; + n = server.cluster->slots[slot]; + + /* Error: If a slot is not served, we are in "cluster down" + * state. However the state is yet to be updated, so this was + * not trapped earlier in processCommand(). Report the same + * error to the client. */ + if (n == NULL) { + getKeysFreeResult(keyindex); + if (error_code) + *error_code = REDIS_CLUSTER_REDIR_DOWN_UNBOUND; + return NULL; + } + + /* If we are migrating or importing this slot, we need to check + * if we have all the keys in the request (the only way we + * can safely serve the request, otherwise we return a TRYAGAIN + * error). To do so we set the importing/migrating state and + * increment a counter for every missing key. */ + if (n == myself && + server.cluster->migrating_slots_to[slot] != NULL) + { + migrating_slot = 1; + } else if (server.cluster->importing_slots_from[slot] != NULL) { + importing_slot = 1; + } + } else { + /* If it is not the first key, make sure it is exactly + * the same key as the first we saw. */ + if (!equalStringObjects(firstkey,thiskey)) { + if (slot != thisslot) { + /* Error: multiple keys from different slots. */ + getKeysFreeResult(keyindex); + if (error_code) + *error_code = REDIS_CLUSTER_REDIR_CROSS_SLOT; + return NULL; + } else { + /* Flag this request as one with multiple different + * keys. */ + multiple_keys = 1; + } + } + } + + /* Migarting / Improrting slot? Count keys we don't have. */ + if ((migrating_slot || importing_slot) && + lookupKeyRead(&server.db[0],thiskey) == NULL) + { + missing_keys++; + } + } + getKeysFreeResult(keyindex); + } + + /* No key at all in command? then we can serve the request + * without redirections or errors. */ + if (n == NULL) return myself; + + /* Return the hashslot by reference. */ + if (hashslot) *hashslot = slot; + + /* This request is about a slot we are migrating into another instance? + * Then if we have all the keys. */ + + /* If we don't have all the keys and we are migrating the slot, send + * an ASK redirection. */ + if (migrating_slot && missing_keys) { + if (error_code) *error_code = REDIS_CLUSTER_REDIR_ASK; + return server.cluster->migrating_slots_to[slot]; + } + + /* If we are receiving the slot, and the client correctly flagged the + * request as "ASKING", we can serve the request. However if the request + * involves multiple keys and we don't have them all, the only option is + * to send a TRYAGAIN error. */ + if (importing_slot && + (c->flags & REDIS_ASKING || cmd->flags & REDIS_CMD_ASKING)) + { + if (multiple_keys && missing_keys) { + if (error_code) *error_code = REDIS_CLUSTER_REDIR_UNSTABLE; + return NULL; + } else { + return myself; + } + } + + /* Handle the read-only client case reading from a slave: if this + * node is a slave and the request is about an hash slot our master + * is serving, we can reply without redirection. */ + if (c->flags & REDIS_READONLY && + cmd->flags & REDIS_CMD_READONLY && + nodeIsSlave(myself) && + myself->slaveof == n) + { + return myself; + } + + /* Base case: just return the right node. However if this node is not + * myself, set error_code to MOVED since we need to issue a rediretion. */ + if (n != myself && error_code) *error_code = REDIS_CLUSTER_REDIR_MOVED; + return n; +} + +/* Send the client the right redirection code, according to error_code + * that should be set to one of REDIS_CLUSTER_REDIR_* macros. + * + * If REDIS_CLUSTER_REDIR_ASK or REDIS_CLUSTER_REDIR_MOVED error codes + * are used, then the node 'n' should not be NULL, but should be the + * node we want to mention in the redirection. Moreover hashslot should + * be set to the hash slot that caused the redirection. */ +void clusterRedirectClient(redisClient *c, clusterNode *n, int hashslot, int error_code) { + if (error_code == REDIS_CLUSTER_REDIR_CROSS_SLOT) { + addReplySds(c,sdsnew("-CROSSSLOT Keys in request don't hash to the same slot\r\n")); + } else if (error_code == REDIS_CLUSTER_REDIR_UNSTABLE) { + /* The request spawns mutliple keys in the same slot, + * but the slot is not "stable" currently as there is + * a migration or import in progress. */ + addReplySds(c,sdsnew("-TRYAGAIN Multiple keys request during rehashing of slot\r\n")); + } else if (error_code == REDIS_CLUSTER_REDIR_DOWN_STATE) { + addReplySds(c,sdsnew("-CLUSTERDOWN The cluster is down\r\n")); + } else if (error_code == REDIS_CLUSTER_REDIR_DOWN_UNBOUND) { + addReplySds(c,sdsnew("-CLUSTERDOWN Hash slot not served\r\n")); + } else if (error_code == REDIS_CLUSTER_REDIR_MOVED || + error_code == REDIS_CLUSTER_REDIR_ASK) + { + addReplySds(c,sdscatprintf(sdsempty(), + "-%s %d %s:%d\r\n", + (error_code == REDIS_CLUSTER_REDIR_ASK) ? "ASK" : "MOVED", + hashslot,n->ip,n->port)); + } else { + redisPanic("getNodeByQuery() unknown error."); + } +} + +/* This function is called by the function processing clients incrementally + * to detect timeouts, in order to handle the following case: + * + * 1) A client blocks with BLPOP or similar blocking operation. + * 2) The master migrates the hash slot elsewhere or turns into a slave. + * 3) The client may remain blocked forever (or up to the max timeout time) + * waiting for a key change that will never happen. + * + * If the client is found to be blocked into an hash slot this node no + * longer handles, the client is sent a redirection error, and the function + * returns 1. Otherwise 0 is returned and no operation is performed. */ +int clusterRedirectBlockedClientIfNeeded(redisClient *c) { + if (c->flags & REDIS_BLOCKED && c->btype == REDIS_BLOCKED_LIST) { + dictEntry *de; + dictIterator *di; + + /* If the cluster is down, unblock the client with the right error. */ + if (server.cluster->state == REDIS_CLUSTER_FAIL) { + clusterRedirectClient(c,NULL,0,REDIS_CLUSTER_REDIR_DOWN_STATE); + return 1; + } + + di = dictGetIterator(c->bpop.keys); + while((de = dictNext(di)) != NULL) { + robj *key = dictGetKey(de); + int slot = keyHashSlot((char*)key->ptr, sdslen(key->ptr)); + clusterNode *node = server.cluster->slots[slot]; + + /* We send an error and unblock the client if: + * 1) The slot is unassigned, emitting a cluster down error. + * 2) The slot is not handled by this node, nor being imported. */ + if (node != myself && + server.cluster->importing_slots_from[slot] == NULL) + { + if (node == NULL) { + clusterRedirectClient(c,NULL,0, + REDIS_CLUSTER_REDIR_DOWN_UNBOUND); + } else { + clusterRedirectClient(c,node,slot, + REDIS_CLUSTER_REDIR_MOVED); + } + return 1; + } + } + dictReleaseIterator(di); + } + return 0; +} diff --git a/codeview/src/main/assets/training-set/coffeescript/coffee-script.coffee b/codeview/src/main/assets/training-set/coffeescript/coffee-script.coffee new file mode 100755 index 0000000..8059ed5 --- /dev/null +++ b/codeview/src/main/assets/training-set/coffeescript/coffee-script.coffee @@ -0,0 +1,2030 @@ +# `nodes.coffee` contains all of the node classes for the syntax tree. Most +# nodes are created as the result of actions in the [grammar](grammar.html), +# but some are created by other nodes as a method of code generation. To convert +# the syntax tree into a string of JavaScript code, call `compile()` on the root. + +{Scope} = require './scope' +{RESERVED, STRICT_PROSCRIBED} = require './lexer' + +# Import the helpers we plan to use. +{compact, flatten, extend, merge, del, starts, ends, last, some} = require './helpers' + +exports.extend = extend # for parser + +# Constant functions for nodes that don't need customization. +YES = -> yes +NO = -> no +THIS = -> this +NEGATE = -> @negated = not @negated; this + +#### Base + +# The **Base** is the abstract base class for all nodes in the syntax tree. +# Each subclass implements the `compileNode` method, which performs the +# code generation for that node. To compile a node to JavaScript, +# call `compile` on it, which wraps `compileNode` in some generic extra smarts, +# to know when the generated code needs to be wrapped up in a closure. +# An options hash is passed and cloned throughout, containing information about +# the environment from higher in the tree (such as if a returned value is +# being requested by the surrounding function), information about the current +# scope, and indentation level. +exports.Base = class Base + + # Common logic for determining whether to wrap this node in a closure before + # compiling it, or to compile directly. We need to wrap if this node is a + # *statement*, and it's not a *pureStatement*, and we're not at + # the top level of a block (which would be unnecessary), and we haven't + # already been asked to return the result (because statements know how to + # return results). + compile: (o, lvl) -> + o = extend {}, o + o.level = lvl if lvl + node = @unfoldSoak(o) or this + node.tab = o.indent + if o.level is LEVEL_TOP or not node.isStatement(o) + node.compileNode o + else + node.compileClosure o + + # Statements converted into expressions via closure-wrapping share a scope + # object with their parent closure, to preserve the expected lexical scope. + compileClosure: (o) -> + if @jumps() + throw SyntaxError 'cannot use a pure statement in an expression.' + o.sharedScope = yes + Closure.wrap(this).compileNode o + + # If the code generation wishes to use the result of a complex expression + # in multiple places, ensure that the expression is only ever evaluated once, + # by assigning it to a temporary variable. Pass a level to precompile. + cache: (o, level, reused) -> + unless @isComplex() + ref = if level then @compile o, level else this + [ref, ref] + else + ref = new Literal reused or o.scope.freeVariable 'ref' + sub = new Assign ref, this + if level then [sub.compile(o, level), ref.value] else [sub, ref] + + # Compile to a source/variable pair suitable for looping. + compileLoopReference: (o, name) -> + src = tmp = @compile o, LEVEL_LIST + unless -Infinity < +src < Infinity or IDENTIFIER.test(src) and o.scope.check(src, yes) + src = "#{ tmp = o.scope.freeVariable name } = #{src}" + [src, tmp] + + # Construct a node that returns the current node's result. + # Note that this is overridden for smarter behavior for + # many statement nodes (e.g. If, For)... + makeReturn: (res) -> + me = @unwrapAll() + if res + new Call new Literal("#{res}.push"), [me] + else + new Return me + + # Does this node, or any of its children, contain a node of a certain kind? + # Recursively traverses down the *children* of the nodes, yielding to a block + # and returning true when the block finds a match. `contains` does not cross + # scope boundaries. + contains: (pred) -> + contains = no + @traverseChildren no, (node) -> + if pred node + contains = yes + return no + contains + + # Is this node of a certain type, or does it contain the type? + containsType: (type) -> + this instanceof type or @contains (node) -> node instanceof type + + # Pull out the last non-comment node of a node list. + lastNonComment: (list) -> + i = list.length + return list[i] while i-- when list[i] not instanceof Comment + null + + # `toString` representation of the node, for inspecting the parse tree. + # This is what `coffee --nodes` prints out. + toString: (idt = '', name = @constructor.name) -> + tree = '\n' + idt + name + tree += '?' if @soak + @eachChild (node) -> tree += node.toString idt + TAB + tree + + # Passes each child to a function, breaking when the function returns `false`. + eachChild: (func) -> + return this unless @children + for attr in @children when @[attr] + for child in flatten [@[attr]] + return this if func(child) is false + this + + traverseChildren: (crossScope, func) -> + @eachChild (child) -> + return false if func(child) is false + child.traverseChildren crossScope, func + + invert: -> + new Op '!', this + + unwrapAll: -> + node = this + continue until node is node = node.unwrap() + node + + # Default implementations of the common node properties and methods. Nodes + # will override these with custom logic, if needed. + children: [] + + isStatement : NO + jumps : NO + isComplex : YES + isChainable : NO + isAssignable : NO + + unwrap : THIS + unfoldSoak : NO + + # Is this node used to assign a certain variable? + assigns: NO + +#### Block + +# The block is the list of expressions that forms the body of an +# indented block of code -- the implementation of a function, a clause in an +# `if`, `switch`, or `try`, and so on... +exports.Block = class Block extends Base + constructor: (nodes) -> + @expressions = compact flatten nodes or [] + + children: ['expressions'] + + # Tack an expression on to the end of this expression list. + push: (node) -> + @expressions.push node + this + + # Remove and return the last expression of this expression list. + pop: -> + @expressions.pop() + + # Add an expression at the beginning of this expression list. + unshift: (node) -> + @expressions.unshift node + this + + # If this Block consists of just a single node, unwrap it by pulling + # it back out. + unwrap: -> + if @expressions.length is 1 then @expressions[0] else this + + # Is this an empty block of code? + isEmpty: -> + not @expressions.length + + isStatement: (o) -> + for exp in @expressions when exp.isStatement o + return yes + no + + jumps: (o) -> + for exp in @expressions + return exp if exp.jumps o + + # A Block node does not return its entire body, rather it + # ensures that the final expression is returned. + makeReturn: (res) -> + len = @expressions.length + while len-- + expr = @expressions[len] + if expr not instanceof Comment + @expressions[len] = expr.makeReturn res + @expressions.splice(len, 1) if expr instanceof Return and not expr.expression + break + this + + # A **Block** is the only node that can serve as the root. + compile: (o = {}, level) -> + if o.scope then super o, level else @compileRoot o + + # Compile all expressions within the **Block** body. If we need to + # return the result, and it's an expression, simply return it. If it's a + # statement, ask the statement to do so. + compileNode: (o) -> + @tab = o.indent + top = o.level is LEVEL_TOP + codes = [] + for node in @expressions + node = node.unwrapAll() + node = (node.unfoldSoak(o) or node) + if node instanceof Block + # This is a nested block. We don't do anything special here unlike enclose + # it in a new scope; we just compile the statements in this block along with + # our own + codes.push node.compileNode o + else if top + node.front = true + code = node.compile o + unless node.isStatement o + code = "#{@tab}#{code};" + codes.push code + else + codes.push node.compile o, LEVEL_LIST + if top + if @spaced + return "\n#{codes.join '\n\n'}\n" + else + return codes.join '\n' + code = codes.join(', ') or 'void 0' + if codes.length > 1 and o.level >= LEVEL_LIST then "(#{code})" else code + + # If we happen to be the top-level **Block**, wrap everything in + # a safety closure, unless requested not to. + # It would be better not to generate them in the first place, but for now, + # clean up obvious double-parentheses. + compileRoot: (o) -> + o.indent = if o.bare then '' else TAB + o.scope = new Scope null, this, null + o.level = LEVEL_TOP + @spaced = yes + prelude = "" + unless o.bare + preludeExps = for exp, i in @expressions + break unless exp.unwrap() instanceof Comment + exp + rest = @expressions[preludeExps.length...] + @expressions = preludeExps + prelude = "#{@compileNode merge(o, indent: '')}\n" if preludeExps.length + @expressions = rest + code = @compileWithDeclarations o + return code if o.bare + "#{prelude}(function() {\n#{code}\n}).call(this);\n" + + # Compile the expressions body for the contents of a function, with + # declarations of all inner variables pushed up to the top. + compileWithDeclarations: (o) -> + code = post = '' + for exp, i in @expressions + exp = exp.unwrap() + break unless exp instanceof Comment or exp instanceof Literal + o = merge(o, level: LEVEL_TOP) + if i + rest = @expressions.splice i, 9e9 + [spaced, @spaced] = [@spaced, no] + [code , @spaced] = [(@compileNode o), spaced] + @expressions = rest + post = @compileNode o + {scope} = o + if scope.expressions is this + declars = o.scope.hasDeclarations() + assigns = scope.hasAssignments + if declars or assigns + code += '\n' if i + code += "#{@tab}var " + if declars + code += scope.declaredVariables().join ', ' + if assigns + code += ",\n#{@tab + TAB}" if declars + code += scope.assignedVariables().join ",\n#{@tab + TAB}" + code += ';\n' + code + post + + # Wrap up the given nodes as a **Block**, unless it already happens + # to be one. + @wrap: (nodes) -> + return nodes[0] if nodes.length is 1 and nodes[0] instanceof Block + new Block nodes + +#### Literal + +# Literals are static values that can be passed through directly into +# JavaScript without translation, such as: strings, numbers, +# `true`, `false`, `null`... +exports.Literal = class Literal extends Base + constructor: (@value) -> + + makeReturn: -> + if @isStatement() then this else super + + isAssignable: -> + IDENTIFIER.test @value + + isStatement: -> + @value in ['break', 'continue', 'debugger'] + + isComplex: NO + + assigns: (name) -> + name is @value + + jumps: (o) -> + return this if @value is 'break' and not (o?.loop or o?.block) + return this if @value is 'continue' and not o?.loop + + compileNode: (o) -> + code = if @value is 'this' + if o.scope.method?.bound then o.scope.method.context else @value + else if @value.reserved + "\"#{@value}\"" + else + @value + if @isStatement() then "#{@tab}#{code};" else code + + toString: -> + ' "' + @value + '"' + +class exports.Undefined extends Base + isAssignable: NO + isComplex: NO + compileNode: (o) -> + if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0' + +class exports.Null extends Base + isAssignable: NO + isComplex: NO + compileNode: -> "null" + +class exports.Bool extends Base + isAssignable: NO + isComplex: NO + compileNode: -> @val + constructor: (@val) -> + +#### Return + +# A `return` is a *pureStatement* -- wrapping it in a closure wouldn't +# make sense. +exports.Return = class Return extends Base + constructor: (expr) -> + @expression = expr if expr and not expr.unwrap().isUndefined + + children: ['expression'] + + isStatement: YES + makeReturn: THIS + jumps: THIS + + compile: (o, level) -> + expr = @expression?.makeReturn() + if expr and expr not instanceof Return then expr.compile o, level else super o, level + + compileNode: (o) -> + @tab + "return#{[" #{@expression.compile o, LEVEL_PAREN}" if @expression]};" + +#### Value + +# A value, variable or literal or parenthesized, indexed or dotted into, +# or vanilla. +exports.Value = class Value extends Base + constructor: (base, props, tag) -> + return base if not props and base instanceof Value + @base = base + @properties = props or [] + @[tag] = true if tag + return this + + children: ['base', 'properties'] + + # Add a property (or *properties* ) `Access` to the list. + add: (props) -> + @properties = @properties.concat props + this + + hasProperties: -> + !!@properties.length + + # Some boolean checks for the benefit of other nodes. + isArray : -> not @properties.length and @base instanceof Arr + isComplex : -> @hasProperties() or @base.isComplex() + isAssignable : -> @hasProperties() or @base.isAssignable() + isSimpleNumber : -> @base instanceof Literal and SIMPLENUM.test @base.value + isString : -> @base instanceof Literal and IS_STRING.test @base.value + isAtomic : -> + for node in @properties.concat @base + return no if node.soak or node instanceof Call + yes + + isStatement : (o) -> not @properties.length and @base.isStatement o + assigns : (name) -> not @properties.length and @base.assigns name + jumps : (o) -> not @properties.length and @base.jumps o + + isObject: (onlyGenerated) -> + return no if @properties.length + (@base instanceof Obj) and (not onlyGenerated or @base.generated) + + isSplice: -> + last(@properties) instanceof Slice + + # The value can be unwrapped as its inner node, if there are no attached + # properties. + unwrap: -> + if @properties.length then this else @base + + # A reference has base part (`this` value) and name part. + # We cache them separately for compiling complex expressions. + # `a()[b()] ?= c` -> `(_base = a())[_name = b()] ? _base[_name] = c` + cacheReference: (o) -> + name = last @properties + if @properties.length < 2 and not @base.isComplex() and not name?.isComplex() + return [this, this] # `a` `a.b` + base = new Value @base, @properties[...-1] + if base.isComplex() # `a().b` + bref = new Literal o.scope.freeVariable 'base' + base = new Value new Parens new Assign bref, base + return [base, bref] unless name # `a()` + if name.isComplex() # `a[b()]` + nref = new Literal o.scope.freeVariable 'name' + name = new Index new Assign nref, name.index + nref = new Index nref + [base.add(name), new Value(bref or base.base, [nref or name])] + + # We compile a value to JavaScript by compiling and joining each property. + # Things get much more interesting if the chain of properties has *soak* + # operators `?.` interspersed. Then we have to take care not to accidentally + # evaluate anything twice when building the soak chain. + compileNode: (o) -> + @base.front = @front + props = @properties + code = @base.compile o, if props.length then LEVEL_ACCESS else null + code = "#{code}." if (@base instanceof Parens or props.length) and SIMPLENUM.test code + code += prop.compile o for prop in props + code + + # Unfold a soak into an `If`: `a?.b` -> `a.b if a?` + unfoldSoak: (o) -> + return @unfoldedSoak if @unfoldedSoak? + result = do => + if ifn = @base.unfoldSoak o + Array::push.apply ifn.body.properties, @properties + return ifn + for prop, i in @properties when prop.soak + prop.soak = off + fst = new Value @base, @properties[...i] + snd = new Value @base, @properties[i..] + if fst.isComplex() + ref = new Literal o.scope.freeVariable 'ref' + fst = new Parens new Assign ref, fst + snd.base = ref + return new If new Existence(fst), snd, soak: on + null + @unfoldedSoak = result or no + +#### Comment + +# CoffeeScript passes through block comments as JavaScript block comments +# at the same position. +exports.Comment = class Comment extends Base + constructor: (@comment) -> + + isStatement: YES + makeReturn: THIS + + compileNode: (o, level) -> + code = '/*' + multident(@comment, @tab) + "\n#{@tab}*/\n" + code = o.indent + code if (level or o.level) is LEVEL_TOP + code + +#### Call + +# Node for a function invocation. Takes care of converting `super()` calls into +# calls against the prototype's function of the same name. +exports.Call = class Call extends Base + constructor: (variable, @args = [], @soak) -> + @isNew = false + @isSuper = variable is 'super' + @variable = if @isSuper then null else variable + + children: ['variable', 'args'] + + # Tag this invocation as creating a new instance. + newInstance: -> + base = @variable?.base or @variable + if base instanceof Call and not base.isNew + base.newInstance() + else + @isNew = true + this + + # Grab the reference to the superclass's implementation of the current + # method. + superReference: (o) -> + method = o.scope.namedMethod() + throw SyntaxError 'cannot call super outside of a function.' unless method + {name} = method + throw SyntaxError 'cannot call super on an anonymous function.' unless name? + if method.klass + accesses = [new Access(new Literal '__super__')] + accesses.push new Access new Literal 'constructor' if method.static + accesses.push new Access new Literal name + (new Value (new Literal method.klass), accesses).compile o + else + "#{name}.__super__.constructor" + + # The appropriate `this` value for a `super` call. + superThis : (o) -> + method = o.scope.method + (method and not method.klass and method.context) or "this" + + # Soaked chained invocations unfold into if/else ternary structures. + unfoldSoak: (o) -> + if @soak + if @variable + return ifn if ifn = unfoldSoak o, this, 'variable' + [left, rite] = new Value(@variable).cacheReference o + else + left = new Literal @superReference o + rite = new Value left + rite = new Call rite, @args + rite.isNew = @isNew + left = new Literal "typeof #{ left.compile o } === \"function\"" + return new If left, new Value(rite), soak: yes + call = this + list = [] + loop + if call.variable instanceof Call + list.push call + call = call.variable + continue + break unless call.variable instanceof Value + list.push call + break unless (call = call.variable.base) instanceof Call + for call in list.reverse() + if ifn + if call.variable instanceof Call + call.variable = ifn + else + call.variable.base = ifn + ifn = unfoldSoak o, call, 'variable' + ifn + + # Walk through the objects in the arguments, moving over simple values. + # This allows syntax unlike `call a: b, c` into `call({a: b}, c);` + filterImplicitObjects: (list) -> + nodes = [] + for node in list + unless node.isObject?() and node.base.generated + nodes.push node + continue + obj = null + for prop in node.base.properties + if prop instanceof Assign or prop instanceof Comment + nodes.push obj = new Obj properties = [], true if not obj + properties.push prop + else + nodes.push prop + obj = null + nodes + + # Compile a vanilla function call. + compileNode: (o) -> + @variable?.front = @front + if code = Splat.compileSplattedArray o, @args, true + return @compileSplat o, code + args = @filterImplicitObjects @args + args = (arg.compile o, LEVEL_LIST for arg in args).join ', ' + if @isSuper + @superReference(o) + ".call(#{@superThis(o)}#{ args and ', ' + args })" + else + (if @isNew then 'new ' else '') + @variable.compile(o, LEVEL_ACCESS) + "(#{args})" + + # `super()` is converted into a call against the superclass's implementation + # of the current function. + compileSuper: (args, o) -> + "#{@superReference(o)}.call(#{@superThis(o)}#{ if args.length then ', ' else '' }#{args})" + + # If you call a function with a splat, it's converted into a JavaScript + # `.apply()` call to allow an array of arguments to be passed. + # If it's a constructor, then things get real tricky. We have to inject an + # inner constructor in order to be able to pass the varargs. + compileSplat: (o, splatArgs) -> + return "#{ @superReference o }.apply(#{@superThis(o)}, #{splatArgs})" if @isSuper + if @isNew + idt = @tab + TAB + return """ + (function(func, args, ctor) { + #{idt}ctor.prototype = func.prototype; + #{idt}var child = new ctor, result = func.apply(child, args); + #{idt}return Object(result) === result ? result : child; + #{@tab}})(#{ @variable.compile o, LEVEL_LIST }, #{splatArgs}, function(){}) + """ + base = new Value @variable + if (name = base.properties.pop()) and base.isComplex() + ref = o.scope.freeVariable 'ref' + fun = "(#{ref} = #{ base.compile o, LEVEL_LIST })#{ name.compile o }" + else + fun = base.compile o, LEVEL_ACCESS + fun = "(#{fun})" if SIMPLENUM.test fun + if name + ref = fun + fun += name.compile o + else + ref = 'null' + "#{fun}.apply(#{ref}, #{splatArgs})" + +#### Extends + +# Node to extend an object's prototype with an ancestor object. +# After `goog.inherits` from the +# [Closure Library](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.html). +exports.Extends = class Extends extends Base + constructor: (@child, @parent) -> + + children: ['child', 'parent'] + + # Hooks one constructor into another's prototype chain. + compile: (o) -> + new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compile o + +#### Access + +# A `.` access into a property of a value, or the `::` shorthand for +# an access into the object's prototype. +exports.Access = class Access extends Base + constructor: (@name, tag) -> + @name.asKey = yes + @soak = tag is 'soak' + + children: ['name'] + + compile: (o) -> + name = @name.compile o + if IDENTIFIER.test name then ".#{name}" else "[#{name}]" + + isComplex: NO + +#### Index + +# A `[ ... ]` indexed access into an array or object. +exports.Index = class Index extends Base + constructor: (@index) -> + + children: ['index'] + + compile: (o) -> + "[#{ @index.compile o, LEVEL_PAREN }]" + + isComplex: -> + @index.isComplex() + +#### Range + +# A range literal. Ranges can be used to extract portions (slices) of arrays, +# to specify a range for comprehensions, or as a value, to be expanded into the +# corresponding array of integers at runtime. +exports.Range = class Range extends Base + + children: ['from', 'to'] + + constructor: (@from, @to, tag) -> + @exclusive = tag is 'exclusive' + @equals = if @exclusive then '' else '=' + + # Compiles the range's source variables -- where it starts and where it ends. + # But only if they need to be cached to avoid double evaluation. + compileVariables: (o) -> + o = merge o, top: true + [@fromC, @fromVar] = @from.cache o, LEVEL_LIST + [@toC, @toVar] = @to.cache o, LEVEL_LIST + [@step, @stepVar] = step.cache o, LEVEL_LIST if step = del o, 'step' + [@fromNum, @toNum] = [@fromVar.match(SIMPLENUM), @toVar.match(SIMPLENUM)] + @stepNum = @stepVar.match(SIMPLENUM) if @stepVar + + # When compiled normally, the range returns the contents of the *for loop* + # needed to iterate over the values in the range. Used by comprehensions. + compileNode: (o) -> + @compileVariables o unless @fromVar + return @compileArray(o) unless o.index + + # Set up endpoints. + known = @fromNum and @toNum + idx = del o, 'index' + idxName = del o, 'name' + namedIndex = idxName and idxName isnt idx + varPart = "#{idx} = #{@fromC}" + varPart += ", #{@toC}" if @toC isnt @toVar + varPart += ", #{@step}" if @step isnt @stepVar + [lt, gt] = ["#{idx} <#{@equals}", "#{idx} >#{@equals}"] + + # Generate the condition. + condPart = if @stepNum + if +@stepNum > 0 then "#{lt} #{@toVar}" else "#{gt} #{@toVar}" + else if known + [from, to] = [+@fromNum, +@toNum] + if from <= to then "#{lt} #{to}" else "#{gt} #{to}" + else + cond = "#{@fromVar} <= #{@toVar}" + "#{cond} ? #{lt} #{@toVar} : #{gt} #{@toVar}" + + # Generate the step. + stepPart = if @stepVar + "#{idx} += #{@stepVar}" + else if known + if namedIndex + if from <= to then "++#{idx}" else "--#{idx}" + else + if from <= to then "#{idx}++" else "#{idx}--" + else + if namedIndex + "#{cond} ? ++#{idx} : --#{idx}" + else + "#{cond} ? #{idx}++ : #{idx}--" + + varPart = "#{idxName} = #{varPart}" if namedIndex + stepPart = "#{idxName} = #{stepPart}" if namedIndex + + # The final loop body. + "#{varPart}; #{condPart}; #{stepPart}" + + + # When used as a value, expand the range into the equivalent array. + compileArray: (o) -> + if @fromNum and @toNum and Math.abs(@fromNum - @toNum) <= 20 + range = [+@fromNum..+@toNum] + range.pop() if @exclusive + return "[#{ range.join(', ') }]" + idt = @tab + TAB + i = o.scope.freeVariable 'i' + result = o.scope.freeVariable 'results' + pre = "\n#{idt}#{result} = [];" + if @fromNum and @toNum + o.index = i + body = @compileNode o + else + vars = "#{i} = #{@fromC}" + if @toC isnt @toVar then ", #{@toC}" else '' + cond = "#{@fromVar} <= #{@toVar}" + body = "var #{vars}; #{cond} ? #{i} <#{@equals} #{@toVar} : #{i} >#{@equals} #{@toVar}; #{cond} ? #{i}++ : #{i}--" + post = "{ #{result}.push(#{i}); }\n#{idt}return #{result};\n#{o.indent}" + hasArgs = (node) -> node?.contains (n) -> n instanceof Literal and n.value is 'arguments' and not n.asKey + args = ', arguments' if hasArgs(@from) or hasArgs(@to) + "(function() {#{pre}\n#{idt}for (#{body})#{post}}).apply(this#{args ? ''})" + +#### Slice + +# An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter +# specifies the index of the end of the slice, just as the first parameter +# is the index of the beginning. +exports.Slice = class Slice extends Base + + children: ['range'] + + constructor: (@range) -> + super() + + # We have to be careful when trying to slice through the end of the array, + # `9e9` is used because not all implementations respect `undefined` or `1/0`. + # `9e9` should be safe because `9e9` > `2**32`, the max array length. + compileNode: (o) -> + {to, from} = @range + fromStr = from and from.compile(o, LEVEL_PAREN) or '0' + compiled = to and to.compile o, LEVEL_PAREN + if to and not (not @range.exclusive and +compiled is -1) + toStr = ', ' + if @range.exclusive + compiled + else if SIMPLENUM.test compiled + "#{+compiled + 1}" + else + compiled = to.compile o, LEVEL_ACCESS + "+#{compiled} + 1 || 9e9" + ".slice(#{ fromStr }#{ toStr or '' })" + +#### Obj + +# An object literal, nothing fancy. +exports.Obj = class Obj extends Base + constructor: (props, @generated = false) -> + @objects = @properties = props or [] + + children: ['properties'] + + compileNode: (o) -> + props = @properties + return (if @front then '({})' else '{}') unless props.length + if @generated + for node in props when node instanceof Value + throw new Error 'cannot have an implicit value in an implicit object' + idt = o.indent += TAB + lastNoncom = @lastNonComment @properties + props = for prop, i in props + join = if i is props.length - 1 + '' + else if prop is lastNoncom or prop instanceof Comment + '\n' + else + ',\n' + indent = if prop instanceof Comment then '' else idt + if prop instanceof Value and prop.this + prop = new Assign prop.properties[0].name, prop, 'object' + if prop not instanceof Comment + if prop not instanceof Assign + prop = new Assign prop, prop, 'object' + (prop.variable.base or prop.variable).asKey = yes + indent + prop.compile(o, LEVEL_TOP) + join + props = props.join '' + obj = "{#{ props and '\n' + props + '\n' + @tab }}" + if @front then "(#{obj})" else obj + + assigns: (name) -> + for prop in @properties when prop.assigns name then return yes + no + +#### Arr + +# An array literal. +exports.Arr = class Arr extends Base + constructor: (objs) -> + @objects = objs or [] + + children: ['objects'] + + filterImplicitObjects: Call::filterImplicitObjects + + compileNode: (o) -> + return '[]' unless @objects.length + o.indent += TAB + objs = @filterImplicitObjects @objects + return code if code = Splat.compileSplattedArray o, objs + code = (obj.compile o, LEVEL_LIST for obj in objs).join ', ' + if code.indexOf('\n') >= 0 + "[\n#{o.indent}#{code}\n#{@tab}]" + else + "[#{code}]" + + assigns: (name) -> + for obj in @objects when obj.assigns name then return yes + no + +#### Class + +# The CoffeeScript class definition. +# Initialize a **Class** with its name, an optional superclass, and a +# list of prototype property assignments. +exports.Class = class Class extends Base + constructor: (@variable, @parent, @body = new Block) -> + @boundFuncs = [] + @body.classBody = yes + + children: ['variable', 'parent', 'body'] + + # Figure out the appropriate name for the constructor function of this class. + determineName: -> + return null unless @variable + decl = if tail = last @variable.properties + tail instanceof Access and tail.name.value + else + @variable.base.value + if decl in STRICT_PROSCRIBED + throw SyntaxError "variable name may not be #{decl}" + decl and= IDENTIFIER.test(decl) and decl + + # For all `this`-references and bound functions in the class definition, + # `this` is the Class being constructed. + setContext: (name) -> + @body.traverseChildren false, (node) -> + return false if node.classBody + if node instanceof Literal and node.value is 'this' + node.value = name + else if node instanceof Code + node.klass = name + node.context = name if node.bound + + # Ensure that all functions bound to the instance are proxied in the + # constructor. + addBoundFunctions: (o) -> + if @boundFuncs.length + for bvar in @boundFuncs + lhs = (new Value (new Literal "this"), [new Access bvar]).compile o + @ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)" + + # Merge the properties from a top-level object as prototypal properties + # on the class. + addProperties: (node, name, o) -> + props = node.base.properties[..] + exprs = while assign = props.shift() + if assign instanceof Assign + base = assign.variable.base + delete assign.context + func = assign.value + if base.value is 'constructor' + if @ctor + throw new Error 'cannot define more than one constructor in a class' + if func.bound + throw new Error 'cannot define a constructor as a bound function' + if func instanceof Code + assign = @ctor = func + else + @externalCtor = o.scope.freeVariable 'class' + assign = new Assign new Literal(@externalCtor), func + else + if assign.variable.this + func.static = yes + if func.bound + func.context = name + else + assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ]) + if func instanceof Code and func.bound + @boundFuncs.push base + func.bound = no + assign + compact exprs + + # Walk the body of the class, looking for prototype properties to be converted. + walkBody: (name, o) -> + @traverseChildren false, (child) => + return false if child instanceof Class + if child instanceof Block + for node, i in exps = child.expressions + if node instanceof Value and node.isObject(true) + exps[i] = @addProperties node, name, o + child.expressions = exps = flatten exps + + # `use strict` (and other directives) must be the first expression statement(s) + # of a function body. This method ensures the prologue is correctly positioned + # above the `constructor`. + hoistDirectivePrologue: -> + index = 0 + {expressions} = @body + ++index while (node = expressions[index]) and node instanceof Comment or + node instanceof Value and node.isString() + @directives = expressions.splice 0, index + + # Make sure that a constructor is defined for the class, and properly + # configured. + ensureConstructor: (name) -> + if not @ctor + @ctor = new Code + @ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent + @ctor.body.push new Literal "#{@externalCtor}.apply(this, arguments)" if @externalCtor + @ctor.body.makeReturn() + @body.expressions.unshift @ctor + @ctor.ctor = @ctor.name = name + @ctor.klass = null + @ctor.noReturn = yes + + # Instead of generating the JavaScript string directly, we build up the + # equivalent syntax tree and compile that, in pieces. You can see the + # constructor, property assignments, and inheritance getting built out below. + compileNode: (o) -> + decl = @determineName() + name = decl or '_Class' + name = "_#{name}" if name.reserved + lname = new Literal name + + @hoistDirectivePrologue() + @setContext name + @walkBody name, o + @ensureConstructor name + @body.spaced = yes + @body.expressions.unshift @ctor unless @ctor instanceof Code + @body.expressions.push lname + @body.expressions.unshift @directives... + @addBoundFunctions o + + call = Closure.wrap @body + + if @parent + @superClass = new Literal o.scope.freeVariable 'super', no + @body.expressions.unshift new Extends lname, @superClass + call.args.push @parent + params = call.variable.params or call.variable.base.params + params.push new Param @superClass + + klass = new Parens call, yes + klass = new Assign @variable, klass if @variable + klass.compile o + +#### Assign + +# The **Assign** is used to assign a local variable to value, or to set the +# property of an object -- including within object literals. +exports.Assign = class Assign extends Base + constructor: (@variable, @value, @context, options) -> + @param = options and options.param + @subpattern = options and options.subpattern + forbidden = (name = @variable.unwrapAll().value) in STRICT_PROSCRIBED + if forbidden and @context isnt 'object' + throw SyntaxError "variable name may not be \"#{name}\"" + + children: ['variable', 'value'] + + isStatement: (o) -> + o?.level is LEVEL_TOP and @context? and "?" in @context + + assigns: (name) -> + @[if @context is 'object' then 'value' else 'variable'].assigns name + + unfoldSoak: (o) -> + unfoldSoak o, this, 'variable' + + # Compile an assignment, delegating to `compilePatternMatch` or + # `compileSplice` if appropriate. Keep track of the name of the base object + # we've been assigned to, for correct internal references. If the variable + # has not been seen yet within the current scope, declare it. + compileNode: (o) -> + if isValue = @variable instanceof Value + return @compilePatternMatch o if @variable.isArray() or @variable.isObject() + return @compileSplice o if @variable.isSplice() + return @compileConditional o if @context in ['||=', '&&=', '?='] + name = @variable.compile o, LEVEL_LIST + unless @context + unless (varBase = @variable.unwrapAll()).isAssignable() + throw SyntaxError "\"#{ @variable.compile o }\" cannot be assigned." + unless varBase.hasProperties?() + if @param + o.scope.add name, 'var' + else + o.scope.find name + if @value instanceof Code and match = METHOD_DEF.exec name + @value.klass = match[1] if match[1] + @value.name = match[2] ? match[3] ? match[4] ? match[5] + val = @value.compile o, LEVEL_LIST + return "#{name}: #{val}" if @context is 'object' + val = name + " #{ @context or '=' } " + val + if o.level <= LEVEL_LIST then val else "(#{val})" + + # Brief implementation of recursive pattern matching, when assigning array or + # object literals to a value. Peeks at their properties to assign inner names. + # See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring) + # for details. + compilePatternMatch: (o) -> + top = o.level is LEVEL_TOP + {value} = this + {objects} = @variable.base + unless olen = objects.length + code = value.compile o + return if o.level >= LEVEL_OP then "(#{code})" else code + isObject = @variable.isObject() + if top and olen is 1 and (obj = objects[0]) not instanceof Splat + # Unroll simplest cases: `{v} = x` -> `v = x.v` + if obj instanceof Assign + {variable: {base: idx}, value: obj} = obj + else + if obj.base instanceof Parens + [obj, idx] = new Value(obj.unwrapAll()).cacheReference o + else + idx = if isObject + if obj.this then obj.properties[0].name else obj + else + new Literal 0 + acc = IDENTIFIER.test idx.unwrap().value or 0 + value = new Value value + value.properties.push new (if acc then Access else Index) idx + if obj.unwrap().value in RESERVED + throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{value.compile o}" + return new Assign(obj, value, null, param: @param).compile o, LEVEL_TOP + vvar = value.compile o, LEVEL_LIST + assigns = [] + splat = false + if not IDENTIFIER.test(vvar) or @variable.assigns(vvar) + assigns.push "#{ ref = o.scope.freeVariable 'ref' } = #{vvar}" + vvar = ref + for obj, i in objects + # A regular array pattern-match. + idx = i + if isObject + if obj instanceof Assign + # A regular object pattern-match. + {variable: {base: idx}, value: obj} = obj + else + # A shorthand `{a, b, @c} = val` pattern-match. + if obj.base instanceof Parens + [obj, idx] = new Value(obj.unwrapAll()).cacheReference o + else + idx = if obj.this then obj.properties[0].name else obj + if not splat and obj instanceof Splat + name = obj.name.unwrap().value + obj = obj.unwrap() + val = "#{olen} <= #{vvar}.length ? #{ utility 'slice' }.call(#{vvar}, #{i}" + if rest = olen - i - 1 + ivar = o.scope.freeVariable 'i' + val += ", #{ivar} = #{vvar}.length - #{rest}) : (#{ivar} = #{i}, [])" + else + val += ") : []" + val = new Literal val + splat = "#{ivar}++" + else + name = obj.unwrap().value + if obj instanceof Splat + obj = obj.name.compile o + throw new SyntaxError \ + "multiple splats are disallowed in an assignment: #{obj}..." + if typeof idx is 'number' + idx = new Literal splat or idx + acc = no + else + acc = isObject and IDENTIFIER.test idx.unwrap().value or 0 + val = new Value new Literal(vvar), [new (if acc then Access else Index) idx] + if name? and name in RESERVED + throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{val.compile o}" + assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compile o, LEVEL_LIST + assigns.push vvar unless top or @subpattern + code = assigns.join ', ' + if o.level < LEVEL_LIST then code else "(#{code})" + + # When compiling a conditional assignment, take care to ensure that the + # operands are only evaluated once, even though we have to reference them + # more than once. + compileConditional: (o) -> + [left, right] = @variable.cacheReference o + # Disallow conditional assignment of undefined variables. + if not left.properties.length and left.base instanceof Literal and + left.base.value != "this" and not o.scope.check left.base.value + throw new Error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been defined." + if "?" in @context then o.isExistentialEquals = true + new Op(@context[...-1], left, new Assign(right, @value, '=') ).compile o + + # Compile the assignment from an array splice literal, using JavaScript's + # `Array#splice` method. + compileSplice: (o) -> + {range: {from, to, exclusive}} = @variable.properties.pop() + name = @variable.compile o + [fromDecl, fromRef] = from?.cache(o, LEVEL_OP) or ['0', '0'] + if to + if from?.isSimpleNumber() and to.isSimpleNumber() + to = +to.compile(o) - +fromRef + to += 1 unless exclusive + else + to = to.compile(o, LEVEL_ACCESS) + ' - ' + fromRef + to += ' + 1' unless exclusive + else + to = "9e9" + [valDef, valRef] = @value.cache o, LEVEL_LIST + code = "[].splice.apply(#{name}, [#{fromDecl}, #{to}].concat(#{valDef})), #{valRef}" + if o.level > LEVEL_TOP then "(#{code})" else code + +#### Code + +# A function definition. This is the only node that creates a new Scope. +# When for the purposes of walking the contents of a function body, the Code +# has no *children* -- they're within the inner scope. +exports.Code = class Code extends Base + constructor: (params, body, tag) -> + @params = params or [] + @body = body or new Block + @bound = tag is 'boundfunc' + @context = '_this' if @bound + + children: ['params', 'body'] + + isStatement: -> !!@ctor + + jumps: NO + + # Compilation creates a new scope unless explicitly asked to share with the + # outer scope. Handles splat parameters in the parameter list by peeking at + # the JavaScript `arguments` object. If the function is bound with the `=>` + # arrow, generates a wrapper that saves the current value of `this` through + # a closure. + compileNode: (o) -> + o.scope = new Scope o.scope, @body, this + o.scope.shared = del(o, 'sharedScope') + o.indent += TAB + delete o.bare + delete o.isExistentialEquals + params = [] + exprs = [] + for name in @paramNames() # this step must be performed before the others + unless o.scope.check name then o.scope.parameter name + for param in @params when param.splat + for {name: p} in @params + if p.this then p = p.properties[0].name + if p.value then o.scope.add p.value, 'var', yes + splats = new Assign new Value(new Arr(p.asReference o for p in @params)), + new Value new Literal 'arguments' + break + for param in @params + if param.isComplex() + val = ref = param.asReference o + val = new Op '?', ref, param.value if param.value + exprs.push new Assign new Value(param.name), val, '=', param: yes + else + ref = param + if param.value + lit = new Literal ref.name.value + ' == null' + val = new Assign new Value(param.name), param.value, '=' + exprs.push new If lit, val + params.push ref unless splats + wasEmpty = @body.isEmpty() + exprs.unshift splats if splats + @body.expressions.unshift exprs... if exprs.length + o.scope.parameter params[i] = p.compile o for p, i in params + uniqs = [] + for name in @paramNames() + throw SyntaxError "multiple parameters named '#{name}'" if name in uniqs + uniqs.push name + @body.makeReturn() unless wasEmpty or @noReturn + if @bound + if o.scope.parent.method?.bound + @bound = @context = o.scope.parent.method.context + else if not @static + o.scope.parent.assign '_this', 'this' + idt = o.indent + code = 'function' + code += ' ' + @name if @ctor + code += '(' + params.join(', ') + ') {' + code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty() + code += '}' + return @tab + code if @ctor + if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code + + # A list of parameter names, excluding those generated by the compiler. + paramNames: -> + names = [] + names.push param.names()... for param in @params + names + + # Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries + # unless `crossScope` is `true`. + traverseChildren: (crossScope, func) -> + super(crossScope, func) if crossScope + +#### Param + +# A parameter in a function definition. Beyond a typical Javascript parameter, +# these parameters can also attach themselves to the context of the function, +# as well as be a splat, gathering up a group of parameters into an array. +exports.Param = class Param extends Base + constructor: (@name, @value, @splat) -> + if (name = @name.unwrapAll().value) in STRICT_PROSCRIBED + throw SyntaxError "parameter name \"#{name}\" is not allowed" + + children: ['name', 'value'] + + compile: (o) -> + @name.compile o, LEVEL_LIST + + asReference: (o) -> + return @reference if @reference + node = @name + if node.this + node = node.properties[0].name + if node.value.reserved + node = new Literal o.scope.freeVariable node.value + else if node.isComplex() + node = new Literal o.scope.freeVariable 'arg' + node = new Value node + node = new Splat node if @splat + @reference = node + + isComplex: -> + @name.isComplex() + + # Finds the name or names of a `Param`; useful for detecting duplicates. + # In a sense, a destructured parameter represents multiple JS parameters, + # thus this method returns an `Array` of names. + # Reserved words used as param names, as well as the Object and Array + # literals used for destructured params, get a compiler generated name + # during the `Code` compilation step, so this is necessarily an incomplete + # list of a parameter's names. + names: (name = @name)-> + atParam = (obj) -> + {value} = obj.properties[0].name + return if value.reserved then [] else [value] + # * simple literals `foo` + return [name.value] if name instanceof Literal + # * at-params `@foo` + return atParam(name) if name instanceof Value + names = [] + for obj in name.objects + # * assignments within destructured parameters `{foo:bar}` + if obj instanceof Assign + names.push obj.value.unwrap().value + # * splats within destructured parameters `[xs...]` + else if obj instanceof Splat + names.push obj.name.unwrap().value + else if obj instanceof Value + # * destructured parameters within destructured parameters `[{a}]` + if obj.isArray() or obj.isObject() + names.push @names(obj.base)... + # * at-params within destructured parameters `{@foo}` + else if obj.this + names.push atParam(obj)... + # * simple destructured parameters {foo} + else names.push obj.base.value + else + throw SyntaxError "illegal parameter #{obj.compile()}" + names + +#### Splat + +# A splat, either as a parameter to a function, an argument to a call, +# or as part of a destructuring assignment. +exports.Splat = class Splat extends Base + + children: ['name'] + + isAssignable: YES + + constructor: (name) -> + @name = if name.compile then name else new Literal name + + assigns: (name) -> + @name.assigns name + + compile: (o) -> + if @index? then @compileParam o else @name.compile o + + unwrap: -> @name + + # Utility function that converts an arbitrary number of elements, mixed with + # splats, to a proper array. + @compileSplattedArray: (o, list, apply) -> + index = -1 + continue while (node = list[++index]) and node not instanceof Splat + return '' if index >= list.length + if list.length is 1 + code = list[0].compile o, LEVEL_LIST + return code if apply + return "#{ utility 'slice' }.call(#{code})" + args = list[index..] + for node, i in args + code = node.compile o, LEVEL_LIST + args[i] = if node instanceof Splat + then "#{ utility 'slice' }.call(#{code})" + else "[#{code}]" + return args[0] + ".concat(#{ args[1..].join ', ' })" if index is 0 + base = (node.compile o, LEVEL_LIST for node in list[...index]) + "[#{ base.join ', ' }].concat(#{ args.join ', ' })" + +#### While + +# A while loop, the only sort of low-level loop exposed by CoffeeScript. From +# it, all other loops can be manufactured. Useful in cases where you need more +# flexibility or more speed than a comprehension can provide. +exports.While = class While extends Base + constructor: (condition, options) -> + @condition = if options?.invert then condition.invert() else condition + @guard = options?.guard + + children: ['condition', 'guard', 'body'] + + isStatement: YES + + makeReturn: (res) -> + if res + super + else + @returns = not @jumps loop: yes + this + + addBody: (@body) -> + this + + jumps: -> + {expressions} = @body + return no unless expressions.length + for node in expressions + return node if node.jumps loop: yes + no + + # The main difference from a JavaScript *while* is that the CoffeeScript + # *while* can be used as a part of a larger expression -- while loops may + # return an array containing the computed result of each iteration. + compileNode: (o) -> + o.indent += TAB + set = '' + {body} = this + if body.isEmpty() + body = '' + else + if @returns + body.makeReturn rvar = o.scope.freeVariable 'results' + set = "#{@tab}#{rvar} = [];\n" + if @guard + if body.expressions.length > 1 + body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue" + else + body = Block.wrap [new If @guard, body] if @guard + body = "\n#{ body.compile o, LEVEL_TOP }\n#{@tab}" + code = set + @tab + "while (#{ @condition.compile o, LEVEL_PAREN }) {#{body}}" + if @returns + code += "\n#{@tab}return #{rvar};" + code + +#### Op + +# Simple Arithmetic and logical operations. Performs some conversion from +# CoffeeScript operations into their JavaScript equivalents. +exports.Op = class Op extends Base + constructor: (op, first, second, flip ) -> + return new In first, second if op is 'in' + if op is 'do' + return @generateDo first + if op is 'new' + return first.newInstance() if first instanceof Call and not first.do and not first.isNew + first = new Parens first if first instanceof Code and first.bound or first.do + @operator = CONVERSIONS[op] or op + @first = first + @second = second + @flip = !!flip + return this + + # The map of conversions from CoffeeScript to JavaScript symbols. + CONVERSIONS = + '==': '===' + '!=': '!==' + 'of': 'in' + + # The map of invertible operators. + INVERSIONS = + '!==': '===' + '===': '!==' + + children: ['first', 'second'] + + isSimpleNumber: NO + + isUnary: -> + not @second + + isComplex: -> + not (@isUnary() and (@operator in ['+', '-'])) or @first.isComplex() + + # Am I capable of + # [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)? + isChainable: -> + @operator in ['<', '>', '>=', '<=', '===', '!=='] + + invert: -> + if @isChainable() and @first.isChainable() + allInvertable = yes + curr = this + while curr and curr.operator + allInvertable and= (curr.operator of INVERSIONS) + curr = curr.first + return new Parens(this).invert() unless allInvertable + curr = this + while curr and curr.operator + curr.invert = !curr.invert + curr.operator = INVERSIONS[curr.operator] + curr = curr.first + this + else if op = INVERSIONS[@operator] + @operator = op + if @first.unwrap() instanceof Op + @first.invert() + this + else if @second + new Parens(this).invert() + else if @operator is '!' and (fst = @first.unwrap()) instanceof Op and + fst.operator in ['!', 'in', 'instanceof'] + fst + else + new Op '!', this + + unfoldSoak: (o) -> + @operator in ['++', '--', 'delete'] and unfoldSoak o, this, 'first' + + generateDo: (exp) -> + passedParams = [] + func = if exp instanceof Assign and (ref = exp.value.unwrap()) instanceof Code + ref + else + exp + for param in func.params or [] + if param.value + passedParams.push param.value + delete param.value + else + passedParams.push param + call = new Call exp, passedParams + call.do = yes + call + + compileNode: (o) -> + isChain = @isChainable() and @first.isChainable() + # In chains, there's no need to wrap bare obj literals in parens, + # as the chained expression is wrapped. + @first.front = @front unless isChain + if @operator is 'delete' and o.scope.check(@first.unwrapAll().value) + throw SyntaxError 'delete operand may not be argument or var' + if @operator in ['--', '++'] and @first.unwrapAll().value in STRICT_PROSCRIBED + throw SyntaxError 'prefix increment/decrement may not have eval or arguments operand' + return @compileUnary o if @isUnary() + return @compileChain o if isChain + return @compileExistence o if @operator is '?' + code = @first.compile(o, LEVEL_OP) + ' ' + @operator + ' ' + + @second.compile(o, LEVEL_OP) + if o.level <= LEVEL_OP then code else "(#{code})" + + # Mimic Python's chained comparisons when multiple comparison operators are + # used sequentially. For example: + # + # bin/coffee -e 'console.log 50 < 65 > 10' + # true + compileChain: (o) -> + [@first.second, shared] = @first.second.cache o + fst = @first.compile o, LEVEL_OP + code = "#{fst} #{if @invert then '&&' else '||'} #{ shared.compile o } #{@operator} #{ @second.compile o, LEVEL_OP }" + "(#{code})" + + compileExistence: (o) -> + if @first.isComplex() + ref = new Literal o.scope.freeVariable 'ref' + fst = new Parens new Assign ref, @first + else + fst = @first + ref = fst + new If(new Existence(fst), ref, type: 'if').addElse(@second).compile o + + # Compile a unary **Op**. + compileUnary: (o) -> + parts = [op = @operator] + if op is '!' and @first instanceof Existence + @first.negated = not @first.negated + return @first.compile o + if o.level >= LEVEL_ACCESS + return (new Parens this).compile o + plusMinus = op in ['+', '-'] + parts.push ' ' if op in ['new', 'typeof', 'delete'] or + plusMinus and @first instanceof Op and @first.operator is op + if (plusMinus && @first instanceof Op) or (op is 'new' and @first.isStatement o) + @first = new Parens @first + parts.push @first.compile o, LEVEL_OP + parts.reverse() if @flip + parts.join '' + + toString: (idt) -> + super idt, @constructor.name + ' ' + @operator + +#### In +exports.In = class In extends Base + constructor: (@object, @array) -> + + children: ['object', 'array'] + + invert: NEGATE + + compileNode: (o) -> + if @array instanceof Value and @array.isArray() + for obj in @array.base.objects when obj instanceof Splat + hasSplat = yes + break + # `compileOrTest` only if we have an array literal with no splats + return @compileOrTest o unless hasSplat + @compileLoopTest o + + compileOrTest: (o) -> + return "#{!!@negated}" if @array.base.objects.length is 0 + [sub, ref] = @object.cache o, LEVEL_OP + [cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || '] + tests = for item, i in @array.base.objects + (if i then ref else sub) + cmp + item.compile o, LEVEL_ACCESS + tests = tests.join cnj + if o.level < LEVEL_OP then tests else "(#{tests})" + + compileLoopTest: (o) -> + [sub, ref] = @object.cache o, LEVEL_LIST + code = utility('indexOf') + ".call(#{ @array.compile o, LEVEL_LIST }, #{ref}) " + + if @negated then '< 0' else '>= 0' + return code if sub is ref + code = sub + ', ' + code + if o.level < LEVEL_LIST then code else "(#{code})" + + toString: (idt) -> + super idt, @constructor.name + if @negated then '!' else '' + +#### Try + +# A classic *try/catch/finally* block. +exports.Try = class Try extends Base + constructor: (@attempt, @error, @recovery, @ensure) -> + + children: ['attempt', 'recovery', 'ensure'] + + isStatement: YES + + jumps: (o) -> @attempt.jumps(o) or @recovery?.jumps(o) + + makeReturn: (res) -> + @attempt = @attempt .makeReturn res if @attempt + @recovery = @recovery.makeReturn res if @recovery + this + + # Compilation is more or less as you would expect -- the *finally* clause + # is optional, the *catch* is not. + compileNode: (o) -> + o.indent += TAB + tryPart = @attempt.compile o, LEVEL_TOP + + catchPart = if @recovery + if @error.isObject?() + placeholder = new Literal '_error' + @recovery.unshift new Assign @error, placeholder + @error = placeholder + if @error.value in STRICT_PROSCRIBED + throw SyntaxError "catch variable may not be \"#{@error.value}\"" + o.scope.add @error.value, 'param' unless o.scope.check @error.value + " catch (#{ @error.compile o }) {\n#{ @recovery.compile o, LEVEL_TOP }\n#{@tab}}" + else unless @ensure or @recovery + ' catch (_error) {}' + + ensurePart = if @ensure then " finally {\n#{ @ensure.compile o, LEVEL_TOP }\n#{@tab}}" else '' + + """#{@tab}try { + #{tryPart} + #{@tab}}#{ catchPart or '' }#{ensurePart}""" + +#### Throw + +# Simple node to throw an exception. +exports.Throw = class Throw extends Base + constructor: (@expression) -> + + children: ['expression'] + + isStatement: YES + jumps: NO + + # A **Throw** is already a return, of sorts... + makeReturn: THIS + + compileNode: (o) -> + @tab + "throw #{ @expression.compile o };" + +#### Existence + +# Checks a variable for existence -- not *null* and not *undefined*. This is +# similar to `.nil?` in Ruby, and avoids having to consult a JavaScript truth +# table. +exports.Existence = class Existence extends Base + constructor: (@expression) -> + + children: ['expression'] + + invert: NEGATE + + compileNode: (o) -> + @expression.front = @front + code = @expression.compile o, LEVEL_OP + if IDENTIFIER.test(code) and not o.scope.check code + [cmp, cnj] = if @negated then ['===', '||'] else ['!==', '&&'] + code = "typeof #{code} #{cmp} \"undefined\" #{cnj} #{code} #{cmp} null" + else + # do not use strict equality here; it will break existing code + code = "#{code} #{if @negated then '==' else '!='} null" + if o.level <= LEVEL_COND then code else "(#{code})" + +#### Parens + +# An extra set of parentheses, specified explicitly in the source. At one time +# we tried to clean up the results by detecting and removing redundant +# parentheses, but no longer -- you can put in as many as you please. +# +# Parentheses are a good way to force any statement to become an expression. +exports.Parens = class Parens extends Base + constructor: (@body) -> + + children: ['body'] + + unwrap : -> @body + isComplex : -> @body.isComplex() + + compileNode: (o) -> + expr = @body.unwrap() + if expr instanceof Value and expr.isAtomic() + expr.front = @front + return expr.compile o + code = expr.compile o, LEVEL_PAREN + bare = o.level < LEVEL_OP and (expr instanceof Op or expr instanceof Call or + (expr instanceof For and expr.returns)) + if bare then code else "(#{code})" + +#### For + +# CoffeeScript's replacement for the *for* loop is our array and object +# comprehensions, that compile into *for* loops here. They also act as an +# expression, able to return the result of each filtered iteration. +# +# Unlike Python array comprehensions, they can be multi-line, and you can pass +# the current index of the loop as a second parameter. Unlike Ruby blocks, +# you can map and filter in a single pass. +exports.For = class For extends While + constructor: (body, source) -> + {@source, @guard, @step, @name, @index} = source + @body = Block.wrap [body] + @own = !!source.own + @object = !!source.object + [@name, @index] = [@index, @name] if @object + throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value + @range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length + @pattern = @name instanceof Value + throw SyntaxError 'indexes do not apply to range loops' if @range and @index + throw SyntaxError 'cannot pattern match over range loops' if @range and @pattern + @returns = false + + children: ['body', 'source', 'guard', 'step'] + + # Welcome to the hairiest method in all of CoffeeScript. Handles the inner + # loop, filtering, stepping, and result saving for array, object, and range + # comprehensions. Some of the generated code can be shared in common, and + # some cannot. + compileNode: (o) -> + body = Block.wrap [@body] + lastJumps = last(body.expressions)?.jumps() + @returns = no if lastJumps and lastJumps instanceof Return + source = if @range then @source.base else @source + scope = o.scope + name = @name and @name.compile o, LEVEL_LIST + index = @index and @index.compile o, LEVEL_LIST + scope.find(name) if name and not @pattern + scope.find(index) if index + rvar = scope.freeVariable 'results' if @returns + ivar = (@object and index) or scope.freeVariable 'i' + kvar = (@range and name) or index or ivar + kvarAssign = if kvar isnt ivar then "#{kvar} = " else "" + # the `_by` variable is created twice in `Range`s if we don't prevent it from being declared here + stepvar = scope.freeVariable "step" if @step and not @range + name = ivar if @pattern + varPart = '' + guardPart = '' + defPart = '' + idt1 = @tab + TAB + if @range + forPart = source.compile merge(o, {index: ivar, name, @step}) + else + svar = @source.compile o, LEVEL_LIST + if (name or @own) and not IDENTIFIER.test svar + defPart = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n" + svar = ref + if name and not @pattern + namePart = "#{name} = #{svar}[#{kvar}]" + unless @object + lvar = scope.freeVariable 'len' + forVarPart = "#{kvarAssign}#{ivar} = 0, #{lvar} = #{svar}.length" + forVarPart += ", #{stepvar} = #{@step.compile o, LEVEL_OP}" if @step + stepPart = "#{kvarAssign}#{if @step then "#{ivar} += #{stepvar}" else (if kvar isnt ivar then "++#{ivar}" else "#{ivar}++")}" + forPart = "#{forVarPart}; #{ivar} < #{lvar}; #{stepPart}" + if @returns + resultPart = "#{@tab}#{rvar} = [];\n" + returnResult = "\n#{@tab}return #{rvar};" + body.makeReturn rvar + if @guard + if body.expressions.length > 1 + body.expressions.unshift new If (new Parens @guard).invert(), new Literal "continue" + else + body = Block.wrap [new If @guard, body] if @guard + if @pattern + body.expressions.unshift new Assign @name, new Literal "#{svar}[#{kvar}]" + defPart += @pluckDirectCall o, body + varPart = "\n#{idt1}#{namePart};" if namePart + if @object + forPart = "#{kvar} in #{svar}" + guardPart = "\n#{idt1}if (!#{utility 'hasProp'}.call(#{svar}, #{kvar})) continue;" if @own + body = body.compile merge(o, indent: idt1), LEVEL_TOP + body = '\n' + body + '\n' if body + """ + #{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''} + """ + + pluckDirectCall: (o, body) -> + defs = '' + for expr, idx in body.expressions + expr = expr.unwrapAll() + continue unless expr instanceof Call + val = expr.variable.unwrapAll() + continue unless (val instanceof Code) or + (val instanceof Value and + val.base?.unwrapAll() instanceof Code and + val.properties.length is 1 and + val.properties[0].name?.value in ['call', 'apply']) + fn = val.base?.unwrapAll() or val + ref = new Literal o.scope.freeVariable 'fn' + base = new Value ref + if val.base + [val.base, base] = [base, val] + body.expressions[idx] = new Call base, expr.args + defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n' + defs + +#### Switch + +# A JavaScript *switch* statement. Converts into a returnable expression on-demand. +exports.Switch = class Switch extends Base + constructor: (@subject, @cases, @otherwise) -> + + children: ['subject', 'cases', 'otherwise'] + + isStatement: YES + + jumps: (o = {block: yes}) -> + for [conds, block] in @cases + return block if block.jumps o + @otherwise?.jumps o + + makeReturn: (res) -> + pair[1].makeReturn res for pair in @cases + @otherwise or= new Block [new Literal 'void 0'] if res + @otherwise?.makeReturn res + this + + compileNode: (o) -> + idt1 = o.indent + TAB + idt2 = o.indent = idt1 + TAB + code = @tab + "switch (#{ @subject?.compile(o, LEVEL_PAREN) or false }) {\n" + for [conditions, block], i in @cases + for cond in flatten [conditions] + cond = cond.invert() unless @subject + code += idt1 + "case #{ cond.compile o, LEVEL_PAREN }:\n" + code += body + '\n' if body = block.compile o, LEVEL_TOP + break if i is @cases.length - 1 and not @otherwise + expr = @lastNonComment block.expressions + continue if expr instanceof Return or (expr instanceof Literal and expr.jumps() and expr.value isnt 'debugger') + code += idt2 + 'break;\n' + code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length + code + @tab + '}' + +#### If + +# *If/else* statements. Acts as an expression by pushing down requested returns +# to the last line of each clause. +# +# Single-expression **Ifs** are compiled into conditional operators if possible, +# because ternaries are already proper expressions, and don't need conversion. +exports.If = class If extends Base + constructor: (condition, @body, options = {}) -> + @condition = if options.type is 'unless' then condition.invert() else condition + @elseBody = null + @isChain = false + {@soak} = options + + children: ['condition', 'body', 'elseBody'] + + bodyNode: -> @body?.unwrap() + elseBodyNode: -> @elseBody?.unwrap() + + # Rewrite a chain of **Ifs** to add a default case as the final *else*. + addElse: (elseBody) -> + if @isChain + @elseBodyNode().addElse elseBody + else + @isChain = elseBody instanceof If + @elseBody = @ensureBlock elseBody + this + + # The **If** only compiles into a statement if either of its bodies needs + # to be a statement. Otherwise a conditional operator is safe. + isStatement: (o) -> + o?.level is LEVEL_TOP or + @bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o) + + jumps: (o) -> @body.jumps(o) or @elseBody?.jumps(o) + + compileNode: (o) -> + if @isStatement o then @compileStatement o else @compileExpression o + + makeReturn: (res) -> + @elseBody or= new Block [new Literal 'void 0'] if res + @body and= new Block [@body.makeReturn res] + @elseBody and= new Block [@elseBody.makeReturn res] + this + + ensureBlock: (node) -> + if node instanceof Block then node else new Block [node] + + # Compile the `If` as a regular *if-else* statement. Flattened chains + # force inner *else* bodies into statement form. + compileStatement: (o) -> + child = del o, 'chainChild' + exeq = del o, 'isExistentialEquals' + + if exeq + return new If(@condition.invert(), @elseBodyNode(), type: 'if').compile o + + cond = @condition.compile o, LEVEL_PAREN + o.indent += TAB + body = @ensureBlock(@body) + ifPart = "if (#{cond}) {\n#{body.compile(o)}\n#{@tab}}" + ifPart = @tab + ifPart unless child + return ifPart unless @elseBody + ifPart + ' else ' + if @isChain + o.indent = @tab + o.chainChild = yes + @elseBody.unwrap().compile o, LEVEL_TOP + else + "{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}" + + # Compile the `If` as a conditional operator. + compileExpression: (o) -> + cond = @condition.compile o, LEVEL_COND + body = @bodyNode().compile o, LEVEL_LIST + alt = if @elseBodyNode() then @elseBodyNode().compile(o, LEVEL_LIST) else 'void 0' + code = "#{cond} ? #{body} : #{alt}" + if o.level >= LEVEL_COND then "(#{code})" else code + + unfoldSoak: -> + @soak and this + +# Faux-Nodes +# ---------- +# Faux-nodes are never created by the grammar, but are used during code +# generation to generate other combinations of nodes. + +#### Closure + +# A faux-node used to wrap an expressions body in a closure. +Closure = + + # Wrap the expressions body, unless it contains a pure statement, + # in which case, no dice. If the body mentions `this` or `arguments`, + # then make sure that the closure wrapper preserves the original values. + wrap: (expressions, statement, noReturn) -> + return expressions if expressions.jumps() + func = new Code [], Block.wrap [expressions] + args = [] + if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis + meth = new Literal if mentionsArgs then 'apply' else 'call' + args = [new Literal 'this'] + args.push new Literal 'arguments' if mentionsArgs + func = new Value func, [new Access meth] + func.noReturn = noReturn + call = new Call func, args + if statement then Block.wrap [call] else call + + literalArgs: (node) -> + node instanceof Literal and node.value is 'arguments' and not node.asKey + + literalThis: (node) -> + (node instanceof Literal and node.value is 'this' and not node.asKey) or + (node instanceof Code and node.bound) or + (node instanceof Call and node.isSuper) + +# Unfold a node's child if soak, then tuck the node under created `If` +unfoldSoak = (o, parent, name) -> + return unless ifn = parent[name].unfoldSoak o + parent[name] = ifn.body + ifn.body = new Value parent + ifn + +# Constants +# --------- + +UTILITIES = + + # Correctly set up a prototype chain for inheritance, including a reference + # to the superclass for `super()` calls, and copies of any static properties. + extends: -> """ + function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; } + """ + + # Create a function bound to the current value of "this". + bind: -> ''' + function(fn, me){ return function(){ return fn.apply(me, arguments); }; } + ''' + + # Discover if an item is in an array. + indexOf: -> """ + [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; } + """ + + # Shortcuts to speed up the lookup time for native functions. + hasProp: -> '{}.hasOwnProperty' + slice : -> '[].slice' + +# Levels indicate a node's position in the AST. Useful for knowing if +# parens are necessary or superfluous. +LEVEL_TOP = 1 # ...; +LEVEL_PAREN = 2 # (...) +LEVEL_LIST = 3 # [...] +LEVEL_COND = 4 # ... ? x : y +LEVEL_OP = 5 # !... +LEVEL_ACCESS = 6 # ...[0] + +# Tabs are two spaces for pretty printing. +TAB = ' ' + +IDENTIFIER_STR = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*" +IDENTIFIER = /// ^ #{IDENTIFIER_STR} $ /// +SIMPLENUM = /^[+-]?\d+$/ +METHOD_DEF = /// + ^ + (?: + (#{IDENTIFIER_STR}) + \.prototype + (?: + \.(#{IDENTIFIER_STR}) + | \[("(?:[^\\"\r\n]|\\.)*"|'(?:[^\\'\r\n]|\\.)*')\] + | \[(0x[\da-fA-F]+ | \d*\.?\d+ (?:[eE][+-]?\d+)?)\] + ) + ) + | + (#{IDENTIFIER_STR}) + $ +/// + +# Is a literal value a string? +IS_STRING = /^['"]/ + +# Utility Functions +# ----------------- + +# Helper for ensuring that utility functions are assigned at the top level. +utility = (name) -> + ref = "__#{name}" + Scope.root.assign ref, UTILITIES[name]() + ref + +multident = (code, tab) -> + code = code.replace /\n/g, '$&' + tab + code.replace /\s+$/, '' diff --git a/codeview/src/main/assets/training-set/csharp/BasicAuthenticationFixture.cs b/codeview/src/main/assets/training-set/csharp/BasicAuthenticationFixture.cs new file mode 100755 index 0000000..2838a57 --- /dev/null +++ b/codeview/src/main/assets/training-set/csharp/BasicAuthenticationFixture.cs @@ -0,0 +1,321 @@ +namespace Nancy.Authentication.Basic.Tests +{ + using System; + using System.Collections.Generic; + using System.Text; + using System.Threading; + using FakeItEasy; + using Nancy.Security; + using Nancy.Tests; + using Xunit; + using Nancy.Bootstrapper; + using Nancy.Tests.Fakes; + + public class BasicAuthenticationFixture + { + private readonly BasicAuthenticationConfiguration config; + const string ajaxRequestHeaderKey = "X-Requested-With"; + const string ajaxRequestHeaderValue = "XMLHttpRequest"; + private readonly IPipelines hooks; + + public BasicAuthenticationFixture() + { + this.config = new BasicAuthenticationConfiguration(A.Fake(), "realm", UserPromptBehaviour.Always); + this.hooks = new Pipelines(); + BasicAuthentication.Enable(this.hooks, this.config); + } + + [Fact] + public void Should_add_a_pre_and_post_hook_in_application_when_enabled() + { + // Given + var pipelines = A.Fake(); + + // When + BasicAuthentication.Enable(pipelines, this.config); + + // Then + A.CallTo(() => pipelines.BeforeRequest.AddItemToStartOfPipeline(A>.Ignored)) + .MustHaveHappened(Repeated.Exactly.Once); + A.CallTo(() => pipelines.AfterRequest.AddItemToEndOfPipeline(A>.Ignored)) + .MustHaveHappened(Repeated.Exactly.Once); + } + + [Fact] + public void Should_add_both_basic_and_requires_auth_pre_and_post_hooks_in_module_when_enabled() + { + // Given + var module = new FakeModule(); + + // When + BasicAuthentication.Enable(module, this.config); + + // Then + module.Before.PipelineDelegates.ShouldHaveCount(2); + module.After.PipelineDelegates.ShouldHaveCount(1); + } + + [Fact] + public void Should_throw_with_null_config_passed_to_enable_with_application() + { + // Given, When + var result = Record.Exception(() => BasicAuthentication.Enable(A.Fake(), null)); + + // Then + result.ShouldBeOfType(typeof(ArgumentNullException)); + } + + [Fact] + public void Should_throw_with_null_config_passed_to_enable_with_module() + { + // Given, When + var result = Record.Exception(() => BasicAuthentication.Enable(new FakeModule(), null)); + + // Then + result.ShouldBeOfType(typeof(ArgumentNullException)); + } + + [Fact] + public void Should_throw_with_null_pipeline_passed_to_enable_with_config() + { + // Given, When + var result = Record.Exception(() => BasicAuthentication.Enable((IPipelines)null, this.config)); + + // Then + result.ShouldBeOfType(typeof(ArgumentNullException)); + } + + [Fact] + public void Should_throw_with_null_module_passed_to_enable_with_config() + { + // Given, When + var result = Record.Exception(() => BasicAuthentication.Enable((INancyModule)null, this.config)); + + // Then + result.ShouldBeOfType(typeof(ArgumentNullException)); + } + + [Fact] + public void Pre_request_hook_should_not_set_auth_details_with_no_auth_headers() + { + // Given + var context = new NancyContext() + { + Request = new FakeRequest("GET", "/") + }; + + // When + var result = this.hooks.BeforeRequest.Invoke(context, new CancellationToken()); + + // Then + result.Result.ShouldBeNull(); + context.CurrentUser.ShouldBeNull(); + } + + [Fact] + public void Post_request_hook_should_return_challenge_when_unauthorized_returned_from_route() + { + // Given + var context = new NancyContext() + { + Request = new FakeRequest("GET", "/") + }; + + string wwwAuthenticate; + context.Response = new Response { StatusCode = HttpStatusCode.Unauthorized }; + + // When + this.hooks.AfterRequest.Invoke(context, new CancellationToken()); + + // Then + context.Response.Headers.TryGetValue("WWW-Authenticate", out wwwAuthenticate); + context.Response.StatusCode.ShouldEqual(HttpStatusCode.Unauthorized); + context.Response.Headers.ContainsKey("WWW-Authenticate").ShouldBeTrue(); + context.Response.Headers["WWW-Authenticate"].ShouldContain("Basic"); + context.Response.Headers["WWW-Authenticate"].ShouldContain("realm=\"" + this.config.Realm + "\""); + } + + [Fact] + public void Post_request_hook_should_not_return_a_challenge_when_set_to_never() + { + // Given + var config = new BasicAuthenticationConfiguration(A.Fake(), "realm", UserPromptBehaviour.Never); + var hooks = new Pipelines(); + BasicAuthentication.Enable(hooks, config); + + var context = new NancyContext() + { + Request = new FakeRequest("GET", "/") + }; + + context.Response = new Response { StatusCode = HttpStatusCode.Unauthorized }; + + // When + hooks.AfterRequest.Invoke(context, new CancellationToken()); + + // Then + context.Response.Headers.ContainsKey("WWW-Authenticate").ShouldBeFalse(); + } + + [Fact] + public void Post_request_hook_should_not_return_a_challenge_on_an_ajax_request_when_set_to_nonajax() + { + // Given + var config = new BasicAuthenticationConfiguration(A.Fake(), "realm", UserPromptBehaviour.NonAjax); + var hooks = new Pipelines(); + BasicAuthentication.Enable(hooks, config); + var headers = new Dictionary>(); + headers.Add(ajaxRequestHeaderKey, new [] { ajaxRequestHeaderValue }); + + var context = new NancyContext() + { + Request = new FakeRequest("GET", "/", headers) + }; + + context.Response = new Response { StatusCode = HttpStatusCode.Unauthorized }; + + // When + hooks.AfterRequest.Invoke(context, new CancellationToken()); + + // Then + context.Response.Headers.ContainsKey("WWW-Authenticate").ShouldBeFalse(); + } + + [Fact] + public void Post_request_hook_should_return_a_challenge_on_a_nonajax_request_when_set_to_nonajax() + { + // Given + var config = new BasicAuthenticationConfiguration(A.Fake(), "realm", UserPromptBehaviour.NonAjax); + var hooks = new Pipelines(); + BasicAuthentication.Enable(hooks, config); + + var context = new NancyContext() + { + Request = new FakeRequest("GET", "/") + }; + + context.Response = new Response { StatusCode = HttpStatusCode.Unauthorized }; + + // When + hooks.AfterRequest.Invoke(context, new CancellationToken()); + + // Then + context.Response.Headers.ContainsKey("WWW-Authenticate").ShouldBeTrue(); + } + + + [Fact] + public void Pre_request_hook_should_not_set_auth_details_when_invalid_scheme_in_auth_header() + { + // Given + var context = CreateContextWithHeader( + "Authorization", new[] { "FooScheme" + " " + EncodeCredentials("foo", "bar") }); + + // When + var result = this.hooks.BeforeRequest.Invoke(context, new CancellationToken()); + + // Then + result.Result.ShouldBeNull(); + context.CurrentUser.ShouldBeNull(); + } + + [Fact] + public void Pre_request_hook_should_not_authenticate_when_invalid_encoded_username_in_auth_header() + { + // Given + var context = CreateContextWithHeader( + "Authorization", new[] { "Basic" + " " + "some credentials" }); + + // When + var result = this.hooks.BeforeRequest.Invoke(context, new CancellationToken()); + + // Then + result.Result.ShouldBeNull(); + context.CurrentUser.ShouldBeNull(); + } + + [Fact] + public void Pre_request_hook_should_call_user_validator_with_username_in_auth_header() + { + // Given + var context = CreateContextWithHeader( + "Authorization", new[] { "Basic" + " " + EncodeCredentials("foo", "bar") }); + + // When + this.hooks.BeforeRequest.Invoke(context, new CancellationToken()); + + // Then + A.CallTo(() => config.UserValidator.Validate("foo", "bar")).MustHaveHappened(); + } + + [Fact] + public void Pre_request_hook_should_call_user_validator_with_password_in_auth_header_containing_colon() + { + // Given + var context = CreateContextWithHeader( + "Authorization", new[] {"Basic" + " " + EncodeCredentials("foo", "bar:baz")}); + + // When + this.hooks.BeforeRequest.Invoke(context, new CancellationToken()); + + // Then + A.CallTo(() => config.UserValidator.Validate("foo", "bar:baz")).MustHaveHappened(); + } + + [Fact] + public void Should_set_user_in_context_with_valid_username_in_auth_header() + { + // Given + var fakePipelines = new Pipelines(); + + var validator = A.Fake(); + var fakeUser = A.Fake(); + A.CallTo(() => validator.Validate("foo", "bar")).Returns(fakeUser); + + var cfg = new BasicAuthenticationConfiguration(validator, "realm"); + + var context = CreateContextWithHeader( + "Authorization", new [] { "Basic" + " " + EncodeCredentials("foo", "bar") }); + + BasicAuthentication.Enable(fakePipelines, cfg); + + // When + fakePipelines.BeforeRequest.Invoke(context, new CancellationToken()); + + // Then + context.CurrentUser.ShouldBeSameAs(fakeUser); + } + + private static NancyContext CreateContextWithHeader(string name, IEnumerable values) + { + var header = new Dictionary> + { + { name, values } + }; + + return new NancyContext() + { + Request = new FakeRequest("GET", "/", header) + }; + } + + private static string EncodeCredentials(string username, string password) + { + var credentials = string.Format("{0}:{1}", username, password); + + var encodedCredentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials)); + + return encodedCredentials; + } + + class FakeModule : NancyModule + { + public FakeModule() + { + this.After = new AfterPipeline(); + this.Before = new BeforePipeline(); + this.OnError = new ErrorPipeline(); + } + } + } +} diff --git a/codeview/src/main/assets/training-set/csharp/ChromiumWebBrowser.cs b/codeview/src/main/assets/training-set/csharp/ChromiumWebBrowser.cs new file mode 100755 index 0000000..7f02cc8 --- /dev/null +++ b/codeview/src/main/assets/training-set/csharp/ChromiumWebBrowser.cs @@ -0,0 +1,347 @@ +// Copyright © 2010-2015 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +using System; +using System.Windows.Forms; +using CefSharp.Internals; +using CefSharp.WinForms.Internals; + +namespace CefSharp.WinForms +{ + public class ChromiumWebBrowser : Control, IWebBrowserInternal, IWinFormsWebBrowser + { + private ManagedCefBrowserAdapter managedCefBrowserAdapter; + private ParentFormMessageInterceptor parentFormMessageInterceptor; + + /// + /// Set to true while handing an activating WM_ACTIVATE message. + /// MUST ONLY be cleared by DefaultFocusHandler. + /// + public bool IsActivating { get; set; } + + public BrowserSettings BrowserSettings { get; set; } + public string Title { get; set; } + public bool IsLoading { get; private set; } + public string TooltipText { get; private set; } + public string Address { get; private set; } + + public IDialogHandler DialogHandler { get; set; } + public IJsDialogHandler JsDialogHandler { get; set; } + public IKeyboardHandler KeyboardHandler { get; set; } + public IRequestHandler RequestHandler { get; set; } + public IDownloadHandler DownloadHandler { get; set; } + public ILifeSpanHandler LifeSpanHandler { get; set; } + public IPopupHandler PopupHandler { get; set; } + public IMenuHandler MenuHandler { get; set; } + + /// + /// The for this ChromiumWebBrowser. + /// + /// + /// If you need customized focus handling behavior for WinForms, the suggested + /// best practice would be to inherit from DefaultFocusHandler and try to avoid + /// needing to override the logic in OnGotFocus. The implementation in + /// DefaultFocusHandler relies on very detailed behavior of how WinForms and + /// Windows interact during window activation. + /// + public IFocusHandler FocusHandler { get; set; } + public IDragHandler DragHandler { get; set; } + public IResourceHandlerFactory ResourceHandlerFactory { get; set; } + public IGeolocationHandler GeolocationHandler { get; set; } + + public event EventHandler LoadError; + public event EventHandler FrameLoadStart; + public event EventHandler FrameLoadEnd; + public event EventHandler LoadingStateChanged; + public event EventHandler ConsoleMessage; + public event EventHandler StatusMessage; + public event EventHandler AddressChanged; + public event EventHandler TitleChanged; + public event EventHandler IsBrowserInitializedChanged; + + public bool CanGoForward { get; private set; } + public bool CanGoBack { get; private set; } + public bool CanReload { get; private set; } + public bool IsBrowserInitialized { get; private set; } + + static ChromiumWebBrowser() + { + Application.ApplicationExit += OnApplicationExit; + } + + private static void OnApplicationExit(object sender, EventArgs e) + { + Cef.Shutdown(); + } + + public ChromiumWebBrowser(string address) + { + if (!Cef.IsInitialized && !Cef.Initialize()) + { + throw new InvalidOperationException("Cef::Initialize() failed"); + } + + Cef.AddDisposable(this); + Address = address; + + Dock = DockStyle.Fill; + + FocusHandler = new DefaultFocusHandler(this); + ResourceHandlerFactory = new DefaultResourceHandlerFactory(); + BrowserSettings = new BrowserSettings(); + + managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this, false); + } + + protected override void Dispose(bool disposing) + { + // Don't utilize any of the handlers anymore: + this.SetHandlersToNull(); + + Cef.RemoveDisposable(this); + + if (disposing) + { + IsBrowserInitialized = false; + + if (BrowserSettings != null) + { + BrowserSettings.Dispose(); + BrowserSettings = null; + } + + if (parentFormMessageInterceptor != null) + { + parentFormMessageInterceptor.Dispose(); + parentFormMessageInterceptor = null; + } + + if (managedCefBrowserAdapter != null) + { + managedCefBrowserAdapter.Dispose(); + managedCefBrowserAdapter = null; + } + + // Don't maintain a reference to event listeners anylonger: + LoadError = null; + FrameLoadStart = null; + FrameLoadEnd = null; + LoadingStateChanged = null; + ConsoleMessage = null; + StatusMessage = null; + AddressChanged = null; + TitleChanged = null; + IsBrowserInitializedChanged = null; + } + base.Dispose(disposing); + } + + public void Load(String url) + { + if (IsBrowserInitialized) + { + this.GetMainFrame().LoadUrl(url); + } + else + { + Address = url; + } + } + + public void RegisterJsObject(string name, object objectToBind, bool camelCaseJavascriptNames = true) + { + if (IsBrowserInitialized) + { + throw new Exception("Browser is already initialized. RegisterJsObject must be" + + "called before the underlying CEF browser is created."); + } + managedCefBrowserAdapter.RegisterJsObject(name, objectToBind, camelCaseJavascriptNames); + } + + protected override void OnHandleCreated(EventArgs e) + { + managedCefBrowserAdapter.CreateBrowser(BrowserSettings, Handle, Address); + + base.OnHandleCreated(e); + } + + void IWebBrowserInternal.OnAfterBrowserCreated() + { + IsBrowserInitialized = true; + + // By the time this callback gets called, this control + // is most likely hooked into a browser Form of some sort. + // (Which is what ParentFormMessageInterceptor relies on.) + // Ensure the ParentFormMessageInterceptor construction occurs on the WinForms UI thread: + this.InvokeOnUiThreadIfRequired(() => + { + parentFormMessageInterceptor = new ParentFormMessageInterceptor(this); + }); + + ResizeBrowser(); + + var handler = IsBrowserInitializedChanged; + + if (handler != null) + { + handler(this, new IsBrowserInitializedChangedEventArgs(IsBrowserInitialized)); + } + } + + void IWebBrowserInternal.SetAddress(string address) + { + Address = address; + + var handler = AddressChanged; + if (handler != null) + { + handler(this, new AddressChangedEventArgs(address)); + } + } + + void IWebBrowserInternal.SetLoadingStateChange(bool canGoBack, bool canGoForward, bool isLoading) + { + CanGoBack = canGoBack; + CanGoForward = canGoForward; + CanReload = !isLoading; + IsLoading = isLoading; + + var handler = LoadingStateChanged; + if (handler != null) + { + handler(this, new LoadingStateChangedEventArgs(canGoBack, canGoForward, isLoading)); + } + } + + void IWebBrowserInternal.SetTitle(string title) + { + Title = title; + + var handler = TitleChanged; + if (handler != null) + { + handler(this, new TitleChangedEventArgs(title)); + } + } + + void IWebBrowserInternal.SetTooltipText(string tooltipText) + { + TooltipText = tooltipText; + } + + void IWebBrowserInternal.OnFrameLoadStart(FrameLoadStartEventArgs args) + { + var handler = FrameLoadStart; + if (handler != null) + { + handler(this, args); + } + } + + void IWebBrowserInternal.OnFrameLoadEnd(FrameLoadEndEventArgs args) + { + var handler = FrameLoadEnd; + if (handler != null) + { + handler(this, args); + } + } + + void IWebBrowserInternal.OnConsoleMessage(string message, string source, int line) + { + var handler = ConsoleMessage; + if (handler != null) + { + handler(this, new ConsoleMessageEventArgs(message, source, line)); + } + } + + void IWebBrowserInternal.OnStatusMessage(string value) + { + var handler = StatusMessage; + if (handler != null) + { + handler(this, new StatusMessageEventArgs(value)); + } + } + + void IWebBrowserInternal.OnLoadError(IFrame frame, CefErrorCode errorCode, string errorText, string failedUrl) + { + var handler = LoadError; + if (handler != null) + { + handler(this, new LoadErrorEventArgs(frame, errorCode, errorText, failedUrl)); + } + } + + /// + /// Manually implement Focused because cef does not implement it. + /// + /// + /// This is also how the Microsoft's WebBrowserControl implements the Focused property. + /// + public override bool Focused + { + get + { + if (base.Focused) + { + return true; + } + + if (!IsHandleCreated) + { + return false; + } + + return NativeMethodWrapper.IsFocused(Handle); + } + } + + protected override void OnSizeChanged(EventArgs e) + { + base.OnSizeChanged(e); + + ResizeBrowser(); + } + + private void ResizeBrowser() + { + if (IsBrowserInitialized) + { + managedCefBrowserAdapter.Resize(Width, Height); + } + } + + public void NotifyMoveOrResizeStarted() + { + this.ThrowExceptionIfBrowserNotInitialized(); + + managedCefBrowserAdapter.NotifyMoveOrResizeStarted(); + } + + protected override void OnGotFocus(EventArgs e) + { + SetFocus(true); + base.OnGotFocus(e); + } + + /// + /// Tell the browser to acquire/release focus. + /// + public void SetFocus(bool isFocused) + { + this.ThrowExceptionIfBrowserNotInitialized(); + + managedCefBrowserAdapter.SetFocus(isFocused); + } + + public IBrowser GetBrowser() + { + this.ThrowExceptionIfBrowserNotInitialized(); + + return managedCefBrowserAdapter.GetBrowser(); + } + } +} diff --git a/codeview/src/main/assets/training-set/csharp/MemberIdentifier.cs b/codeview/src/main/assets/training-set/csharp/MemberIdentifier.cs new file mode 100755 index 0000000..97d399b --- /dev/null +++ b/codeview/src/main/assets/training-set/csharp/MemberIdentifier.cs @@ -0,0 +1,458 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using JSIL.Ast; +using Mono.Cecil; + +namespace JSIL.Internal { + public struct MemberIdentifier { + public class Comparer : IEqualityComparer { + public readonly ITypeInfoSource TypeInfo; + + public Comparer (ITypeInfoSource typeInfo) { + TypeInfo = typeInfo; + } + + public bool Equals (MemberIdentifier x, MemberIdentifier y) { + /* + if (x == null) + return x == y; + */ + + return x.Equals(y, TypeInfo); + } + + public int GetHashCode (MemberIdentifier obj) { + return obj.GetHashCode(); + } + } + + public enum MemberType : byte { + Field = 0, + Method = 1, + Property = 2, + Event = 3, + } + + public readonly bool IsStatic; + public readonly MemberType Type; + public readonly string Name; + public readonly TypeReference ReturnType; + public readonly TypeReference[] ParameterTypes; + public readonly int GenericArgumentCount; + + private readonly int HashCode; + + public static readonly TypeReference[] AnyParameterTypes = { }; + + public static MemberIdentifier New (ITypeInfoSource ti, MemberReference mr) { + MethodReference method; + PropertyReference property; + EventReference evt; + FieldReference field; + + if ((method = mr as MethodReference) != null) + return new MemberIdentifier(ti, method); + else if ((field = mr as FieldReference) != null) + return new MemberIdentifier(ti, field); + else if ((property = mr as PropertyReference) != null) + return new MemberIdentifier(ti, property); + else if ((evt = mr as EventReference) != null) + return new MemberIdentifier(ti, evt); + else + throw new NotImplementedException(String.Format( + "Unsupported member reference type: {0}", + mr + )); + } + + private MemberIdentifier ( + bool isStatic, + MemberType type, + string name, + TypeReference returnType, + TypeReference[] parameterTypes, + int genericArgumentCount + ) { + IsStatic = isStatic; + Type = type; + Name = name; + ReturnType = returnType; + ParameterTypes = parameterTypes; + GenericArgumentCount = genericArgumentCount; + + HashCode = Type.GetHashCode() ^ Name.GetHashCode(); + } + + public MemberIdentifier (ITypeInfoSource ti, MethodReference mr, string newName = null) { + IsStatic = !mr.HasThis; + Type = MemberType.Method; + Name = newName ?? mr.Name; + ReturnType = mr.ReturnType; + ParameterTypes = GetParameterTypes(mr.Parameters); + + if (mr is GenericInstanceMethod) + GenericArgumentCount = ((GenericInstanceMethod)mr).GenericArguments.Count; + else if (mr.HasGenericParameters) + GenericArgumentCount = mr.GenericParameters.Count; + else + GenericArgumentCount = 0; + + ti.CacheProxyNames(mr); + + HashCode = Type.GetHashCode() ^ Name.GetHashCode(); + } + + public MemberIdentifier (ITypeInfoSource ti, PropertyReference pr) { + Type = MemberType.Property; + Name = pr.Name; + ReturnType = pr.PropertyType; + GenericArgumentCount = 0; + ParameterTypes = null; + ti.CacheProxyNames(pr); + + var pd = pr.Resolve(); + if (pd != null) { + IsStatic = !pd.HasThis; + if (pd.GetMethod != null) { + ParameterTypes = GetParameterTypes(pd.GetMethod.Parameters); + } else if (pd.SetMethod != null) { + ParameterTypes = GetParameterTypes(pd.SetMethod.Parameters) + .Take(pd.SetMethod.Parameters.Count - 1).ToArray(); + } + } else { + // FIXME + IsStatic = false; + } + + HashCode = Type.GetHashCode() ^ Name.GetHashCode(); + } + + public MemberIdentifier (ITypeInfoSource ti, FieldReference fr) { + Type = MemberType.Field; + Name = fr.Name; + ReturnType = fr.FieldType; + GenericArgumentCount = 0; + ParameterTypes = null; + ti.CacheProxyNames(fr); + + var resolved = fr.Resolve(); + if (resolved != null) { + IsStatic = resolved.IsStatic; + } else { + // FIXME + IsStatic = false; + } + + HashCode = Type.GetHashCode() ^ Name.GetHashCode(); + } + + public MemberIdentifier (ITypeInfoSource ti, EventReference er) { + Type = MemberType.Event; + Name = er.Name; + ReturnType = er.EventType; + GenericArgumentCount = 0; + ParameterTypes = null; + ti.CacheProxyNames(er); + + var ed = er.Resolve(); + if (ed != null) { + if (ed.AddMethod != null) { + IsStatic = ed.AddMethod.IsStatic; + } else if (ed.RemoveMethod != null) { + IsStatic = ed.RemoveMethod.IsStatic; + } else { + // FIXME + IsStatic = false; + } + } else { + // FIXME + IsStatic = false; + } + + HashCode = Type.GetHashCode() ^ Name.GetHashCode(); + } + + static TypeReference[] GetParameterTypes (IList parameters) { + if (parameters.Count == 0) + return null; + + if (parameters.Count == 1) { + var p = parameters[0]; + for (int c = p.CustomAttributes.Count, i = 0; i < c; i++) { + var ca = p.CustomAttributes[i]; + if ((ca.AttributeType.Name == "ParamArrayAttribute") && (ca.AttributeType.Namespace == "System")) { + var t = JSExpression.DeReferenceType(parameters[0].ParameterType); + var at = t as ArrayType; + if ((at != null) && IsAnyType(at.ElementType)) + return AnyParameterTypes; + } + } + } + + { + int c = parameters.Count; + var result = new TypeReference[c]; + for (int i = 0; i < c; i++) { + TypeReference parameterType = parameters[i].ParameterType, expandedParameterType; + + if (TypeUtil.ExpandPositionalGenericParameters(parameterType, out expandedParameterType)) + result[i] = expandedParameterType; + else + result[i] = parameterType; + } + + return result; + } + } + + public static bool IsAnyType (TypeReference t) { + if (t == null) + return false; + + return (t.Name == "AnyType" && t.Namespace == "JSIL.Proxy"); + } + + public static bool TypesAreEqual (ITypeInfoSource typeInfo, TypeReference lhs, TypeReference rhs) { + bool shallowMatch; + + if (lhs == rhs) + return true; + else if (lhs == null || rhs == null) + return false; + else if (TypeUtil.TypesAreTriviallyEqual(lhs, rhs, out shallowMatch)) + return true; + + var lhsReference = lhs as ByReferenceType; + var rhsReference = rhs as ByReferenceType; + + if ((lhsReference != null) || (rhsReference != null)) { + if ((lhsReference == null) || (rhsReference == null)) + return false; + + return TypesAreEqual(typeInfo, lhsReference.ElementType, rhsReference.ElementType); + } + + var lhsArray = lhs as ArrayType; + var rhsArray = rhs as ArrayType; + + if ((lhsArray != null) || (rhsArray != null)) { + if ((lhsArray == null) || (rhsArray == null)) + return false; + + return TypesAreEqual(typeInfo, lhsArray.ElementType, rhsArray.ElementType); + } + + var lhsGit = lhs as GenericInstanceType; + var rhsGit = rhs as GenericInstanceType; + + if ((lhsGit != null) && (rhsGit != null)) { + if (lhsGit.GenericArguments.Count != rhsGit.GenericArguments.Count) + return false; + + if (!TypesAreEqual(typeInfo, lhsGit.ElementType, rhsGit.ElementType)) + return false; + + using (var eLeft = lhsGit.GenericArguments.GetEnumerator()) + using (var eRight = rhsGit.GenericArguments.GetEnumerator()) + while (eLeft.MoveNext() && eRight.MoveNext()) { + if (!TypesAreEqual(typeInfo, eLeft.Current, eRight.Current)) + return false; + } + + return true; + } + + ArraySegment proxyTargets; + if ( + typeInfo.TryGetProxyNames(lhs, out proxyTargets) && + (proxyTargets.Array != null) && + proxyTargets.ToEnumerable().Contains(rhs.FullName) + ) { + return true; + } else if ( + typeInfo.TryGetProxyNames(rhs, out proxyTargets) && + (proxyTargets.Array != null) && + proxyTargets.ToEnumerable().Contains(lhs.FullName) + ) { + return true; + } + + if (IsAnyType(lhs) || IsAnyType(rhs)) + return true; + + return TypeUtil.TypesAreEqual(lhs, rhs); + } + + public bool Equals (MemberIdentifier rhs, ITypeInfoSource typeInfo) { + /* + if (this == rhs) + return true; + */ + + if (IsStatic != rhs.IsStatic) + return false; + + if (Type != rhs.Type) + return false; + + if (GenericArgumentCount != rhs.GenericArgumentCount) + return false; + + if (!String.Equals(Name, rhs.Name)) + return false; + + if (!TypesAreEqual(typeInfo, ReturnType, rhs.ReturnType)) + return false; + + if ((ParameterTypes == AnyParameterTypes) || (rhs.ParameterTypes == AnyParameterTypes)) { + } else if ((ParameterTypes == null) || (rhs.ParameterTypes == null)) { + if (ParameterTypes != rhs.ParameterTypes) + return false; + } else { + if (ParameterTypes.Length != rhs.ParameterTypes.Length) + return false; + + for (int i = 0, c = ParameterTypes.Length; i < c; i++) { + if (!TypesAreEqual(typeInfo, ParameterTypes[i], rhs.ParameterTypes[i])) + return false; + } + } + + return true; + } + + public MemberIdentifier Getter { + get { + if (Type != MemberType.Property) + throw new InvalidOperationException(); + + return new MemberIdentifier( + IsStatic, MemberType.Method, + "get_" + Name, + ReturnType, ParameterTypes, + 0 + ); + } + } + + public MemberIdentifier Setter { + get { + if (Type != MemberType.Property) + throw new InvalidOperationException(); + + TypeReference[] parameterTypes; + if (ParameterTypes == null) + parameterTypes = new [] { ReturnType }; + else + parameterTypes = ParameterTypes.Concat(new [] { ReturnType }).ToArray(); + + return new MemberIdentifier( + IsStatic, MemberType.Method, + "set_" + Name, + null, parameterTypes, + 0 + ); + } + } + + public override bool Equals (object obj) { + throw new InvalidOperationException("Use MemberIdentifier.Equals(...) explicitly."); + } + + public override int GetHashCode () { + return HashCode; + } + + public string ToString (string name) { + if (GenericArgumentCount != 0) + name = String.Format("{0}`{1}", name, GenericArgumentCount); + + if (ParameterTypes != null) + return String.Format( + "{0} {1} ( {2} )", ReturnType, name, + String.Join(", ", (from p in ParameterTypes select p.ToString()).ToArray()) + ); + else + return String.Format( + "{0} {1}", ReturnType, name + ); + } + + public override string ToString () { + return ToString(Name); + } + } + + public struct QualifiedMemberIdentifier { + public class Comparer : IEqualityComparer { + public readonly ITypeInfoSource TypeInfo; + + public Comparer (ITypeInfoSource typeInfo) { + TypeInfo = typeInfo; + } + + public bool Equals (QualifiedMemberIdentifier x, QualifiedMemberIdentifier y) { + /* + if (x == null) + return x == y; + */ + + return x.Equals(y, TypeInfo); + } + + public int GetHashCode (QualifiedMemberIdentifier obj) { + return obj.GetHashCode(); + } + } + + public readonly TypeIdentifier Type; + public readonly MemberIdentifier Member; + + public QualifiedMemberIdentifier (TypeIdentifier type, MemberIdentifier member) { + Type = type; + Member = member; + } + + public override int GetHashCode () { + return Type.GetHashCode() ^ Member.GetHashCode(); + } + + public bool Equals (MemberReference lhs, MemberReference rhs, ITypeInfoSource typeInfo) { + if ((lhs == null) || (rhs == null)) + return lhs == rhs; + + if (lhs == rhs) + return true; + + var declaringType = rhs.DeclaringType.Resolve(); + if (declaringType == null) + return false; + + var rhsType = new TypeIdentifier(declaringType); + + if (!Type.Equals(rhsType)) + return false; + + var rhsMember = MemberIdentifier.New(typeInfo, rhs); + + return Member.Equals(rhsMember, typeInfo); + } + + public bool Equals (QualifiedMemberIdentifier rhs, ITypeInfoSource typeInfo) { + if (!Type.Equals(rhs.Type)) + return false; + + return Member.Equals(rhs.Member, typeInfo); + } + + public override bool Equals (object obj) { + throw new InvalidOperationException("Use QualifiedMemberIdentifier.Equals(...) explicitly."); + } + + public override string ToString () { + return String.Format("{0} {1}", Type, Member); + } + } +} diff --git a/codeview/src/main/assets/training-set/csharp/csharp.cs b/codeview/src/main/assets/training-set/csharp/csharp.cs new file mode 100755 index 0000000..84ee06c --- /dev/null +++ b/codeview/src/main/assets/training-set/csharp/csharp.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using CodeClassifier.StringTokenizer; + +namespace CodeClassifier +{ + public class CodeClassifier + { + private static CodeClassifier _instance; + + private const double SCORE_MULTIPLIER_PER_LEVEL = 2; + private const double SCORE_MULTIPLIER_FOR_EXACT_MATCH = 5; + + private static List _matchTrees; + + private CodeClassifier() + { + string trainingSetPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + if (trainingSetPath == null) + { + throw new DirectoryNotFoundException("Could not find the training-set folder."); + } + + // Train classifier + string path = Path.Combine(trainingSetPath, "training-set"); + string[] folders = Directory.GetDirectories(path); + foreach (string folder in folders) + { + string[] files = Directory.GetFiles(folder); + _matchTrees = new List(); + foreach (string filePath in files) + { + string languageName = Path.GetFileNameWithoutExtension(filePath); + if (languageName != null) + { + // Calculate the total possible score to normalize the score results + double totalPossibleScore; + TokenNode rootNode = BuildMatchTree(File.ReadAllText(filePath), out totalPossibleScore); + _matchTrees.Add(new MatchTree(rootNode, languageName, totalPossibleScore)); + } + } + } + } + + private static TokenNode BuildMatchTree(string trainingCode, out double totalScorePossible) + { + List tokens = GetAllTokens(trainingCode); + + // Recursivly build the tree + TokenNode root = new TokenNode(TokenKind.Unknown, 0, 1, null); + double totalScore = 0; + for (int index = 0; index < tokens.Count-1; index++) + { + totalScore += AddTokens(root, tokens, index); + } + + totalScorePossible = totalScore; + return root; + } + + private static double AddTokens(TokenNode tokenNode, IList tokens, int index) + { + double totalScore = 0; + while (index < tokens.Count && tokenNode.Level < 10) + { + Token codeToken = tokens[index]; + TokenNode nextTreeToken = tokenNode.NextTokens.FirstOrDefault(nt => nt.Kind == codeToken.Kind); + if (nextTreeToken == null) + { + // Token doesn't exist on this tree level yet + var newToken = new TokenNode(codeToken.Kind, tokenNode.Level + 1, tokenNode.Score * SCORE_MULTIPLIER_PER_LEVEL, codeToken.Value); + totalScore += tokenNode.Score * SCORE_MULTIPLIER_PER_LEVEL; + tokenNode.NextTokens.Add(newToken); + tokenNode = newToken; + } + else + { + // Token already exists on this level + nextTreeToken.Examples.Add(codeToken.Value); + tokenNode = nextTreeToken; + } + index++; + } + return totalScore; + } + + private static List GetAllTokens(string code) + { + StringTokenizer.StringTokenizer stringTokenizer = new StringTokenizer.StringTokenizer(code); + + List tokens = new List(); + Token token; + do + { + token = stringTokenizer.Next(); + tokens.Add(token); + } while (token.Kind != TokenKind.Eof); + return tokens; + } + + public static string Classify(string snippet ) + { + // ReSharper disable once RedundantAssignment + Dictionary scores; + return Classify(snippet, out scores); + } + + public static string Classify(string snippet, out Dictionary scores ) + { + if (_instance == null) + { + _instance = new CodeClassifier(); + } + + scores = new Dictionary(); + + List tokens = GetAllTokens(snippet); + double maxScore = 0; + string bestMatchLanguage = null; + + foreach (MatchTree matchTree in _matchTrees) + { + double score = 0; + for (int index = 0; index < tokens.Count; index++) + { + score += ScoreTokens(matchTree.MatchTreeRoot, tokens, index); + } + score = score / tokens.Count() / matchTree.TotalPossibleScore; + + //Console.WriteLine(matchTree.Language + "\t" + score); + scores.Add(matchTree.Language, score); + if (score > maxScore) + { + maxScore = score; + bestMatchLanguage = matchTree.Language; + } + } + return bestMatchLanguage; + } + + private static double ScoreTokens(TokenNode tokenNode, IList tokens, int index) + { + Token codeToken = tokens[index]; + TokenNode nextToken = tokenNode.NextTokens.FirstOrDefault(nt => nt.Kind == codeToken.Kind); + if (nextToken != null) + { + // Token exists in match tree => points !!! + double score = nextToken.Examples.Contains(codeToken.Value) ? + SCORE_MULTIPLIER_FOR_EXACT_MATCH: + SCORE_MULTIPLIER_PER_LEVEL; + + if (index < tokens.Count() - 1) + { + return score * ScoreTokens(nextToken, tokens, index + 1); + } + return score; + } + // Token did not exist => no points + return 1; + } + } +} \ No newline at end of file diff --git a/codeview/src/main/assets/training-set/css/css.css b/codeview/src/main/assets/training-set/css/css.css new file mode 100755 index 0000000..939b5f4 --- /dev/null +++ b/codeview/src/main/assets/training-set/css/css.css @@ -0,0 +1,151 @@ + +html { + margin: 0; + padding: 0; + border: 0; + -moz-transition: all; + -o-transition: all; + -webkit-transition: all; + transition: all; +} + +.hidden { + display: none !important; + visibility: hidden !important; +} + +body { + stroke: #eee; + stroke-width: 2; + stroke-dasharray: 0; +} + +a { + text-align: center; + font-size: 1.1rem; + padding: 12px 0; +} + +li { + -webkit-touch-callout: none; + -moz-user-select: none; + -ms-user-select: none; + -webkit-user-select: none; + user-select: none; +} + +/* points of interest */ +ul > li { + stroke: steelblue; + stroke-width: 2; + fill: #FFF; + -moz-transform-origin: center; + -ms-transform-origin: center; + -o-transform-origin: center; + -webkit-transform-origin: center; + transform-origin: center; +} + +a + div { + background-size: cover; +} + + + +div { + background: #fff; +} + +.n2-charts-close { + font-size: 32px; + position: absolute; + top: 20px; + right: 20px; + padding: 2px 12px; + cursor: pointer; +} + +/* Landscape styles */ +@media screen and (orientation:landscape) { + + .chart.fullscreen { + font-size: 32px; + position: absolute; + top: 20px; + right: 20px; + padding: 2px 12px; + cursor: pointer; + } +} + +@-moz-keyframes n2-poi-blink { + 0% { + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + } + + 100% { + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@-ms-keyframes n2-poi-blink { + 0% { + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + } + + 100% { + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@-webkit-keyframes n2-poi-blink { + 0% { + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + } + + 100% { + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes n2-poi-blink { + 0% { + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + } + + 100% { + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + } +} diff --git a/codeview/src/main/assets/training-set/css/new 6.txt b/codeview/src/main/assets/training-set/css/new 6.txt new file mode 100755 index 0000000..4e6f015 --- /dev/null +++ b/codeview/src/main/assets/training-set/css/new 6.txt @@ -0,0 +1 @@ +@font-face{font-family:html5test;src:url(/fonts/html5test.eot);src:url(/fonts/html5test.eot?#iefix) format('embedded-opentype'),url(/fonts/html5test.woff) format('woff'),url(/fonts/html5test.ttf) format('truetype'),url(/fonts/html5test.svg#html5test) format('svg');font-weight:400;font-style:normal}@font-face{font-family:'League Gothic';src:url(/fonts/leaguegothic-regular-webfont.eot);src:url(/fonts/leaguegothic-regular-webfont.eot?#iefix) format('embedded-opentype'),url(/fonts/leaguegothic-regular-webfont.woff) format('woff'),url(/fonts/leaguegothic-regular-webfont.ttf) format('truetype'),url(/fonts/leaguegothic-regular-webfont.svg#league_gothicregular) format('svg');font-weight:400;font-style:normal}*{padding:0;margin:0;-webkit-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}html{font-family:HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-weight:200;font-size:1.1em;overflow-x:hidden}body{background:#d9d9d9}h2{font-family:'League Gothic',Impact;font-weight:400;font-size:3.8em;line-height:100%;text-transform:uppercase;color:#0092bf}h3{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:1.05em}b,h4,strong,th{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif}button{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:.75em}input,textarea{font-family:HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif}button,input,textarea{-webkit-appearance:none;border-radius:0;box-sizing:border-box}img{border:0}table{border-collapse:collapse;width:100%}tbody tr:hover>td,tbody tr:hover>th{background-color:#f6f6f6}body>div#contentwrapper{-webkit-transition:-webkit-transform .4s,-webkit-filter 1.2s,opacity 1.2s;transition:transform .4s,filter 1.2s,opacity 1.2s;background:#d9d9d9}body.indexVisible>div#contentwrapper{opacity:.7;-webkit-transform:translateX(240px);transform:translateX(240px);-webkit-filter:brightness(75%) saturate(0%);filter:brightness(65%) saturate(15%)}@media (max-width:680px){body>div#contentwrapper{margin:auto}}.header{background:#eee}.header h1{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-weight:700;font-size:.9em;text-align:left;text-transform:uppercase;color:#666;padding:8px 40px;margin:0 auto;max-width:900px}.header h1 span{margin-right:10px}.header h1 em,.header h1 span{zoom:1;display:inline-block;*display:inline}.header h1 strong{font-family:html5test;font-weight:400;font-size:1.8em;color:#ec6534;-webkit-font-smoothing:antialiased;position:relative;top:7px}.header h1 em{font-style:normal;text-transform:lowercase;font-size:1.15em;color:#bbb}.header div{margin:10px auto 0;overflow:hidden;max-width:900px;padding:0 40px}.header ul{list-style-type:none;margin-bottom:8px}.header ul.left{float:left}.header ul.right{float:right}.header ul li{display:block;float:left;margin:0 3px 0 0;padding:0 10px;line-height:32px;color:#fff;font-size:.9em;text-transform:lowercase;background:#aaa}.header ul li.selected{background:#0092bf}.header ul li:hover{box-shadow:inset 0 32px 0 rgba(0,0,0,.05)}.header ul li a{color:#fff;text-decoration:none}@media (max-width:680px){.header h1{width:400px;padding-left:0;padding-right:0;text-align:center}.header h1 em{font-size:1em}.header div{width:auto}.header ul{padding:0!important;margin:0 0 12px!important;width:50%}.header ul li{line-height:30px;margin-bottom:3px;clear:left}.header ul.right{padding-left:10px}.header ul.left li{float:right;clear:right;margin-right:6px}.header ul.right li{margin-left:6px}}@media (max-width:432px){.header h1{width:auto;padding-left:16px;padding-right:16px}.header h1 em{font-size:.9em}.header ul{font-size:.85em}.header ul.left{padding-left:16px}.header ul li{padding:0 8px;line-height:28px}}body>div#index{display:block;position:fixed;top:0;left:0}body>div#index div#indexmenu{display:block;position:fixed;top:0;left:-240px;width:220px;height:100%;margin:-10px 0 0 0;padding:20px 10px 10px;background-color:#0092bf;color:#FFF;z-index:1;-webkit-overflow-scrolling:touch;overflow-y:auto;-webkit-transition:-webkit-transform .4s;transition:transform .4s}body.indexVisible>div#index div#indexmenu{-webkit-transform:translateX(240px);transform:translateX(240px)}body>div#index div#indexmenu li{display:block;float:none;background-color:#0092bf;font-size:14px;font-weight:700;margin-left:10px;line-height:150%;text-transform:lowercase}body>div#index div#indexmenu li a{text-decoration:none}body>div#index div#indexmenu li a::before{font-family:html5test;font-weight:400;font-size:1.2em;padding-right:4px;vertical-align:middle;-webkit-font-smoothing:antialiased}body>div#index div#indexmenu li.category{margin-top:10px}body>div#index div#indexmenu li.category.semantics a:before{content:''}body>div#index div#indexmenu li.category.offlinestorage a:before{content:''}body>div#index div#indexmenu li.category.deviceaccess a:before{content:''}body>div#index div#indexmenu li.category.connectivity a:before{content:''}body>div#index div#indexmenu li.category.multimedia a:before{content:''}body>div#index div#indexmenu li.category.graphicseffects a:before{content:''}body>div#index div#indexmenu li.category.performanceintegration a:before{content:''}body>div#index div#indexmenu li a{display:block;color:#FFF}body>div#index div#indexmenu li ul li{background-color:#0092bf;line-height:160%;font-size:12px;font-weight:400;margin-left:20px;text-transform:none}body>div#index div#indexmenu li ul li:first-child{margin-top:5px}body>div#index div#indexmenu li ul li a{display:block;color:#FFF}body>div#index div#indexmenu li ul li a::before{content:''!important}body>div#index button#indexbutton{position:fixed;top:10px;left:0;width:36px;height:40px;font-family:html5test;font-size:1.4em;color:#999;background-color:transparent;border:0;outline:0;z-index:100000;cursor:pointer;-webkit-transition:-webkit-transform .4s,color .5s,text-indent .5s;transition:transform .4s,color .5s,text-indent .5s}body.indexVisible>div#index button#indexbutton{-webkit-transform:translateX(240px);transform:translateX(240px);color:#eee}@media (max-width:1010px){body>div#index button#indexbutton{text-indent:-28px}}@media (max-width:680px){body>div#index button#indexbutton{text-indent:0}}@media (max-width:488px){body>div#index button#indexbutton{text-indent:-28px}}.footer{background:#eee;margin-top:30px;padding:20px;overflow:hidden;min-height:43px}.footer>div{position:relative;padding-right:300px}.footer>div .copyright{font-size:.75em;color:#777}.footer>div .copyright a{color:#888}.footer>div .copyright p{margin-bottom:.8em}#cloudvps a{position:absolute;top:0;right:0;border-left:1px solid #ccc;display:block;background:url(/images/sponsors/cloudvps.png) no-repeat 10px top;background-size:59px 43px;padding-top:0;padding-left:80px;text-decoration:none;color:#04446d;font-size:90%;min-height:43px}#cloudvps a b{font-size:110%}@media only screen and (-webkit-min-device-pixel-ratio:2){#cloudvps a{background-image:url(/images/sponsors/cloudvps@2x.png);background-size:59px 43px}}@media (max-width:680px){.footer>div{padding-right:0;padding-bottom:60px}#cloudvps a{top:auto;left:0;border-left:0;border-top:1px solid #ccc;padding-top:12px;padding-left:70px;background-position:left 12px}}.page{margin:2.5em auto 0;max-width:900px;padding:0 40px}.page>.column{position:relative;zoom:1;display:inline-block;*display:inline;vertical-align:top}.page>.column .left,.page>.column .right{width:50%;zoom:1;display:inline-block;*display:inline;vertical-align:top;box-sizing:border-box;-moz-box-sizing:border-box}.page>.column .left>div{padding-right:10px}.page>.column .right>div{padding-left:10px}@media (max-width:680px){.page{width:100%;text-align:center;padding:0}.page>.column{width:auto;max-width:400px;overflow:hidden;text-align:left}.page>.column .left,.page>.column .right{width:100%}.page>.column .left>div,.page>.column .right>div{padding:0}}@media (max-width:432px){.page>.column{width:90%!important}}.message{background:#f6f6f6;color:#000;font-size:.75em;line-height:165%;margin:0;padding:10px}.paper{position:relative;background:#fff;color:#000;font-size:.75em;line-height:165%;margin-bottom:60px}.paper.hasNavigation{top:32px;margin-bottom:52px}.paper>ul.navigation{position:absolute;top:-32px;margin:0;overflow:hidden;list-style-type:none;width:100%}.paper>ul.navigation li{display:block;float:left;margin:0 3px 0 0;padding:0 10px;line-height:32px;color:#fff;font-size:1.1em;text-transform:lowercase;background:#aaa}.paper>ul.navigation li.more{float:right;margin:0 0 0 3px}.paper>ul.navigation li.selected{background:#fff}.paper>ul.navigation li a{color:#fff;text-decoration:none}.paper>ul.navigation li.selected a{color:#000}.paper>div{padding:20px}.paper>div h2{clear:both;margin-bottom:10px}.paper>div h3{margin:1em 0 .5em}.paper>div p{margin:0 0 .5em}.paper>div p+h3{margin-top:1.5em}.paper>div hr{clear:both;margin:20px -20px;border:0;border-top:8px solid #d9d9d9}.paper>div .text{-moz-column-count:3;-moz-column-gap:16px;-webkit-column-count:3;-webkit-column-gap:16px;column-count:3;column-gap:16px}.paper>div .text.no-columns{-webkit-column-count:1!important;-moz-column-count:1!important;column-count:1!important}.break-2,.break-3{-webkit-column-break-before:always;break-before:always}@media (max-width:767px){.paper>div .text{-webkit-column-count:2;-moz-column-count:2;column-count:2}.break-3{margin-top:1.5em!important;-webkit-column-break-before:auto;break-before:auto}}@media (max-width:680px){.paper>div .text{-webkit-column-count:1;-moz-column-count:1;column-count:1}.break-2{margin-top:1.5em!important;-webkit-column-break-before:auto;break-before:auto}.paper ul.navigation li span{display:none}}.paper>div .text a{color:#0092bf;text-decoration:none}.paper>div .text a:hover{color:#0092bf;text-decoration:underline}.paper>div .text a.button{color:inherit}.paper>div .text a.button:hover{text-decoration:inherit}.intro{font-size:1.05em;line-height:150%;font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-weight:700;color:#555}.paper>div .text dl dt{margin:1em 0 0}.paper>div .text dl dd{font-size:.9em}.break{-webkit-column-break-before:always;break-before:always}.text table{margin:1em 0}.text table td,.text table th{font-weight:200;text-align:left;border-top:1px solid #ddd;padding:4px 0;vertical-align:top;font-size:1em;padding-left:10px;padding-right:10px}.text table thead th{text-align:left;padding-left:10px;padding-bottom:10px;border-top:0;font-weight:700;position:relative}.text table thead th::after{display:block;position:absolute;content:'';width:0;height:10px;border-right:1px solid #ddd;left:0;bottom:0}.text table thead th:last-child::before{display:block;position:absolute;content:'';width:10px;height:10px;border-right:1px solid #ddd;right:0;bottom:0}.text ul{list-style-type:square;padding:0 0 0 20px}.popupPanel{position:absolute;background:#fff;z-index:1;border:4px solid #aaa}.popupPanel.pointsLeft::before,.popupPanel.pointsRight::before{content:'';display:block;position:absolute;width:0;height:0;top:-13px;left:7px;z-index:10;border-bottom:11px solid #aaa;border-right:11px solid transparent;border-left:11px solid transparent}.popupPanel.pointsLeft::after,.popupPanel.pointsRight::after{content:'';display:block;position:absolute;width:0;height:0;top:-7px;left:10px;z-index:11;border-bottom:8px solid #fff;border-right:8px solid transparent;border-left:8px solid transparent}.popupPanel.pointsRight::before{left:auto;right:7px}.popupPanel.pointsRight::after{left:auto;right:10px}.search{position:relative;width:100%;height:40px;line-height:40px;background:#eee}.filters .search{width:200px}.search input{position:absolute;top:0;left:0;right:0;height:40px;padding-left:40px;width:100%;font-family:HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:1em;border:0;background:0 0}.search:after{content:'';display:block;position:absolute;top:0;left:0;width:40px;height:40px;font-family:html5test;text-align:center;font-size:1.2em;color:#666;-webkit-font-smoothing:antialiased}.search button{position:absolute;top:4px;right:4px;height:32px;width:32px;font-size:1.2em;color:#bbb;background:0 0;border:0;cursor:pointer}#searchResults{width:100%}#searchBusy #loading{min-height:inherit;height:0;overflow:hidden;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}#searchBusy.visible #loading{height:300px}#searchBusy #loading div{font-size:22px!important}.toggle{display:block;cursor:pointer;position:relative;width:200px;height:40px;line-height:40px;text-align:center;background:#eee}.toggle .part{position:absolute;top:0;left:0;bottom:0;width:100px;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.toggle .first{color:#fff}.toggle.selected .first{color:inherit}.toggle .second{left:100px}.toggle.selected .second{color:#fff}.toggle .background{position:absolute;top:0;left:0;bottom:0;width:100px;background:#0092bf;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.toggle.selected .background{left:100px}.button{display:block;box-sizing:border-box;-moz-box-sizing:border-box;width:100%;border:0;padding:10px 0;margin:0;cursor:pointer;vertical-align:top;font-family:HelveticaNeue-Light,"Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:1em;text-decoration:none;text-align:left}.button:hover{box-shadow:inset 0 50px 0 rgba(0,0,0,.05)}.button>span{margin:0 2px 0 10px;vertical-align:middle;white-space:nowrap}.button>span::before{font-family:html5test;font-weight:400;font-size:1.4em;margin-right:6px;vertical-align:top;-webkit-font-smoothing:antialiased}.button.website{background:#444;color:#fff}.button.website>span::before{content:''}.button.followme{background:#0092bf;color:#fff}.button.followme>span::before{content:''}.button.donate{background:#ffd500;color:#000}.button.donate>span::before{content:''}.button.developed{background:#ccc;color:#000}.button.developed>span::before{content:''}.button.compare{background:#33af33;color:#fff}.button.compare>span::before{content:'⚏'}.button.save{background:#0092bf;color:#fff}.button.save>span::before{content:'☁'}.button.latest{background:#0092bf;color:#fff}.button.latest>span::before{content:''}.button.share{background:#ec6534;color:#fff}.button.share>span::before{content:''}.button.contact{background:#ec6534;color:#fff}.button.contact>span::before{content:'☎'}.button.schedule{background:#ec6534;color:#fff}.button.schedule>span::before{content:''}.button.labs{background:#33af33;color:#fff}.button.labs>span::before{content:'☟'}.button.info{background:#33af33;color:#fff}.button.info>span::before{content:''}.detailsTable .ballot,.detailsTable .buggy,.detailsTable .check,.detailsTable .partial,.detailsTable .unknown{position:relative;display:inline-block;top:-1px;color:#888;font-size:1.2em;margin:0 0 0 6px;width:1em;text-align:center;vertical-align:middle}.detailsTable .check{font-family:html5test;font-weight:400;color:#1c8c1d}.detailsTable .ballot{font-family:html5test;font-weight:400;color:#853333}.detailsTable .buggy{font-family:html5test;font-weight:400;color:#ec6534}.detailsTable .partial{font-family:html5test;font-weight:400}.detailsTable .partially{color:#888}@keyframes loader{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}@-webkit-keyframes loader{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}#loading{min-height:500px;position:relative}#loading div{display:block;position:absolute;top:100px;left:50%;width:100px;height:100px;margin-left:-50px;font-family:html5test;font-size:100px;line-height:100px;text-align:center;color:#bbb;-webkit-animation:loader 1s steps(8) infinite;animation:loader 1s steps(8) infinite}#score{z-index:10}.pointsPanel{background:#fff;min-height:145px;padding:0 155px 0 0}.saved .pointsPanel{padding:0}.pointsPanel h2{font-size:2.3em;color:#aaa;text-align:center;line-height:40px;margin:0}.pointsPanel h2>span,.pointsPanel h2>strong{display:inline-block;vertical-align:middle;-webkit-transform:translateY(6px);-moz-transform:translateY(6px);-ms-transform:translateY(6px);-o-transform:translateY(6px);transform:translateY(6px)}.pointsPanel h2>strong{font-family:'League Gothic',Impact;font-weight:400;font-size:3.8em;color:#0092bf;line-height:145px;margin:0 10px}.pointsPanel hr{border:0;border-top:8px solid #d9d9d9}.blocked{background:#ec6534;padding:20px;margin-bottom:40px}.blocked h2{color:#fff;font-size:2.6em}.blocked p{color:#fff;font-size:.8em;line-height:150%}.blocked button{margin-top:10px;background:rgba(0,0,0,.3);color:#fff;border:0;padding:10px}.wrapper{margin:8px 0 20px;position:relative}@media (max-width:900px){.blocked,.pointsPanel{font-size:90%}}@media (max-width:820px){.pointsPanel{font-size:80%}}@media (max-width:767px){.pointsPanel{font-size:100%}.pointsPanel h2{padding:10px 0}.pointsPanel h2>span,.pointsPanel h2>strong{display:block}}@media (max-width:680px){.pointsPanel{padding:0}.blocked{margin-left:20px;margin-right:20px}}.popupPanel.feedback{width:210px;margin-top:10px;margin-left:-130px;padding:10px;text-align:left;color:#000;cursor:auto;font-size:1.1em}.popupPanel.feedback h3{margin:0}.popupPanel.feedback textarea{width:100%;height:160px;padding:10px;margin:10px 0;font-size:1em;border:0;background:#eee}.popupPanel.feedback button{width:100%;border:0;background:#33af33;text-align:left;font-size:1em;color:#fff;padding:10px;cursor:pointer}.popupPanel.feedback button span{font-family:html5test;font-size:1.2em;margin-right:4px}.popupPanel.save{width:210px;margin-top:21px;padding:20px 10px 10px;text-align:center;color:#000;cursor:auto}.popupPanel.save a{color:#0092bf;font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-weight:700;text-decoration:none}.popupPanel.save a:hover{text-decoration:underline}.popupPanel.save p{margin-bottom:1em}.popupPanel.save code{font-size:1.5em}.popupPanel.share{width:210px;margin-top:21px}#share{display:block;height:94px;position:relative;overflow:hidden}#share #twitter{position:absolute;top:15px;left:15px}#share #facebook{position:absolute;top:15px;left:82px}#share #google{position:absolute;top:15px;left:141px}.wrapper .buttons{font-size:.75em}.wrapper .buttons>*{width:25%;display:inline-block;overflow:hidden}@media (max-width:680px){.wrapper .buttons>*{width:50%}}@media (max-width:280px){.wrapper .buttons>*{width:100%}.wrapper .buttons .donate{display:none}}.useragent{position:relative;box-sizing:border-box;border-top:8px solid #d9d9d9;display:block;text-align:left;text-transform:none;font-size:.8em;color:#222;padding:10px 100px 10px 10px;background:#eee}.saved .useragent{position:relative;left:auto;border-left:0;padding:0;cursor:pointer}.saved .useragent p{padding:10px}.useragent>span{position:absolute;right:10px;top:8px;font-size:.85em;color:#aaa;line-height:20px}.useragent>span a{font-family:html5test;font-weight:400;font-size:1.6em;padding:0 0 0 6px;cursor:pointer;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.useragent>span a.correct:hover{color:#1c8c1d}.useragent>span a.wrong:hover{color:#853333}@media (max-width:680px){.useragent{position:relative;border-left:0;font-size:.75em;min-height:1.7em}}.useragent .expandWidget{position:absolute;top:0;right:0;width:38px;height:38px;line-height:38px;text-align:center;color:#888;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.useragent .expandedPanel{border-top:4px solid #d9d9d9;margin:0;box-sizing:border-box;overflow:hidden;height:0;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;-ms-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.useragent.expanded .expandedPanel{height:100px}.useragent.expanded .expandWidget{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.useragent table{margin:10px;width:auto}.useragent table th{padding-right:16px;white-space:nowrap;font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif}.useragent table td,.useragent table th{vertical-align:top;font-size:.9em;padding-bottom:5px;text-align:left}.resultsTable{margin-bottom:40px}.resultsTable .category{border-top:1px solid rgba(0,0,0,0)}.resultsTable .category h2{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;text-transform:lowercase}.resultsTable .category h2::before{font-family:html5test;font-weight:400;font-size:1.2em;padding-right:4px;vertical-align:middle;-webkit-font-smoothing:antialiased}.resultsTable .category.semantics h2::before{content:''}.resultsTable .category.offlinestorage h2::before{content:''}.resultsTable .category.deviceaccess h2::before{content:''}.resultsTable .category.connectivity h2::before{content:''}.resultsTable .category.multimedia h2::before{content:''}.resultsTable .category.graphicseffects h2::before{content:''}.resultsTable .category.performanceintegration h2::before{content:''}.resultsTable table{border-spacing:0;position:relative;margin:0 0 24px;background:#fff;color:#000;border-collapse:separate}.resultsTable table thead tr{color:#fff;background:#0092bf}.resultsTable table thead tr>*{border-bottom:8px solid #d9d9d9}.resultsTable table thead th{position:relative;padding:0 10px;height:44px;font-family:'League Gothic',Impact;font-weight:400;font-size:2em;text-align:left}.resultsTable table thead td{position:relative;padding:0 10px;width:44px;text-align:right}.resultsTable table thead th div.grade{position:absolute;top:0;right:0}.resultsTable table thead th div>span{display:block;height:100%;line-height:44px;padding:0 10px;font-family:'League Gothic',Impact;font-size:.8em}.resultsTable table thead th span.none{background-color:#853333}.resultsTable table thead th span.badly{background-color:#d68533}.resultsTable table thead th span.reasonable{background-color:#e7c333}.resultsTable table thead th span.good{background-color:#88b038}.resultsTable table thead th span.great{background-color:#33af33}.resultsTable table tbody th{padding:5px 10px;font-size:.75em;font-weight:400;text-align:left;position:relative}.resultsTable table tbody td{padding:5px 10px;font-size:.75em;text-align:right;white-space:nowrap}.resultsTable table tbody tr:first-child td,.resultsTable table tbody tr:first-child th{padding-top:8px}.resultsTable table tbody tr:last-child td,.resultsTable table tbody tr:last-child th{padding-bottom:8px}.resultsTable table tbody th code{font-size:12px}.resultsTable table th.details{padding:16px 40px 5px 10px}.resultsTable table tr:first-child th.details{padding-top:8px}.resultsTable table th.details em{color:#666;font-size:90%}.resultsTable table tr.hasChild th{cursor:pointer;padding-left:28px}.resultsTable table tr th.hasLink:hover{cursor:pointer}.resultsTable table tr th.hasLink:hover span{text-decoration:underline}.resultsTable table tr.hasChild th>*{position:relative}.resultsTable table tr.hasChild th>::before{position:absolute;top:2px;left:-18px;display:block;font-family:html5test;font-size:11px;content:'â–¼';color:#888}.resultsTable table tr.hasChild.hidden th>::before{content:'â–¶'}.resultsTable table tr.hasChild td,.resultsTable table tr.hasChild th{border-bottom:1px solid #ccc}.resultsTable table tr.hasChild.hidden td,.resultsTable table tr.hasChild.hidden th{border-bottom:0}.resultsTable table tr.isChild{display:none}.resultsTable table tr.isChild.expanded{display:table-row}.resultsTable table tr.isChild th{background:#f6f6f6;font-size:.7em;padding:5px 10px 3px 28px}.resultsTable table tr.isChild td{background:#f6f6f6;font-size:.7em;padding:5px 10px}.resultsTable table tr.isChild th code{font-size:11px}.resultsTable h2{font-size:1.2em;font-weight:700;color:#aaa;margin:2em 0 .5em}.resultsTable a{color:#000;text-decoration:none}.resultsTable a:hover{text-decoration:underline}.resultsTable .linksPanel{max-width:120%;min-width:291px;padding:4px 0;margin-top:9px;margin-left:-2px}.resultsTable .linksPanel.popupPanel.pointsLeft::after,.resultsTable .linksPanel.popupPanel.pointsRight::after{border-bottom:8px solid #f6f6f6}.resultsTable .linksPanel .info{position:relative;border-bottom:4px solid #eee;background:#f6f6f6;top:-4px;font-size:.75em;height:66px;margin-bottom:6px}.resultsTable .linksPanel .info .column{position:absolute;width:33%;height:66px;top:0;cursor:default;box-sizing:border-box;border-left:2px solid #eee;border-right:2px solid #eee}.resultsTable .linksPanel .info .left{left:0;border-left:0}.resultsTable .linksPanel .info .middle{left:33%;width:34%}.resultsTable .linksPanel .info .right{left:67%;border-right:0}.resultsTable .linksPanel .info .column a{display:block;width:100%;height:66px}.resultsTable .linksPanel .info .column a:hover{background:#eee}.resultsTable .linksPanel .info .column span{position:absolute;left:0;width:100%;top:46px;text-align:center;text-transform:uppercase;text-decoration:none;font-size:.9em;font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif}.resultsTable .linksPanel .info .middle em{position:absolute;top:10px;left:50%;margin-left:-16px;display:block;width:32px;height:32px;color:#fff;text-align:center;line-height:34px;font-style:normal;font-family:'League Gothic',Impact;font-weight:400;font-size:2.5em;z-index:2}.resultsTable .linksPanel .info .middle em::before{position:absolute;top:0;display:block;content:'';width:0;height:0;border:16px solid #0092bf;border-radius:16px;z-index:-1}.resultsTable .linksPanel .info .middle.none em::before{border:16px solid #aaa}.resultsTable .linksPanel .info .middle.none em{font-family:html5test;font-size:1.5em}.resultsTable .linksPanel .info .status::after{position:absolute;top:12px;width:100%;text-align:center;display:block;content:'';font-family:html5test;font-size:29px}.resultsTable .linksPanel .info .status.recommendation::after,.resultsTable .linksPanel .info .status.stable::after{content:'';color:#33af33}.resultsTable .linksPanel .info .status.proposal::after{content:'';color:#88b038}.resultsTable .linksPanel .info .status.experimental::after{content:'';color:#ec6534}.resultsTable .linksPanel .info .status.controversial::after{content:'';color:#ec6534}.resultsTable .linksPanel .info .status.optional::after{content:'';color:#aaa}.resultsTable .linksPanel .info .status.rejected::after{content:'';color:#853333}.resultsTable .linksPanel .info .column a.compare::before{position:absolute;top:12px;width:100%;text-align:center;display:block;content:'⚏';font-family:html5test;font-size:30px;color:#33af33}.resultsTable .linksPanel h3{line-height:32px;padding:0 10px;border-bottom:1px solid #eee}.resultsTable .linksPanel .links a{display:block;white-space:nowrap;line-height:30px;padding:0 10px;background-size:24px 24px;background-position:10px center;background-repeat:no-repeat;overflow:hidden;text-overflow:ellipsis}.resultsTable .linksPanel .links a:hover{background-color:#eee;text-decoration:none}.resultsTable .linksPanel .links a.w3c{background-image:url(/images/external/w3c.png);background-size:24px 24px;text-indent:32px}.resultsTable .linksPanel .links a.whatwg{background-image:url(/images/external/whatwg.svg);background-size:20px 20px;text-indent:32px}.resultsTable .linksPanel .links a.khronos{background-image:url(/images/external/khronos.png);background-size:24px 24px;text-indent:32px}.resultsTable .linksPanel .links a.wp{background-image:url(/images/external/wp.png);background-size:24px 24px;text-indent:32px}.resultsTable .linksPanel .links a.mdn{background-image:url(/images/external/mdn.png);text-indent:32px}.resultsTable .linksPanel .links a.ricg{background-image:url(/images/external/ricg.svg);background-size:30px 30px;text-indent:32px}#html5{float:right;display:block;width:74px;height:102px;margin:16px 0 10px 10px;background:url(/images/html5.png);background-size:74px 102px}@media only screen and (-webkit-min-device-pixel-ratio:2){#html5{background-image:url(/images/html5@2x.png)}}.paper .buttons{padding:0!important;overflow:hidden}.paper .buttons>*{display:inline-block;float:left;width:25%;overflow:hidden;text-overflow:ellipsis}@media (max-width:680px){.paper .buttons>*{width:50%}}@media (max-width:432px){.paper .buttons>*{width:100%}}#headerad{position:absolute;top:0;right:0;width:125px;height:125px;background:#eee;overflow:hidden;padding:10px;border-bottom:8px solid #d9d9d9;border-left:8px solid #d9d9d9}#headerad div{width:125px;height:125px;display:inline-block}#footerad{margin-top:30px;overflow:hidden;background:#eee;padding:10px;text-align:center}#footerad>div a{width:125px;height:125px;overflow:hidden;margin:0 5px;display:inline-block;float:none}@media (max-width:680px){#headerad{position:static;border:0;width:100%;padding:10px 0;text-align:center;margin-bottom:30px}} \ No newline at end of file diff --git a/codeview/src/main/assets/training-set/css/new 7.txt b/codeview/src/main/assets/training-set/css/new 7.txt new file mode 100755 index 0000000..c86ada9 --- /dev/null +++ b/codeview/src/main/assets/training-set/css/new 7.txt @@ -0,0 +1,2 @@ +/*! De Standaard - 2015-07-03T15:04:00 *www.standaard.be* Copyright (c) 2015 Mediahuis */ +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:87.5%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}button,html,input,select,textarea{font-family:sans-serif;color:#444}body{margin:0}html{font-family:Georgia,Cambria,Times New Roman,Times,sans-serif}body{font-size:14px;font-size:1rem;line-height:1.35}h1{font-size:36px;font-size:2.5714285714rem}h2{font-size:28px;font-size:2rem;line-height:1.07143}h3,h4{font-size:20px;font-size:1.4285714286rem;line-height:1.1}h5{font-size:18px;font-size:1.2857142857rem}h6{font-size:16px;font-size:1.1428571429rem}h1,h2,h3,h4,h5,h6{margin:0 0 .8571428571rem;font-weight:400}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1.4285714286rem}dfn{font-style:italic}mark{background:#ff0;color:#000}p,pre{margin:0 0 1.4285714286rem}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:after,q:before{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1.4285714286rem 0}dl{padding:0}dd{margin:0 0 0 2.8571428571rem}menu,ol,ul{padding:0 0 0 2.8571428571rem}nav ol,nav ul{list-style:none;margin:0;padding:0}nav ol:after,nav ul:after{content:".";display:block;height:0;clear:both;visibility:hidden}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0 0 1.4285714286rem}fieldset{border:0;margin:0;padding:0}legend{border:0;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline}button,input{line-height:normal}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto}table{border-collapse:collapse;border-spacing:0}@font-face{font-family:Din;src:url(../font/dincomp.eot);src:url(../font/dincomp.eot?#iefix) format('embedded-opentype'),url(../font/dincomp.woff) format('woff'),url(../font/dincomp.ttf) format('truetype'),url(../font/dincomp.svg#dincomp) format('svg');font-weight:400;font-style:normal}@font-face{font-family:Din;src:url(../font/dincomp-light.eot);src:url(../font/dincomp-light.eot?#iefix) format('embedded-opentype'),url(../font/dincomp-light.woff) format('woff'),url(../font/dincomp-light.ttf) format('truetype'),url(../font/dincomp-light.svg#dincomp-light) format('svg');font-weight:300;font-style:normal}@font-face{font-family:Din;src:url(../font/dincomp-bold.eot);src:url(../font/dincomp-bold.eot?#iefix) format('embedded-opentype'),url(../font/dincomp-bold.woff) format('woff'),url(../font/dincomp-bold.ttf) format('truetype'),url(../font/dincomp-bold.svg#dincomp-bold) format('svg');font-weight:600;font-style:normal}@font-face{font-family:Dso-icons;src:url(../font/dso-icons.eot?1);src:url(../font/dso-icons.eot?1#iefix) format('embedded-opentype'),url(../font/dso-icons.woff?1) format('woff'),url(../font/dso-icons.ttf?1) format('truetype'),url(../font/dso-icons.svg?1#dso-icons) format('svg');font-weight:400;font-style:normal}html{overflow-x:hidden;-webkit-tap-highlight-color:transparent}@media screen and (min-width:62.1875em){html{padding:0}}body{background-color:#eee;overflow-x:hidden}::selection{background:#000;color:#fff;text-shadow:none}::-moz-selection{background:#000;color:#fff;text-shadow:none}a{text-decoration:none;color:#44c4d1}a:visited{color:#44c4d1}a:focus,a:hover{color:#318f98;text-decoration:none}.group-invert a,a.invert{text-decoration:none;color:#fff}.group-invert a:visited,a.invert:visited{color:#fff}.group-invert a:focus,.group-invert a:hover,a.invert:focus,a.invert:hover{color:#c00;text-decoration:none}a.mute{text-decoration:none;color:#aaa}a.mute:visited{color:#aaa}a.mute:focus,a.mute:hover{color:#c00;text-decoration:none}a:focus{outline:dotted thin}a:active,a:hover{outline:0}li a{text-decoration:none}time{font-size:12px;font-size:.8571428571rem;color:#aaa;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;line-height:1}aside>:last-child{margin-bottom:0}iframe{border:none}.pull-left{float:left}.pull-right{float:right}.comment__footer menu li,.inline{display:inline!important}.inline-block{display:inline-block}.ellipsis{display:block;overflow:hidden;max-width:100%;text-overflow:ellipsis;white-space:nowrap}.right-aligned{text-align:right!important}.center-aligned,.theme-morningedition .article-stock,.theme-morningedition .l-front,.theme-morningedition .l-front .section-header{text-align:center}.accessible-text,.radio--custom input,.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.mute,.theme-morningedition .l-front article+article p{color:#aaa}.bold{font-weight:700}.no-borders,.no-borders>li{border:0!important}.nowrap{white-space:nowrap}.blend-in-link,.blend-in-link:visited{text-decoration:none!important}.blend-in-link:active,.blend-in-link:focus,.blend-in-link:hover{text-decoration:underline!important}.flush-right{margin-right:-1.4285714286rem}.flush-left{margin-left:-1.4285714286rem}.flush-full{margin-left:-1.4285714286rem;margin-right:-1.4285714286rem}.push-left{padding-right:25%!important}.push-right{padding-left:25%!important}.padder--xxyy{padding:1.4285714286rem}.padder--yy{padding-top:1.4285714286rem;padding-bottom:1.4285714286rem}.padder--xx{padding-left:1.4285714286rem;padding-right:1.4285714286rem}.padder--x0{padding-left:1.4285714286rem}.padder--0x{padding-right:1.4285714286rem}.padder--y0{padding-top:1.4285714286rem}.padder--0y{padding-bottom:1.4285714286rem}.padder--half.padder--xxyy{padding:.8571428571rem}.padder--half.padder--yy{padding-top:.8571428571rem;padding-bottom:.8571428571rem}.padder--half.padder--xx{padding-left:.8571428571rem;padding-right:.8571428571rem}.padder--half.padder--x0{padding-left:.8571428571rem}.padder--half.padder--0x{padding-right:.8571428571rem}.padder--half.padder--y0{padding-top:.8571428571rem}.padder--half.padder--0y{padding-bottom:.8571428571rem}.overflow--x{overflow-x:auto}.overflow--y{overflow-y:auto}.cf:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ad--advertorial1 .ad__wrapper,.ad--advertorial2 .ad__wrapper,.ad--advertorial3 .ad__wrapper,.ad--advertorialinhouse .ad__wrapper,.ad--banthird .ad__wrapper,.ad--halfmediumrectangle .ad__wrapper,.ad--halfpage .ad__wrapper,.ad--halfpage2 .ad__wrapper,.ad--mediumrectangle .ad__wrapper,.ad--mediumrectangle2 .ad__wrapper,.ad--mediumrectangle3 .ad__wrapper,.ad--mediumrectangle4 .ad__wrapper,.ad--mediumrectangleinhouse .ad__wrapper,.ad--xlhalfpage .ad__wrapper,.ad--xlmediumrectangle .ad__wrapper{display:block;margin-left:auto;margin-right:auto}.ad--splash .ad__inner img,.ad--splash .article img,.ad--splash article img,.ad--xlsplash .article img,.ad--xlsplash article img,.avatar,.breaking-news-wrapper img,.dsavond-widget img,.ekrant__attachments a img,.list-visuals img,.logo img,.main-container .article img,.main-container article img,.modalbox .article img,.modalbox article img,.promo img,.rwd-img,.slideshow__image .slideshow__image__inner img,.stock-bar img,.tab-pane img,.topic__heading img,.widget__footer img,.widget__header img,[class*=" thumbnail-"],[class^=thumbnail-]{display:block;height:auto!important;width:auto;max-width:100%;padding:0}.brand--small[class*=brand-]{background-image:url(../img/sprite-small-16619.png);text-indent:150%;overflow:hidden}.brand--small.brand--gezondheid-inverted{background-position:0 0;height:16px;width:59px}.brand--small.brand--gezondheid{background-position:0 -21px;height:16px;width:59px}.brand--small.brand--jobat{background-position:0 -126px;height:14px;width:122px}.brand--small.brand--nieuwsblad{background-position:-64px 0;height:16px;width:78px}.brand--small.brand--rondom{background-position:-64px -21px;height:16px;width:54px}.brand--small.brand--sportwereld{background-position:0 -42px;height:16px;width:117px}.brand--small.brand--vroom{background-position:0 -63px;height:16px;width:76px}.brand--small.brand--wematch{background-position:0 -84px;height:16px;width:69px}.brand--small.brand--zdnet{background-position:-81px -63px;height:16px;width:25px}.brand--small.brand--zimmo{background-position:0 -105px;height:16px;width:89px}[class*=" brand-"],[class^=brand-]{background-image:url(../img/sprite@1x-16619.png);background-repeat:no-repeat;display:inline-block;vertical-align:middle;text-decoration:none}.brand--gezondheid-inverted{background-position:0 0;height:32px;width:117px}.brand--gezondheid{background-position:0 -37px;height:32px;width:117px}.brand--jobat{background-position:0 -222px;height:28px;width:242px}.brand--nieuwsblad{background-position:-122px 0;height:32px;width:155px}.brand--rondom{background-position:-122px -37px;height:32px;width:107px}.brand--sportwereld{background-position:0 -74px;height:32px;width:234px}.brand--vroom{background-position:0 -111px;height:32px;width:152px}.brand--wematch{background-position:0 -148px;height:32px;width:138px}.brand--zdnet{background-position:-157px -111px;height:32px;width:49px}.brand--zimmo{background-position:0 -185px;height:32px;width:178px}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brands--small[class*=brand-]{background-image:url(../img/sprite@1x-16619.png);-webkit-background-size:69.25px auto;-moz-background-size:69.25px auto;background-size:69.25px auto}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--gezondheid-inverted{background-position:0 0;height:16px;width:58.5px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--gezondheid{background-position:0 -18.5px;height:16px;width:58.5px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--jobat{background-position:0 -111px;height:14px;width:121px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--nieuwsblad{background-position:-61px 0;height:16px;width:77.5px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--rondom{background-position:-61px -18.5px;height:16px;width:53.5px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--sportwereld{background-position:0 -37px;height:16px;width:117px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--vroom{background-position:0 -55.5px;height:16px;width:76px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--wematch{background-position:0 -74px;height:16px;width:69px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--zdnet{background-position:-78.5px -55.5px;height:16px;width:24.5px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--small.brand--zimmo{background-position:0 -92.5px;height:16px;width:89px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){[class*=" brand-"],[class^=brand-]{background-image:url(../img/sprite@2x-16619.png);-webkit-background-size:274.5px auto;-moz-background-size:274.5px auto;background-size:274.5px auto}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--gezondheid-inverted{background-position:0 0;height:32px;width:117px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--gezondheid{background-position:0 -34.5px;height:32px;width:117px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--jobat{background-position:0 -207px;height:28px;width:242px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--nieuwsblad{background-position:-119.5px 0;height:32px;width:155px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--rondom{background-position:-119.5px -34.5px;height:32px;width:106.5px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--sportwereld{background-position:0 -69px;height:32px;width:234px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--vroom{background-position:0 -103.5px;height:32px;width:151.5px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--wematch{background-position:0 -138px;height:32px;width:138px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--zdnet{background-position:-154px -103.5px;height:32px;width:48.5px}}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (-webkit-min-device-pixel-ratio:1.3020833333333333),only screen and (min-resolution:125dpi){.brand--zimmo{background-position:0 -172.5px;height:32px;width:178px}}@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);transform:translateY(0px)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);transform:translateY(0px)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);transform:translateY(0px)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.dropzone{min-height:150px;border:2px solid rgba(0,0,0,.3);background:#fff;padding:20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview.dz-file-preview .dz-image{-webkit-border-radius:20px;-moz-border-radius:20px;border-radius:20px;background:#999;background:-webkit-gradient(linear,left top,left bottom,from(#eee),to(#ddd));background:-webkit-linear-gradient(top,#eee,#ddd);background:-moz-linear-gradient(top,#eee,#ddd);background:linear-gradient(to bottom,#eee,#ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:#fff}.dropzone .dz-preview.dz-image-preview .dz-details{-webkit-transition:opacity .2s linear;-moz-transition:opacity .2s linear;transition:opacity .2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,.8);background-color:rgba(255,255,255,.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,.4);padding:0 .4em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{-webkit-transform:scale(1.05,1.05);-moz-transform:scale(1.05,1.05);-ms-transform:scale(1.05,1.05);transform:scale(1.05,1.05);-webkit-filter:blur(8px);filter:blur(8px)}.dropzone .dz-preview .dz-image{-webkit-border-radius:20px;-moz-border-radius:20px;border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{-webkit-animation:passing-through 3s cubic-bezier(0.77,0,.175,1);-moz-animation:passing-through 3s cubic-bezier(0.77,0,.175,1);animation:passing-through 3s cubic-bezier(0.77,0,.175,1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;-webkit-animation:slide-in 3s cubic-bezier(0.77,0,.175,1);-moz-animation:slide-in 3s cubic-bezier(0.77,0,.175,1);animation:slide-in 3s cubic-bezier(0.77,0,.175,1)}.dropzone .dz-preview .dz-error-mark,.dropzone .dz-preview .dz-success-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px}.dropzone .dz-preview .dz-error-mark svg,.dropzone .dz-preview .dz-success-mark svg{display:block;width:54px;height:54px}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;-webkit-transition:all .2s linear;-moz-transition:all .2s linear;transition:all .2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;-webkit-transition:opacity .4s ease-in;-moz-transition:opacity .4s ease-in;transition:opacity .4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{-webkit-animation:pulse 6s ease infinite;-moz-animation:pulse 6s ease infinite;animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:16px;left:50%;top:50%;margin-top:-8px;width:80px;margin-left:-40px;background:rgba(255,255,255,.9);-webkit-transform:scale(1);-webkit-border-radius:8px;-moz-border-radius:8px;border-radius:8px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#333;background:-webkit-gradient(linear,left top,left bottom,from(#666),to(#444));background:-webkit-linear-gradient(top,#666,#444);background:-moz-linear-gradient(top,#666,#444);background:linear-gradient(to bottom,#666,#444);position:absolute;top:0;left:0;bottom:0;width:0;-webkit-transition:width 300ms ease-in-out;-moz-transition:width 300ms ease-in-out;transition:width 300ms ease-in-out}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;-webkit-transition:opacity .3s ease;-moz-transition:opacity .3s ease;transition:opacity .3s ease;-webkit-border-radius:8px;-moz-border-radius:8px;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#be2626;background:-webkit-gradient(linear,left top,left bottom,from(#be2626),to(#a92222));background:-webkit-linear-gradient(top,#be2626,#a92222);background:-moz-linear-gradient(top,#be2626,#a92222);background:linear-gradient(to bottom,#be2626,#a92222);padding:.5em 1.2em;color:#fff}.dropzone .dz-preview .dz-error-message:after{content:'';position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #be2626}.is-closed .comment__footer [data-comments-reply-id],.is-hidden{display:none!important}.is-visible{display:block!important}.is-offscreen,.slideshow__pager li span{left:-9999em!important;position:absolute;top:-9999em!important}.is-disabled a{cursor:default;text-decoration:none;color:#aaa!important}.is-disabled a:visited{color:#aaa!important}.is-disabled a:focus,.is-disabled a:hover{color:#aaa!important;text-decoration:none}.layout-leaderboard .theme-live .main-container,.layout-tvleaderboard .theme-live .main-container,.layout-xlleaderboard .theme-live .main-container{margin-top:0}.layout-mediumrectangle .ad--mediumrectangle{display:block}@media screen and (min-width:18.75em){.layout-mediumrectangle .ad--mediumrectangle.ad-slot--a{display:none}}@media screen and (min-width:55em){.layout-mediumrectangle .ad--mediumrectangle.ad-slot--a{display:block}}@media screen and (min-width:18.75em){.layout-mediumrectangle .ad--mediumrectangle.ad-slot--b{display:block}}@media screen and (min-width:55em){.layout-mediumrectangle .ad--mediumrectangle.ad-slot--b{display:none}}.layout-photospecial.layout-mediumrectangle .article-full .ad--mediumrectangle{display:none}.layout-advertorial1 .ad--advertorial1,.layout-advertorial2 .ad--advertorial2,.layout-advertorial3 .ad--advertorial3,.layout-advertorialinhouse .ad--advertorialinhouse,.layout-banthird .ad--banthird,.layout-crosspromo1 .ad--crosspromo1,.layout-crosspromo2 .ad--crosspromo2,.layout-crosspromo3 .ad--crosspromo3,.layout-fortuneo .ad--fortuneo,.layout-halfmediumrectangle .ad--halfmediumrectangle,.layout-halfpage .ad--halfpage,.layout-halfpage2 .ad--halfpage2,.layout-leaderboard .ad--leaderboard,.layout-leaderboard.layout-xlleaderboard .ad--leaderboard,.layout-mediumrectangle2 .ad--mediumrectangle2,.layout-mediumrectangle3 .ad--mediumrectangle3,.layout-mediumrectangle4 .ad--mediumrectangle4,.layout-mediumrectangleinhouse .ad--mediumrectangleinhouse,.layout-textlink .ad--textlink,.layout-tvleaderboard1 .ad--tvleaderboard1,.layout-tvleaderboard2 .ad--tvleaderboard2,.layout-tvleaderboard3 .ad--tvleaderboard3,.layout-tvleaderboard4 .ad--tvleaderboard4,.layout-xlhalfpage .ad--xlhalfpage,.layout-xlleaderboard1 .ad--xlleaderboard1,.layout-xlleaderboard2 .ad--xlleaderboard2,.layout-xlleaderboard3 .ad--xlleaderboard3,.layout-xlmediumrectangle .ad--xlmediumrectangle{display:block}@media screen and (min-width:18.75em){.layout-halfmediumrectangle .ad--halfmediumrectangle.ad-slot--a{display:none}}@media screen and (min-width:55em){.layout-halfmediumrectangle .ad--halfmediumrectangle.ad-slot--a{display:block}}@media screen and (min-width:18.75em){.layout-halfmediumrectangle .ad--halfmediumrectangle.ad-slot--b{display:block}}@media screen and (min-width:55em){.layout-halfmediumrectangle .ad--halfmediumrectangle.ad-slot--b{display:none}}@media screen and (min-width:18.75em){.layout-xlmediumrectangle .ad--xlmediumrectangle.ad-slot--a{display:none}}@media screen and (min-width:55em){.layout-xlmediumrectangle .ad--xlmediumrectangle.ad-slot--a{display:block}}@media screen and (min-width:18.75em){.layout-xlmediumrectangle .ad--xlmediumrectangle.ad-slot--b{display:block}}@media screen and (min-width:55em){.layout-xlmediumrectangle .ad--xlmediumrectangle.ad-slot--b{display:none}}@media screen and (min-width:18.75em){.layout-halfpage .ad--halfpage.ad-slot--a{display:none}}@media screen and (min-width:55em){.layout-halfpage .ad--halfpage.ad-slot--a{display:block}}@media screen and (min-width:18.75em){.layout-halfpage .ad--halfpage.ad-slot--b{display:block}}@media screen and (min-width:55em){.layout-halfpage .ad--halfpage.ad-slot--b{display:none}}@media screen and (min-width:18.75em){.layout-halfpage2 .ad--halfpage2.ad-slot--a{display:none}}@media screen and (min-width:55em){.layout-halfpage2 .ad--halfpage2.ad-slot--a{display:block}}@media screen and (min-width:18.75em){.layout-halfpage2 .ad--halfpage2.ad-slot--b{display:block}}@media screen and (min-width:55em){.layout-halfpage2 .ad--halfpage2.ad-slot--b{display:none}}@media screen and (min-width:18.75em){.layout-xlhalfpage .ad--xlhalfpage.ad-slot--a{display:none}}@media screen and (min-width:55em){.layout-xlhalfpage .ad--xlhalfpage.ad-slot--a{display:block}}@media screen and (min-width:18.75em){.layout-xlhalfpage .ad--xlhalfpage.ad-slot--b{display:block}}@media screen and (min-width:55em){.layout-xlhalfpage .ad--xlhalfpage.ad-slot--b{display:none}}@media screen and (min-width:48em){.layout-xlleaderboard .ad--xlleaderboard{display:block}}@media screen and (min-width:48em){.layout-leaderboard.layout-xlleaderboard .ad--leaderboard{display:none}}@media screen and (min-width:18.75em){.layout-tvleaderboard .ad--tvleaderboard{display:block}}@media screen and (min-width:62.1875em){.layout-wallpaper .ad--wallpaper{display:block}}@media screen and (min-width:62.1875em){.layout-wideskyscraper .ad--wideskyscraper{display:block}}@media screen and (min-width:18.75em){.layout-wideskyscraper .ad--wideskyscraper.ad-slot--b{display:block}}@media screen and (min-width:62.1875em){.layout-wideskyscraper .ad--wideskyscraper.ad-slot--b{display:none}}@media screen and (min-width:55em){.layout-wideskyscraper body{overflow:visible}}.layout-wallpaper body{margin-left:0;margin-right:0;max-width:none!important}@media screen and (min-width:62.1875em){.layout-wallpaper body{margin-left:12%;margin-right:12%}}.layout-wallpaper .container,.layout-wallpaper .main-footer,.layout-wallpaper .main-header,.layout-wallpaper .session-expired{margin-left:auto!important}.layout-wallpaper .main-container{background:#eee}@media screen and (min-width:62.1875em){.layout-wallpaper .ad--wallpaper-a{-moz-background-size:128%;background-size:128%;-webkit-background-size:128% auto}}@media screen and (min-width:82.125em){.layout-wallpaper .ad--wallpaper-a{-moz-background-size:auto;background-size:auto;-webkit-background-size:auto}}.layout-wallpaper .ad--smallskyscraper,.layout-wallpaper .ad--wideskyscraper{display:none}.l-stacked,.l-stacked__item,.layout-4K .ad--4K,.layout-4k .ad--4k,.layout-acc100 .ad--acc100,.layout-acc150 .ad--acc150,.layout-acc2 .ad--acc2,.layout-acc3 .ad--acc3,.layout-acc50 .ad--acc50,.layout-ap100 .ad--ap100,.layout-ap200 .ad--ap200,.layout-ap400 .ad--ap400,.layout-ap50 .ad--ap50,.layout-art1000 .ad--art1000,.layout-art125 .ad--art125,.layout-art250 .ad--art250,.layout-art500 .ad--art500,.layout-art750 .ad--art750,.layout-halfpano .ad--halfpano,.layout-pano .ad--pano,.layout-preroll .ad--preroll{display:block}@media screen and (min-width:40em){.layout-splash .ad--splash{display:block}}@media screen and (min-width:40em){.layout-xlsplash .ad--xlsplash{display:block}}@media screen and (min-width:40em){.layout-overlayer .ad--overlayer{display:block}}@media screen and (min-width:62.1875em){.layout-fullpagelayer .ad--fullpagelayer{display:block}}@media screen and (min-width:48em){.layout-floorad .ad--floorad{display:block}}.l-block--bp2,.l-inline-block--bp2{display:none!important}@media screen and (min-width:40em){.l-inline-block--bp2{display:inline-block!important}}@media screen and (min-width:40em){.l-block--bp2{display:block!important}}@media screen and (min-width:40em){.l-hidden--bp2{display:none!important}}.row,.slideshow,.slideshow__teasers .widget__list{position:relative}.row:after,.slideshow:after,.slideshow__teasers .widget__list:after{content:".";display:block;height:0;clear:both;visibility:hidden}@media screen and (min-width:40em){.row,.slideshow,.slideshow__teasers .widget__list{padding-left:1.4285714286rem}}.layout-archive .l-zone .row,.layout-archive .l-zone .slideshow,.layout-archive .l-zone .slideshow__teasers .widget__list,.layout-morningedition .l-zone .row,.layout-morningedition .l-zone .slideshow,.layout-morningedition .l-zone .slideshow__teasers .widget__list,.row .row,.row .slideshow,.row .slideshow__teasers .widget__list,.slideshow .row,.slideshow .slideshow,.slideshow .slideshow__teasers .widget__list,.slideshow__teasers .layout-archive .l-zone .widget__list,.slideshow__teasers .layout-morningedition .l-zone .widget__list,.slideshow__teasers .row .widget__list,.slideshow__teasers .slideshow .widget__list,.slideshow__teasers .theme-archive-overview .l-zone.theme-archive-overview--tile .widget__list,.slideshow__teasers .widget__list .row,.slideshow__teasers .widget__list .slideshow,.slideshow__teasers .widget__list .widget__list,.theme-archive-overview .l-zone.theme-archive-overview--tile .row,.theme-archive-overview .l-zone.theme-archive-overview--tile .slideshow,.theme-archive-overview .l-zone.theme-archive-overview--tile .slideshow__teasers .widget__list{padding-left:0}.slideshow__teasers .theme-archive-overview .l-zone .widget__list,.theme-archive-overview .l-zone .row,.theme-archive-overview .l-zone .slideshow,.theme-archive-overview .l-zone .slideshow__teasers .widget__list{padding-left:1.4285714286rem}.slideshow__teasers .theme-archive-overview .l-zone .row .widget__list,.slideshow__teasers .theme-archive-overview .l-zone .slideshow .widget__list,.slideshow__teasers .theme-archive-overview .l-zone .widget__list .row,.slideshow__teasers .theme-archive-overview .l-zone .widget__list .slideshow,.slideshow__teasers .theme-archive-overview .l-zone .widget__list .widget__list,.theme-archive-overview .l-zone .row .row,.theme-archive-overview .l-zone .row .slideshow,.theme-archive-overview .l-zone .row .slideshow__teasers .widget__list,.theme-archive-overview .l-zone .slideshow .row,.theme-archive-overview .l-zone .slideshow .slideshow,.theme-archive-overview .l-zone .slideshow .slideshow__teasers .widget__list,.theme-archive-overview .l-zone .slideshow__teasers .widget__list .row,.theme-archive-overview .l-zone .slideshow__teasers .widget__list .slideshow,.theme-archive-overview .l-zone .slideshow__teasers .widget__list .widget__list{padding-left:0}.slideshow__teasers .theme-live .main-header .widget__list,.theme-live .main-header .row,.theme-live .main-header .slideshow,.theme-live .main-header .slideshow__teasers .widget__list{z-index:499}.col,[class*=" col-"],[class^=col-]{min-height:1px;float:left;width:100%}.cols-2--bp0>.row>.col-1--bp0,.cols-2--bp0>.slideshow>.col-1--bp0,.slideshow__teasers .cols-2--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-2--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class^=cols-] .cols-2--bp0>.widget__list>.col-1--bp0,[class*=" cols-"] .cols-2--bp0>.row>.col-1--bp0,[class*=" cols-"] .cols-2--bp0>.slideshow>.col-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-2--bp0>.widget__list>.col-1--bp0,[class^=cols-] .cols-2--bp0>.row>.col-1--bp0,[class^=cols-] .cols-2--bp0>.slideshow>.col-1--bp0,[class^=cols-] .slideshow__teasers .cols-2--bp0>.widget__list>.col-1--bp0{width:50%}.cols-2--bp0>.row>.col-1--bp0:nth-child(2n+1),.cols-2--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),.slideshow__teasers .cols-2--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-2--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-2--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .cols-2--bp0>.row>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .cols-2--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-2--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),[class^=cols-] .cols-2--bp0>.row>.col-1--bp0:nth-child(2n+1),[class^=cols-] .cols-2--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-2--bp0>.widget__list>.col-1--bp0:nth-child(2n+1){clear:both}.cols-3--bp0>.row>.col-1--bp0,.cols-3--bp0>.slideshow>.col-1--bp0,.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0,.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0,.slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0,.slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-3--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0,.slideshow__teasers [class^=cols-] .cols-3--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0,[class*=" cols-"] .cols-3--bp0>.row>.col-1--bp0,[class*=" cols-"] .cols-3--bp0>.slideshow>.col-1--bp0,[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0,[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0,[class^=cols-] .cols-3--bp0>.row>.col-1--bp0,[class^=cols-] .cols-3--bp0>.slideshow>.col-1--bp0,[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0,[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0,[class^=cols-] .slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0,[class^=cols-] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0{width:33.33333%}.cols-3--bp0>.row>.col-1--bp0:nth-child(2n+1),.cols-3--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0:nth-child(2n+1),.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0:nth-child(2n+1),.slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .cols-3--bp0>.row>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .cols-3--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(2n+1),[class^=cols-] .cols-3--bp0>.row>.col-1--bp0:nth-child(2n+1),[class^=cols-] .cols-3--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0:nth-child(2n+1),[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(2n+1){clear:none}.cols-3--bp0>.row>.col-1--bp0:nth-child(3n+1),.cols-3--bp0>.slideshow>.col-1--bp0:nth-child(3n+1),.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0:nth-child(3n+1),.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0:nth-child(3n+1),.slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),.slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .cols-3--bp0>.row>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .cols-3--bp0>.slideshow>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(3n+1),[class^=cols-] .cols-3--bp0>.row>.col-1--bp0:nth-child(3n+1),[class^=cols-] .cols-3--bp0>.slideshow>.col-1--bp0:nth-child(3n+1),[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp0:nth-child(3n+1),[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp0:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp0:nth-child(3n+1){clear:both}.cols-3--bp0>.row>.col-2--bp0,.cols-3--bp0>.slideshow>.col-2--bp0,.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--bp0,.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--bp0,.slideshow__teasers .cols-3--bp0>.widget__list>.col-2--bp0,.slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-3--bp0>.widget__list>.col-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp0,.slideshow__teasers [class^=cols-] .cols-3--bp0>.widget__list>.col-2--bp0,.slideshow__teasers [class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp0,[class*=" cols-"] .cols-3--bp0>.row>.col-2--bp0,[class*=" cols-"] .cols-3--bp0>.slideshow>.col-2--bp0,[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--bp0,[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-3--bp0>.widget__list>.col-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp0,[class^=cols-] .cols-3--bp0>.row>.col-2--bp0,[class^=cols-] .cols-3--bp0>.slideshow>.col-2--bp0,[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--bp0,[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--bp0,[class^=cols-] .slideshow__teasers .cols-3--bp0>.widget__list>.col-2--bp0,[class^=cols-] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp0{width:66.66666%}.cols-3--bp0>.row>.offset-1--bp0,.cols-3--bp0>.slideshow>.offset-1--bp0,.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--bp0,.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--bp0,.slideshow__teasers .cols-3--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-3--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp0,.slideshow__teasers [class^=cols-] .cols-3--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers [class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp0,[class*=" cols-"] .cols-3--bp0>.row>.offset-1--bp0,[class*=" cols-"] .cols-3--bp0>.slideshow>.offset-1--bp0,[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--bp0,[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-3--bp0>.widget__list>.offset-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp0,[class^=cols-] .cols-3--bp0>.row>.offset-1--bp0,[class^=cols-] .cols-3--bp0>.slideshow>.offset-1--bp0,[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--bp0,[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--bp0,[class^=cols-] .slideshow__teasers .cols-3--bp0>.widget__list>.offset-1--bp0,[class^=cols-] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp0{margin-left:33.33333%}.cols-3--bp0>.row>.offset-2--bp0,.cols-3--bp0>.slideshow>.offset-2--bp0,.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--bp0,.cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--bp0,.slideshow__teasers .cols-3--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-3--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp0,.slideshow__teasers [class^=cols-] .cols-3--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers [class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp0,[class*=" cols-"] .cols-3--bp0>.row>.offset-2--bp0,[class*=" cols-"] .cols-3--bp0>.slideshow>.offset-2--bp0,[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--bp0,[class*=" cols-"] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-3--bp0>.widget__list>.offset-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp0,[class^=cols-] .cols-3--bp0>.row>.offset-2--bp0,[class^=cols-] .cols-3--bp0>.slideshow>.offset-2--bp0,[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--bp0,[class^=cols-] .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--bp0,[class^=cols-] .slideshow__teasers .cols-3--bp0>.widget__list>.offset-2--bp0,[class^=cols-] .slideshow__teasers .cols-3--bp0>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp0{margin-left:66.66666%}.cols-4--bp0>.row>.col-1--bp0,.cols-4--bp0>.slideshow>.col-1--bp0,.slideshow__teasers .cols-4--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-4--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class^=cols-] .cols-4--bp0>.widget__list>.col-1--bp0,[class*=" cols-"] .cols-4--bp0>.row>.col-1--bp0,[class*=" cols-"] .cols-4--bp0>.slideshow>.col-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-4--bp0>.widget__list>.col-1--bp0,[class^=cols-] .cols-4--bp0>.row>.col-1--bp0,[class^=cols-] .cols-4--bp0>.slideshow>.col-1--bp0,[class^=cols-] .slideshow__teasers .cols-4--bp0>.widget__list>.col-1--bp0{width:25%}.cols-4--bp0>.row>.col-1--bp0:nth-child(2n+1),.cols-4--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),.slideshow__teasers .cols-4--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-4--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-4--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .cols-4--bp0>.row>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .cols-4--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-4--bp0>.widget__list>.col-1--bp0:nth-child(2n+1),[class^=cols-] .cols-4--bp0>.row>.col-1--bp0:nth-child(2n+1),[class^=cols-] .cols-4--bp0>.slideshow>.col-1--bp0:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-4--bp0>.widget__list>.col-1--bp0:nth-child(2n+1){clear:none}.cols-4--bp0>.row>.col-2--bp0,.cols-4--bp0>.slideshow>.col-2--bp0,.slideshow__teasers .cols-4--bp0>.widget__list>.col-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-4--bp0>.widget__list>.col-2--bp0,.slideshow__teasers [class^=cols-] .cols-4--bp0>.widget__list>.col-2--bp0,[class*=" cols-"] .cols-4--bp0>.row>.col-2--bp0,[class*=" cols-"] .cols-4--bp0>.slideshow>.col-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-4--bp0>.widget__list>.col-2--bp0,[class^=cols-] .cols-4--bp0>.row>.col-2--bp0,[class^=cols-] .cols-4--bp0>.slideshow>.col-2--bp0,[class^=cols-] .slideshow__teasers .cols-4--bp0>.widget__list>.col-2--bp0{width:50%}.cols-4--bp0>.row>.col-3--bp0,.cols-4--bp0>.slideshow>.col-3--bp0,.slideshow__teasers .cols-4--bp0>.widget__list>.col-3--bp0,.slideshow__teasers [class*=" cols-"] .cols-4--bp0>.widget__list>.col-3--bp0,.slideshow__teasers [class^=cols-] .cols-4--bp0>.widget__list>.col-3--bp0,[class*=" cols-"] .cols-4--bp0>.row>.col-3--bp0,[class*=" cols-"] .cols-4--bp0>.slideshow>.col-3--bp0,[class*=" cols-"] .slideshow__teasers .cols-4--bp0>.widget__list>.col-3--bp0,[class^=cols-] .cols-4--bp0>.row>.col-3--bp0,[class^=cols-] .cols-4--bp0>.slideshow>.col-3--bp0,[class^=cols-] .slideshow__teasers .cols-4--bp0>.widget__list>.col-3--bp0{width:75%}.cols-4--bp0>.row>.offset-1--bp0,.cols-4--bp0>.slideshow>.offset-1--bp0,.slideshow__teasers .cols-4--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-4--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers [class^=cols-] .cols-4--bp0>.widget__list>.offset-1--bp0,[class*=" cols-"] .cols-4--bp0>.row>.offset-1--bp0,[class*=" cols-"] .cols-4--bp0>.slideshow>.offset-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-4--bp0>.widget__list>.offset-1--bp0,[class^=cols-] .cols-4--bp0>.row>.offset-1--bp0,[class^=cols-] .cols-4--bp0>.slideshow>.offset-1--bp0,[class^=cols-] .slideshow__teasers .cols-4--bp0>.widget__list>.offset-1--bp0{margin-left:25%}.cols-4--bp0>.row>.offset-2--bp0,.cols-4--bp0>.slideshow>.offset-2--bp0,.slideshow__teasers .cols-4--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-4--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers [class^=cols-] .cols-4--bp0>.widget__list>.offset-2--bp0,[class*=" cols-"] .cols-4--bp0>.row>.offset-2--bp0,[class*=" cols-"] .cols-4--bp0>.slideshow>.offset-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-4--bp0>.widget__list>.offset-2--bp0,[class^=cols-] .cols-4--bp0>.row>.offset-2--bp0,[class^=cols-] .cols-4--bp0>.slideshow>.offset-2--bp0,[class^=cols-] .slideshow__teasers .cols-4--bp0>.widget__list>.offset-2--bp0{margin-left:50%}.cols-4--bp0>.row>.offset-3--bp0,.cols-4--bp0>.slideshow>.offset-3--bp0,.slideshow__teasers .cols-4--bp0>.widget__list>.offset-3--bp0,.slideshow__teasers [class*=" cols-"] .cols-4--bp0>.widget__list>.offset-3--bp0,.slideshow__teasers [class^=cols-] .cols-4--bp0>.widget__list>.offset-3--bp0,[class*=" cols-"] .cols-4--bp0>.row>.offset-3--bp0,[class*=" cols-"] .cols-4--bp0>.slideshow>.offset-3--bp0,[class*=" cols-"] .slideshow__teasers .cols-4--bp0>.widget__list>.offset-3--bp0,[class^=cols-] .cols-4--bp0>.row>.offset-3--bp0,[class^=cols-] .cols-4--bp0>.slideshow>.offset-3--bp0,[class^=cols-] .slideshow__teasers .cols-4--bp0>.widget__list>.offset-3--bp0{margin-left:75%}.cols-5--bp0>.row>.col-1--bp0,.cols-5--bp0>.slideshow>.col-1--bp0,.slideshow__teasers .cols-5--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-5--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class^=cols-] .cols-5--bp0>.widget__list>.col-1--bp0,[class*=" cols-"] .cols-5--bp0>.row>.col-1--bp0,[class*=" cols-"] .cols-5--bp0>.slideshow>.col-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-5--bp0>.widget__list>.col-1--bp0,[class^=cols-] .cols-5--bp0>.row>.col-1--bp0,[class^=cols-] .cols-5--bp0>.slideshow>.col-1--bp0,[class^=cols-] .slideshow__teasers .cols-5--bp0>.widget__list>.col-1--bp0{width:20%}.cols-5--bp0>.row>.col-2--bp0,.cols-5--bp0>.slideshow>.col-2--bp0,.slideshow__teasers .cols-5--bp0>.widget__list>.col-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-5--bp0>.widget__list>.col-2--bp0,.slideshow__teasers [class^=cols-] .cols-5--bp0>.widget__list>.col-2--bp0,[class*=" cols-"] .cols-5--bp0>.row>.col-2--bp0,[class*=" cols-"] .cols-5--bp0>.slideshow>.col-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-5--bp0>.widget__list>.col-2--bp0,[class^=cols-] .cols-5--bp0>.row>.col-2--bp0,[class^=cols-] .cols-5--bp0>.slideshow>.col-2--bp0,[class^=cols-] .slideshow__teasers .cols-5--bp0>.widget__list>.col-2--bp0{width:40%}.cols-5--bp0>.row>.col-3--bp0,.cols-5--bp0>.slideshow>.col-3--bp0,.slideshow__teasers .cols-5--bp0>.widget__list>.col-3--bp0,.slideshow__teasers [class*=" cols-"] .cols-5--bp0>.widget__list>.col-3--bp0,.slideshow__teasers [class^=cols-] .cols-5--bp0>.widget__list>.col-3--bp0,[class*=" cols-"] .cols-5--bp0>.row>.col-3--bp0,[class*=" cols-"] .cols-5--bp0>.slideshow>.col-3--bp0,[class*=" cols-"] .slideshow__teasers .cols-5--bp0>.widget__list>.col-3--bp0,[class^=cols-] .cols-5--bp0>.row>.col-3--bp0,[class^=cols-] .cols-5--bp0>.slideshow>.col-3--bp0,[class^=cols-] .slideshow__teasers .cols-5--bp0>.widget__list>.col-3--bp0{width:60%}.cols-5--bp0>.row>.col-4--bp0,.cols-5--bp0>.slideshow>.col-4--bp0,.slideshow__teasers .cols-5--bp0>.widget__list>.col-4--bp0,.slideshow__teasers [class*=" cols-"] .cols-5--bp0>.widget__list>.col-4--bp0,.slideshow__teasers [class^=cols-] .cols-5--bp0>.widget__list>.col-4--bp0,[class*=" cols-"] .cols-5--bp0>.row>.col-4--bp0,[class*=" cols-"] .cols-5--bp0>.slideshow>.col-4--bp0,[class*=" cols-"] .slideshow__teasers .cols-5--bp0>.widget__list>.col-4--bp0,[class^=cols-] .cols-5--bp0>.row>.col-4--bp0,[class^=cols-] .cols-5--bp0>.slideshow>.col-4--bp0,[class^=cols-] .slideshow__teasers .cols-5--bp0>.widget__list>.col-4--bp0{width:80%}.cols-5--bp0>.row>.offset-1--bp0,.cols-5--bp0>.slideshow>.offset-1--bp0,.slideshow__teasers .cols-5--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-5--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers [class^=cols-] .cols-5--bp0>.widget__list>.offset-1--bp0,[class*=" cols-"] .cols-5--bp0>.row>.offset-1--bp0,[class*=" cols-"] .cols-5--bp0>.slideshow>.offset-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-5--bp0>.widget__list>.offset-1--bp0,[class^=cols-] .cols-5--bp0>.row>.offset-1--bp0,[class^=cols-] .cols-5--bp0>.slideshow>.offset-1--bp0,[class^=cols-] .slideshow__teasers .cols-5--bp0>.widget__list>.offset-1--bp0{margin-left:20%}.cols-5--bp0>.row>.offset-2--bp0,.cols-5--bp0>.slideshow>.offset-2--bp0,.slideshow__teasers .cols-5--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-5--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers [class^=cols-] .cols-5--bp0>.widget__list>.offset-2--bp0,[class*=" cols-"] .cols-5--bp0>.row>.offset-2--bp0,[class*=" cols-"] .cols-5--bp0>.slideshow>.offset-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-5--bp0>.widget__list>.offset-2--bp0,[class^=cols-] .cols-5--bp0>.row>.offset-2--bp0,[class^=cols-] .cols-5--bp0>.slideshow>.offset-2--bp0,[class^=cols-] .slideshow__teasers .cols-5--bp0>.widget__list>.offset-2--bp0{margin-left:40%}.cols-5--bp0>.row>.offset-3--bp0,.cols-5--bp0>.slideshow>.offset-3--bp0,.slideshow__teasers .cols-5--bp0>.widget__list>.offset-3--bp0,.slideshow__teasers [class*=" cols-"] .cols-5--bp0>.widget__list>.offset-3--bp0,.slideshow__teasers [class^=cols-] .cols-5--bp0>.widget__list>.offset-3--bp0,[class*=" cols-"] .cols-5--bp0>.row>.offset-3--bp0,[class*=" cols-"] .cols-5--bp0>.slideshow>.offset-3--bp0,[class*=" cols-"] .slideshow__teasers .cols-5--bp0>.widget__list>.offset-3--bp0,[class^=cols-] .cols-5--bp0>.row>.offset-3--bp0,[class^=cols-] .cols-5--bp0>.slideshow>.offset-3--bp0,[class^=cols-] .slideshow__teasers .cols-5--bp0>.widget__list>.offset-3--bp0{margin-left:60%}.cols-5--bp0>.row>.offset-4--bp0,.cols-5--bp0>.slideshow>.offset-4--bp0,.slideshow__teasers .cols-5--bp0>.widget__list>.offset-4--bp0,.slideshow__teasers [class*=" cols-"] .cols-5--bp0>.widget__list>.offset-4--bp0,.slideshow__teasers [class^=cols-] .cols-5--bp0>.widget__list>.offset-4--bp0,[class*=" cols-"] .cols-5--bp0>.row>.offset-4--bp0,[class*=" cols-"] .cols-5--bp0>.slideshow>.offset-4--bp0,[class*=" cols-"] .slideshow__teasers .cols-5--bp0>.widget__list>.offset-4--bp0,[class^=cols-] .cols-5--bp0>.row>.offset-4--bp0,[class^=cols-] .cols-5--bp0>.slideshow>.offset-4--bp0,[class^=cols-] .slideshow__teasers .cols-5--bp0>.widget__list>.offset-4--bp0{margin-left:80%}.cols-6--bp0>.row>.col-1--bp0,.cols-6--bp0>.slideshow>.col-1--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.col-1--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.col-1--bp0,[class*=" cols-"] .cols-6--bp0>.row>.col-1--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.col-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.col-1--bp0,[class^=cols-] .cols-6--bp0>.row>.col-1--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.col-1--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.col-1--bp0{width:16.66666%}.cols-6--bp0>.row>.col-1--bp0:nth-child(3n+1),.cols-6--bp0>.slideshow>.col-1--bp0:nth-child(3n+1),.slideshow__teasers .cols-6--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .cols-6--bp0>.row>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .cols-6--bp0>.slideshow>.col-1--bp0:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.col-1--bp0:nth-child(3n+1),[class^=cols-] .cols-6--bp0>.row>.col-1--bp0:nth-child(3n+1),[class^=cols-] .cols-6--bp0>.slideshow>.col-1--bp0:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.col-1--bp0:nth-child(3n+1){clear:none}.cols-6--bp0>.row>.col-2--bp0,.cols-6--bp0>.slideshow>.col-2--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.col-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.col-2--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.col-2--bp0,[class*=" cols-"] .cols-6--bp0>.row>.col-2--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.col-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.col-2--bp0,[class^=cols-] .cols-6--bp0>.row>.col-2--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.col-2--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.col-2--bp0{width:33.33332%}.cols-6--bp0>.row>.col-3--bp0,.cols-6--bp0>.slideshow>.col-3--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.col-3--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.col-3--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.col-3--bp0,[class*=" cols-"] .cols-6--bp0>.row>.col-3--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.col-3--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.col-3--bp0,[class^=cols-] .cols-6--bp0>.row>.col-3--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.col-3--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.col-3--bp0{width:50%}.cols-6--bp0>.row>.col-4--bp0,.cols-6--bp0>.slideshow>.col-4--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.col-4--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.col-4--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.col-4--bp0,[class*=" cols-"] .cols-6--bp0>.row>.col-4--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.col-4--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.col-4--bp0,[class^=cols-] .cols-6--bp0>.row>.col-4--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.col-4--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.col-4--bp0{width:66.66666%}.cols-6--bp0>.row>.col-5--bp0,.cols-6--bp0>.slideshow>.col-5--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.col-5--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.col-5--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.col-5--bp0,[class*=" cols-"] .cols-6--bp0>.row>.col-5--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.col-5--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.col-5--bp0,[class^=cols-] .cols-6--bp0>.row>.col-5--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.col-5--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.col-5--bp0{width:83.33333%}.cols-6--bp0>.row>.offset-1--bp0,.cols-6--bp0>.slideshow>.offset-1--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.offset-1--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.offset-1--bp0,[class*=" cols-"] .cols-6--bp0>.row>.offset-1--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.offset-1--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-1--bp0,[class^=cols-] .cols-6--bp0>.row>.offset-1--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.offset-1--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-1--bp0{margin-left:16.66666%}.cols-6--bp0>.row>.offset-2--bp0,.cols-6--bp0>.slideshow>.offset-2--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.offset-2--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.offset-2--bp0,[class*=" cols-"] .cols-6--bp0>.row>.offset-2--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.offset-2--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-2--bp0,[class^=cols-] .cols-6--bp0>.row>.offset-2--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.offset-2--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-2--bp0{margin-left:33.33332%}.cols-6--bp0>.row>.offset-3--bp0,.cols-6--bp0>.slideshow>.offset-3--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.offset-3--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.offset-3--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.offset-3--bp0,[class*=" cols-"] .cols-6--bp0>.row>.offset-3--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.offset-3--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-3--bp0,[class^=cols-] .cols-6--bp0>.row>.offset-3--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.offset-3--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-3--bp0{margin-left:50%}.cols-6--bp0>.row>.offset-4--bp0,.cols-6--bp0>.slideshow>.offset-4--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.offset-4--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.offset-4--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.offset-4--bp0,[class*=" cols-"] .cols-6--bp0>.row>.offset-4--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.offset-4--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-4--bp0,[class^=cols-] .cols-6--bp0>.row>.offset-4--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.offset-4--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-4--bp0{margin-left:66.66666%}.cols-6--bp0>.row>.offset-5--bp0,.cols-6--bp0>.slideshow>.offset-5--bp0,.slideshow__teasers .cols-6--bp0>.widget__list>.offset-5--bp0,.slideshow__teasers [class*=" cols-"] .cols-6--bp0>.widget__list>.offset-5--bp0,.slideshow__teasers [class^=cols-] .cols-6--bp0>.widget__list>.offset-5--bp0,[class*=" cols-"] .cols-6--bp0>.row>.offset-5--bp0,[class*=" cols-"] .cols-6--bp0>.slideshow>.offset-5--bp0,[class*=" cols-"] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-5--bp0,[class^=cols-] .cols-6--bp0>.row>.offset-5--bp0,[class^=cols-] .cols-6--bp0>.slideshow>.offset-5--bp0,[class^=cols-] .slideshow__teasers .cols-6--bp0>.widget__list>.offset-5--bp0{margin-left:83.33333%}@media screen and (min-width:30em){.cols-2--bp1a>.row>.col-1--bp1a,.cols-2--bp1a>.slideshow>.col-1--bp1a,.slideshow__teasers .cols-2--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-2--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class^=cols-] .cols-2--bp1a>.widget__list>.col-1--bp1a,[class*=" cols-"] .cols-2--bp1a>.row>.col-1--bp1a,[class*=" cols-"] .cols-2--bp1a>.slideshow>.col-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-2--bp1a>.widget__list>.col-1--bp1a,[class^=cols-] .cols-2--bp1a>.row>.col-1--bp1a,[class^=cols-] .cols-2--bp1a>.slideshow>.col-1--bp1a,[class^=cols-] .slideshow__teasers .cols-2--bp1a>.widget__list>.col-1--bp1a{width:50%}.cols-2--bp1a>.row>.col-1--bp1a:nth-child(2n+1),.cols-2--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers .cols-2--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-2--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-2--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .cols-2--bp1a>.row>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .cols-2--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-2--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .cols-2--bp1a>.row>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .cols-2--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-2--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1){clear:both}.cols-3--bp1a>.row>.col-1--bp1a,.cols-3--bp1a>.slideshow>.col-1--bp1a,.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a,.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a,.slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a,.slideshow__teasers [class^=cols-] .cols-3--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a,[class*=" cols-"] .cols-3--bp1a>.row>.col-1--bp1a,[class*=" cols-"] .cols-3--bp1a>.slideshow>.col-1--bp1a,[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a,[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a,[class^=cols-] .cols-3--bp1a>.row>.col-1--bp1a,[class^=cols-] .cols-3--bp1a>.slideshow>.col-1--bp1a,[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a,[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a,[class^=cols-] .slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a,[class^=cols-] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a{width:33.33333%}.cols-3--bp1a>.row>.col-1--bp1a:nth-child(2n+1),.cols-3--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a:nth-child(2n+1),.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .cols-3--bp1a>.row>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .cols-3--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .cols-3--bp1a>.row>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .cols-3--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(2n+1){clear:none}.cols-3--bp1a>.row>.col-1--bp1a:nth-child(3n+1),.cols-3--bp1a>.slideshow>.col-1--bp1a:nth-child(3n+1),.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a:nth-child(3n+1),.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .cols-3--bp1a>.row>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .cols-3--bp1a>.slideshow>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .cols-3--bp1a>.row>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .cols-3--bp1a>.slideshow>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--bp1a:nth-child(3n+1){clear:both}.cols-3--bp1a>.row>.col-2--bp1a,.cols-3--bp1a>.slideshow>.col-2--bp1a,.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--bp1a,.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--bp1a,.slideshow__teasers .cols-3--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp1a,.slideshow__teasers [class^=cols-] .cols-3--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers [class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp1a,[class*=" cols-"] .cols-3--bp1a>.row>.col-2--bp1a,[class*=" cols-"] .cols-3--bp1a>.slideshow>.col-2--bp1a,[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--bp1a,[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>.widget__list>.col-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp1a,[class^=cols-] .cols-3--bp1a>.row>.col-2--bp1a,[class^=cols-] .cols-3--bp1a>.slideshow>.col-2--bp1a,[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--bp1a,[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--bp1a,[class^=cols-] .slideshow__teasers .cols-3--bp1a>.widget__list>.col-2--bp1a,[class^=cols-] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--bp1a{width:66.66666%}.cols-3--bp1a>.row>.offset-1--bp1a,.cols-3--bp1a>.slideshow>.offset-1--bp1a,.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--bp1a,.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--bp1a,.slideshow__teasers .cols-3--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp1a,.slideshow__teasers [class^=cols-] .cols-3--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers [class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp1a,[class*=" cols-"] .cols-3--bp1a>.row>.offset-1--bp1a,[class*=" cols-"] .cols-3--bp1a>.slideshow>.offset-1--bp1a,[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--bp1a,[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>.widget__list>.offset-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp1a,[class^=cols-] .cols-3--bp1a>.row>.offset-1--bp1a,[class^=cols-] .cols-3--bp1a>.slideshow>.offset-1--bp1a,[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--bp1a,[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--bp1a,[class^=cols-] .slideshow__teasers .cols-3--bp1a>.widget__list>.offset-1--bp1a,[class^=cols-] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--bp1a{margin-left:33.33333%}.cols-3--bp1a>.row>.offset-2--bp1a,.cols-3--bp1a>.slideshow>.offset-2--bp1a,.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--bp1a,.cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--bp1a,.slideshow__teasers .cols-3--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp1a,.slideshow__teasers [class^=cols-] .cols-3--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers [class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp1a,[class*=" cols-"] .cols-3--bp1a>.row>.offset-2--bp1a,[class*=" cols-"] .cols-3--bp1a>.slideshow>.offset-2--bp1a,[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--bp1a,[class*=" cols-"] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>.widget__list>.offset-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp1a,[class^=cols-] .cols-3--bp1a>.row>.offset-2--bp1a,[class^=cols-] .cols-3--bp1a>.slideshow>.offset-2--bp1a,[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--bp1a,[class^=cols-] .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--bp1a,[class^=cols-] .slideshow__teasers .cols-3--bp1a>.widget__list>.offset-2--bp1a,[class^=cols-] .slideshow__teasers .cols-3--bp1a>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--bp1a{margin-left:66.66666%}.cols-4--bp1a>.row>.col-1--bp1a,.cols-4--bp1a>.slideshow>.col-1--bp1a,.slideshow__teasers .cols-4--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-4--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class^=cols-] .cols-4--bp1a>.widget__list>.col-1--bp1a,[class*=" cols-"] .cols-4--bp1a>.row>.col-1--bp1a,[class*=" cols-"] .cols-4--bp1a>.slideshow>.col-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-4--bp1a>.widget__list>.col-1--bp1a,[class^=cols-] .cols-4--bp1a>.row>.col-1--bp1a,[class^=cols-] .cols-4--bp1a>.slideshow>.col-1--bp1a,[class^=cols-] .slideshow__teasers .cols-4--bp1a>.widget__list>.col-1--bp1a{width:25%}.cols-4--bp1a>.row>.col-1--bp1a:nth-child(2n+1),.cols-4--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers .cols-4--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-4--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-4--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .cols-4--bp1a>.row>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .cols-4--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-4--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .cols-4--bp1a>.row>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .cols-4--bp1a>.slideshow>.col-1--bp1a:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-4--bp1a>.widget__list>.col-1--bp1a:nth-child(2n+1){clear:none}.cols-4--bp1a>.row>.col-2--bp1a,.cols-4--bp1a>.slideshow>.col-2--bp1a,.slideshow__teasers .cols-4--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-4--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers [class^=cols-] .cols-4--bp1a>.widget__list>.col-2--bp1a,[class*=" cols-"] .cols-4--bp1a>.row>.col-2--bp1a,[class*=" cols-"] .cols-4--bp1a>.slideshow>.col-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-4--bp1a>.widget__list>.col-2--bp1a,[class^=cols-] .cols-4--bp1a>.row>.col-2--bp1a,[class^=cols-] .cols-4--bp1a>.slideshow>.col-2--bp1a,[class^=cols-] .slideshow__teasers .cols-4--bp1a>.widget__list>.col-2--bp1a{width:50%}.cols-4--bp1a>.row>.col-3--bp1a,.cols-4--bp1a>.slideshow>.col-3--bp1a,.slideshow__teasers .cols-4--bp1a>.widget__list>.col-3--bp1a,.slideshow__teasers [class*=" cols-"] .cols-4--bp1a>.widget__list>.col-3--bp1a,.slideshow__teasers [class^=cols-] .cols-4--bp1a>.widget__list>.col-3--bp1a,[class*=" cols-"] .cols-4--bp1a>.row>.col-3--bp1a,[class*=" cols-"] .cols-4--bp1a>.slideshow>.col-3--bp1a,[class*=" cols-"] .slideshow__teasers .cols-4--bp1a>.widget__list>.col-3--bp1a,[class^=cols-] .cols-4--bp1a>.row>.col-3--bp1a,[class^=cols-] .cols-4--bp1a>.slideshow>.col-3--bp1a,[class^=cols-] .slideshow__teasers .cols-4--bp1a>.widget__list>.col-3--bp1a{width:75%}.cols-4--bp1a>.row>.offset-1--bp1a,.cols-4--bp1a>.slideshow>.offset-1--bp1a,.slideshow__teasers .cols-4--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-4--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers [class^=cols-] .cols-4--bp1a>.widget__list>.offset-1--bp1a,[class*=" cols-"] .cols-4--bp1a>.row>.offset-1--bp1a,[class*=" cols-"] .cols-4--bp1a>.slideshow>.offset-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-4--bp1a>.widget__list>.offset-1--bp1a,[class^=cols-] .cols-4--bp1a>.row>.offset-1--bp1a,[class^=cols-] .cols-4--bp1a>.slideshow>.offset-1--bp1a,[class^=cols-] .slideshow__teasers .cols-4--bp1a>.widget__list>.offset-1--bp1a{margin-left:25%}.cols-4--bp1a>.row>.offset-2--bp1a,.cols-4--bp1a>.slideshow>.offset-2--bp1a,.slideshow__teasers .cols-4--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-4--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers [class^=cols-] .cols-4--bp1a>.widget__list>.offset-2--bp1a,[class*=" cols-"] .cols-4--bp1a>.row>.offset-2--bp1a,[class*=" cols-"] .cols-4--bp1a>.slideshow>.offset-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-4--bp1a>.widget__list>.offset-2--bp1a,[class^=cols-] .cols-4--bp1a>.row>.offset-2--bp1a,[class^=cols-] .cols-4--bp1a>.slideshow>.offset-2--bp1a,[class^=cols-] .slideshow__teasers .cols-4--bp1a>.widget__list>.offset-2--bp1a{margin-left:50%}.cols-4--bp1a>.row>.offset-3--bp1a,.cols-4--bp1a>.slideshow>.offset-3--bp1a,.slideshow__teasers .cols-4--bp1a>.widget__list>.offset-3--bp1a,.slideshow__teasers [class*=" cols-"] .cols-4--bp1a>.widget__list>.offset-3--bp1a,.slideshow__teasers [class^=cols-] .cols-4--bp1a>.widget__list>.offset-3--bp1a,[class*=" cols-"] .cols-4--bp1a>.row>.offset-3--bp1a,[class*=" cols-"] .cols-4--bp1a>.slideshow>.offset-3--bp1a,[class*=" cols-"] .slideshow__teasers .cols-4--bp1a>.widget__list>.offset-3--bp1a,[class^=cols-] .cols-4--bp1a>.row>.offset-3--bp1a,[class^=cols-] .cols-4--bp1a>.slideshow>.offset-3--bp1a,[class^=cols-] .slideshow__teasers .cols-4--bp1a>.widget__list>.offset-3--bp1a{margin-left:75%}.cols-5--bp1a>.row>.col-1--bp1a,.cols-5--bp1a>.slideshow>.col-1--bp1a,.slideshow__teasers .cols-5--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-5--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class^=cols-] .cols-5--bp1a>.widget__list>.col-1--bp1a,[class*=" cols-"] .cols-5--bp1a>.row>.col-1--bp1a,[class*=" cols-"] .cols-5--bp1a>.slideshow>.col-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-5--bp1a>.widget__list>.col-1--bp1a,[class^=cols-] .cols-5--bp1a>.row>.col-1--bp1a,[class^=cols-] .cols-5--bp1a>.slideshow>.col-1--bp1a,[class^=cols-] .slideshow__teasers .cols-5--bp1a>.widget__list>.col-1--bp1a{width:20%}.cols-5--bp1a>.row>.col-2--bp1a,.cols-5--bp1a>.slideshow>.col-2--bp1a,.slideshow__teasers .cols-5--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-5--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers [class^=cols-] .cols-5--bp1a>.widget__list>.col-2--bp1a,[class*=" cols-"] .cols-5--bp1a>.row>.col-2--bp1a,[class*=" cols-"] .cols-5--bp1a>.slideshow>.col-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-5--bp1a>.widget__list>.col-2--bp1a,[class^=cols-] .cols-5--bp1a>.row>.col-2--bp1a,[class^=cols-] .cols-5--bp1a>.slideshow>.col-2--bp1a,[class^=cols-] .slideshow__teasers .cols-5--bp1a>.widget__list>.col-2--bp1a{width:40%}.cols-5--bp1a>.row>.col-3--bp1a,.cols-5--bp1a>.slideshow>.col-3--bp1a,.slideshow__teasers .cols-5--bp1a>.widget__list>.col-3--bp1a,.slideshow__teasers [class*=" cols-"] .cols-5--bp1a>.widget__list>.col-3--bp1a,.slideshow__teasers [class^=cols-] .cols-5--bp1a>.widget__list>.col-3--bp1a,[class*=" cols-"] .cols-5--bp1a>.row>.col-3--bp1a,[class*=" cols-"] .cols-5--bp1a>.slideshow>.col-3--bp1a,[class*=" cols-"] .slideshow__teasers .cols-5--bp1a>.widget__list>.col-3--bp1a,[class^=cols-] .cols-5--bp1a>.row>.col-3--bp1a,[class^=cols-] .cols-5--bp1a>.slideshow>.col-3--bp1a,[class^=cols-] .slideshow__teasers .cols-5--bp1a>.widget__list>.col-3--bp1a{width:60%}.cols-5--bp1a>.row>.col-4--bp1a,.cols-5--bp1a>.slideshow>.col-4--bp1a,.slideshow__teasers .cols-5--bp1a>.widget__list>.col-4--bp1a,.slideshow__teasers [class*=" cols-"] .cols-5--bp1a>.widget__list>.col-4--bp1a,.slideshow__teasers [class^=cols-] .cols-5--bp1a>.widget__list>.col-4--bp1a,[class*=" cols-"] .cols-5--bp1a>.row>.col-4--bp1a,[class*=" cols-"] .cols-5--bp1a>.slideshow>.col-4--bp1a,[class*=" cols-"] .slideshow__teasers .cols-5--bp1a>.widget__list>.col-4--bp1a,[class^=cols-] .cols-5--bp1a>.row>.col-4--bp1a,[class^=cols-] .cols-5--bp1a>.slideshow>.col-4--bp1a,[class^=cols-] .slideshow__teasers .cols-5--bp1a>.widget__list>.col-4--bp1a{width:80%}.cols-5--bp1a>.row>.offset-1--bp1a,.cols-5--bp1a>.slideshow>.offset-1--bp1a,.slideshow__teasers .cols-5--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-5--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers [class^=cols-] .cols-5--bp1a>.widget__list>.offset-1--bp1a,[class*=" cols-"] .cols-5--bp1a>.row>.offset-1--bp1a,[class*=" cols-"] .cols-5--bp1a>.slideshow>.offset-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-5--bp1a>.widget__list>.offset-1--bp1a,[class^=cols-] .cols-5--bp1a>.row>.offset-1--bp1a,[class^=cols-] .cols-5--bp1a>.slideshow>.offset-1--bp1a,[class^=cols-] .slideshow__teasers .cols-5--bp1a>.widget__list>.offset-1--bp1a{margin-left:20%}.cols-5--bp1a>.row>.offset-2--bp1a,.cols-5--bp1a>.slideshow>.offset-2--bp1a,.slideshow__teasers .cols-5--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-5--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers [class^=cols-] .cols-5--bp1a>.widget__list>.offset-2--bp1a,[class*=" cols-"] .cols-5--bp1a>.row>.offset-2--bp1a,[class*=" cols-"] .cols-5--bp1a>.slideshow>.offset-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-5--bp1a>.widget__list>.offset-2--bp1a,[class^=cols-] .cols-5--bp1a>.row>.offset-2--bp1a,[class^=cols-] .cols-5--bp1a>.slideshow>.offset-2--bp1a,[class^=cols-] .slideshow__teasers .cols-5--bp1a>.widget__list>.offset-2--bp1a{margin-left:40%}.cols-5--bp1a>.row>.offset-3--bp1a,.cols-5--bp1a>.slideshow>.offset-3--bp1a,.slideshow__teasers .cols-5--bp1a>.widget__list>.offset-3--bp1a,.slideshow__teasers [class*=" cols-"] .cols-5--bp1a>.widget__list>.offset-3--bp1a,.slideshow__teasers [class^=cols-] .cols-5--bp1a>.widget__list>.offset-3--bp1a,[class*=" cols-"] .cols-5--bp1a>.row>.offset-3--bp1a,[class*=" cols-"] .cols-5--bp1a>.slideshow>.offset-3--bp1a,[class*=" cols-"] .slideshow__teasers .cols-5--bp1a>.widget__list>.offset-3--bp1a,[class^=cols-] .cols-5--bp1a>.row>.offset-3--bp1a,[class^=cols-] .cols-5--bp1a>.slideshow>.offset-3--bp1a,[class^=cols-] .slideshow__teasers .cols-5--bp1a>.widget__list>.offset-3--bp1a{margin-left:60%}.cols-5--bp1a>.row>.offset-4--bp1a,.cols-5--bp1a>.slideshow>.offset-4--bp1a,.slideshow__teasers .cols-5--bp1a>.widget__list>.offset-4--bp1a,.slideshow__teasers [class*=" cols-"] .cols-5--bp1a>.widget__list>.offset-4--bp1a,.slideshow__teasers [class^=cols-] .cols-5--bp1a>.widget__list>.offset-4--bp1a,[class*=" cols-"] .cols-5--bp1a>.row>.offset-4--bp1a,[class*=" cols-"] .cols-5--bp1a>.slideshow>.offset-4--bp1a,[class*=" cols-"] .slideshow__teasers .cols-5--bp1a>.widget__list>.offset-4--bp1a,[class^=cols-] .cols-5--bp1a>.row>.offset-4--bp1a,[class^=cols-] .cols-5--bp1a>.slideshow>.offset-4--bp1a,[class^=cols-] .slideshow__teasers .cols-5--bp1a>.widget__list>.offset-4--bp1a{margin-left:80%}.cols-6--bp1a>.row>.col-1--bp1a,.cols-6--bp1a>.slideshow>.col-1--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.col-1--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.col-1--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.col-1--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.col-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-1--bp1a,[class^=cols-] .cols-6--bp1a>.row>.col-1--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.col-1--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-1--bp1a{width:16.66666%}.cols-6--bp1a>.row>.col-1--bp1a:nth-child(3n+1),.cols-6--bp1a>.slideshow>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers .cols-6--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .cols-6--bp1a>.row>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .cols-6--bp1a>.slideshow>.col-1--bp1a:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .cols-6--bp1a>.row>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .cols-6--bp1a>.slideshow>.col-1--bp1a:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-1--bp1a:nth-child(3n+1){clear:none}.cols-6--bp1a>.row>.col-2--bp1a,.cols-6--bp1a>.slideshow>.col-2--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.col-2--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.col-2--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.col-2--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.col-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-2--bp1a,[class^=cols-] .cols-6--bp1a>.row>.col-2--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.col-2--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-2--bp1a{width:33.33332%}.cols-6--bp1a>.row>.col-3--bp1a,.cols-6--bp1a>.slideshow>.col-3--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.col-3--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.col-3--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.col-3--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.col-3--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.col-3--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-3--bp1a,[class^=cols-] .cols-6--bp1a>.row>.col-3--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.col-3--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-3--bp1a{width:50%}.cols-6--bp1a>.row>.col-4--bp1a,.cols-6--bp1a>.slideshow>.col-4--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.col-4--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.col-4--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.col-4--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.col-4--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.col-4--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-4--bp1a,[class^=cols-] .cols-6--bp1a>.row>.col-4--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.col-4--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-4--bp1a{width:66.66666%}.cols-6--bp1a>.row>.col-5--bp1a,.cols-6--bp1a>.slideshow>.col-5--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.col-5--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.col-5--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.col-5--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.col-5--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.col-5--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-5--bp1a,[class^=cols-] .cols-6--bp1a>.row>.col-5--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.col-5--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.col-5--bp1a{width:83.33333%}.cols-6--bp1a>.row>.offset-1--bp1a,.cols-6--bp1a>.slideshow>.offset-1--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.offset-1--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.offset-1--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.offset-1--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.offset-1--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-1--bp1a,[class^=cols-] .cols-6--bp1a>.row>.offset-1--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.offset-1--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-1--bp1a{margin-left:16.66666%}.cols-6--bp1a>.row>.offset-2--bp1a,.cols-6--bp1a>.slideshow>.offset-2--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.offset-2--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.offset-2--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.offset-2--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.offset-2--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-2--bp1a,[class^=cols-] .cols-6--bp1a>.row>.offset-2--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.offset-2--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-2--bp1a{margin-left:33.33332%}.cols-6--bp1a>.row>.offset-3--bp1a,.cols-6--bp1a>.slideshow>.offset-3--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.offset-3--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.offset-3--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.offset-3--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.offset-3--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.offset-3--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-3--bp1a,[class^=cols-] .cols-6--bp1a>.row>.offset-3--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.offset-3--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-3--bp1a{margin-left:50%}.cols-6--bp1a>.row>.offset-4--bp1a,.cols-6--bp1a>.slideshow>.offset-4--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.offset-4--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.offset-4--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.offset-4--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.offset-4--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.offset-4--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-4--bp1a,[class^=cols-] .cols-6--bp1a>.row>.offset-4--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.offset-4--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-4--bp1a{margin-left:66.66666%}.cols-6--bp1a>.row>.offset-5--bp1a,.cols-6--bp1a>.slideshow>.offset-5--bp1a,.slideshow__teasers .cols-6--bp1a>.widget__list>.offset-5--bp1a,.slideshow__teasers [class*=" cols-"] .cols-6--bp1a>.widget__list>.offset-5--bp1a,.slideshow__teasers [class^=cols-] .cols-6--bp1a>.widget__list>.offset-5--bp1a,[class*=" cols-"] .cols-6--bp1a>.row>.offset-5--bp1a,[class*=" cols-"] .cols-6--bp1a>.slideshow>.offset-5--bp1a,[class*=" cols-"] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-5--bp1a,[class^=cols-] .cols-6--bp1a>.row>.offset-5--bp1a,[class^=cols-] .cols-6--bp1a>.slideshow>.offset-5--bp1a,[class^=cols-] .slideshow__teasers .cols-6--bp1a>.widget__list>.offset-5--bp1a{margin-left:83.33333%}}@media screen and (min-width:40em){.cols-2>.row>.col-1,.cols-2>.slideshow>.col-1,.slideshow__teasers .cols-2>.widget__list>.col-1,.slideshow__teasers [class*=" cols-"] .cols-2>.widget__list>.col-1,.slideshow__teasers [class^=cols-] .cols-2>.widget__list>.col-1,[class*=" cols-"] .cols-2>.row>.col-1,[class*=" cols-"] .cols-2>.slideshow>.col-1,[class*=" cols-"] .slideshow__teasers .cols-2>.widget__list>.col-1,[class^=cols-] .cols-2>.row>.col-1,[class^=cols-] .cols-2>.slideshow>.col-1,[class^=cols-] .slideshow__teasers .cols-2>.widget__list>.col-1{width:50%}.cols-2>.row>.col-1:nth-child(2n+1),.cols-2>.slideshow>.col-1:nth-child(2n+1),.slideshow__teasers .cols-2>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-2>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-2>.widget__list>.col-1:nth-child(2n+1),[class*=" cols-"] .cols-2>.row>.col-1:nth-child(2n+1),[class*=" cols-"] .cols-2>.slideshow>.col-1:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-2>.widget__list>.col-1:nth-child(2n+1),[class^=cols-] .cols-2>.row>.col-1:nth-child(2n+1),[class^=cols-] .cols-2>.slideshow>.col-1:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-2>.widget__list>.col-1:nth-child(2n+1){clear:both}.cols-3>.row>.col-1,.cols-3>.slideshow>.col-1,.cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1,.cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1,.slideshow__teasers .cols-3>.widget__list>.col-1,.slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1,.slideshow__teasers [class*=" cols-"] .cols-3>.widget__list>.col-1,.slideshow__teasers [class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1,.slideshow__teasers [class^=cols-] .cols-3>.widget__list>.col-1,.slideshow__teasers [class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1,[class*=" cols-"] .cols-3>.row>.col-1,[class*=" cols-"] .cols-3>.slideshow>.col-1,[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1,[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1,[class*=" cols-"] .slideshow__teasers .cols-3>.widget__list>.col-1,[class*=" cols-"] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1,[class^=cols-] .cols-3>.row>.col-1,[class^=cols-] .cols-3>.slideshow>.col-1,[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1,[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1,[class^=cols-] .slideshow__teasers .cols-3>.widget__list>.col-1,[class^=cols-] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1{width:33.33333%}.cols-3>.row>.col-1:nth-child(2n+1),.cols-3>.slideshow>.col-1:nth-child(2n+1),.cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1:nth-child(2n+1),.cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1:nth-child(2n+1),.slideshow__teasers .cols-3>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(2n+1),[class*=" cols-"] .cols-3>.row>.col-1:nth-child(2n+1),[class*=" cols-"] .cols-3>.slideshow>.col-1:nth-child(2n+1),[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1:nth-child(2n+1),[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3>.widget__list>.col-1:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(2n+1),[class^=cols-] .cols-3>.row>.col-1:nth-child(2n+1),[class^=cols-] .cols-3>.slideshow>.col-1:nth-child(2n+1),[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1:nth-child(2n+1),[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3>.widget__list>.col-1:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(2n+1){clear:none}.cols-3>.row>.col-1:nth-child(3n+1),.cols-3>.slideshow>.col-1:nth-child(3n+1),.cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1:nth-child(3n+1),.cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1:nth-child(3n+1),.slideshow__teasers .cols-3>.widget__list>.col-1:nth-child(3n+1),.slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3>.widget__list>.col-1:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3>.widget__list>.col-1:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(3n+1),[class*=" cols-"] .cols-3>.row>.col-1:nth-child(3n+1),[class*=" cols-"] .cols-3>.slideshow>.col-1:nth-child(3n+1),[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1:nth-child(3n+1),[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3>.widget__list>.col-1:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(3n+1),[class^=cols-] .cols-3>.row>.col-1:nth-child(3n+1),[class^=cols-] .cols-3>.slideshow>.col-1:nth-child(3n+1),[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-1:nth-child(3n+1),[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3>.widget__list>.col-1:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1:nth-child(3n+1){clear:both}.cols-3>.row>.col-2,.cols-3>.slideshow>.col-2,.cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-2,.cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2,.slideshow__teasers .cols-3>.widget__list>.col-2,.slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2,.slideshow__teasers [class*=" cols-"] .cols-3>.widget__list>.col-2,.slideshow__teasers [class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2,.slideshow__teasers [class^=cols-] .cols-3>.widget__list>.col-2,.slideshow__teasers [class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2,[class*=" cols-"] .cols-3>.row>.col-2,[class*=" cols-"] .cols-3>.slideshow>.col-2,[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-2,[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2,[class*=" cols-"] .slideshow__teasers .cols-3>.widget__list>.col-2,[class*=" cols-"] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2,[class^=cols-] .cols-3>.row>.col-2,[class^=cols-] .cols-3>.slideshow>.col-2,[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.col-2,[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2,[class^=cols-] .slideshow__teasers .cols-3>.widget__list>.col-2,[class^=cols-] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2{width:66.66666%}.cols-3>.row>.offset-1,.cols-3>.slideshow>.offset-1,.cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1,.cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1,.slideshow__teasers .cols-3>.widget__list>.offset-1,.slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1,.slideshow__teasers [class*=" cols-"] .cols-3>.widget__list>.offset-1,.slideshow__teasers [class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1,.slideshow__teasers [class^=cols-] .cols-3>.widget__list>.offset-1,.slideshow__teasers [class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1,[class*=" cols-"] .cols-3>.row>.offset-1,[class*=" cols-"] .cols-3>.slideshow>.offset-1,[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1,[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1,[class*=" cols-"] .slideshow__teasers .cols-3>.widget__list>.offset-1,[class*=" cols-"] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1,[class^=cols-] .cols-3>.row>.offset-1,[class^=cols-] .cols-3>.slideshow>.offset-1,[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1,[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1,[class^=cols-] .slideshow__teasers .cols-3>.widget__list>.offset-1,[class^=cols-] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1{margin-left:33.33333%}.cols-3>.row>.offset-2,.cols-3>.slideshow>.offset-2,.cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2,.cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2,.slideshow__teasers .cols-3>.widget__list>.offset-2,.slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2,.slideshow__teasers [class*=" cols-"] .cols-3>.widget__list>.offset-2,.slideshow__teasers [class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2,.slideshow__teasers [class^=cols-] .cols-3>.widget__list>.offset-2,.slideshow__teasers [class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2,[class*=" cols-"] .cols-3>.row>.offset-2,[class*=" cols-"] .cols-3>.slideshow>.offset-2,[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2,[class*=" cols-"] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2,[class*=" cols-"] .slideshow__teasers .cols-3>.widget__list>.offset-2,[class*=" cols-"] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2,[class^=cols-] .cols-3>.row>.offset-2,[class^=cols-] .cols-3>.slideshow>.offset-2,[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2,[class^=cols-] .cols-3>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2,[class^=cols-] .slideshow__teasers .cols-3>.widget__list>.offset-2,[class^=cols-] .slideshow__teasers .cols-3>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2{margin-left:66.66666%}.cols-4>.row>.col-1,.cols-4>.slideshow>.col-1,.slideshow__teasers .cols-4>.widget__list>.col-1,.slideshow__teasers [class*=" cols-"] .cols-4>.widget__list>.col-1,.slideshow__teasers [class^=cols-] .cols-4>.widget__list>.col-1,[class*=" cols-"] .cols-4>.row>.col-1,[class*=" cols-"] .cols-4>.slideshow>.col-1,[class*=" cols-"] .slideshow__teasers .cols-4>.widget__list>.col-1,[class^=cols-] .cols-4>.row>.col-1,[class^=cols-] .cols-4>.slideshow>.col-1,[class^=cols-] .slideshow__teasers .cols-4>.widget__list>.col-1{width:25%}.cols-4>.row>.col-1:nth-child(2n+1),.cols-4>.slideshow>.col-1:nth-child(2n+1),.slideshow__teasers .cols-4>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-4>.widget__list>.col-1:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-4>.widget__list>.col-1:nth-child(2n+1),[class*=" cols-"] .cols-4>.row>.col-1:nth-child(2n+1),[class*=" cols-"] .cols-4>.slideshow>.col-1:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-4>.widget__list>.col-1:nth-child(2n+1),[class^=cols-] .cols-4>.row>.col-1:nth-child(2n+1),[class^=cols-] .cols-4>.slideshow>.col-1:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-4>.widget__list>.col-1:nth-child(2n+1){clear:none}.cols-4>.row>.col-2,.cols-4>.slideshow>.col-2,.slideshow__teasers .cols-4>.widget__list>.col-2,.slideshow__teasers [class*=" cols-"] .cols-4>.widget__list>.col-2,.slideshow__teasers [class^=cols-] .cols-4>.widget__list>.col-2,[class*=" cols-"] .cols-4>.row>.col-2,[class*=" cols-"] .cols-4>.slideshow>.col-2,[class*=" cols-"] .slideshow__teasers .cols-4>.widget__list>.col-2,[class^=cols-] .cols-4>.row>.col-2,[class^=cols-] .cols-4>.slideshow>.col-2,[class^=cols-] .slideshow__teasers .cols-4>.widget__list>.col-2{width:50%}.cols-4>.row>.col-3,.cols-4>.slideshow>.col-3,.slideshow__teasers .cols-4>.widget__list>.col-3,.slideshow__teasers [class*=" cols-"] .cols-4>.widget__list>.col-3,.slideshow__teasers [class^=cols-] .cols-4>.widget__list>.col-3,[class*=" cols-"] .cols-4>.row>.col-3,[class*=" cols-"] .cols-4>.slideshow>.col-3,[class*=" cols-"] .slideshow__teasers .cols-4>.widget__list>.col-3,[class^=cols-] .cols-4>.row>.col-3,[class^=cols-] .cols-4>.slideshow>.col-3,[class^=cols-] .slideshow__teasers .cols-4>.widget__list>.col-3{width:75%}.cols-4>.row>.offset-1,.cols-4>.slideshow>.offset-1,.slideshow__teasers .cols-4>.widget__list>.offset-1,.slideshow__teasers [class*=" cols-"] .cols-4>.widget__list>.offset-1,.slideshow__teasers [class^=cols-] .cols-4>.widget__list>.offset-1,[class*=" cols-"] .cols-4>.row>.offset-1,[class*=" cols-"] .cols-4>.slideshow>.offset-1,[class*=" cols-"] .slideshow__teasers .cols-4>.widget__list>.offset-1,[class^=cols-] .cols-4>.row>.offset-1,[class^=cols-] .cols-4>.slideshow>.offset-1,[class^=cols-] .slideshow__teasers .cols-4>.widget__list>.offset-1{margin-left:25%}.cols-4>.row>.offset-2,.cols-4>.slideshow>.offset-2,.slideshow__teasers .cols-4>.widget__list>.offset-2,.slideshow__teasers [class*=" cols-"] .cols-4>.widget__list>.offset-2,.slideshow__teasers [class^=cols-] .cols-4>.widget__list>.offset-2,[class*=" cols-"] .cols-4>.row>.offset-2,[class*=" cols-"] .cols-4>.slideshow>.offset-2,[class*=" cols-"] .slideshow__teasers .cols-4>.widget__list>.offset-2,[class^=cols-] .cols-4>.row>.offset-2,[class^=cols-] .cols-4>.slideshow>.offset-2,[class^=cols-] .slideshow__teasers .cols-4>.widget__list>.offset-2{margin-left:50%}.cols-4>.row>.offset-3,.cols-4>.slideshow>.offset-3,.slideshow__teasers .cols-4>.widget__list>.offset-3,.slideshow__teasers [class*=" cols-"] .cols-4>.widget__list>.offset-3,.slideshow__teasers [class^=cols-] .cols-4>.widget__list>.offset-3,[class*=" cols-"] .cols-4>.row>.offset-3,[class*=" cols-"] .cols-4>.slideshow>.offset-3,[class*=" cols-"] .slideshow__teasers .cols-4>.widget__list>.offset-3,[class^=cols-] .cols-4>.row>.offset-3,[class^=cols-] .cols-4>.slideshow>.offset-3,[class^=cols-] .slideshow__teasers .cols-4>.widget__list>.offset-3{margin-left:75%}.cols-5>.row>.col-1,.cols-5>.slideshow>.col-1,.slideshow__teasers .cols-5>.widget__list>.col-1,.slideshow__teasers [class*=" cols-"] .cols-5>.widget__list>.col-1,.slideshow__teasers [class^=cols-] .cols-5>.widget__list>.col-1,[class*=" cols-"] .cols-5>.row>.col-1,[class*=" cols-"] .cols-5>.slideshow>.col-1,[class*=" cols-"] .slideshow__teasers .cols-5>.widget__list>.col-1,[class^=cols-] .cols-5>.row>.col-1,[class^=cols-] .cols-5>.slideshow>.col-1,[class^=cols-] .slideshow__teasers .cols-5>.widget__list>.col-1{width:20%}.cols-5>.row>.col-2,.cols-5>.slideshow>.col-2,.slideshow__teasers .cols-5>.widget__list>.col-2,.slideshow__teasers [class*=" cols-"] .cols-5>.widget__list>.col-2,.slideshow__teasers [class^=cols-] .cols-5>.widget__list>.col-2,[class*=" cols-"] .cols-5>.row>.col-2,[class*=" cols-"] .cols-5>.slideshow>.col-2,[class*=" cols-"] .slideshow__teasers .cols-5>.widget__list>.col-2,[class^=cols-] .cols-5>.row>.col-2,[class^=cols-] .cols-5>.slideshow>.col-2,[class^=cols-] .slideshow__teasers .cols-5>.widget__list>.col-2{width:40%}.cols-5>.row>.col-3,.cols-5>.slideshow>.col-3,.slideshow__teasers .cols-5>.widget__list>.col-3,.slideshow__teasers [class*=" cols-"] .cols-5>.widget__list>.col-3,.slideshow__teasers [class^=cols-] .cols-5>.widget__list>.col-3,[class*=" cols-"] .cols-5>.row>.col-3,[class*=" cols-"] .cols-5>.slideshow>.col-3,[class*=" cols-"] .slideshow__teasers .cols-5>.widget__list>.col-3,[class^=cols-] .cols-5>.row>.col-3,[class^=cols-] .cols-5>.slideshow>.col-3,[class^=cols-] .slideshow__teasers .cols-5>.widget__list>.col-3{width:60%}.cols-5>.row>.col-4,.cols-5>.slideshow>.col-4,.slideshow__teasers .cols-5>.widget__list>.col-4,.slideshow__teasers [class*=" cols-"] .cols-5>.widget__list>.col-4,.slideshow__teasers [class^=cols-] .cols-5>.widget__list>.col-4,[class*=" cols-"] .cols-5>.row>.col-4,[class*=" cols-"] .cols-5>.slideshow>.col-4,[class*=" cols-"] .slideshow__teasers .cols-5>.widget__list>.col-4,[class^=cols-] .cols-5>.row>.col-4,[class^=cols-] .cols-5>.slideshow>.col-4,[class^=cols-] .slideshow__teasers .cols-5>.widget__list>.col-4{width:80%}.cols-5>.row>.offset-1,.cols-5>.slideshow>.offset-1,.slideshow__teasers .cols-5>.widget__list>.offset-1,.slideshow__teasers [class*=" cols-"] .cols-5>.widget__list>.offset-1,.slideshow__teasers [class^=cols-] .cols-5>.widget__list>.offset-1,[class*=" cols-"] .cols-5>.row>.offset-1,[class*=" cols-"] .cols-5>.slideshow>.offset-1,[class*=" cols-"] .slideshow__teasers .cols-5>.widget__list>.offset-1,[class^=cols-] .cols-5>.row>.offset-1,[class^=cols-] .cols-5>.slideshow>.offset-1,[class^=cols-] .slideshow__teasers .cols-5>.widget__list>.offset-1{margin-left:20%}.cols-5>.row>.offset-2,.cols-5>.slideshow>.offset-2,.slideshow__teasers .cols-5>.widget__list>.offset-2,.slideshow__teasers [class*=" cols-"] .cols-5>.widget__list>.offset-2,.slideshow__teasers [class^=cols-] .cols-5>.widget__list>.offset-2,[class*=" cols-"] .cols-5>.row>.offset-2,[class*=" cols-"] .cols-5>.slideshow>.offset-2,[class*=" cols-"] .slideshow__teasers .cols-5>.widget__list>.offset-2,[class^=cols-] .cols-5>.row>.offset-2,[class^=cols-] .cols-5>.slideshow>.offset-2,[class^=cols-] .slideshow__teasers .cols-5>.widget__list>.offset-2{margin-left:40%}.cols-5>.row>.offset-3,.cols-5>.slideshow>.offset-3,.slideshow__teasers .cols-5>.widget__list>.offset-3,.slideshow__teasers [class*=" cols-"] .cols-5>.widget__list>.offset-3,.slideshow__teasers [class^=cols-] .cols-5>.widget__list>.offset-3,[class*=" cols-"] .cols-5>.row>.offset-3,[class*=" cols-"] .cols-5>.slideshow>.offset-3,[class*=" cols-"] .slideshow__teasers .cols-5>.widget__list>.offset-3,[class^=cols-] .cols-5>.row>.offset-3,[class^=cols-] .cols-5>.slideshow>.offset-3,[class^=cols-] .slideshow__teasers .cols-5>.widget__list>.offset-3{margin-left:60%}.cols-5>.row>.offset-4,.cols-5>.slideshow>.offset-4,.slideshow__teasers .cols-5>.widget__list>.offset-4,.slideshow__teasers [class*=" cols-"] .cols-5>.widget__list>.offset-4,.slideshow__teasers [class^=cols-] .cols-5>.widget__list>.offset-4,[class*=" cols-"] .cols-5>.row>.offset-4,[class*=" cols-"] .cols-5>.slideshow>.offset-4,[class*=" cols-"] .slideshow__teasers .cols-5>.widget__list>.offset-4,[class^=cols-] .cols-5>.row>.offset-4,[class^=cols-] .cols-5>.slideshow>.offset-4,[class^=cols-] .slideshow__teasers .cols-5>.widget__list>.offset-4{margin-left:80%}.cols-6>.row>.col-1,.cols-6>.slideshow>.col-1,.slideshow__teasers .cols-6>.widget__list>.col-1,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.col-1,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.col-1,[class*=" cols-"] .cols-6>.row>.col-1,[class*=" cols-"] .cols-6>.slideshow>.col-1,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.col-1,[class^=cols-] .cols-6>.row>.col-1,[class^=cols-] .cols-6>.slideshow>.col-1,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.col-1{width:16.66666%}.cols-6>.row>.col-1:nth-child(3n+1),.cols-6>.slideshow>.col-1:nth-child(3n+1),.slideshow__teasers .cols-6>.widget__list>.col-1:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.col-1:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.col-1:nth-child(3n+1),[class*=" cols-"] .cols-6>.row>.col-1:nth-child(3n+1),[class*=" cols-"] .cols-6>.slideshow>.col-1:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.col-1:nth-child(3n+1),[class^=cols-] .cols-6>.row>.col-1:nth-child(3n+1),[class^=cols-] .cols-6>.slideshow>.col-1:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.col-1:nth-child(3n+1){clear:none}.cols-6>.row>.col-2,.cols-6>.slideshow>.col-2,.slideshow__teasers .cols-6>.widget__list>.col-2,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.col-2,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.col-2,[class*=" cols-"] .cols-6>.row>.col-2,[class*=" cols-"] .cols-6>.slideshow>.col-2,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.col-2,[class^=cols-] .cols-6>.row>.col-2,[class^=cols-] .cols-6>.slideshow>.col-2,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.col-2{width:33.33332%}.cols-6>.row>.col-3,.cols-6>.slideshow>.col-3,.slideshow__teasers .cols-6>.widget__list>.col-3,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.col-3,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.col-3,[class*=" cols-"] .cols-6>.row>.col-3,[class*=" cols-"] .cols-6>.slideshow>.col-3,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.col-3,[class^=cols-] .cols-6>.row>.col-3,[class^=cols-] .cols-6>.slideshow>.col-3,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.col-3{width:50%}.cols-6>.row>.col-4,.cols-6>.slideshow>.col-4,.slideshow__teasers .cols-6>.widget__list>.col-4,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.col-4,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.col-4,[class*=" cols-"] .cols-6>.row>.col-4,[class*=" cols-"] .cols-6>.slideshow>.col-4,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.col-4,[class^=cols-] .cols-6>.row>.col-4,[class^=cols-] .cols-6>.slideshow>.col-4,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.col-4{width:66.66666%}.cols-6>.row>.col-5,.cols-6>.slideshow>.col-5,.slideshow__teasers .cols-6>.widget__list>.col-5,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.col-5,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.col-5,[class*=" cols-"] .cols-6>.row>.col-5,[class*=" cols-"] .cols-6>.slideshow>.col-5,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.col-5,[class^=cols-] .cols-6>.row>.col-5,[class^=cols-] .cols-6>.slideshow>.col-5,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.col-5{width:83.33333%}.cols-6>.row>.offset-1,.cols-6>.slideshow>.offset-1,.slideshow__teasers .cols-6>.widget__list>.offset-1,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.offset-1,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.offset-1,[class*=" cols-"] .cols-6>.row>.offset-1,[class*=" cols-"] .cols-6>.slideshow>.offset-1,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.offset-1,[class^=cols-] .cols-6>.row>.offset-1,[class^=cols-] .cols-6>.slideshow>.offset-1,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.offset-1{margin-left:16.66666%}.cols-6>.row>.offset-2,.cols-6>.slideshow>.offset-2,.slideshow__teasers .cols-6>.widget__list>.offset-2,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.offset-2,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.offset-2,[class*=" cols-"] .cols-6>.row>.offset-2,[class*=" cols-"] .cols-6>.slideshow>.offset-2,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.offset-2,[class^=cols-] .cols-6>.row>.offset-2,[class^=cols-] .cols-6>.slideshow>.offset-2,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.offset-2{margin-left:33.33332%}.cols-6>.row>.offset-3,.cols-6>.slideshow>.offset-3,.slideshow__teasers .cols-6>.widget__list>.offset-3,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.offset-3,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.offset-3,[class*=" cols-"] .cols-6>.row>.offset-3,[class*=" cols-"] .cols-6>.slideshow>.offset-3,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.offset-3,[class^=cols-] .cols-6>.row>.offset-3,[class^=cols-] .cols-6>.slideshow>.offset-3,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.offset-3{margin-left:50%}.cols-6>.row>.offset-4,.cols-6>.slideshow>.offset-4,.slideshow__teasers .cols-6>.widget__list>.offset-4,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.offset-4,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.offset-4,[class*=" cols-"] .cols-6>.row>.offset-4,[class*=" cols-"] .cols-6>.slideshow>.offset-4,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.offset-4,[class^=cols-] .cols-6>.row>.offset-4,[class^=cols-] .cols-6>.slideshow>.offset-4,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.offset-4{margin-left:66.66666%}.cols-6>.row>.offset-5,.cols-6>.slideshow>.offset-5,.slideshow__teasers .cols-6>.widget__list>.offset-5,.slideshow__teasers [class*=" cols-"] .cols-6>.widget__list>.offset-5,.slideshow__teasers [class^=cols-] .cols-6>.widget__list>.offset-5,[class*=" cols-"] .cols-6>.row>.offset-5,[class*=" cols-"] .cols-6>.slideshow>.offset-5,[class*=" cols-"] .slideshow__teasers .cols-6>.widget__list>.offset-5,[class^=cols-] .cols-6>.row>.offset-5,[class^=cols-] .cols-6>.slideshow>.offset-5,[class^=cols-] .slideshow__teasers .cols-6>.widget__list>.offset-5{margin-left:83.33333%}}@media screen and (min-width:48em){.cols-2--tablet>.row>.col-1--tablet,.cols-2--tablet>.slideshow>.col-1--tablet,.slideshow__teasers .cols-2--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-2--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class^=cols-] .cols-2--tablet>.widget__list>.col-1--tablet,[class*=" cols-"] .cols-2--tablet>.row>.col-1--tablet,[class*=" cols-"] .cols-2--tablet>.slideshow>.col-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-2--tablet>.widget__list>.col-1--tablet,[class^=cols-] .cols-2--tablet>.row>.col-1--tablet,[class^=cols-] .cols-2--tablet>.slideshow>.col-1--tablet,[class^=cols-] .slideshow__teasers .cols-2--tablet>.widget__list>.col-1--tablet{width:50%}.cols-2--tablet>.row>.col-1--tablet:nth-child(2n+1),.cols-2--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),.slideshow__teasers .cols-2--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-2--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-2--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .cols-2--tablet>.row>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .cols-2--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-2--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),[class^=cols-] .cols-2--tablet>.row>.col-1--tablet:nth-child(2n+1),[class^=cols-] .cols-2--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-2--tablet>.widget__list>.col-1--tablet:nth-child(2n+1){clear:both}.cols-3--tablet>.row>.col-1--tablet,.cols-3--tablet>.slideshow>.col-1--tablet,.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet,.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet,.slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet,.slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-3--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet,.slideshow__teasers [class^=cols-] .cols-3--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet,[class*=" cols-"] .cols-3--tablet>.row>.col-1--tablet,[class*=" cols-"] .cols-3--tablet>.slideshow>.col-1--tablet,[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet,[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet,[class^=cols-] .cols-3--tablet>.row>.col-1--tablet,[class^=cols-] .cols-3--tablet>.slideshow>.col-1--tablet,[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet,[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet,[class^=cols-] .slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet,[class^=cols-] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet{width:33.33333%}.cols-3--tablet>.row>.col-1--tablet:nth-child(2n+1),.cols-3--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet:nth-child(2n+1),.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet:nth-child(2n+1),.slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .cols-3--tablet>.row>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .cols-3--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(2n+1),[class^=cols-] .cols-3--tablet>.row>.col-1--tablet:nth-child(2n+1),[class^=cols-] .cols-3--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet:nth-child(2n+1),[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(2n+1){clear:none}.cols-3--tablet>.row>.col-1--tablet:nth-child(3n+1),.cols-3--tablet>.slideshow>.col-1--tablet:nth-child(3n+1),.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet:nth-child(3n+1),.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet:nth-child(3n+1),.slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),.slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .cols-3--tablet>.row>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .cols-3--tablet>.slideshow>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(3n+1),[class^=cols-] .cols-3--tablet>.row>.col-1--tablet:nth-child(3n+1),[class^=cols-] .cols-3--tablet>.slideshow>.col-1--tablet:nth-child(3n+1),[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--tablet:nth-child(3n+1),[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--tablet:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--tablet:nth-child(3n+1){clear:both}.cols-3--tablet>.row>.col-2--tablet,.cols-3--tablet>.slideshow>.col-2--tablet,.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--tablet,.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--tablet,.slideshow__teasers .cols-3--tablet>.widget__list>.col-2--tablet,.slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-3--tablet>.widget__list>.col-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--tablet,.slideshow__teasers [class^=cols-] .cols-3--tablet>.widget__list>.col-2--tablet,.slideshow__teasers [class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--tablet,[class*=" cols-"] .cols-3--tablet>.row>.col-2--tablet,[class*=" cols-"] .cols-3--tablet>.slideshow>.col-2--tablet,[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--tablet,[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-3--tablet>.widget__list>.col-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--tablet,[class^=cols-] .cols-3--tablet>.row>.col-2--tablet,[class^=cols-] .cols-3--tablet>.slideshow>.col-2--tablet,[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--tablet,[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--tablet,[class^=cols-] .slideshow__teasers .cols-3--tablet>.widget__list>.col-2--tablet,[class^=cols-] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--tablet{width:66.66666%}.cols-3--tablet>.row>.offset-1--tablet,.cols-3--tablet>.slideshow>.offset-1--tablet,.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--tablet,.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--tablet,.slideshow__teasers .cols-3--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-3--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--tablet,.slideshow__teasers [class^=cols-] .cols-3--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers [class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--tablet,[class*=" cols-"] .cols-3--tablet>.row>.offset-1--tablet,[class*=" cols-"] .cols-3--tablet>.slideshow>.offset-1--tablet,[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--tablet,[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-3--tablet>.widget__list>.offset-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--tablet,[class^=cols-] .cols-3--tablet>.row>.offset-1--tablet,[class^=cols-] .cols-3--tablet>.slideshow>.offset-1--tablet,[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--tablet,[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--tablet,[class^=cols-] .slideshow__teasers .cols-3--tablet>.widget__list>.offset-1--tablet,[class^=cols-] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--tablet{margin-left:33.33333%}.cols-3--tablet>.row>.offset-2--tablet,.cols-3--tablet>.slideshow>.offset-2--tablet,.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--tablet,.cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--tablet,.slideshow__teasers .cols-3--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-3--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--tablet,.slideshow__teasers [class^=cols-] .cols-3--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers [class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--tablet,[class*=" cols-"] .cols-3--tablet>.row>.offset-2--tablet,[class*=" cols-"] .cols-3--tablet>.slideshow>.offset-2--tablet,[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--tablet,[class*=" cols-"] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-3--tablet>.widget__list>.offset-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--tablet,[class^=cols-] .cols-3--tablet>.row>.offset-2--tablet,[class^=cols-] .cols-3--tablet>.slideshow>.offset-2--tablet,[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--tablet,[class^=cols-] .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--tablet,[class^=cols-] .slideshow__teasers .cols-3--tablet>.widget__list>.offset-2--tablet,[class^=cols-] .slideshow__teasers .cols-3--tablet>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--tablet{margin-left:66.66666%}.cols-4--tablet>.row>.col-1--tablet,.cols-4--tablet>.slideshow>.col-1--tablet,.slideshow__teasers .cols-4--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-4--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class^=cols-] .cols-4--tablet>.widget__list>.col-1--tablet,[class*=" cols-"] .cols-4--tablet>.row>.col-1--tablet,[class*=" cols-"] .cols-4--tablet>.slideshow>.col-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-4--tablet>.widget__list>.col-1--tablet,[class^=cols-] .cols-4--tablet>.row>.col-1--tablet,[class^=cols-] .cols-4--tablet>.slideshow>.col-1--tablet,[class^=cols-] .slideshow__teasers .cols-4--tablet>.widget__list>.col-1--tablet{width:25%}.cols-4--tablet>.row>.col-1--tablet:nth-child(2n+1),.cols-4--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),.slideshow__teasers .cols-4--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-4--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-4--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .cols-4--tablet>.row>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .cols-4--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-4--tablet>.widget__list>.col-1--tablet:nth-child(2n+1),[class^=cols-] .cols-4--tablet>.row>.col-1--tablet:nth-child(2n+1),[class^=cols-] .cols-4--tablet>.slideshow>.col-1--tablet:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-4--tablet>.widget__list>.col-1--tablet:nth-child(2n+1){clear:none}.cols-4--tablet>.row>.col-2--tablet,.cols-4--tablet>.slideshow>.col-2--tablet,.slideshow__teasers .cols-4--tablet>.widget__list>.col-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-4--tablet>.widget__list>.col-2--tablet,.slideshow__teasers [class^=cols-] .cols-4--tablet>.widget__list>.col-2--tablet,[class*=" cols-"] .cols-4--tablet>.row>.col-2--tablet,[class*=" cols-"] .cols-4--tablet>.slideshow>.col-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-4--tablet>.widget__list>.col-2--tablet,[class^=cols-] .cols-4--tablet>.row>.col-2--tablet,[class^=cols-] .cols-4--tablet>.slideshow>.col-2--tablet,[class^=cols-] .slideshow__teasers .cols-4--tablet>.widget__list>.col-2--tablet{width:50%}.cols-4--tablet>.row>.col-3--tablet,.cols-4--tablet>.slideshow>.col-3--tablet,.slideshow__teasers .cols-4--tablet>.widget__list>.col-3--tablet,.slideshow__teasers [class*=" cols-"] .cols-4--tablet>.widget__list>.col-3--tablet,.slideshow__teasers [class^=cols-] .cols-4--tablet>.widget__list>.col-3--tablet,[class*=" cols-"] .cols-4--tablet>.row>.col-3--tablet,[class*=" cols-"] .cols-4--tablet>.slideshow>.col-3--tablet,[class*=" cols-"] .slideshow__teasers .cols-4--tablet>.widget__list>.col-3--tablet,[class^=cols-] .cols-4--tablet>.row>.col-3--tablet,[class^=cols-] .cols-4--tablet>.slideshow>.col-3--tablet,[class^=cols-] .slideshow__teasers .cols-4--tablet>.widget__list>.col-3--tablet{width:75%}.cols-4--tablet>.row>.offset-1--tablet,.cols-4--tablet>.slideshow>.offset-1--tablet,.slideshow__teasers .cols-4--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-4--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers [class^=cols-] .cols-4--tablet>.widget__list>.offset-1--tablet,[class*=" cols-"] .cols-4--tablet>.row>.offset-1--tablet,[class*=" cols-"] .cols-4--tablet>.slideshow>.offset-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-4--tablet>.widget__list>.offset-1--tablet,[class^=cols-] .cols-4--tablet>.row>.offset-1--tablet,[class^=cols-] .cols-4--tablet>.slideshow>.offset-1--tablet,[class^=cols-] .slideshow__teasers .cols-4--tablet>.widget__list>.offset-1--tablet{margin-left:25%}.cols-4--tablet>.row>.offset-2--tablet,.cols-4--tablet>.slideshow>.offset-2--tablet,.slideshow__teasers .cols-4--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-4--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers [class^=cols-] .cols-4--tablet>.widget__list>.offset-2--tablet,[class*=" cols-"] .cols-4--tablet>.row>.offset-2--tablet,[class*=" cols-"] .cols-4--tablet>.slideshow>.offset-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-4--tablet>.widget__list>.offset-2--tablet,[class^=cols-] .cols-4--tablet>.row>.offset-2--tablet,[class^=cols-] .cols-4--tablet>.slideshow>.offset-2--tablet,[class^=cols-] .slideshow__teasers .cols-4--tablet>.widget__list>.offset-2--tablet{margin-left:50%}.cols-4--tablet>.row>.offset-3--tablet,.cols-4--tablet>.slideshow>.offset-3--tablet,.slideshow__teasers .cols-4--tablet>.widget__list>.offset-3--tablet,.slideshow__teasers [class*=" cols-"] .cols-4--tablet>.widget__list>.offset-3--tablet,.slideshow__teasers [class^=cols-] .cols-4--tablet>.widget__list>.offset-3--tablet,[class*=" cols-"] .cols-4--tablet>.row>.offset-3--tablet,[class*=" cols-"] .cols-4--tablet>.slideshow>.offset-3--tablet,[class*=" cols-"] .slideshow__teasers .cols-4--tablet>.widget__list>.offset-3--tablet,[class^=cols-] .cols-4--tablet>.row>.offset-3--tablet,[class^=cols-] .cols-4--tablet>.slideshow>.offset-3--tablet,[class^=cols-] .slideshow__teasers .cols-4--tablet>.widget__list>.offset-3--tablet{margin-left:75%}.cols-5--tablet>.row>.col-1--tablet,.cols-5--tablet>.slideshow>.col-1--tablet,.slideshow__teasers .cols-5--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-5--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class^=cols-] .cols-5--tablet>.widget__list>.col-1--tablet,[class*=" cols-"] .cols-5--tablet>.row>.col-1--tablet,[class*=" cols-"] .cols-5--tablet>.slideshow>.col-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-5--tablet>.widget__list>.col-1--tablet,[class^=cols-] .cols-5--tablet>.row>.col-1--tablet,[class^=cols-] .cols-5--tablet>.slideshow>.col-1--tablet,[class^=cols-] .slideshow__teasers .cols-5--tablet>.widget__list>.col-1--tablet{width:20%}.cols-5--tablet>.row>.col-2--tablet,.cols-5--tablet>.slideshow>.col-2--tablet,.slideshow__teasers .cols-5--tablet>.widget__list>.col-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-5--tablet>.widget__list>.col-2--tablet,.slideshow__teasers [class^=cols-] .cols-5--tablet>.widget__list>.col-2--tablet,[class*=" cols-"] .cols-5--tablet>.row>.col-2--tablet,[class*=" cols-"] .cols-5--tablet>.slideshow>.col-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-5--tablet>.widget__list>.col-2--tablet,[class^=cols-] .cols-5--tablet>.row>.col-2--tablet,[class^=cols-] .cols-5--tablet>.slideshow>.col-2--tablet,[class^=cols-] .slideshow__teasers .cols-5--tablet>.widget__list>.col-2--tablet{width:40%}.cols-5--tablet>.row>.col-3--tablet,.cols-5--tablet>.slideshow>.col-3--tablet,.slideshow__teasers .cols-5--tablet>.widget__list>.col-3--tablet,.slideshow__teasers [class*=" cols-"] .cols-5--tablet>.widget__list>.col-3--tablet,.slideshow__teasers [class^=cols-] .cols-5--tablet>.widget__list>.col-3--tablet,[class*=" cols-"] .cols-5--tablet>.row>.col-3--tablet,[class*=" cols-"] .cols-5--tablet>.slideshow>.col-3--tablet,[class*=" cols-"] .slideshow__teasers .cols-5--tablet>.widget__list>.col-3--tablet,[class^=cols-] .cols-5--tablet>.row>.col-3--tablet,[class^=cols-] .cols-5--tablet>.slideshow>.col-3--tablet,[class^=cols-] .slideshow__teasers .cols-5--tablet>.widget__list>.col-3--tablet{width:60%}.cols-5--tablet>.row>.col-4--tablet,.cols-5--tablet>.slideshow>.col-4--tablet,.slideshow__teasers .cols-5--tablet>.widget__list>.col-4--tablet,.slideshow__teasers [class*=" cols-"] .cols-5--tablet>.widget__list>.col-4--tablet,.slideshow__teasers [class^=cols-] .cols-5--tablet>.widget__list>.col-4--tablet,[class*=" cols-"] .cols-5--tablet>.row>.col-4--tablet,[class*=" cols-"] .cols-5--tablet>.slideshow>.col-4--tablet,[class*=" cols-"] .slideshow__teasers .cols-5--tablet>.widget__list>.col-4--tablet,[class^=cols-] .cols-5--tablet>.row>.col-4--tablet,[class^=cols-] .cols-5--tablet>.slideshow>.col-4--tablet,[class^=cols-] .slideshow__teasers .cols-5--tablet>.widget__list>.col-4--tablet{width:80%}.cols-5--tablet>.row>.offset-1--tablet,.cols-5--tablet>.slideshow>.offset-1--tablet,.slideshow__teasers .cols-5--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-5--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers [class^=cols-] .cols-5--tablet>.widget__list>.offset-1--tablet,[class*=" cols-"] .cols-5--tablet>.row>.offset-1--tablet,[class*=" cols-"] .cols-5--tablet>.slideshow>.offset-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-5--tablet>.widget__list>.offset-1--tablet,[class^=cols-] .cols-5--tablet>.row>.offset-1--tablet,[class^=cols-] .cols-5--tablet>.slideshow>.offset-1--tablet,[class^=cols-] .slideshow__teasers .cols-5--tablet>.widget__list>.offset-1--tablet{margin-left:20%}.cols-5--tablet>.row>.offset-2--tablet,.cols-5--tablet>.slideshow>.offset-2--tablet,.slideshow__teasers .cols-5--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-5--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers [class^=cols-] .cols-5--tablet>.widget__list>.offset-2--tablet,[class*=" cols-"] .cols-5--tablet>.row>.offset-2--tablet,[class*=" cols-"] .cols-5--tablet>.slideshow>.offset-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-5--tablet>.widget__list>.offset-2--tablet,[class^=cols-] .cols-5--tablet>.row>.offset-2--tablet,[class^=cols-] .cols-5--tablet>.slideshow>.offset-2--tablet,[class^=cols-] .slideshow__teasers .cols-5--tablet>.widget__list>.offset-2--tablet{margin-left:40%}.cols-5--tablet>.row>.offset-3--tablet,.cols-5--tablet>.slideshow>.offset-3--tablet,.slideshow__teasers .cols-5--tablet>.widget__list>.offset-3--tablet,.slideshow__teasers [class*=" cols-"] .cols-5--tablet>.widget__list>.offset-3--tablet,.slideshow__teasers [class^=cols-] .cols-5--tablet>.widget__list>.offset-3--tablet,[class*=" cols-"] .cols-5--tablet>.row>.offset-3--tablet,[class*=" cols-"] .cols-5--tablet>.slideshow>.offset-3--tablet,[class*=" cols-"] .slideshow__teasers .cols-5--tablet>.widget__list>.offset-3--tablet,[class^=cols-] .cols-5--tablet>.row>.offset-3--tablet,[class^=cols-] .cols-5--tablet>.slideshow>.offset-3--tablet,[class^=cols-] .slideshow__teasers .cols-5--tablet>.widget__list>.offset-3--tablet{margin-left:60%}.cols-5--tablet>.row>.offset-4--tablet,.cols-5--tablet>.slideshow>.offset-4--tablet,.slideshow__teasers .cols-5--tablet>.widget__list>.offset-4--tablet,.slideshow__teasers [class*=" cols-"] .cols-5--tablet>.widget__list>.offset-4--tablet,.slideshow__teasers [class^=cols-] .cols-5--tablet>.widget__list>.offset-4--tablet,[class*=" cols-"] .cols-5--tablet>.row>.offset-4--tablet,[class*=" cols-"] .cols-5--tablet>.slideshow>.offset-4--tablet,[class*=" cols-"] .slideshow__teasers .cols-5--tablet>.widget__list>.offset-4--tablet,[class^=cols-] .cols-5--tablet>.row>.offset-4--tablet,[class^=cols-] .cols-5--tablet>.slideshow>.offset-4--tablet,[class^=cols-] .slideshow__teasers .cols-5--tablet>.widget__list>.offset-4--tablet{margin-left:80%}.cols-6--tablet>.row>.col-1--tablet,.cols-6--tablet>.slideshow>.col-1--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.col-1--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.col-1--tablet,[class*=" cols-"] .cols-6--tablet>.row>.col-1--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.col-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.col-1--tablet,[class^=cols-] .cols-6--tablet>.row>.col-1--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.col-1--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.col-1--tablet{width:16.66666%}.cols-6--tablet>.row>.col-1--tablet:nth-child(3n+1),.cols-6--tablet>.slideshow>.col-1--tablet:nth-child(3n+1),.slideshow__teasers .cols-6--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .cols-6--tablet>.row>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .cols-6--tablet>.slideshow>.col-1--tablet:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.col-1--tablet:nth-child(3n+1),[class^=cols-] .cols-6--tablet>.row>.col-1--tablet:nth-child(3n+1),[class^=cols-] .cols-6--tablet>.slideshow>.col-1--tablet:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.col-1--tablet:nth-child(3n+1){clear:none}.cols-6--tablet>.row>.col-2--tablet,.cols-6--tablet>.slideshow>.col-2--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.col-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.col-2--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.col-2--tablet,[class*=" cols-"] .cols-6--tablet>.row>.col-2--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.col-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.col-2--tablet,[class^=cols-] .cols-6--tablet>.row>.col-2--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.col-2--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.col-2--tablet{width:33.33332%}.cols-6--tablet>.row>.col-3--tablet,.cols-6--tablet>.slideshow>.col-3--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.col-3--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.col-3--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.col-3--tablet,[class*=" cols-"] .cols-6--tablet>.row>.col-3--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.col-3--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.col-3--tablet,[class^=cols-] .cols-6--tablet>.row>.col-3--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.col-3--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.col-3--tablet{width:50%}.cols-6--tablet>.row>.col-4--tablet,.cols-6--tablet>.slideshow>.col-4--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.col-4--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.col-4--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.col-4--tablet,[class*=" cols-"] .cols-6--tablet>.row>.col-4--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.col-4--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.col-4--tablet,[class^=cols-] .cols-6--tablet>.row>.col-4--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.col-4--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.col-4--tablet{width:66.66666%}.cols-6--tablet>.row>.col-5--tablet,.cols-6--tablet>.slideshow>.col-5--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.col-5--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.col-5--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.col-5--tablet,[class*=" cols-"] .cols-6--tablet>.row>.col-5--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.col-5--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.col-5--tablet,[class^=cols-] .cols-6--tablet>.row>.col-5--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.col-5--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.col-5--tablet{width:83.33333%}.cols-6--tablet>.row>.offset-1--tablet,.cols-6--tablet>.slideshow>.offset-1--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.offset-1--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.offset-1--tablet,[class*=" cols-"] .cols-6--tablet>.row>.offset-1--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.offset-1--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-1--tablet,[class^=cols-] .cols-6--tablet>.row>.offset-1--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.offset-1--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-1--tablet{margin-left:16.66666%}.cols-6--tablet>.row>.offset-2--tablet,.cols-6--tablet>.slideshow>.offset-2--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.offset-2--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.offset-2--tablet,[class*=" cols-"] .cols-6--tablet>.row>.offset-2--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.offset-2--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-2--tablet,[class^=cols-] .cols-6--tablet>.row>.offset-2--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.offset-2--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-2--tablet{margin-left:33.33332%}.cols-6--tablet>.row>.offset-3--tablet,.cols-6--tablet>.slideshow>.offset-3--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.offset-3--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.offset-3--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.offset-3--tablet,[class*=" cols-"] .cols-6--tablet>.row>.offset-3--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.offset-3--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-3--tablet,[class^=cols-] .cols-6--tablet>.row>.offset-3--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.offset-3--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-3--tablet{margin-left:50%}.cols-6--tablet>.row>.offset-4--tablet,.cols-6--tablet>.slideshow>.offset-4--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.offset-4--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.offset-4--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.offset-4--tablet,[class*=" cols-"] .cols-6--tablet>.row>.offset-4--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.offset-4--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-4--tablet,[class^=cols-] .cols-6--tablet>.row>.offset-4--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.offset-4--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-4--tablet{margin-left:66.66666%}.cols-6--tablet>.row>.offset-5--tablet,.cols-6--tablet>.slideshow>.offset-5--tablet,.slideshow__teasers .cols-6--tablet>.widget__list>.offset-5--tablet,.slideshow__teasers [class*=" cols-"] .cols-6--tablet>.widget__list>.offset-5--tablet,.slideshow__teasers [class^=cols-] .cols-6--tablet>.widget__list>.offset-5--tablet,[class*=" cols-"] .cols-6--tablet>.row>.offset-5--tablet,[class*=" cols-"] .cols-6--tablet>.slideshow>.offset-5--tablet,[class*=" cols-"] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-5--tablet,[class^=cols-] .cols-6--tablet>.row>.offset-5--tablet,[class^=cols-] .cols-6--tablet>.slideshow>.offset-5--tablet,[class^=cols-] .slideshow__teasers .cols-6--tablet>.widget__list>.offset-5--tablet{margin-left:83.33333%}}@media screen and (min-width:62.1875em){.cols-2--desktop>.row>.col-1--desktop,.cols-2--desktop>.slideshow>.col-1--desktop,.slideshow__teasers .cols-2--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-2--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class^=cols-] .cols-2--desktop>.widget__list>.col-1--desktop,[class*=" cols-"] .cols-2--desktop>.row>.col-1--desktop,[class*=" cols-"] .cols-2--desktop>.slideshow>.col-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-2--desktop>.widget__list>.col-1--desktop,[class^=cols-] .cols-2--desktop>.row>.col-1--desktop,[class^=cols-] .cols-2--desktop>.slideshow>.col-1--desktop,[class^=cols-] .slideshow__teasers .cols-2--desktop>.widget__list>.col-1--desktop{width:50%}.cols-2--desktop>.row>.col-1--desktop:nth-child(2n+1),.cols-2--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),.slideshow__teasers .cols-2--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-2--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-2--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .cols-2--desktop>.row>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .cols-2--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-2--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),[class^=cols-] .cols-2--desktop>.row>.col-1--desktop:nth-child(2n+1),[class^=cols-] .cols-2--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-2--desktop>.widget__list>.col-1--desktop:nth-child(2n+1){clear:both}.cols-3--desktop>.row>.col-1--desktop,.cols-3--desktop>.slideshow>.col-1--desktop,.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop,.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop,.slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop,.slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-3--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop,.slideshow__teasers [class^=cols-] .cols-3--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop,[class*=" cols-"] .cols-3--desktop>.row>.col-1--desktop,[class*=" cols-"] .cols-3--desktop>.slideshow>.col-1--desktop,[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop,[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop,[class^=cols-] .cols-3--desktop>.row>.col-1--desktop,[class^=cols-] .cols-3--desktop>.slideshow>.col-1--desktop,[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop,[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop,[class^=cols-] .slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop,[class^=cols-] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop{width:33.33333%}.cols-3--desktop>.row>.col-1--desktop:nth-child(2n+1),.cols-3--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop:nth-child(2n+1),.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop:nth-child(2n+1),.slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .cols-3--desktop>.row>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .cols-3--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(2n+1),[class^=cols-] .cols-3--desktop>.row>.col-1--desktop:nth-child(2n+1),[class^=cols-] .cols-3--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop:nth-child(2n+1),[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(2n+1){clear:none}.cols-3--desktop>.row>.col-1--desktop:nth-child(3n+1),.cols-3--desktop>.slideshow>.col-1--desktop:nth-child(3n+1),.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop:nth-child(3n+1),.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop:nth-child(3n+1),.slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),.slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .cols-3--desktop>.row>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .cols-3--desktop>.slideshow>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(3n+1),[class^=cols-] .cols-3--desktop>.row>.col-1--desktop:nth-child(3n+1),[class^=cols-] .cols-3--desktop>.slideshow>.col-1--desktop:nth-child(3n+1),[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-1--desktop:nth-child(3n+1),[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-1--desktop:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-1--desktop:nth-child(3n+1){clear:both}.cols-3--desktop>.row>.col-2--desktop,.cols-3--desktop>.slideshow>.col-2--desktop,.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--desktop,.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--desktop,.slideshow__teasers .cols-3--desktop>.widget__list>.col-2--desktop,.slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-3--desktop>.widget__list>.col-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--desktop,.slideshow__teasers [class^=cols-] .cols-3--desktop>.widget__list>.col-2--desktop,.slideshow__teasers [class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--desktop,[class*=" cols-"] .cols-3--desktop>.row>.col-2--desktop,[class*=" cols-"] .cols-3--desktop>.slideshow>.col-2--desktop,[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--desktop,[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-3--desktop>.widget__list>.col-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--desktop,[class^=cols-] .cols-3--desktop>.row>.col-2--desktop,[class^=cols-] .cols-3--desktop>.slideshow>.col-2--desktop,[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.col-2--desktop,[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.col-2--desktop,[class^=cols-] .slideshow__teasers .cols-3--desktop>.widget__list>.col-2--desktop,[class^=cols-] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.col-2--desktop{width:66.66666%}.cols-3--desktop>.row>.offset-1--desktop,.cols-3--desktop>.slideshow>.offset-1--desktop,.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--desktop,.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--desktop,.slideshow__teasers .cols-3--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-3--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--desktop,.slideshow__teasers [class^=cols-] .cols-3--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers [class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--desktop,[class*=" cols-"] .cols-3--desktop>.row>.offset-1--desktop,[class*=" cols-"] .cols-3--desktop>.slideshow>.offset-1--desktop,[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--desktop,[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-3--desktop>.widget__list>.offset-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--desktop,[class^=cols-] .cols-3--desktop>.row>.offset-1--desktop,[class^=cols-] .cols-3--desktop>.slideshow>.offset-1--desktop,[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.offset-1--desktop,[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-1--desktop,[class^=cols-] .slideshow__teasers .cols-3--desktop>.widget__list>.offset-1--desktop,[class^=cols-] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-1--desktop{margin-left:33.33333%}.cols-3--desktop>.row>.offset-2--desktop,.cols-3--desktop>.slideshow>.offset-2--desktop,.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--desktop,.cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--desktop,.slideshow__teasers .cols-3--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-3--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--desktop,.slideshow__teasers [class^=cols-] .cols-3--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers [class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--desktop,[class*=" cols-"] .cols-3--desktop>.row>.offset-2--desktop,[class*=" cols-"] .cols-3--desktop>.slideshow>.offset-2--desktop,[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--desktop,[class*=" cols-"] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-3--desktop>.widget__list>.offset-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--desktop,[class^=cols-] .cols-3--desktop>.row>.offset-2--desktop,[class^=cols-] .cols-3--desktop>.slideshow>.offset-2--desktop,[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.row>.offset-2--desktop,[class^=cols-] .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.slideshow>.offset-2--desktop,[class^=cols-] .slideshow__teasers .cols-3--desktop>.widget__list>.offset-2--desktop,[class^=cols-] .slideshow__teasers .cols-3--desktop>div[data-mht-block]>div[data-mht-widget]>.widget__list>.offset-2--desktop{margin-left:66.66666%}.cols-4--desktop>.row>.col-1--desktop,.cols-4--desktop>.slideshow>.col-1--desktop,.slideshow__teasers .cols-4--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-4--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class^=cols-] .cols-4--desktop>.widget__list>.col-1--desktop,[class*=" cols-"] .cols-4--desktop>.row>.col-1--desktop,[class*=" cols-"] .cols-4--desktop>.slideshow>.col-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-4--desktop>.widget__list>.col-1--desktop,[class^=cols-] .cols-4--desktop>.row>.col-1--desktop,[class^=cols-] .cols-4--desktop>.slideshow>.col-1--desktop,[class^=cols-] .slideshow__teasers .cols-4--desktop>.widget__list>.col-1--desktop{width:25%}.cols-4--desktop>.row>.col-1--desktop:nth-child(2n+1),.cols-4--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),.slideshow__teasers .cols-4--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers [class*=" cols-"] .cols-4--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),.slideshow__teasers [class^=cols-] .cols-4--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .cols-4--desktop>.row>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .cols-4--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),[class*=" cols-"] .slideshow__teasers .cols-4--desktop>.widget__list>.col-1--desktop:nth-child(2n+1),[class^=cols-] .cols-4--desktop>.row>.col-1--desktop:nth-child(2n+1),[class^=cols-] .cols-4--desktop>.slideshow>.col-1--desktop:nth-child(2n+1),[class^=cols-] .slideshow__teasers .cols-4--desktop>.widget__list>.col-1--desktop:nth-child(2n+1){clear:none}.cols-4--desktop>.row>.col-2--desktop,.cols-4--desktop>.slideshow>.col-2--desktop,.slideshow__teasers .cols-4--desktop>.widget__list>.col-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-4--desktop>.widget__list>.col-2--desktop,.slideshow__teasers [class^=cols-] .cols-4--desktop>.widget__list>.col-2--desktop,[class*=" cols-"] .cols-4--desktop>.row>.col-2--desktop,[class*=" cols-"] .cols-4--desktop>.slideshow>.col-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-4--desktop>.widget__list>.col-2--desktop,[class^=cols-] .cols-4--desktop>.row>.col-2--desktop,[class^=cols-] .cols-4--desktop>.slideshow>.col-2--desktop,[class^=cols-] .slideshow__teasers .cols-4--desktop>.widget__list>.col-2--desktop{width:50%}.cols-4--desktop>.row>.col-3--desktop,.cols-4--desktop>.slideshow>.col-3--desktop,.slideshow__teasers .cols-4--desktop>.widget__list>.col-3--desktop,.slideshow__teasers [class*=" cols-"] .cols-4--desktop>.widget__list>.col-3--desktop,.slideshow__teasers [class^=cols-] .cols-4--desktop>.widget__list>.col-3--desktop,[class*=" cols-"] .cols-4--desktop>.row>.col-3--desktop,[class*=" cols-"] .cols-4--desktop>.slideshow>.col-3--desktop,[class*=" cols-"] .slideshow__teasers .cols-4--desktop>.widget__list>.col-3--desktop,[class^=cols-] .cols-4--desktop>.row>.col-3--desktop,[class^=cols-] .cols-4--desktop>.slideshow>.col-3--desktop,[class^=cols-] .slideshow__teasers .cols-4--desktop>.widget__list>.col-3--desktop{width:75%}.cols-4--desktop>.row>.offset-1--desktop,.cols-4--desktop>.slideshow>.offset-1--desktop,.slideshow__teasers .cols-4--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-4--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers [class^=cols-] .cols-4--desktop>.widget__list>.offset-1--desktop,[class*=" cols-"] .cols-4--desktop>.row>.offset-1--desktop,[class*=" cols-"] .cols-4--desktop>.slideshow>.offset-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-4--desktop>.widget__list>.offset-1--desktop,[class^=cols-] .cols-4--desktop>.row>.offset-1--desktop,[class^=cols-] .cols-4--desktop>.slideshow>.offset-1--desktop,[class^=cols-] .slideshow__teasers .cols-4--desktop>.widget__list>.offset-1--desktop{margin-left:25%}.cols-4--desktop>.row>.offset-2--desktop,.cols-4--desktop>.slideshow>.offset-2--desktop,.slideshow__teasers .cols-4--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-4--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers [class^=cols-] .cols-4--desktop>.widget__list>.offset-2--desktop,[class*=" cols-"] .cols-4--desktop>.row>.offset-2--desktop,[class*=" cols-"] .cols-4--desktop>.slideshow>.offset-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-4--desktop>.widget__list>.offset-2--desktop,[class^=cols-] .cols-4--desktop>.row>.offset-2--desktop,[class^=cols-] .cols-4--desktop>.slideshow>.offset-2--desktop,[class^=cols-] .slideshow__teasers .cols-4--desktop>.widget__list>.offset-2--desktop{margin-left:50%}.cols-4--desktop>.row>.offset-3--desktop,.cols-4--desktop>.slideshow>.offset-3--desktop,.slideshow__teasers .cols-4--desktop>.widget__list>.offset-3--desktop,.slideshow__teasers [class*=" cols-"] .cols-4--desktop>.widget__list>.offset-3--desktop,.slideshow__teasers [class^=cols-] .cols-4--desktop>.widget__list>.offset-3--desktop,[class*=" cols-"] .cols-4--desktop>.row>.offset-3--desktop,[class*=" cols-"] .cols-4--desktop>.slideshow>.offset-3--desktop,[class*=" cols-"] .slideshow__teasers .cols-4--desktop>.widget__list>.offset-3--desktop,[class^=cols-] .cols-4--desktop>.row>.offset-3--desktop,[class^=cols-] .cols-4--desktop>.slideshow>.offset-3--desktop,[class^=cols-] .slideshow__teasers .cols-4--desktop>.widget__list>.offset-3--desktop{margin-left:75%}.cols-5--desktop>.row>.col-1--desktop,.cols-5--desktop>.slideshow>.col-1--desktop,.slideshow__teasers .cols-5--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-5--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class^=cols-] .cols-5--desktop>.widget__list>.col-1--desktop,[class*=" cols-"] .cols-5--desktop>.row>.col-1--desktop,[class*=" cols-"] .cols-5--desktop>.slideshow>.col-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-5--desktop>.widget__list>.col-1--desktop,[class^=cols-] .cols-5--desktop>.row>.col-1--desktop,[class^=cols-] .cols-5--desktop>.slideshow>.col-1--desktop,[class^=cols-] .slideshow__teasers .cols-5--desktop>.widget__list>.col-1--desktop{width:20%}.cols-5--desktop>.row>.col-2--desktop,.cols-5--desktop>.slideshow>.col-2--desktop,.slideshow__teasers .cols-5--desktop>.widget__list>.col-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-5--desktop>.widget__list>.col-2--desktop,.slideshow__teasers [class^=cols-] .cols-5--desktop>.widget__list>.col-2--desktop,[class*=" cols-"] .cols-5--desktop>.row>.col-2--desktop,[class*=" cols-"] .cols-5--desktop>.slideshow>.col-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-5--desktop>.widget__list>.col-2--desktop,[class^=cols-] .cols-5--desktop>.row>.col-2--desktop,[class^=cols-] .cols-5--desktop>.slideshow>.col-2--desktop,[class^=cols-] .slideshow__teasers .cols-5--desktop>.widget__list>.col-2--desktop{width:40%}.cols-5--desktop>.row>.col-3--desktop,.cols-5--desktop>.slideshow>.col-3--desktop,.slideshow__teasers .cols-5--desktop>.widget__list>.col-3--desktop,.slideshow__teasers [class*=" cols-"] .cols-5--desktop>.widget__list>.col-3--desktop,.slideshow__teasers [class^=cols-] .cols-5--desktop>.widget__list>.col-3--desktop,[class*=" cols-"] .cols-5--desktop>.row>.col-3--desktop,[class*=" cols-"] .cols-5--desktop>.slideshow>.col-3--desktop,[class*=" cols-"] .slideshow__teasers .cols-5--desktop>.widget__list>.col-3--desktop,[class^=cols-] .cols-5--desktop>.row>.col-3--desktop,[class^=cols-] .cols-5--desktop>.slideshow>.col-3--desktop,[class^=cols-] .slideshow__teasers .cols-5--desktop>.widget__list>.col-3--desktop{width:60%}.cols-5--desktop>.row>.col-4--desktop,.cols-5--desktop>.slideshow>.col-4--desktop,.slideshow__teasers .cols-5--desktop>.widget__list>.col-4--desktop,.slideshow__teasers [class*=" cols-"] .cols-5--desktop>.widget__list>.col-4--desktop,.slideshow__teasers [class^=cols-] .cols-5--desktop>.widget__list>.col-4--desktop,[class*=" cols-"] .cols-5--desktop>.row>.col-4--desktop,[class*=" cols-"] .cols-5--desktop>.slideshow>.col-4--desktop,[class*=" cols-"] .slideshow__teasers .cols-5--desktop>.widget__list>.col-4--desktop,[class^=cols-] .cols-5--desktop>.row>.col-4--desktop,[class^=cols-] .cols-5--desktop>.slideshow>.col-4--desktop,[class^=cols-] .slideshow__teasers .cols-5--desktop>.widget__list>.col-4--desktop{width:80%}.cols-5--desktop>.row>.offset-1--desktop,.cols-5--desktop>.slideshow>.offset-1--desktop,.slideshow__teasers .cols-5--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-5--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers [class^=cols-] .cols-5--desktop>.widget__list>.offset-1--desktop,[class*=" cols-"] .cols-5--desktop>.row>.offset-1--desktop,[class*=" cols-"] .cols-5--desktop>.slideshow>.offset-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-5--desktop>.widget__list>.offset-1--desktop,[class^=cols-] .cols-5--desktop>.row>.offset-1--desktop,[class^=cols-] .cols-5--desktop>.slideshow>.offset-1--desktop,[class^=cols-] .slideshow__teasers .cols-5--desktop>.widget__list>.offset-1--desktop{margin-left:20%}.cols-5--desktop>.row>.offset-2--desktop,.cols-5--desktop>.slideshow>.offset-2--desktop,.slideshow__teasers .cols-5--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-5--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers [class^=cols-] .cols-5--desktop>.widget__list>.offset-2--desktop,[class*=" cols-"] .cols-5--desktop>.row>.offset-2--desktop,[class*=" cols-"] .cols-5--desktop>.slideshow>.offset-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-5--desktop>.widget__list>.offset-2--desktop,[class^=cols-] .cols-5--desktop>.row>.offset-2--desktop,[class^=cols-] .cols-5--desktop>.slideshow>.offset-2--desktop,[class^=cols-] .slideshow__teasers .cols-5--desktop>.widget__list>.offset-2--desktop{margin-left:40%}.cols-5--desktop>.row>.offset-3--desktop,.cols-5--desktop>.slideshow>.offset-3--desktop,.slideshow__teasers .cols-5--desktop>.widget__list>.offset-3--desktop,.slideshow__teasers [class*=" cols-"] .cols-5--desktop>.widget__list>.offset-3--desktop,.slideshow__teasers [class^=cols-] .cols-5--desktop>.widget__list>.offset-3--desktop,[class*=" cols-"] .cols-5--desktop>.row>.offset-3--desktop,[class*=" cols-"] .cols-5--desktop>.slideshow>.offset-3--desktop,[class*=" cols-"] .slideshow__teasers .cols-5--desktop>.widget__list>.offset-3--desktop,[class^=cols-] .cols-5--desktop>.row>.offset-3--desktop,[class^=cols-] .cols-5--desktop>.slideshow>.offset-3--desktop,[class^=cols-] .slideshow__teasers .cols-5--desktop>.widget__list>.offset-3--desktop{margin-left:60%}.cols-5--desktop>.row>.offset-4--desktop,.cols-5--desktop>.slideshow>.offset-4--desktop,.slideshow__teasers .cols-5--desktop>.widget__list>.offset-4--desktop,.slideshow__teasers [class*=" cols-"] .cols-5--desktop>.widget__list>.offset-4--desktop,.slideshow__teasers [class^=cols-] .cols-5--desktop>.widget__list>.offset-4--desktop,[class*=" cols-"] .cols-5--desktop>.row>.offset-4--desktop,[class*=" cols-"] .cols-5--desktop>.slideshow>.offset-4--desktop,[class*=" cols-"] .slideshow__teasers .cols-5--desktop>.widget__list>.offset-4--desktop,[class^=cols-] .cols-5--desktop>.row>.offset-4--desktop,[class^=cols-] .cols-5--desktop>.slideshow>.offset-4--desktop,[class^=cols-] .slideshow__teasers .cols-5--desktop>.widget__list>.offset-4--desktop{margin-left:80%}.cols-6--desktop>.row>.col-1--desktop,.cols-6--desktop>.slideshow>.col-1--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.col-1--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.col-1--desktop,[class*=" cols-"] .cols-6--desktop>.row>.col-1--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.col-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.col-1--desktop,[class^=cols-] .cols-6--desktop>.row>.col-1--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.col-1--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.col-1--desktop{width:16.66666%}.cols-6--desktop>.row>.col-1--desktop:nth-child(3n+1),.cols-6--desktop>.slideshow>.col-1--desktop:nth-child(3n+1),.slideshow__teasers .cols-6--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .cols-6--desktop>.row>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .cols-6--desktop>.slideshow>.col-1--desktop:nth-child(3n+1),[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.col-1--desktop:nth-child(3n+1),[class^=cols-] .cols-6--desktop>.row>.col-1--desktop:nth-child(3n+1),[class^=cols-] .cols-6--desktop>.slideshow>.col-1--desktop:nth-child(3n+1),[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.col-1--desktop:nth-child(3n+1){clear:none}.cols-6--desktop>.row>.col-2--desktop,.cols-6--desktop>.slideshow>.col-2--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.col-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.col-2--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.col-2--desktop,[class*=" cols-"] .cols-6--desktop>.row>.col-2--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.col-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.col-2--desktop,[class^=cols-] .cols-6--desktop>.row>.col-2--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.col-2--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.col-2--desktop{width:33.33332%}.cols-6--desktop>.row>.col-3--desktop,.cols-6--desktop>.slideshow>.col-3--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.col-3--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.col-3--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.col-3--desktop,[class*=" cols-"] .cols-6--desktop>.row>.col-3--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.col-3--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.col-3--desktop,[class^=cols-] .cols-6--desktop>.row>.col-3--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.col-3--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.col-3--desktop{width:50%}.cols-6--desktop>.row>.col-4--desktop,.cols-6--desktop>.slideshow>.col-4--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.col-4--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.col-4--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.col-4--desktop,[class*=" cols-"] .cols-6--desktop>.row>.col-4--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.col-4--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.col-4--desktop,[class^=cols-] .cols-6--desktop>.row>.col-4--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.col-4--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.col-4--desktop{width:66.66666%}.cols-6--desktop>.row>.col-5--desktop,.cols-6--desktop>.slideshow>.col-5--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.col-5--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.col-5--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.col-5--desktop,[class*=" cols-"] .cols-6--desktop>.row>.col-5--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.col-5--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.col-5--desktop,[class^=cols-] .cols-6--desktop>.row>.col-5--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.col-5--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.col-5--desktop{width:83.33333%}.cols-6--desktop>.row>.offset-1--desktop,.cols-6--desktop>.slideshow>.offset-1--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.offset-1--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.offset-1--desktop,[class*=" cols-"] .cols-6--desktop>.row>.offset-1--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.offset-1--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-1--desktop,[class^=cols-] .cols-6--desktop>.row>.offset-1--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.offset-1--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-1--desktop{margin-left:16.66666%}.cols-6--desktop>.row>.offset-2--desktop,.cols-6--desktop>.slideshow>.offset-2--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.offset-2--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.offset-2--desktop,[class*=" cols-"] .cols-6--desktop>.row>.offset-2--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.offset-2--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-2--desktop,[class^=cols-] .cols-6--desktop>.row>.offset-2--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.offset-2--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-2--desktop{margin-left:33.33332%}.cols-6--desktop>.row>.offset-3--desktop,.cols-6--desktop>.slideshow>.offset-3--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.offset-3--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.offset-3--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.offset-3--desktop,[class*=" cols-"] .cols-6--desktop>.row>.offset-3--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.offset-3--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-3--desktop,[class^=cols-] .cols-6--desktop>.row>.offset-3--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.offset-3--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-3--desktop{margin-left:50%}.cols-6--desktop>.row>.offset-4--desktop,.cols-6--desktop>.slideshow>.offset-4--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.offset-4--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.offset-4--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.offset-4--desktop,[class*=" cols-"] .cols-6--desktop>.row>.offset-4--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.offset-4--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-4--desktop,[class^=cols-] .cols-6--desktop>.row>.offset-4--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.offset-4--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-4--desktop{margin-left:66.66666%}.cols-6--desktop>.row>.offset-5--desktop,.cols-6--desktop>.slideshow>.offset-5--desktop,.slideshow__teasers .cols-6--desktop>.widget__list>.offset-5--desktop,.slideshow__teasers [class*=" cols-"] .cols-6--desktop>.widget__list>.offset-5--desktop,.slideshow__teasers [class^=cols-] .cols-6--desktop>.widget__list>.offset-5--desktop,[class*=" cols-"] .cols-6--desktop>.row>.offset-5--desktop,[class*=" cols-"] .cols-6--desktop>.slideshow>.offset-5--desktop,[class*=" cols-"] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-5--desktop,[class^=cols-] .cols-6--desktop>.row>.offset-5--desktop,[class^=cols-] .cols-6--desktop>.slideshow>.offset-5--desktop,[class^=cols-] .slideshow__teasers .cols-6--desktop>.widget__list>.offset-5--desktop{margin-left:83.33333%}}.col__cell{padding:0 .8571428571rem}.col__cell:after{content:".";display:block;height:0;clear:both;visibility:hidden}@media screen and (min-width:40em){.col__cell{padding:0 1.4285714286rem 0 0}}@media screen and (min-width:40em){.layout-archive .main-container .col__cell{padding-left:0;padding-right:0}}.layout-archive .theme-archive-overview .main-container .col__cell{padding-right:1.4285714286rem}.layout-archive .theme-archive-overview .main-container .theme-archive-overview--tile .col__cell{padding-right:0}.layout-archive .l-reversed .secondary-col .col__cell{padding-left:0}.col__cell--half-padder{padding-top:.8571428571rem;padding-bottom:.8571428571rem}.col__cell--no-padder{padding-top:0;padding-bottom:0}.col__cell--no-top-padder{padding-top:0}.col__cell--no-bottom-padder{padding-bottom:0}.col-bleeder>.col__cell{padding:0;margin-left:-20px}.slideshow__teasers [class^=cols-] .secondary-col [class^=cols-] .widget__list,[class^=cols-] .secondary-col [class^=cols-] .row,[class^=cols-] .secondary-col [class^=cols-] .slideshow,[class^=cols-] .secondary-col [class^=cols-] .slideshow__teasers .widget__list{margin-left:0}.layout-morningedition .l-1p3k .primary-col,.layout-morningedition .l-1p3k .secondary-col,.layout-morningedition .l-3k1p .primary-col,.layout-morningedition .l-3k1p .secondary-col,.slideshow__teasers .theme-live [class*=" cols-"]>.widget__list>.primary-col,.slideshow__teasers .theme-live [class*=" cols-"]>.widget__list>.secondary-col,.slideshow__teasers .theme-live [class^=cols-]>.widget__list>.primary-col,.slideshow__teasers .theme-live [class^=cols-]>.widget__list>.secondary-col,.theme-live .slideshow__teasers [class*=" cols-"]>.widget__list>.primary-col,.theme-live .slideshow__teasers [class*=" cols-"]>.widget__list>.secondary-col,.theme-live .slideshow__teasers [class^=cols-]>.widget__list>.primary-col,.theme-live .slideshow__teasers [class^=cols-]>.widget__list>.secondary-col,.theme-live [class*=" cols-"]>.row>.primary-col,.theme-live [class*=" cols-"]>.row>.secondary-col,.theme-live [class*=" cols-"]>.slideshow>.primary-col,.theme-live [class*=" cols-"]>.slideshow>.secondary-col,.theme-live [class^=cols-]>.row>.primary-col,.theme-live [class^=cols-]>.row>.secondary-col,.theme-live [class^=cols-]>.slideshow>.primary-col,.theme-live [class^=cols-]>.slideshow>.secondary-col{float:none;width:100%}@media screen and (min-width:55em){.slideshow__teasers .theme-live [class*=" cols-"]>.widget__list>.primary-col,.slideshow__teasers .theme-live [class*=" cols-"]>.widget__list>.secondary-col,.slideshow__teasers .theme-live [class^=cols-]>.widget__list>.primary-col,.slideshow__teasers .theme-live [class^=cols-]>.widget__list>.secondary-col,.theme-live .slideshow__teasers [class*=" cols-"]>.widget__list>.primary-col,.theme-live .slideshow__teasers [class*=" cols-"]>.widget__list>.secondary-col,.theme-live .slideshow__teasers [class^=cols-]>.widget__list>.primary-col,.theme-live .slideshow__teasers [class^=cols-]>.widget__list>.secondary-col,.theme-live [class*=" cols-"]>.row>.primary-col,.theme-live [class*=" cols-"]>.row>.secondary-col,.theme-live [class*=" cols-"]>.slideshow>.primary-col,.theme-live [class*=" cols-"]>.slideshow>.secondary-col,.theme-live [class^=cols-]>.row>.primary-col,.theme-live [class^=cols-]>.row>.secondary-col,.theme-live [class^=cols-]>.slideshow>.primary-col,.theme-live [class^=cols-]>.slideshow>.secondary-col{float:left}}@media screen and (min-width:55em){.slideshow__teasers .theme-live [class*=" cols-"]>.widget__list>.primary-col,.slideshow__teasers .theme-live [class^=cols-]>.widget__list>.primary-col,.theme-live .slideshow__teasers [class*=" cols-"]>.widget__list>.primary-col,.theme-live .slideshow__teasers [class^=cols-]>.widget__list>.primary-col,.theme-live [class*=" cols-"]>.row>.primary-col,.theme-live [class*=" cols-"]>.slideshow>.primary-col,.theme-live [class^=cols-]>.row>.primary-col,.theme-live [class^=cols-]>.slideshow>.primary-col{width:60%}}@media screen and (min-width:55em){.slideshow__teasers .theme-live [class*=" cols-"]>.widget__list>.secondary-col,.slideshow__teasers .theme-live [class^=cols-]>.widget__list>.secondary-col,.theme-live .slideshow__teasers [class*=" cols-"]>.widget__list>.secondary-col,.theme-live .slideshow__teasers [class^=cols-]>.widget__list>.secondary-col,.theme-live [class*=" cols-"]>.row>.secondary-col,.theme-live [class*=" cols-"]>.slideshow>.secondary-col,.theme-live [class^=cols-]>.row>.secondary-col,.theme-live [class^=cols-]>.slideshow>.secondary-col{width:40%}}@media screen and (min-width:55em){.separator{border-right:1px solid #ddd}.separator.separator--or{position:relative;height:100%}.separator.separator--or:before{width:30px;width:2.1428571429rem;height:30px;height:2.1428571429rem;line-height:30px;position:absolute;right:-15px;top:20px;content:'of';display:block;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;border:1px solid #ddd;color:#666;background-color:#fff;text-align:center}}@media screen and (min-width:55em){.l-reversed .separator{border-right:0;border-left:1px solid #ddd}}@media screen and (min-width:55em){.layout-wideskyscraper .theme-live .primary-col{float:left;width:60%}.layout-wideskyscraper .theme-live .primary-col .separator{border-right:1px solid #ddd}}@media screen and (min-width:48em){.layout-morningedition .l-1p3k .primary-col,.layout-morningedition .l-3k1p .primary-col{position:relative;z-index:10;float:left;width:75%}}@media screen and (min-width:55em){.secondary-col{float:left;width:40%}}@media screen and (min-width:55em){.layout-wideskyscraper .theme-live .secondary-col{float:left;width:40%}}@media screen and (min-width:55em){.primary-col+.secondary-col .col__cell{padding-left:1.4285714286rem}}@media screen and (min-width:48em){.layout-morningedition .l-1p3k .secondary-col,.layout-morningedition .l-3k1p .secondary-col{float:left;width:25%}}@media screen and (min-width:68.4375em){.modalbox-article-active .secondary-col{position:relative;z-index:1031}}.tertiary-col .col__cell{padding-right:1.4285714286rem;padding-left:0}.tertiary-col+.primary-col .col__cell{padding-left:1.4285714286rem}.col__cell.flush-full{margin-left:-1.4285714286rem;padding-left:0}.layout-morningedition .main-container .col__cell{padding-left:1.4285714286rem}@media screen and (min-width:40em){.col__cell--dashed-right{border-right:1px dotted #ccc}}@media screen and (min-width:40em){.col__cell--dashed-left{border-left:1px dotted #ccc}}.l-reversed .slideshow__teasers [class*=" cols-"]>.widget__list .primary-col,.l-reversed .slideshow__teasers [class^=cols-]>.widget__list .primary-col,.l-reversed [class*=" cols-"]>.row .primary-col,.l-reversed [class*=" cols-"]>.slideshow .primary-col,.l-reversed [class^=cols-]>.row .primary-col,.l-reversed [class^=cols-]>.slideshow .primary-col,.slideshow__teasers .l-reversed [class*=" cols-"]>.widget__list .primary-col,.slideshow__teasers .l-reversed [class^=cols-]>.widget__list .primary-col{float:right}.l-reversed .slideshow__teasers [class*=" cols-"]>.widget__list .primary-col .col__cell,.l-reversed .slideshow__teasers [class^=cols-]>.widget__list .primary-col .col__cell,.l-reversed [class*=" cols-"]>.row .primary-col .col__cell,.l-reversed [class*=" cols-"]>.slideshow .primary-col .col__cell,.l-reversed [class^=cols-]>.row .primary-col .col__cell,.l-reversed [class^=cols-]>.slideshow .primary-col .col__cell,.slideshow__teasers .l-reversed [class*=" cols-"]>.widget__list .primary-col .col__cell,.slideshow__teasers .l-reversed [class^=cols-]>.widget__list .primary-col .col__cell{padding-left:1.4285714286rem}.l-reversed .slideshow__teasers [class*=" cols-"]>.widget__list .secondary-col,.l-reversed .slideshow__teasers [class^=cols-]>.widget__list .secondary-col,.l-reversed [class*=" cols-"]>.row .secondary-col,.l-reversed [class*=" cols-"]>.slideshow .secondary-col,.l-reversed [class^=cols-]>.row .secondary-col,.l-reversed [class^=cols-]>.slideshow .secondary-col,.slideshow__teasers .l-reversed [class*=" cols-"]>.widget__list .secondary-col,.slideshow__teasers .l-reversed [class^=cols-]>.widget__list .secondary-col{float:left}.layout-archive .cols-3 .col-1{position:relative}.layout-archive .cols-3 .col-1:after{content:"";display:block;position:absolute;width:1px;right:0;top:0;background-color:#efefef;height:2000px}.layout-archive .cols-3 .col-1:last-child:after{display:none}@media screen and (max-width:54.9375em){.layout-rwd-alt .cols-5>.row .primary-col,.layout-rwd-alt .cols-5>.row .secondary-col,.layout-rwd-alt .cols-5>.slideshow .primary-col,.layout-rwd-alt .cols-5>.slideshow .secondary-col,.layout-rwd-alt .slideshow__teasers .cols-5>.widget__list .primary-col,.layout-rwd-alt .slideshow__teasers .cols-5>.widget__list .secondary-col,.slideshow__teasers .layout-rwd-alt .cols-5>.widget__list .primary-col,.slideshow__teasers .layout-rwd-alt .cols-5>.widget__list .secondary-col{float:none;width:100%}}@media screen and (max-width:54.9375em){.layout-rwd-alt .cols-5 .separator{border-right:0}}@media screen and (min-width:48em){.layout-rwd-alt .primary-col+.secondary-col .col__cell{padding-left:0}}@media screen and (min-width:55em){.layout-rwd-alt .primary-col+.secondary-col .col__cell{padding-left:1.4285714286rem}}.container,.main-footer,.main-header,.session-expired{max-width:995px;max-width:71.0714285714rem;margin-left:auto;margin-right:auto}.container:after,.main-footer:after,.main-header:after,.session-expired:after{content:".";display:block;height:0;clear:both;visibility:hidden}.main-container{position:relative;z-index:500}@media screen and (min-width:68.4375em){.modalbox-article-active .main-container{position:static}}.main-header{background-color:#fff;position:relative;z-index:501}.main-header:after{content:".";display:block;height:0;clear:both;visibility:hidden}.main-footer{padding-top:1.4285714286rem;padding-bottom:1.4285714286rem;background-color:#fff;clear:both;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;position:relative}.main-footer:after{content:".";display:block;height:0;clear:both;visibility:hidden}.main-footer h6{margin-bottom:.8571428571rem;font-size:14px;font-size:1rem;line-height:1.2857142857;font-weight:500}.carousel .main-footer ol,.main-footer .author-info,.main-footer .carousel ol,.main-footer .child__list,.main-footer .comments-list,.main-footer .currently,.main-footer .ekrant__previous-attachments,.main-footer .history-list,.main-footer .inline-list,.main-footer .list--ellipsis,.main-footer .list--history,.main-footer .nav-tabs,.main-footer .slideshow__pager,.main-footer .star-rating,.main-footer .stock-bar,.main-footer .unstyled,.main-footer .widget__list{margin-top:0}.carousel .main-footer ol li,.main-footer .author-info li,.main-footer .carousel ol li,.main-footer .child__list li,.main-footer .comments-list li,.main-footer .currently li,.main-footer .ekrant__previous-attachments li,.main-footer .history-list li,.main-footer .inline-list li,.main-footer .list--ellipsis li,.main-footer .list--history li,.main-footer .nav-tabs li,.main-footer .slideshow__pager li,.main-footer .star-rating li,.main-footer .stock-bar li,.main-footer .unstyled li,.main-footer .widget__list li{margin:0}.carousel .main-footer ol li a,.main-footer .author-info li a,.main-footer .carousel ol li a,.main-footer .child__list li a,.main-footer .comments-list li a,.main-footer .currently li a,.main-footer .ekrant__previous-attachments li a,.main-footer .history-list li a,.main-footer .inline-list li a,.main-footer .list--ellipsis li a,.main-footer .list--history li a,.main-footer .nav-tabs li a,.main-footer .slideshow__pager li a,.main-footer .star-rating li a,.main-footer .stock-bar li a,.main-footer .unstyled li a,.main-footer .widget__list li a{padding-top:.2142857143rem;padding-bottom:.2142857143rem;display:inline-block}.main-footer .col-4 a{text-decoration:underline;color:#444}.main-footer .col-4 a:visited{color:#444}.main-footer .col-4 a:focus,.main-footer .col-4 a:hover{color:#44c4d1;text-decoration:underline}.main-footer .col-4 a:active{text-decoration:underline}.l-latest-issues{padding:1.4285714286rem 1.4285714286rem 0;border-top:1px dashed #ccc}.js .l-latest-issues{display:none}.l-zone{margin-bottom:1.4285714286rem;background-color:#fff;position:relative}.l-zone:after{content:".";display:block;height:0;clear:both;visibility:hidden}.l-zone--breaking-news{margin-bottom:0;background-color:transparent}.l-zone--breaking-news .cols-5 .row,.l-zone--breaking-news .cols-5 .slideshow,.l-zone--breaking-news .cols-5 .slideshow__teasers .widget__list,.slideshow__teasers .l-zone--breaking-news .cols-5 .widget__list{background-color:#fff}.l-zone--breaking-news .cols-5 .row hr.divider,.l-zone--breaking-news .cols-5 .slideshow hr.divider,.l-zone--breaking-news .cols-5 .slideshow__teasers .widget__list hr.divider,.slideshow__teasers .l-zone--breaking-news .cols-5 .widget__list hr.divider{display:none}.l-zone--breaking-news .cols-5 .row:first-child,.l-zone--breaking-news .cols-5 .slideshow:first-child,.l-zone--breaking-news .cols-5 .slideshow__teasers .widget__list:first-child,.slideshow__teasers .l-zone--breaking-news .cols-5 .widget__list:first-child{background-color:transparent}.l-zone--breaking-news .cols-5 .row .breaking-news-wrapper,.l-zone--breaking-news .cols-5 .slideshow .breaking-news-wrapper,.l-zone--breaking-news .cols-5 .slideshow__teasers .widget__list .breaking-news-wrapper,.slideshow__teasers .l-zone--breaking-news .cols-5 .widget__list .breaking-news-wrapper{margin-bottom:20px}.l-zone--clear{background-color:transparent;margin-bottom:0}.l-zone--clear>*{margin-bottom:1.4285714286rem;background-color:#fff}.arrange{letter-spacing:-.31em}.arrange,.opera:-o-prefocus{word-spacing:-.43em}.arrange__item{display:inline-block;float:none!important;letter-spacing:normal;word-spacing:normal}.arrange--bottom .arrange__item{vertical-align:bottom}@media screen and (min-width:48em){.arrange--bottom--bp3 .arrange__item{vertical-align:bottom}}body:after{content:"bp0";display:block;height:0;overflow:hidden;width:0}@media screen and (min-width:18.75em){body:after{content:"bp1"}}@media screen and (min-width:40em){body:after{content:"bp2"}}@media screen and (min-width:48em){body:after{content:"bp3"}}@media screen and (min-width:55em){body:after{content:"bp3a"}}@media screen and (min-width:62.1875em){body:after{content:"bp4"}}@media screen and (min-width:64em){body:after{content:"bp4a"}}@media screen and (min-width:68.4375em){body:after{content:"bp4b"}}@media screen and (min-width:75em){body:after{content:"bp5"}}.flex-embed,.jobat__inner,html.no-touch .video,html.touch .video:not(.video--dsokaltura){height:0;overflow:hidden;padding:0;position:relative}.flex-embed .flex_embed__item,.flex-embed embed,.flex-embed iframe,.flex-embed img,.flex-embed object,.jobat__inner .flex_embed__item,.jobat__inner embed,.jobat__inner iframe,.jobat__inner img,.jobat__inner object,html.no-touch .video .flex_embed__item,html.no-touch .video embed,html.no-touch .video iframe,html.no-touch .video img,html.no-touch .video object,html.touch .video:not(.video--dsokaltura) .flex_embed__item,html.touch .video:not(.video--dsokaltura) embed,html.touch .video:not(.video--dsokaltura) iframe,html.touch .video:not(.video--dsokaltura) img,html.touch .video:not(.video--dsokaltura) object{height:100%!important;left:0;position:absolute!important;top:0;width:100%!important}.ch{overflow:hidden;width:100%}.ad--fullpagelayer,.ad--overlayer,.ch__push{float:left;left:50%;position:relative}.ad--fullpagelayer .ad__wrapper,.ad--overlayer .ad__wrapper,.ch__pull{left:-50%;position:relative}.theme-archive .ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;border:1px solid #ddd;font-size:18px;background-color:#eee;padding:.5em .5em .5em .7em;zoom:1}.theme-archive .ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.theme-archive .ui-accordion .ui-accordion-icons,.theme-archive .ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.theme-archive .ui-accordion .ui-accordion-noicons{padding-left:.7em}.theme-archive .ui-accordion .ui-accordion-content{padding:1em 12px;border-top:0;overflow:auto;zoom:1}.ad-group{clear:both}.layout-skyscraper .ad-group.ad-group--a{margin-right:0}.ad-group--a{position:relative;z-index:1}.ad{display:none}.ad__inner{-webkit-transition:padding-top .2s ease-out;-moz-transition:padding-top .2s ease-out;transition:padding-top .2s ease-out;height:0;overflow:visible;padding:0;position:relative}.ad__inner embed,.ad__inner iframe,.ad__inner img,.ad__inner object{max-height:100%;left:0;position:absolute!important;top:0;width:100%!important}.ad__inner iframe,.ad__inner img{height:100%!important}.ad__inner div,.ad__inner iframe[src^="http://tap2-cdn.rubiconproject.com"],.ad__inner img[src^="https://d.agkn.com/pixel/"]{height:0!important;position:static!important}.layout-morningedition .ad__inner a{display:block;height:100%;left:0;position:absolute;top:0;width:100%;z-index:1}.ad__inner iframe[height="0"][width="0"],.ad__inner img[height="1"][width="1"],.ad__inner img[height="0"][width="0"]{height:1px!important}.ad--expandable .ad__panel-2,.ad--pushdown .ad__panel-2{display:none;height:100%!important;left:0;position:absolute!important;top:0;width:100%!important}.ad--expandable:hover .ad__panel-2,.ad--pushdown:hover .ad__panel-2{display:block;z-index:1020}.secondary-col .ad__panel-2{left:auto!important;right:0}.ad--leaderboard .ad__wrapper{max-width:728px;max-width:52rem;margin:0 auto}.ad--leaderboard .ad__inner{padding-top:12.3626373626%}.ad--leaderboard.ad--expandable .ad__inner .ad__panel-2{height:444%!important}.ad--leaderboard.ad--pushdown:hover .ad__inner{padding-top:54.9450549451%}.ad--xlleaderboard .ad__wrapper{max-width:995px;max-width:71.0714285714rem}.ad--xlleaderboard .ad__inner{padding-top:12.3618090452%}.ad--xlleaderboard.ad--expandable .ad__inner .ad__panel-2{height:325%!important}.ad--xlleaderboard.ad--pushdown:hover .ad__inner{padding-top:40.2010050251%}.ad--xlleaderboard [id*=expand] object{max-height:325%!important}.ad--xlleaderboard1,.ad--xlleaderboard2,.ad--xlleaderboard3{margin-top:1.4285714286rem}.ad--xlleaderboard1 .ad__wrapper,.ad--xlleaderboard2 .ad__wrapper,.ad--xlleaderboard3 .ad__wrapper{max-width:995px;max-width:71.0714285714rem}.ad--xlleaderboard1 .ad__inner,.ad--xlleaderboard2 .ad__inner,.ad--xlleaderboard3 .ad__inner{padding-top:12.3618090452%}.ad--xlleaderboard1.ad--expandable .ad__inner .ad__panel-2,.ad--xlleaderboard2.ad--expandable .ad__inner .ad__panel-2,.ad--xlleaderboard3.ad--expandable .ad__inner .ad__panel-2{height:325%!important}.ad--xlleaderboard1.ad--pushdown:hover .ad__inner,.ad--xlleaderboard2.ad--pushdown:hover .ad__inner,.ad--xlleaderboard3.ad--pushdown:hover .ad__inner{padding-top:40.2010050251%}.ad--tvleaderboard .ad__wrapper{max-width:995px;max-width:71.0714285714rem}.ad--tvleaderboard .ad__inner{padding-top:25.1256281407%}.ad--tvleaderboard1,.ad--tvleaderboard2,.ad--tvleaderboard3,.ad--tvleaderboard4{margin-top:1.4285714286rem}.ad--tvleaderboard1 .ad__wrapper,.ad--tvleaderboard2 .ad__wrapper,.ad--tvleaderboard3 .ad__wrapper,.ad--tvleaderboard4 .ad__wrapper{max-width:995px;max-width:71.0714285714rem}.ad--tvleaderboard1 .ad__inner,.ad--tvleaderboard2 .ad__inner,.ad--tvleaderboard3 .ad__inner,.ad--tvleaderboard4 .ad__inner{padding-top:25.1256281407%}.ad--tvleaderboard1.ad--expandable .ad__inner .ad__panel-2,.ad--tvleaderboard2.ad--expandable .ad__inner .ad__panel-2,.ad--tvleaderboard3.ad--expandable .ad__inner .ad__panel-2,.ad--tvleaderboard4.ad--expandable .ad__inner .ad__panel-2{height:325%!important}.ad--tvleaderboard1.ad--pushdown:hover .ad__inner,.ad--tvleaderboard2.ad--pushdown:hover .ad__inner,.ad--tvleaderboard3.ad--pushdown:hover .ad__inner,.ad--tvleaderboard4.ad--pushdown:hover .ad__inner{padding-top:40.2010050251%}.ad--wideskyscraper{width:160px;width:11.4285714286rem;min-height:1px;position:absolute;top:0;right:0}@media screen and (min-width:62.1875em){.csspositionsticky .ad--wideskyscraper{height:100%}.csspositionsticky .ad--wideskyscraper .ad__wrapper{top:12px;top:.8571428571rem;position:-webkit-sticky;position:sticky}.no-csspositionsticky.csspositionfixed .ad--wideskyscraper.fixed .ad__wrapper{top:12px;top:.8571428571rem;position:fixed}}@media screen and (min-width:75em){.ad--wideskyscraper{margin-right:-12.2857142857rem}}.ad--wideskyscraper .ad__wrapper{width:160px;width:11.4285714286rem;position:absolute}.ad--wideskyscraper .ad__inner{padding-top:375%}.ad--wideskyscraper .ad__inner .ad__panel-2{left:auto!important;right:0;width:250%!important}.ad--mediumrectangle,.ad--mediumrectangle2,.ad--mediumrectangle3,.ad--mediumrectangle4,.ad--mediumrectangleinhouse{padding:1.4285714286rem 0;border-bottom:1px solid #ededed}.ad--mediumrectangle.ad-slot--c,.ad--mediumrectangle.ad-slot--photospecial,.ad--mediumrectangle2.ad-slot--c,.ad--mediumrectangle2.ad-slot--photospecial,.ad--mediumrectangle3.ad-slot--c,.ad--mediumrectangle3.ad-slot--photospecial,.ad--mediumrectangle4.ad-slot--c,.ad--mediumrectangle4.ad-slot--photospecial,.ad--mediumrectangleinhouse.ad-slot--c,.ad--mediumrectangleinhouse.ad-slot--photospecial{border-bottom:0}.ad--mediumrectangle.ad-slot--c,.ad--mediumrectangle2.ad-slot--c,.ad--mediumrectangle3.ad-slot--c,.ad--mediumrectangle4.ad-slot--c,.ad--mediumrectangleinhouse.ad-slot--c{padding-top:0}.ad--mediumrectangle .ad__wrapper,.ad--mediumrectangle2 .ad__wrapper,.ad--mediumrectangle3 .ad__wrapper,.ad--mediumrectangle4 .ad__wrapper,.ad--mediumrectangleinhouse .ad__wrapper{max-width:300px;max-width:21.4285714286rem}.ad--mediumrectangle .ad__inner,.ad--mediumrectangle2 .ad__inner,.ad--mediumrectangle3 .ad__inner,.ad--mediumrectangle4 .ad__inner,.ad--mediumrectangleinhouse .ad__inner{padding-top:83.3333333333%}.ad--mediumrectangle .ad__inner .ad__panel-2,.ad--mediumrectangle2 .ad__inner .ad__panel-2,.ad--mediumrectangle3 .ad__inner .ad__panel-2,.ad--mediumrectangle4 .ad__inner .ad__panel-2,.ad--mediumrectangleinhouse .ad__inner .ad__panel-2{height:200%!important;width:166.667%!important}.ad--mediumrectangle .GoogleActiveViewClass[style*="width: 500px;"][style*="height: 500px;"],.ad--mediumrectangle2 .GoogleActiveViewClass[style*="width: 500px;"][style*="height: 500px;"],.ad--mediumrectangle3 .GoogleActiveViewClass[style*="width: 500px;"][style*="height: 500px;"],.ad--mediumrectangle4 .GoogleActiveViewClass[style*="width: 500px;"][style*="height: 500px;"],.ad--mediumrectangleinhouse .GoogleActiveViewClass[style*="width: 500px;"][style*="height: 500px;"]{height:200%!important;position:absolute!important;width:166.667%!important;z-index:1020!important}.article__body .ad--mediumrectangle .ad__wrapper{background-color:#eee;background-image:url(../img/load.gif);background-position:center center;background-repeat:no-repeat}.is-loaded-mediumrectangle .article__body .ad--mediumrectangle .ad__wrapper{background:0 0}.ad--mediumrectangle2,.ad--mediumrectangle3,.ad--mediumrectangle4{border-bottom:0;padding:0}.ad--halfmediumrectangle{padding:1.4285714286rem 0;border-bottom:1px solid #ededed}.ad--halfmediumrectangle .ad__wrapper{max-width:300px;max-width:21.4285714286rem}.ad--halfmediumrectangle .ad__inner{padding-top:41.6666666667%}.ad--xlmediumrectangle{padding:1.4285714286rem 0;border-bottom:1px solid #ededed}.ad--xlmediumrectangle .ad__wrapper{max-width:369px;max-width:26.3571428571rem}.ad--xlmediumrectangle .ad__inner{padding-top:83.4688346883%}.ad--xlmediumrectangle .ad__inner .ad__panel-2{height:162.337%!important;width:135.5%!important}article .ad--xlmediumrectangle{margin-bottom:20px}.ad--halfpage,.ad--halfpage2{padding:1.4285714286rem 0;border-bottom:1px solid #ededed}.ad--halfpage .ad__wrapper,.ad--halfpage2 .ad__wrapper{max-width:300px;max-width:21.4285714286rem}.ad--halfpage .ad__inner,.ad--halfpage2 .ad__inner{padding-top:200%}.ad--halfpage .ad__inner .ad__panel-2,.ad--halfpage2 .ad__inner .ad__panel-2{width:200%!important}.ad--halfpage .GoogleActiveViewClass[style*="width: 600px;"],.ad--halfpage2 .GoogleActiveViewClass[style*="width: 600px;"]{height:100%!important;position:absolute!important;width:200%!important}.ad--xlhalfpage{padding:1.4285714286rem 0;border-bottom:1px solid #ededed}.ad--xlhalfpage .ad__wrapper{max-width:369px;max-width:26.3571428571rem}.ad--xlhalfpage .ad__inner{padding-top:162.6016260163%}.ad--xlhalfpage .ad__inner .ad__panel-2{width:162.6%!important}.ad--textlink .ad__wrapper{max-width:568px;max-width:40.5714285714rem}.ad--textlink .ad__inner{padding-top:17.6056338028%}.ad--fortuneo .ad__wrapper{max-width:170px;max-width:12.1428571429rem}.ad--fortuneo .ad__inner{padding-top:41.1764705882%}.ad--crosspromo .ad__wrapper{max-width:325px;max-width:23.2142857143rem;margin:0 auto}.ad--crosspromo .ad__inner{padding-top:66.4615384615%}.ad--advertorial1,.ad--advertorial2,.ad--advertorial3{padding:1.4285714286rem 0;border-bottom:1px solid #ededed}.ad--advertorial1 .ad__wrapper,.ad--advertorial2 .ad__wrapper,.ad--advertorial3 .ad__wrapper{max-width:300px;max-width:21.4285714286rem}.ad--advertorial1 .ad__inner,.ad--advertorial2 .ad__inner,.ad--advertorial3 .ad__inner{padding-top:33.3333333333%}.ad--advertorialinhouse{margin-bottom:1.4285714286rem}.ad--advertorialinhouse .ad__wrapper{max-width:568px;max-width:40.5714285714rem}.ad--advertorialinhouse .ad__inner{overflow:hidden;padding-top:37.8521126761%}.ad--banthird{padding:1.4285714286rem 0;border-bottom:1px solid #ededed}.ad--banthird .ad__wrapper{max-width:568px;max-width:40.5714285714rem}.ad--banthird .ad__inner{overflow:hidden;padding-top:44.8943661972%}.ad--wallpaper{background-position:center top;background-repeat:no-repeat;display:block;width:100%;left:0;position:absolute;top:0;height:1000px;height:71.4285714286rem}.no-touch .ad--wallpaper a{position:fixed}.ad--preroll{background-color:#000;bottom:0;left:0;height:100%;overflow:hidden;position:absolute;right:0;top:0;width:100%;z-index:1030}.ad--preroll .ad__wrapper{max-width:640px;max-width:45.7142857143rem;height:100%;margin:0 auto}.ad--preroll .ad__inner{padding-top:56.25%;width:100%}.ad--splash{height:100%;overflow-y:auto}.ad--splash .ad__wrapper{padding:4.2857142857rem 0;width:640px;width:45.7142857143rem;height:100%;margin:0 auto;max-width:98%;text-align:left!important}.ad--splash .ad__inner{padding-top:75%;width:100%}.ad--splash .ad__inner img{width:auto!important}.ad--splash .center__ghost{display:none}.ad--xlsplash{height:100%;overflow-y:auto}.ad--xlsplash .ad__wrapper{padding:4.2857142857rem 0;width:1000px;width:71.4285714286rem;height:100%;margin:0 auto;max-width:98%;text-align:left!important}.ad--xlsplash .ad__inner{padding-top:75%;width:100%}.ad--xlsplash .ad__inner img{width:auto!important}.ad--xlsplash .center__ghost{display:none}.ad--overlayer{top:300px;top:21.4285714286rem;position:absolute;z-index:1030}.ad--overlayer .ad__inner{max-width:640px;max-width:45.7142857143rem;width:640px;width:45.7142857143rem;padding-top:75%}.ad--fullpagelayer{position:absolute;top:0;z-index:1030}.ad--fullpagelayer .ad__inner{max-width:1000px;max-width:71.4285714286rem;width:1000px;width:71.4285714286rem;padding-top:80%}.ad--floorad{background:rgba(255,255,255,.7);bottom:0;left:0;max-width:100%;position:fixed;width:100%;z-index:1028}.ad--floorad .ad__wrapper{max-width:995px;max-width:71.0714285714rem;margin:0 auto}.ad--floorad .ad__inner{padding-top:10.0502512563%}#adh_incontentContainer{height:0;cursor:pointer;overflow:hidden;margin:0 auto 1.4285714286rem;width:100%;-webkit-transition:height .6s ease-out,margin .6s ease-out;-moz-transition:height .6s ease-out,margin .6s ease-out;transition:height .6s ease-out,margin .6s ease-out;position:relative}#adh_incontentContainer object{margin:0 auto}#adh_incontentContainer #adh_incontentPlayer{height:288px;height:20.5714285714rem;width:100%}#adh_incontentContainer span#linkOverlay{position:absolute;width:100%;height:258px;height:18.4285714286rem;top:0;left:0}.ad--4K .ad__wrapper,.ad--4k .ad__wrapper{max-width:957px;max-width:68.3571428571rem}.ad--4K .ad__inner,.ad--4k .ad__inner{padding-top:67.87109375%}.ad--pano .ad__wrapper{max-width:957px;max-width:68.3571428571rem}.ad--pano .ad__inner{padding-top:72.6227795193%}.ad--halfpano .ad__wrapper{max-width:1024px;max-width:73.1428571429rem}.ad--halfpano .ad__inner{padding-top:36.328125%}.ad--art1000 .ad__wrapper{max-width:460px;max-width:32.8571428571rem}.ad--art1000 .ad__inner{padding-top:151.0869565217%}.ad--art750 .ad__wrapper{max-width:480px;max-width:34.2857142857rem}.ad--art750 .ad__inner{padding-top:141.4583333333%}.ad--art500 .ad__wrapper{max-width:480px;max-width:34.2857142857rem}.ad--art500 .ad__inner{padding-top:76.4583333333%}.ad--art250 .ad__wrapper{max-width:240px;max-width:17.1428571429rem}.ad--art250 .ad__inner{padding-top:140.8333333333%}.ad--art125 .ad__wrapper{max-width:240px;max-width:17.1428571429rem}.ad--art125 .ad__inner{padding-top:159.5833333333%}.ad--acc50 .ad__wrapper{max-width:480px;max-width:34.2857142857rem}.ad--acc50 .ad__inner{padding-top:19.5833333333%}.ad--acc100 .ad__wrapper{max-width:480px;max-width:34.2857142857rem}.ad--acc100 .ad__inner{padding-top:39.1666666667%}.ad--acc150 .ad__wrapper{max-width:480px;max-width:34.2857142857rem}.ad--acc150 .ad__inner{padding-top:58.75%}.ad--acc2 .ad__wrapper{max-width:170px;max-width:12.1428571429rem}.ad--acc2 .ad__inner{padding-top:408.8235294118%}.ad--acc3 .ad__wrapper{max-width:240px;max-width:17.1428571429rem}.ad--acc3 .ad__inner{padding-top:271.25%}.ad--ap50 .ad__wrapper{max-width:144px;max-width:10.2857142857rem}.ad--ap50 .ad__inner{padding-top:111.1111111111%}.ad--ap100 .ad__wrapper{max-width:240px;max-width:17.1428571429rem}.ad--ap100 .ad__inner{padding-top:53.3333333333%}.ad--ap200 .ad__wrapper{max-width:240px;max-width:17.1428571429rem}.ad--ap200 .ad__inner{padding-top:106.6666666667%}.ad--ap400 .ad__wrapper{max-width:480px;max-width:34.2857142857rem}.ad--ap400 .ad__inner{padding-top:52.2916666667%}.alert{margin-bottom:1.4285714286rem;padding:.8571428571rem;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;background-color:#ddd;border:1px solid #aaa;color:#666}.alert a{text-decoration:underline;color:#666}.alert a:visited{color:#666}.alert a:focus,.alert a:hover{color:#333;text-decoration:underline}.alert a:active{text-decoration:underline}.alert--info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad}.alert--info a{text-decoration:underline;color:#3a87ad}.alert--info a:visited{color:#3a87ad}.alert--info a:focus,.alert--info a:hover{color:#204b61;text-decoration:underline}.alert--info a:active{text-decoration:underline}.alert--warning{background-color:#fcf8e3;border:1px solid #fbeed5;color:#c09853}.alert--warning a{text-decoration:underline;color:#c09853}.alert--warning a:visited{color:#c09853}.alert--warning a:focus,.alert--warning a:hover{color:#7f612e;text-decoration:underline}.alert--warning a:active{text-decoration:underline}.alert--success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847}.alert--success a{text-decoration:underline;color:#468847}.alert--success a:visited{color:#468847}.alert--success a:focus,.alert--success a:hover{color:#234524;text-decoration:underline}.alert--success a:active{text-decoration:underline}.alert--error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48}.alert--error a{text-decoration:underline;color:#b94a48}.alert--error a:visited{color:#b94a48}.alert--error a:focus,.alert--error a:hover{color:#702c2b;text-decoration:underline}.alert--error a:active{text-decoration:underline}@media screen and (min-width:48em){.promo .avatar{position:absolute;left:-44px;top:0}}.article-full .article__body .avatar{margin:0 1.4285714286rem 1.4285714286rem 0;float:left}.ad--splash .article,.ad--splash article,.ad--xlsplash .article,.ad--xlsplash article,.main-container .article,.main-container article,.modalbox .article,.modalbox article{padding-top:1.4285714286rem;padding-bottom:1.4285714286rem}.ad--splash .article:after,.ad--splash article:after,.ad--xlsplash .article:after,.ad--xlsplash article:after,.main-container .article:after,.main-container article:after,.modalbox .article:after,.modalbox article:after{content:".";display:block;height:0;clear:both;visibility:hidden}.article img,article img{margin-left:auto;margin-right:auto;width:100%}.widget__list .article,.widget__list article{padding-top:0;padding-bottom:0}.article>a,article>a{display:block}.article>a:after,article>a:after{content:".";display:block;height:0;clear:both;visibility:hidden}.article>a,.article>a:visited,article>a,article>a:visited{color:#444;text-decoration:none}.article>a:active,.article>a:focus,.article>a:hover,article>a:active,article>a:focus,article>a:hover{color:#000;text-decoration:none}.article>a:active .article__header,.article>a:focus .article__header,.article>a:hover .article__header,article>a:active .article__header,article>a:focus .article__header,article>a:hover .article__header{color:#666}.article>a:active img,.article>a:focus img,.article>a:hover img,article>a:active img,article>a:focus img,article>a:hover img{opacity:.9}.island .article,.island article,.islet .article,.islet article{padding-top:0}.island .article:last-child,.island article:last-child,.islet .article:last-child,.islet article:last-child{padding-bottom:0}@media screen and (min-width:68.4375em){.ad--splash article,.ad--xlsplash article,.modalbox article{margin-right:25.8%;margin-left:25.8%}}@media screen and (min-width:68.4375em){.modalbox--template-2k2k.ad--splash article,.modalbox--template-2k2k.ad--xlsplash article,.modalbox.modalbox--template-2k2k article{margin-left:0;margin-right:40%}}.article__header{margin:0 0 .8571428571rem;color:#000;line-height:1.2}.article__subheader{font-size:16px;font-size:1.1428571429rem;margin-bottom:.5714285714rem;color:#aaa;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;line-height:1;text-transform:uppercase}.article__sharelinks:after{content:".";display:block;height:0;clear:both;visibility:hidden}.article__sharelinks .pull-left,.article__sharelinks .pull-right{margin-bottom:1.4285714286rem;float:none;width:100%}@media screen and (min-width:48em){.article__sharelinks .pull-left,.article__sharelinks .pull-right{width:auto}}.article__sharelinks .pull-left>*,.article__sharelinks .pull-right>*{display:inline-block}.article__sharelinks .pull-left>*+*,.article__sharelinks .pull-right>*+*{margin-left:.8571428571rem}.article__sharelinks .pull-left div,.article__sharelinks .pull-right div{vertical-align:top}.article__sharelinks .pull-left .twitter-share-button,.article__sharelinks .pull-left [id^="___plusone"],.article__sharelinks .pull-right .twitter-share-button,.article__sharelinks .pull-right [id^="___plusone"]{position:relative;top:3px}@media screen and (min-width:48em){.article__sharelinks .pull-left{float:left}}@media screen and (min-width:48em){.article__sharelinks .pull-right{float:right}}.article__body>:last-child{margin-bottom:0}.article__body+*{margin-top:1.4285714286rem}@media screen and (min-width:62.1875em){.regionals .primary-col .article-teaser .article__body,.secondary-col .article-teaser .article__body{margin-left:110px}}.is-closed-article .article-full .article__body,.is-closed-article.theme-fs article .article__body{position:relative}.is-closed-article .article-full .article__body:after,.is-closed-article.theme-fs article .article__body:after{height:200px;height:14.2857142857rem;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(40%,rgba(255,255,255,0)),color-stop(80%,#fff));background-image:-webkit-linear-gradient(rgba(255,255,255,0) 40%,#fff 80%);background-image:-moz-linear-gradient(rgba(255,255,255,0) 40%,#fff 80%);background-image:linear-gradient(rgba(255,255,255,0) 40%,#fff 80%);bottom:0;content:'';left:0;position:absolute;width:100%}@media screen and (min-width:48em){.article-full--poster .article__body{margin-left:78%}}.article-teaser--quote .article__body{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;text-align:left}.article-full .intro{margin-bottom:1.4285714286rem;font-weight:700}.article-full .intro .byline,.slideshow__intro .byline{display:none}.article-full{color:#444}.article-full figure{margin-bottom:20px;background-color:#ddd}.article-full figcaption{background-color:#fff;font-size:12px;font-size:.8571428571rem;padding:.5714285714rem 0 0;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;text-align:left}.article-full figcaption span{font-size:11px;font-size:.7857142857rem;color:#aaa}.article-full .article__body{line-height:1.5}.article-full .article__body p{color:#000}.article-full .crossheading,.article-full .question,.article-full .title-text{font-weight:700}.article-full .crossheading,.article-full .title-text{font-size:18px;font-size:1.2857142857rem;margin-bottom:0}.article-full .custom-list{margin-bottom:1.4285714286rem}.article-header-wrapper{padding-left:1.4285714286rem;padding-right:1.4285714286rem;position:relative}@media screen and (min-width:40em){.article-header-wrapper{padding-left:0;padding-right:0}.article-header-wrapper footer,.article-header-wrapper header{margin-right:170px}}.article__meta{clear:both;color:#aaa}.article__meta p{margin-bottom:0}.article__meta span{color:#444}@media screen and (min-width:48em){.article-full--poster .article__meta{margin-left:78%}}.article__content-info{margin-bottom:1.4285714286rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.breaking-news-wrapper{background-color:#fff;margin-left:-20px;margin-right:-20px}.breaking-news-wrapper:after{content:".";display:block;height:0;clear:both;visibility:hidden}.breaking-news-wrapper.breaking-news--fase-1{text-align:center}.breaking-news-wrapper.breaking-news--fase-1 .heading--framed{display:inline-block;margin:0 1.4285714286rem 0 0}.article-breaking-news{background-color:#fff;position:relative}.breaking-news--fase-1 .article-breaking-news .article__header{display:inline-block}@media screen and (min-width:62.1875em){.breaking-news--fase-2 .article-breaking-news,.breaking-news--fase-3 .article-breaking-news{float:left}}@media screen and (min-width:62.1875em){.breaking-news--fase-2 .article-breaking-news{width:60%}}@media screen and (min-width:62.1875em){.breaking-news--fase-3 .article-breaking-news{width:40%}}.breaking-news--fase-2 .article-breaking-news.article--no-thumb,.breaking-news--fase-3 .article-breaking-news.article--no-thumb{margin-top:0}.breaking-news--fase-2 .article-breaking-news.article--no-thumb{width:100%}.article-breaking-news .article__body{padding-left:1.4285714286rem;padding-right:1.4285714286rem}.article-breaking-news .article__header{font-size:28px;font-size:2rem}.article-breaking__related{padding-left:1.4285714286rem;padding-right:1.4285714286rem}.article-breaking__related:after{content:".";display:block;height:0;clear:both;visibility:hidden}@media screen and (min-width:62.1875em){.article-breaking__related{float:left;width:60%;padding:0}}.article-breaking__related article{padding-top:1.4285714286rem!important;float:left;width:33.3333%}.article-breaking__related article:nth-child(3n+1){clear:left}.article-breaking__related article .article__body{padding-right:1.4285714286rem}.article-breaking__related article .article__header{font-size:18px;font-size:1.2857142857rem}.article-chapeau a{display:inline}.article-chapeau a,.article-chapeau a:active,.article-chapeau a:focus,.article-chapeau a:hover,.article-chapeau a:visited{text-decoration:none}.article-chapeau .article__header{font-size:28px;font-size:2rem}.article-chapeau-square .article__body{overflow:hidden}.article-chapeau-square img{margin-bottom:12px}@media screen and (min-width:40em){.article-chapeau-square img{float:left;margin-bottom:0;width:48.2%!important;margin-right:20px}}.secondary-col .article-chapeau-square .article__header{font-size:20px;font-size:1.4285714286rem}.secondary-col .article-chapeau-square .article__content-info,.secondary-col .article-chapeau-square .custom-list{display:none}.article-lsc>a{position:relative}.article-lsc .article__extra,.article-lsc .article__header,.article-lsc .intro{color:#fff}.article-lsc .article__body,.article-lsc .article__extra{position:absolute}.article-lsc .article__extra,.article-lsc .intro{font-size:13px;font-size:.9285714286rem;line-height:1.3846153846}.article-lsc .article__header{font-size:16px;font-size:1.1428571429rem;line-height:1.125;font-weight:700;margin-bottom:.3em}.article-lsc .article__body{padding:.8571428571rem;text-align:left;text-shadow:0 1px 0 #000;-webkit-font-smoothing:antialiased}.article-lsc .article__extra{right:12px;right:.8571428571rem;background-color:#44c4d1;padding:.5em .5em .2em;top:0}.article-headline .article__header{font-size:20px;font-size:1.4285714286rem}.photo-special .article-headline,.video-special .article-headline{padding-right:1.4285714286rem;margin-bottom:1.4285714286rem}.article-headline-rectangle .article__header{font-size:20px;font-size:1.4285714286rem}.article-chapeau:after,.article-headline:after,.article-teaser:after{content:".";display:block;height:0;clear:both;visibility:hidden}.article-chapeau-rectangle img,.article-headline img{margin-bottom:12px}.photo-special .article-teaser,.video-special .article-teaser{padding-right:1.4285714286rem;margin-bottom:1.4285714286rem}.secondary-col .photo-special .article-teaser,.secondary-col .video-special .article-teaser{padding-right:0}.photo-special .article-teaser .article__content-info,.photo-special .article-teaser .article__subheader,.photo-special .article-teaser .intro,.video-special .article-teaser .article__content-info,.video-special .article-teaser .article__subheader,.video-special .article-teaser .intro{display:none}.photo-special .article-teaser .article__header,.video-special .article-teaser .article__header{font-size:14px;font-size:1rem}.photo-special .article-teaser .article-media__helper,.photo-special .article-teaser .article-media__helper img,.photo-special .article-teaser img,.video-special .article-teaser .article-media__helper,.video-special .article-teaser .article-media__helper img,.video-special .article-teaser img{margin-right:0;margin-bottom:0;width:100%!important}.photo-special .article-teaser .article-media__helper img,.photo-special .article-teaser.article-teaser-square img,.video-special .article-teaser .article-media__helper img,.video-special .article-teaser.article-teaser-square img{margin-bottom:12px}.photo-special .article-teaser .article__body,.video-special .article-teaser .article__body{margin-left:0}.article-teaser .article__header{font-size:20px;font-size:1.4285714286rem}.article-teaser-square .article-media__helper,.article-teaser-square.article-teaser img{float:left;width:90px;margin-right:20px;margin-bottom:6px}.article-teaser-square .article-media__helper img{float:none;margin:0}.article-teaser-square .article__header{font-size:18px;font-size:1.2857142857rem}.secondary-col .photo-special .article-teaser-square .intro,.secondary-col .video-special .article-teaser-square .intro{display:block}@media screen and (min-width:40em){.article-teaser-rectangle img{float:left;width:48.2%!important;margin-right:20px}}.article-teaser-rectangle .article__body{margin-left:51.8%}.article-teaser-rectangle.article--no-thumb .article__body{margin-left:0}.article__special:before{content:"#";color:#44c4d1;padding-right:6px}.article-teaser--2k img{margin-bottom:1.4285714286rem}.article--visual{position:relative;overflow:hidden}.row .article--visual,.slideshow .article--visual,.slideshow__teasers .widget__list .article--visual{margin-bottom:.8571428571rem}.row:last-child .article--visual,.slideshow:last-child .article--visual,.slideshow__teasers .widget__list:last-child .article--visual{margin-bottom:0}.article--visual img{margin-top:0;margin-bottom:0}.article--visual h2,.article--visual h3{padding:.8571428571rem;font-size:20px;font-size:1.4285714286rem;background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(#000));background-image:-webkit-linear-gradient(rgba(0,0,0,0),#000);background-image:-moz-linear-gradient(rgba(0,0,0,0),#000);background-image:linear-gradient(rgba(0,0,0,0),#000);color:#fff;bottom:0;left:0;margin:0;position:absolute;right:0;text-align:center;top:auto}.callout--standalone .article--visual.article--visual--large{max-width:292px}.article--visual-medium{max-height:134px}.article-chapeau-square.article--plus a{display:inline-block}.article--plus a{position:relative}.article--plus a .article__body time{color:#000}.article--plus .article__header .plustitle{background:url(../img/plus/logo_naasttitel.png) no-repeat;background:0 0,url(../img/plus/logo_naasttitel.svg) no-repeat;width:40px;width:2.8571428571rem;height:22px;height:1.5714285714rem;display:inline-block;margin-right:.3571428571rem;position:relative}.article--plus .article__header .plustitle #ds_popup{top:-55px}.article--plus .plusimage{background:url(../img/plus/logo_opfoto.png) no-repeat;background:0 0,url(../img/plus/logo_opfoto.svg) no-repeat;width:50px;width:3.5714285714rem;height:30px;height:2.1428571429rem;display:none;z-index:1000;position:absolute;left:-5px;top:10px}@media screen and (min-width:62.1875em){.article--plus .plusimage{display:inline-block}}.article--plus .plusimage #ds_popup{top:-55px}.article--plus #ds_popup{position:absolute;top:-50px;min-width:180px;background-color:#fff;z-index:1030;font-size:13px;font-size:.9285714286rem;color:#dd2727;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;border:1px solid #eee;padding:.3571428571rem}.article--plus #ds_popup:after,.article--plus #ds_popup:before{content:"";position:absolute;width:0;height:0;border-style:solid;border-color:transparent;border-bottom:0}.article--plus #ds_popup:before{bottom:-10px;left:11px;border-top-color:#eee;border-width:10px}.article--plus #ds_popup:after{bottom:-9px;left:12px;border-top-color:#fff;border-width:9px}.article--shared .article__header{margin-top:3.5714285714rem;position:relative}.article--shared .article__header:after,.article--shared .article__header:before{margin:0 0 .3571428571rem;padding:.2142857143rem .1428571429rem .0714285714rem;top:-30px;top:-2.1428571429rem;display:inline-block;content:"Krant - In de kijker";font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:.6em;left:0;position:absolute;text-transform:uppercase;width:100%}.article--shared .article__header:after{content:"Gratis";font-weight:700;left:auto;right:0;width:auto}.article-opinion{margin-top:1.4285714286rem;padding:1.4285714286rem;background-color:#eee}.article-opinion blockquote{font-size:21px;font-size:1.5rem;padding:2.8571428571rem 0 0;font-style:italic;margin:0;position:relative}.article-opinion blockquote:before{content:'“';display:block;font-size:3em;line-height:1;left:0;position:absolute;top:0}.secondary-col .article-opinion{margin-bottom:0}.widget .article-opinion{margin-top:0}.article-opinion,.widget .article-opinion{margin-bottom:1.4285714286rem}.article-opinion--live{background-color:#44c4d1}.article-opinion--live a{-webkit-font-smoothing:antialiased;text-decoration:none;color:#fff}.article-opinion--live a:visited{color:#fff}.article-opinion--live a:focus,.article-opinion--live a:hover{color:#fff;text-decoration:none}.article-opinion--live a .link--proceed{color:#fff}.article-opinion--live .credentials,.article-opinion--live blockquote:before{color:#0e373b!important}.article-spotlight{padding:1.4285714286rem!important;background-color:#7ba2cc}.article-spotlight:after{content:".";display:block;height:0;clear:both;visibility:hidden}.article-spotlight a>img{float:left}.article-spotlight .article__body{margin-left:110px;color:#fff}.article-spotlight .flush-left+.article__body{margin-left:90px}.article-spotlight .article__header{font-size:18px;font-size:1.2857142857rem;line-height:1.3;color:#fff}.article__col{float:left;width:50%}.article__col .gallery{float:none}.article-teaser--editorial .article__col--left{max-width:95px}.article__col__inner .article-teaser--editorial .article__col--left{padding-right:1.4285714286rem}.article-teaser--editorial .article__col--right{float:none;width:auto;margin-left:95px}.article__col--left .article__col__inner,.l-zone>.widget .widget__list article{padding-right:1.4285714286rem}.article-media-photoset .article-media__helper:after,.article-media-video .article-media__helper:after,.photo-special .article-teaser-square .article-media__helper:after,.video-special .article-teaser-square .article-media__helper:after{width:50px;height:36px;line-height:36px;margin-left:-26px;margin-top:-19px;-webkit-border-radius:8px;-moz-border-radius:8px;border-radius:8px;-webkit-background-clip:content-box;-moz-background-clip:content-box;background-clip:content-box;background-color:rgba(0,0,0,.5);border:1px solid #fff;color:#fff;font-family:Dso-icons;font-style:normal;font-weight:400;position:absolute;left:50%;top:50%;text-align:center;speak:none;-webkit-font-smoothing:antialiased}.article-teaser-square .article-media__helper:after,.regionals .primary-col .article-media-photoset .article-media__helper:after,.regionals .primary-col .article-media-video .article-media__helper:after,.secondary-col .article-media-photoset .article-media__helper:after,.secondary-col .article-media-video .article-media__helper:after{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;width:34px;height:24px;line-height:26px;margin-left:-18px;margin-top:-13px;font-size:12px}.article-media__helper{position:relative}.article-media__helper>img{float:none;width:auto;max-width:100%;margin:0 auto}@media screen and (min-width:40em){.article-chapeau-square .article-media__helper,.article-teaser-rectangle .article-media__helper{float:left;width:48.2%;margin-right:20px}}.article-chapeau-square .article-media__helper img,.article-teaser-rectangle .article-media__helper img{width:auto!important;float:none;margin-top:0;margin-bottom:0}.article-chapeau-rectangle .article-media__helper,.article-headline-rectangle .article-media__helper,.article-headline-square .article-media__helper{margin-bottom:12px}.regionals .primary-col .article-teaser .article-media__helper,.secondary-col .article-teaser .article-media__helper{float:left;margin-bottom:6px;margin-right:20px;width:90px}.regionals .primary-col .article-teaser .article-media__helper img,.secondary-col .article-teaser .article-media__helper img{margin-bottom:0;margin-right:0}.no-rgba .article-media-photoset .article-media__helper:after,.no-rgba .article-media-video .article-media__helper:after{display:none}.article-media__helper--fallback{background:#000;color:#fff;font-family:Dso-icons;border:1px solid #fff;width:50px;height:36px;line-height:36px;margin-left:-26px;margin-top:-19px;position:absolute;left:50%;top:50%;text-align:center;speak:none}.regionals .primary-col .article-media__helper--fallback,.secondary-col .article-media__helper--fallback{width:34px;height:24px;line-height:26px;margin-left:-18px;margin-top:-13px;font-size:12px}.article-teaser .is-active{opacity:.4;cursor:default}.article--bg-color--1,.article--bg-color--2,.article--bg-color--3,.article--bg-color--4,.article--bg-color--5,.article--bg-color--6,.article--shared{margin-bottom:1.4285714286rem}.article--bg-color--1:first-child,.article--bg-color--2:first-child,.article--bg-color--3:first-child,.article--bg-color--4:first-child,.article--bg-color--5:first-child,.article--bg-color--6:first-child,.article--shared:first-child{margin-top:1.4285714286rem}article+.article--bg-color--1,article+.article--bg-color--2,article+.article--bg-color--3,article+.article--bg-color--4,article+.article--bg-color--5,article+.article--bg-color--6,article+.article--shared{border-top:0}.main-container .article--bg-color--1,.main-container .article--bg-color--2,.main-container .article--bg-color--3,.main-container .article--bg-color--4,.main-container .article--bg-color--5,.main-container .article--bg-color--6,.main-container .article--shared{padding-top:0}.article--bg-color--1 .article__body,.article--bg-color--1 .credentials,.article--bg-color--1 blockquote,.article--bg-color--2 .article__body,.article--bg-color--2 .credentials,.article--bg-color--2 blockquote,.article--bg-color--3 .article__body,.article--bg-color--3 .credentials,.article--bg-color--3 blockquote,.article--bg-color--4 .article__body,.article--bg-color--4 .credentials,.article--bg-color--4 blockquote,.article--bg-color--5 .article__body,.article--bg-color--5 .credentials,.article--bg-color--5 blockquote,.article--bg-color--6 .article__body,.article--bg-color--6 .credentials,.article--bg-color--6 blockquote,.article--shared .article__body,.article--shared .credentials,.article--shared blockquote{padding-left:.8571428571rem;padding-right:.8571428571rem}.article--bg-color--1 .custom-list,.article--bg-color--2 .custom-list,.article--bg-color--3 .custom-list,.article--bg-color--4 .custom-list,.article--bg-color--5 .custom-list,.article--bg-color--6 .custom-list,.article--shared .custom-list{margin-left:12px!important;margin-right:12px!important;margin-bottom:0}.widget__list .article--bg-color--1,.widget__list .article--bg-color--2,.widget__list .article--bg-color--3,.widget__list .article--bg-color--4,.widget__list .article--bg-color--5,.widget__list .article--bg-color--6,.widget__list .article--shared{padding-top:1.4285714286rem!important;background:0 0;border:0;margin-top:0}.widget__list .article--bg-color--1 .article__header,.widget__list .article--bg-color--2 .article__header,.widget__list .article--bg-color--3 .article__header,.widget__list .article--bg-color--4 .article__header,.widget__list .article--bg-color--5 .article__header,.widget__list .article--bg-color--6 .article__header,.widget__list .article--shared .article__header{margin-top:0}.widget__list .article--bg-color--1 .article__header:after,.widget__list .article--bg-color--1 .article__header:before,.widget__list .article--bg-color--2 .article__header:after,.widget__list .article--bg-color--2 .article__header:before,.widget__list .article--bg-color--3 .article__header:after,.widget__list .article--bg-color--3 .article__header:before,.widget__list .article--bg-color--4 .article__header:after,.widget__list .article--bg-color--4 .article__header:before,.widget__list .article--bg-color--5 .article__header:after,.widget__list .article--bg-color--5 .article__header:before,.widget__list .article--bg-color--6 .article__header:after,.widget__list .article--bg-color--6 .article__header:before,.widget__list .article--shared .article__header:after,.widget__list .article--shared .article__header:before{display:none}.widget__list .article--bg-color--1 .article__body,.widget__list .article--bg-color--2 .article__body,.widget__list .article--bg-color--3 .article__body,.widget__list .article--bg-color--4 .article__body,.widget__list .article--bg-color--5 .article__body,.widget__list .article--bg-color--6 .article__body,.widget__list .article--shared .article__body{padding-left:0;padding-right:0}.article-chapeau-square.article--bg-color--1,.article-chapeau-square.article--bg-color--2,.article-chapeau-square.article--bg-color--3,.article-chapeau-square.article--bg-color--4,.article-chapeau-square.article--bg-color--5,.article-chapeau-square.article--bg-color--6,.article-chapeau-square.article--shared,.article-teaser-square.article--bg-color--1,.article-teaser-square.article--bg-color--2,.article-teaser-square.article--bg-color--3,.article-teaser-square.article--bg-color--4,.article-teaser-square.article--bg-color--5,.article-teaser-square.article--bg-color--6,.article-teaser-square.article--shared{overflow:hidden;padding-bottom:0}.article-chapeau-square.article--bg-color--1 .article-media-helper,.article-chapeau-square.article--bg-color--1 img,.article-chapeau-square.article--bg-color--2 .article-media-helper,.article-chapeau-square.article--bg-color--2 img,.article-chapeau-square.article--bg-color--3 .article-media-helper,.article-chapeau-square.article--bg-color--3 img,.article-chapeau-square.article--bg-color--4 .article-media-helper,.article-chapeau-square.article--bg-color--4 img,.article-chapeau-square.article--bg-color--5 .article-media-helper,.article-chapeau-square.article--bg-color--5 img,.article-chapeau-square.article--bg-color--6 .article-media-helper,.article-chapeau-square.article--bg-color--6 img,.article-chapeau-square.article--shared .article-media-helper,.article-chapeau-square.article--shared img,.article-teaser-square.article--bg-color--1 .article-media-helper,.article-teaser-square.article--bg-color--1 img,.article-teaser-square.article--bg-color--2 .article-media-helper,.article-teaser-square.article--bg-color--2 img,.article-teaser-square.article--bg-color--3 .article-media-helper,.article-teaser-square.article--bg-color--3 img,.article-teaser-square.article--bg-color--4 .article-media-helper,.article-teaser-square.article--bg-color--4 img,.article-teaser-square.article--bg-color--5 .article-media-helper,.article-teaser-square.article--bg-color--5 img,.article-teaser-square.article--bg-color--6 .article-media-helper,.article-teaser-square.article--bg-color--6 img,.article-teaser-square.article--shared .article-media-helper,.article-teaser-square.article--shared img{margin-bottom:0}.article-chapeau-square.article--bg-color--1 .article__body,.article-chapeau-square.article--bg-color--2 .article__body,.article-chapeau-square.article--bg-color--3 .article__body,.article-chapeau-square.article--bg-color--4 .article__body,.article-chapeau-square.article--bg-color--5 .article__body,.article-chapeau-square.article--bg-color--6 .article__body,.article-chapeau-square.article--shared .article__body,.article-teaser-square.article--bg-color--1 .article__body,.article-teaser-square.article--bg-color--2 .article__body,.article-teaser-square.article--bg-color--3 .article__body,.article-teaser-square.article--bg-color--4 .article__body,.article-teaser-square.article--bg-color--5 .article__body,.article-teaser-square.article--bg-color--6 .article__body,.article-teaser-square.article--shared .article__body{overflow:hidden;padding-left:0}.article-chapeau-square.article--bg-color--1 .article__content-info,.article-chapeau-square.article--bg-color--1 .article__subheader,.article-chapeau-square.article--bg-color--1 .custom-list,.article-chapeau-square.article--bg-color--1 .link--proceed,.article-chapeau-square.article--bg-color--2 .article__content-info,.article-chapeau-square.article--bg-color--2 .article__subheader,.article-chapeau-square.article--bg-color--2 .custom-list,.article-chapeau-square.article--bg-color--2 .link--proceed,.article-chapeau-square.article--bg-color--3 .article__content-info,.article-chapeau-square.article--bg-color--3 .article__subheader,.article-chapeau-square.article--bg-color--3 .custom-list,.article-chapeau-square.article--bg-color--3 .link--proceed,.article-chapeau-square.article--bg-color--4 .article__content-info,.article-chapeau-square.article--bg-color--4 .article__subheader,.article-chapeau-square.article--bg-color--4 .custom-list,.article-chapeau-square.article--bg-color--4 .link--proceed,.article-chapeau-square.article--bg-color--5 .article__content-info,.article-chapeau-square.article--bg-color--5 .article__subheader,.article-chapeau-square.article--bg-color--5 .custom-list,.article-chapeau-square.article--bg-color--5 .link--proceed,.article-chapeau-square.article--bg-color--6 .article__content-info,.article-chapeau-square.article--bg-color--6 .article__subheader,.article-chapeau-square.article--bg-color--6 .custom-list,.article-chapeau-square.article--bg-color--6 .link--proceed,.article-chapeau-square.article--shared .article__content-info,.article-chapeau-square.article--shared .article__subheader,.article-chapeau-square.article--shared .custom-list,.article-chapeau-square.article--shared .link--proceed,.article-teaser-square.article--bg-color--1 .article__content-info,.article-teaser-square.article--bg-color--1 .article__subheader,.article-teaser-square.article--bg-color--1 .custom-list,.article-teaser-square.article--bg-color--1 .link--proceed,.article-teaser-square.article--bg-color--2 .article__content-info,.article-teaser-square.article--bg-color--2 .article__subheader,.article-teaser-square.article--bg-color--2 .custom-list,.article-teaser-square.article--bg-color--2 .link--proceed,.article-teaser-square.article--bg-color--3 .article__content-info,.article-teaser-square.article--bg-color--3 .article__subheader,.article-teaser-square.article--bg-color--3 .custom-list,.article-teaser-square.article--bg-color--3 .link--proceed,.article-teaser-square.article--bg-color--4 .article__content-info,.article-teaser-square.article--bg-color--4 .article__subheader,.article-teaser-square.article--bg-color--4 .custom-list,.article-teaser-square.article--bg-color--4 .link--proceed,.article-teaser-square.article--bg-color--5 .article__content-info,.article-teaser-square.article--bg-color--5 .article__subheader,.article-teaser-square.article--bg-color--5 .custom-list,.article-teaser-square.article--bg-color--5 .link--proceed,.article-teaser-square.article--bg-color--6 .article__content-info,.article-teaser-square.article--bg-color--6 .article__subheader,.article-teaser-square.article--bg-color--6 .custom-list,.article-teaser-square.article--bg-color--6 .link--proceed,.article-teaser-square.article--shared .article__content-info,.article-teaser-square.article--shared .article__subheader,.article-teaser-square.article--shared .custom-list,.article-teaser-square.article--shared .link--proceed{display:none}.article-chapeau-square.article--bg-color--1 .article__body,.article-chapeau-square.article--bg-color--2 .article__body,.article-chapeau-square.article--bg-color--3 .article__body,.article-chapeau-square.article--bg-color--4 .article__body,.article-chapeau-square.article--bg-color--5 .article__body,.article-chapeau-square.article--bg-color--6 .article__body,.article-chapeau-square.article--shared .article__body{padding-top:1.4285714286rem}.article-teaser-square.article--bg-color--1 .article__body,.article-teaser-square.article--bg-color--2 .article__body,.article-teaser-square.article--bg-color--3 .article__body,.article-teaser-square.article--bg-color--4 .article__body,.article-teaser-square.article--bg-color--5 .article__body,.article-teaser-square.article--bg-color--6 .article__body,.article-teaser-square.article--shared .article__body{padding-top:.4285714286rem}.article-teaser-square .article__content-info{display:block}.article--bg-color--1,.article--shared{background-color:#eee}.article--bg-color--2{background-color:#44c4d1}.article--bg-color--2 .article__body .link,.article--bg-color--2 .article__body .tag{color:#fff}.article--bg-color--2 .article__body .link .icon-photoset path,.article--bg-color--2 .article__body .link .icon-video path,.article--bg-color--2 .article__body .tag .icon-photoset path,.article--bg-color--2 .article__body .tag .icon-video path{fill:#fff}.article--bg-color--2 a:active .article__body .article__header,.article--bg-color--2 a:focus .article__body .article__header,.article--bg-color--2 a:hover .article__body .article__header{color:#fff}.article--bg-color--3,.article--bg-color--4,.article--bg-color--5,.article--bg-color--6{background-color:#eee}.article--header-size--1 .article__header{font-size:16px}.article--header-size--2 .article__header{font-size:18px}.article--header-size--3 .article__header{font-size:20px}.article--header-size--4 .article__header{font-size:24px}.article--header-size--5 .article__header{font-size:28px}.article--header-size--6 .article__header{font-size:36px}article+article{border-top:1px solid #eee}.before-after{position:relative}.before-after img{max-width:100%}.before-after .before-after__slide.before-after__before{overflow:hidden;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);transform:translateZ(0)}.before-after .before-after__slide.before-after__before .before-after__label{left:0}.before-after .before-after__slide.before-after__after{margin-right:-2px;display:none;border-right:2px solid transparent}.before-after .before-after__slide.before-after__after .before-after__label{right:0}.before-after .before-after__label{background:rgba(0,0,0,.5);padding:5px;display:none;color:#fff;white-space:nowrap;position:absolute;top:0}.before-after .before-after__controller{background:#fff;width:3px;margin-left:-5px;display:none;cursor:col-resize;position:absolute;top:0;bottom:0}.before-after .before-after__controller:before{background:#fff;width:13px;height:10%;margin-left:-5px;content:"";position:absolute;top:45%}.before-after .before-after__controller .icon{width:22px;height:22px;overflow:hidden;-webkit-transition:-webkit-transform .3s ease;-moz-transition:-moz-transform .3s ease;transition:transform .3s ease;position:absolute;top:50%;color:#fff}.before-after .before-after__controller .icon:before{margin:-7px 0 0 -6px;display:block}.before-after .before-after__controller .icon-arrow-left{-webkit-transform:translate3d(-30px,-12px,0) scale(0.6);-moz-transform:translate3d(-30px,-12px,0) scale(0.6);transform:translate3d(-30px,-12px,0) scale(0.6)}.before-after .before-after__controller .icon-arrow-right{-webkit-transform:translate3d(10px,-12px,0) scale(0.6);-moz-transform:translate3d(10px,-12px,0) scale(0.6);transform:translate3d(10px,-12px,0) scale(0.6)}.before-after .before-after__controller.active .icon-arrow-left,.before-after .before-after__controller:hover .icon-arrow-left{-webkit-transform:translate3d(-40px,-12px,0) scale(0.6);-moz-transform:translate3d(-40px,-12px,0) scale(0.6);transform:translate3d(-40px,-12px,0) scale(0.6)}.before-after .before-after__controller.active .icon-arrow-right,.before-after .before-after__controller:hover .icon-arrow-right{-webkit-transform:translate3d(20px,-12px,0) scale(0.6);-moz-transform:translate3d(20px,-12px,0) scale(0.6);transform:translate3d(20px,-12px,0) scale(0.6)}.before-after.initiated img{max-width:none}.before-after.initiated .before-after__controller,.before-after.initiated .before-after__label{display:block}.button,.mail-share-button{background-color:#f5f5f5;border:1px solid #ccc;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#666;cursor:pointer;display:inline-block;font-size:14px;font-size:1rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:400;line-height:1;padding:.5714285714rem .8571428571rem .4285714286rem;margin-bottom:0;text-align:center;text-decoration:none!important}.button:focus,.button:hover,.mail-share-button:focus,.mail-share-button:hover{background-color:#ccc;border-color:#aaa}a.button,a.mail-share-button{text-decoration:none;color:#666}a.button:visited,a.mail-share-button:visited{color:#666}a.button:focus,a.button:hover,a.mail-share-button:focus,a.mail-share-button:hover{color:#222;text-decoration:none}.button--small,.mail-share-button{padding:5px 6px 1px;font-size:11px}.button--medium{font-size:18px;font-size:1.2857142857rem}.button--large{font-size:20px;font-size:1.4285714286rem;padding:.8571428571rem}.button--primary{background-color:#006dcc;color:#fff!important;border-color:#002A80}.button--primary:focus,.button--primary:hover{background-color:#04c}.button--paco{background-color:#dd2727;color:#fff!important;border-color:#9f1919}.button--paco:focus,.button--paco:hover{background-color:#e76969;border-color:#dd2727}.button--facebook{font-size:14px;font-size:1rem;line-height:24px;height:40px;height:2.8571428571rem;border-color:transparent!important;font-weight:600;background-color:#3a5998;background-image:none;color:#fff!important;text-transform:uppercase}.button--facebook:hover{background-color:#253961}.button--facebook .icon-facebook{font-size:24px;font-size:1.7142857143rem;display:inline-block;padding-bottom:4px;vertical-align:middle}.button--mediaid{font-size:14px;font-size:1rem;height:40px;height:2.8571428571rem;border-color:transparent!important;font-weight:600;background-color:#2c84cb;background-image:none;color:#fff!important;text-transform:uppercase}.button--mediaid:hover{background-color:#1e5b8c}.button--mediaid:before{height:26px;height:1.8571428571rem;width:25px;width:1.7857142857rem;display:inline-block;content:' ';margin-right:10px;background:url(../img/mediaID-logo.png) no-repeat;background:0 0,url(../img/mediaID-logo.svg) no-repeat;vertical-align:middle}.button--invert{background-color:#000;color:#fff!important}.button--link{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;background:0 0;border:0}.button--link:focus,.button--link:hover{background:0 0}.ad--splash .button--close,.ad--splash .button--continue,.ad--xlsplash .button--close,.ad--xlsplash .button--continue,.modalbox .button--close,.modalbox .button--continue{opacity:.6;color:#fff!important;padding:0;position:absolute;right:20px;top:20px;width:35px;height:35px;font-size:35px;z-index:1130}.ad--splash .button--close:focus,.ad--splash .button--close:hover,.ad--splash .button--continue:focus,.ad--splash .button--continue:hover,.ad--xlsplash .button--close:focus,.ad--xlsplash .button--close:hover,.ad--xlsplash .button--continue:focus,.ad--xlsplash .button--continue:hover,.modalbox .button--close:focus,.modalbox .button--close:hover,.modalbox .button--continue:focus,.modalbox .button--continue:hover{opacity:1;background-color:transparent}.ad--xlsplash .button--close,.ad--xlsplash .button--continue,.modalbox--invert .button--close,.modalbox--invert .button--continue,.modalbox--invert--opaque .button--close,.modalbox--invert--opaque .button--continue,.modalbox-article .button--close,.modalbox-article .button--continue{color:#000!important;z-index:1031}.ad--splash .button--close,.ad--splash .button--continue{position:fixed}@media screen and (min-width:48em){.ad--splash .button--close,.ad--splash .button--continue{position:absolute;right:-32px;top:-32px}}.ad--floorad .button--close,.ad--floorad .button--continue{position:absolute;right:0;top:0;z-index:1029}.ad--fullpagelayer .button--close,.ad--fullpagelayer .button--continue{position:fixed}.alert .button--close,.alert .button--continue{position:relative;right:-10px;top:0;float:right;border:0;padding:0;background-color:transparent;font-size:21px;font-size:1.5rem;color:inherit}.button--continue{white-space:nowrap}.ad--splash .button--continue,.ad--xlsplash .button--continue,.modalbox .button--continue{width:auto}.ad--xlsplash .button--continue{position:absolute;right:0;top:-40px}.button--block,.button--facebook,.button--mediaid{display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:99.5%}.button--rounded{-webkit-border-radius:999px;-moz-border-radius:999px;border-radius:999px}.button--no-js{display:none;visibility:hidden}.no-js .button--no-js{display:inline-block;visibility:visible}.button--adhese-preview{position:fixed;right:20px;top:20px;z-index:9999}html .button--adhese-preview [class*=" icon-"],html .button--adhese-preview [class^=icon-]{color:#666!important;padding-right:.3em}.button__group{display:inline-block;white-space:nowrap;position:relative}blockquote{font-size:24px;font-size:1.7142857143rem}blockquote .source{font-size:14px;font-size:1rem;font-weight:700;text-transform:uppercase}.breadcrumb{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.breadcrumb li{float:left;display:block}.breadcrumb a{display:block;margin-right:.3em;float:left;text-decoration:none;color:#44c4d1}.breadcrumb a:visited{color:#44c4d1}.breadcrumb a:focus,.breadcrumb a:hover{color:#318f98;text-decoration:none}.breadcrumb b{font-weight:400;display:block}.bc__divider{display:block;color:#44c4d1;margin-right:.3em;position:relative;top:-1px;float:left}.breaker{padding:1.4285714286rem;border-top:1px solid #ededed}.breaker:after{content:".";display:block;height:0;clear:both;visibility:hidden}@media screen and (min-width:62.1875em){.breaker{padding-right:8.5%;padding-left:8.5%}}.breaker.sharer .avatar{float:left;margin-right:12px;margin-bottom:12px}.breaker.paywall{border-top:none}.breaker.paywall .col__cell{padding-right:1.4285714286rem}.breaker.paywall .cols-3 .col-1:after{content:none}.breaker.paywall img{max-width:100%}.breaker>.pull-left,.breaker>.pull-right{float:none}@media screen and (min-width:48em){.breaker>.pull-left{float:left;width:70%}}@media screen and (min-width:48em){.breaker>.pull-right{float:right;width:27%}}.breaker--soft{border-top:0;padding-top:0}.callout{background-color:#444;color:#fff;display:block}.callout:after{content:".";display:block;height:0;clear:both;visibility:hidden}.callout a{text-decoration:none;color:#fff}.callout a:visited{color:#fff}.callout a:focus,.callout a:hover{color:#fff;text-decoration:none}.callout article>a,.callout article>a:visited{color:#fff!important}.callout article>a:focus,.callout article>a:hover .callout article>a:active{color:#fff}.callout--standalone{padding:.8571428571rem}.callout--standalone>:first-child{margin-bottom:1.4285714286rem;padding-top:0;padding-bottom:0;margin-left:0}.carousel{padding:0 2.8571428571rem;position:relative}.carousel:after{content:".";display:block;height:0;clear:both;visibility:hidden}.carousel ol{-webkit-transition:all .2s;-moz-transition:all .2s;transition:all .2s;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);transform:translate3d(0,0,0);font-size:0;margin:0;position:relative;left:0;white-space:nowrap}.carousel ol:after{content:".";display:block;height:0;clear:both;visibility:hidden}.carousel li{display:inline-block;margin:0 .8571428571rem 0 0;font-size:14px}.carousel a{display:block;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;backface-visibility:hidden}.carousel__inner{overflow:hidden}.carousel__next,.carousel__prev{font-size:18px;line-height:1;margin-top:-.5em;left:.6em;position:absolute;top:50%;text-decoration:none;color:#666}.carousel__next:visited,.carousel__prev:visited{color:#666}.carousel__next:focus,.carousel__next:hover,.carousel__prev:focus,.carousel__prev:hover{color:#aaa;text-decoration:none}.carousel__next{left:auto;right:.6em}.center{text-align:center;height:100%;width:100%}.center__ghost,.center__item{display:inline-block;vertical-align:middle}.center__item{margin-left:-.3em!important}.center__ghost{height:100%}.credentials{margin-bottom:1.4285714286rem;margin-top:1.4285714286rem;background-color:#eee}.credentials:after{content:".";display:block;height:0;clear:both;visibility:hidden}.credentials img{float:left;max-width:104px!important;margin-bottom:0}.credentials__content{overflow:hidden;padding:12px}.credentials--clean{background:0 0;margin-bottom:0}.credentials--clean .credentials__content{padding-bottom:0;padding-top:0}.currently{padding-top:.8571428571rem;display:none;float:right;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;margin:0 20px 0 0;text-align:right;white-space:nowrap}@media screen and (min-width:40em){.currently{display:block}}.currently li{margin-left:.2857142857rem;display:inline-block}.currently a{font-size:13px;font-size:.9285714286rem;line-height:1.8}.currently a,.currently a:visited{color:#aaa!important;text-decoration:none}.currently a:active,.currently a:focus,.currently a:hover{color:#666!important;text-decoration:none}.article-comments{position:relative}.article-comments.is-hidden,.is-closed .comment__footer .article-comments[data-comments-reply-id]{display:none}.article-comments .button--close,.article-comments .button--continue{margin-bottom:.8571428571rem;color:#000}.article-comments .alert{background-color:#fff}.article-comments>.form--comment{margin-top:-2.2857142857rem;padding-bottom:1.4285714286rem;border-bottom:1px solid #ededed}.article-comments:focus{outline:0}.comments-list{margin:0}.comment-form+.comments-list{padding-top:1.4285714286rem;border-top:1px solid #ededed}.comment{position:relative}.comment .comment,.comment+.comment{padding-top:.8571428571rem;border-top:1px solid #ededed}.comment .comment{padding-left:1.4285714286rem}.comment .comment:before{top:15px;top:1.0714285714rem;color:#aaa;speak:none;left:0;line-height:1;position:absolute}.comment__header{padding-bottom:.8571428571rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.comment__footer{padding-bottom:.8571428571rem}.comment__footer menu{margin:0;padding:0}.comment__footer menu li{margin:0 .4285714286rem 0 0;color:#aaa;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;list-style:none;padding:0}.comment__footer menu li a{white-space:nowrap}.conversion__header{margin-bottom:.4285714286rem;font-size:26px;overflow:hidden}.conversion__body:after{content:".";display:block;height:0;clear:both;visibility:hidden}.conversion--1k{padding:1.4285714286rem 0;border-bottom:1px solid #ededed}.conversion--1k,.conversion--2k{border-color:#ededed!important}.conversion--2k{padding-bottom:1.4285714286rem}@media screen and (min-width:18.75em){.conversion--2k .conversion__body>div{float:left;width:50%}}.conversion--3k{padding:1.4285714286rem 0 .4285714286rem;border-style:solid;border-width:4px 0}.conversion--3k .conversion__header{text-align:center}.conversion--3k .conversion__title{font-weight:500}@media screen and (min-width:48em){.conversion--3k .conversion__body>div{float:left;margin-left:.5%;width:33%}.conversion--3k .conversion__body>div:first-child{margin-left:0}}#promo-niet-abos{display:none}.layout-conversion-plus #promo-niet-abos{display:block}.datepicker-wrapper>a{display:inline-block;height:30px;width:30px;text-align:center}.datepicker-wrapper i:before{position:relative;top:5px}.datepicker-wrapper input{margin-bottom:0!important}.ui-helper-clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-state-hover>*{background-color:#318f98;color:#fff!important}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0;background-color:#ddd;border:1px solid #aaa;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.ui-datepicker .ui-datepicker-next,.ui-datepicker .ui-datepicker-prev{position:absolute;top:2px;width:1.8em;height:1.8em;font-family:Dso-icons;font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased}.ui-datepicker .ui-datepicker-next:before,.ui-datepicker .ui-datepicker-prev:before{position:absolute;top:7px;left:4px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-next span,.ui-datepicker .ui-datepicker-prev span{display:none}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker .ui-datepicker-title select.ui-datepicker-month-year{width:100%}.ui-datepicker .ui-datepicker-title select.ui-datepicker-month,.ui-datepicker .ui-datepicker-title select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:2px 1px;text-align:center;font-weight:400;border:0;text-transform:none}.ui-datepicker td{border:1px solid #aaa;padding:0;text-align:center}.ui-datepicker td a,.ui-datepicker td span{display:block;padding:8px 4px 4px;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3333333333%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-trigger{display:inline-block;margin-left:12px}.ui-datepicker-calendar td{border:1px solid #318f98;background-color:#81d7e0}.ui-datepicker-calendar td>a{color:#318f98!important}.ui-datepicker-calendar .ui-datepicker-unselectable{border-color:#ddd;background-color:#fff;color:#aaa}.ui-datepicker-calendar .ui-datepicker-other-month{border:0;background-color:#fff}.ui-datepicker-calendar .ui-datepicker-current-day{background-color:#fff}.ui-datepicker-calendar .ui-datepicker-today{border-color:#1e595e;background-color:#318f98;color:#fff!important}.ui-datepicker-calendar .ui-datepicker-today>a{color:#fff!important}.ui-widget{font-size:14px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.ui-widget-content{border:1px solid #ddd;background-color:#fff;color:#666}.divider{padding-bottom:1.4285714286rem;border-bottom:1px solid #ededed}.divider--dashed{border-bottom-style:dashed;border-bottom-color:#ddd}.row+hr.divider,.slideshow+hr.divider,.slideshow__teasers .widget__list+hr.divider,hr.divider{margin:0 1.4285714286rem 0 0;border:0;border-top:1px solid #ededed;clear:both;display:block;float:none;font-size:0;height:0;padding:0}article+hr.divider{margin-right:0}article:nth-last-child(2)+hr.divider{display:none}.main-header hr.divider{margin-left:20px;margin-right:20px}.main-footer hr.divider{margin-left:20px;margin-right:20px;margin-bottom:20px}.row+hr.divider.divider--dashed,.slideshow+hr.divider.divider--dashed,.slideshow__teasers .widget__list+hr.divider.divider--dashed,hr.divider.divider--dashed{border-top-style:dashed;border-top-color:#ddd}.dsavond-widget{margin-left:-1.4285714286rem;margin-right:-1.4285714286rem;padding-left:1.4285714286rem;background-color:#fff;position:relative}.dsavond-widget img{width:100%}.dsavond-widget a:focus img,.dsavond-widget a:hover img{opacity:.9}.dsavond-widget__cover,.dsavond-widget__txt{margin:.8571428571rem 0}.dsavond-widget__cover{display:none;position:absolute;right:0;top:0;width:50%}@media screen and (min-width:30em){.dsavond-widget__cover{display:block}}@media screen and (min-width:40em){.dsavond-widget__cover{position:static;width:auto}}.dsavond-widget__txt{width:auto}@media screen and (min-width:30em){.dsavond-widget__txt{width:50%}}@media screen and (min-width:40em){.dsavond-widget__txt{width:auto}}.dsavond-widget__cover__item{margin-top:.4285714286rem}@media screen and (min-width:30em){.dsavond-widget__cover__item{float:left;width:50%}}.dsavond-widget__txt__item{padding-left:.8571428571rem;display:block;margin-bottom:.5em;position:relative;text-decoration:none;color:#444}.dsavond-widget__txt__item:visited{color:#444}.dsavond-widget__txt__item:focus,.dsavond-widget__txt__item:hover{color:#628226;text-decoration:none}.dsavond-widget__txt__item:before{background-color:#628226;content:'';display:block;height:5px;left:0;position:absolute;top:7px;width:5px}.dsavond-widget__txt__title{font-size:22px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;margin-bottom:.5em;padding-left:0;text-decoration:none;color:#628226}.dsavond-widget__txt__title:visited{color:#628226}.dsavond-widget__txt__title:focus,.dsavond-widget__txt__title:hover{color:#445b1a;text-decoration:none}.dsavond-widget__txt__title:before{display:none}.dsavond-widget__button{text-align:center}.dsavond-widget__button a{margin-left:-2.8571428571rem;margin-right:-1.4285714286rem;font-size:18px;background-color:#628226;display:block;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;padding:.9em 0;text-decoration:none;color:#fff}.dsavond-widget__button a:visited{color:#fff}.dsavond-widget__button a:focus,.dsavond-widget__button a:hover{color:#dbe4c4;text-decoration:none}@media screen and (min-width:40em){.dsavond-widget__button a{margin-left:-1.4285714286rem}}.dsavond-widget--alt{background-color:#7ea933;border-top:2px solid #628226}.dsavond-widget--alt .dsavond-widget__txt__item{text-decoration:none;color:#fff}.dsavond-widget--alt .dsavond-widget__txt__item:visited{color:#fff}.dsavond-widget--alt .dsavond-widget__txt__item:focus,.dsavond-widget--alt .dsavond-widget__txt__item:hover{color:#dbe4c4;text-decoration:none}.edition-nav{-webkit-box-shadow:0 0 9px rgba(0,0,0,.4);-moz-box-shadow:0 0 9px rgba(0,0,0,.4);box-shadow:0 0 9px rgba(0,0,0,.4);background:#ededed;bottom:0;left:0;position:fixed;text-align:center;width:100%;z-index:999}@media screen and (min-width:68.4375em){.edition-nav{position:static}}.edition-nav .current-page{font-size:11px;font-size:.7857142857rem;line-height:7.3636363636;display:inline-block;color:#aaa;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:400}@media screen and (min-width:68.4375em){.edition-nav .current-page{display:none}}.edition-next,.edition-prev{color:#000!important;display:block;text-decoration:none!important}.edition-next i,.edition-next span,.edition-prev i,.edition-prev span{opacity:.3}.edition-next i,.edition-prev i{padding:1.4285714286rem;display:block}.edition-next:focus i,.edition-next:focus span,.edition-next:hover i,.edition-next:hover span,.edition-prev:focus i,.edition-prev:focus span,.edition-prev:hover i,.edition-prev:hover span{opacity:1}@media screen and (min-width:68.4375em){.edition-next,.edition-prev{margin-top:-1.5714285714rem;height:44px;height:3.1428571429rem;width:44px;width:3.1428571429rem;float:none;left:50%;position:fixed;top:50%}.edition-next i,.edition-prev i{padding:0}}.edition-prev{float:left}@media screen and (min-width:68.4375em){.edition-prev{margin-left:-39.6071428571rem}}.edition-next{float:right}@media screen and (min-width:68.4375em){.edition-next{margin-left:36.25rem}}.ekrant__header{padding:12px 20px;text-align:center;position:relative;z-index:999}.ekrant__header:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ekrant__header #MainContent_lnkDownloadLink{visibility:hidden}.ekrant__body{background-color:#ddd;border-top:1px solid #aaa;position:relative;padding:20px}.ekrant__body:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ekrant__side{float:left;position:relative;width:349px;height:531px}.ekrant__page{width:349px;height:531px;position:absolute;left:0;top:0;background-color:#fff}.no-boxshadow .ekrant__page{border:1px solid #aaa}.ekrant__page--left{-webkit-box-shadow:-5px 0 5px rgba(0,0,0,.35);-moz-box-shadow:-5px 0 5px rgba(0,0,0,.35);box-shadow:-5px 0 5px rgba(0,0,0,.35)}.ekrant__page--left.first{background-color:transparent;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;display:none}.no-boxshadow .ekrant__page--left{border-right:none}.ekrant__page--right{border-left:1px solid #aaa;-webkit-box-shadow:5px 0 5px rgba(0,0,0,.35);-moz-box-shadow:5px 0 5px rgba(0,0,0,.35);box-shadow:5px 0 5px rgba(0,0,0,.35)}.ekrant__page--right.last{background-color:transparent;display:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}#left-page-paper,#right-page-info{display:none}.ekrant__page-content{overflow:hidden;width:349px;height:491px}.ekrant__page-content img{display:block;margin-left:-1px}.ekrant__attachments:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ekrant__attachments a{display:block;float:left;margin:0 12px 12px 0}@media screen and (min-width:62.1875em){.ekrant__attachments a{width:48%;margin-right:2%}}.fold{height:531px;width:20px;position:absolute;left:0;top:0}.ekrant__page--left .fold{background-image:-webkit-gradient(linear,right top,left top,from(rgba(0,0,0,.15)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(right,rgba(0,0,0,.15),rgba(0,0,0,0));background-image:-moz-linear-gradient(right,rgba(0,0,0,.15),rgba(0,0,0,0));background-image:linear-gradient(right,rgba(0,0,0,.15),rgba(0,0,0,0));left:auto;right:0}.ekrant__page--right .fold{background-image:-webkit-gradient(linear,left top,left bottom,from(left),color-stop(rgba(0,0,0,.15)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(left,rgba(0,0,0,.15),rgba(0,0,0,0));background-image:-moz-linear-gradient(left,rgba(0,0,0,.15),rgba(0,0,0,0));background-image:linear-gradient(left,rgba(0,0,0,.15),rgba(0,0,0,0))}.ekrant__page--right .first .fold{background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.1)),to(rgba(0,0,0,0)));background-image:-webkit-linear-gradient(left,rgba(0,0,0,.1),rgba(0,0,0,0));background-image:-moz-linear-gradient(left,rgba(0,0,0,.1),rgba(0,0,0,0));background-image:linear-gradient(left,rgba(0,0,0,.1),rgba(0,0,0,0))}.no-cssgradients .fold{display:none}.ekrant__page-footer{text-align:center;line-height:20px;position:relative}.ekrant__pagination{position:absolute;top:0;width:20px;height:20px;color:#fff!important;background-color:#dd2727}.ekrant__pagination--left{left:10px}.ekrant__pagination--right{right:10px}.ekrant__aside{clear:both;padding:20px 0}.ekrant__aside:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ekrant__aside>*{float:left}@media screen and (min-width:62.1875em){.ekrant__aside{clear:none;padding:0;float:right;width:180px}.ekrant__aside>*{float:none}}.ekrant__footer{padding:20px 20px 0}.ekrant__menu{margin-right:20px;max-width:50%}@media screen and (min-width:62.1875em){.ekrant__menu{margin-right:0;max-width:100%}}.ekrant__previous-attachments:after{content:".";display:block;height:0;clear:both;visibility:hidden}.ekrant__previous-attachments li{float:left;margin-right:20px}.ekrant__previous-attachments figcaption{text-align:center}.ekrant__previous-attachments time{display:block}#article-list{display:none;background-color:#fff;padding:5px 12px 5px 20px;-webkit-box-shadow:0 0 5px rgba(0,0,0,.15);-moz-box-shadow:0 0 5px rgba(0,0,0,.15);box-shadow:0 0 5px rgba(0,0,0,.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.figure--4k{position:relative}.figure--4k__teasers{position:absolute;top:40px;right:15px;width:150px;background-color:#f8f8f8}.figure--4k__teasers .article-teaser{margin-left:.7142857143rem;margin-right:.7142857143rem}.stock-bar{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.stock-bar:after{content:".";display:block;height:0;clear:both;visibility:hidden}.stock-bar li{float:left;color:#666}.stock-bar li a{text-decoration:none;color:#666}.stock-bar li a:visited{color:#666}.stock-bar li a:focus,.stock-bar li a:hover{color:#ad9a0a;text-decoration:none}.stock-bar li.current{background-color:#aaa;color:#fff}.stock-bar li.current a{text-decoration:none;color:#fff}.stock-bar li.current a:visited{color:#fff}.stock-bar li.current a:focus,.stock-bar li.current a:hover{color:#fff;text-decoration:none}.stock-bar li.current:focus,.stock-bar li.current:hover{background-color:#ddd}.stock-bar li.current .value{color:inherit}.stock-bar .stock-bar__inner{padding:6px}@media screen and (max-width:54.9375em){.stock-bar .value{display:block;text-align:right}}.stock-bar__header{text-align:center}.stock-bar--cols-2 li{width:50%}.stock-bar--cols-3 li{width:33.3333333333%}.stock-bar--cols-4 li{width:25%}.stock-bar--cols-5 li{width:20%}.stock-bar--cols-6 li{width:16.6666666667%}.stock-bar--cols-7 li{width:14.2857142857%}.stock-bar--cols-8 li{width:12.5%}.stock-bar--cols-9 li{width:11.1111111111%}.stock-bar--cols-10 li{width:10%}.heatmap{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:12px;font-size:.8571428571rem}.heatmap a,.heatmap a:active,.heatmap a:focus,.heatmap a:hover,.heatmap a:visited{color:#000!important;text-decoration:none}.heatmap a:active,.heatmap a:focus,.heatmap a:hover{font-weight:700}.heatmap td{text-align:center;width:20%}.heatmap span{display:block}.heatmap .key,.heatmap .value{color:inherit;text-align:inherit}.hm--pos30{background-color:#0cae00}.hm--pos20{background-color:#11fb00}.hm--pos10{background-color:#55ff48}.hm--pos05{background-color:#9cff95}.hm--neutral{background-color:#aaa}.hm--neg05{background-color:#ffe3e3}.hm--neg10{background-color:#ff9696}.hm--neg20{background-color:#ff4949}.hm--neg30{background-color:#fc0000}.flag{padding:.4285714286rem}@media screen and (min-width:48em){.flag{text-align:center}}.flag--inverted{background-color:#000;color:#fff}.promo .island{position:relative}.promo .flag{font-size:20px;font-size:1.4285714286rem;float:left;margin-right:1.4285714286rem}@media screen and (min-width:48em){.promo .flag{position:absolute;width:88px;top:20px;left:-100px;float:none;margin:0}}@media screen and (min-width:48em){.promo .flag .x-small{display:block}}.form:after{content:".";display:block;height:0;clear:both;visibility:hidden}.regionals .form{margin-bottom:0}.form__group,.katura-upload .form-group{margin-bottom:1rem}.form__group:after,.katura-upload .form-group:after{content:".";display:block;height:0;clear:both;visibility:hidden}.form__group .button,.form__group .mail-share-button,.form__group button,.form__group input,.form__group label,.form__group legend,.form__group select,.form__group textarea,.katura-upload .form-group .button,.katura-upload .form-group .mail-share-button,.katura-upload .form-group button,.katura-upload .form-group input,.katura-upload .form-group label,.katura-upload .form-group legend,.katura-upload .form-group select,.katura-upload .form-group textarea{margin-bottom:.4285714286rem;display:block}.form__group [type=checkbox],.form__group [type=radio],.katura-upload .form-group [type=checkbox],.katura-upload .form-group [type=radio]{margin-bottom:0}.form__group label>input,.katura-upload .form-group label>input{display:inline-block}@media screen and (min-width:48em){.form__group--inline .form__controls,.form__group--inline>.button,.form__group--inline>.mail-share-button,.form__group--inline>button,.form__group--inline>input,.form__group--inline>label,.form__group--inline>select,.form__group--inline>textarea{display:inline-block}.form__group--inline .form__label,.form__group--inline fieldset>.form__controls{float:left}}.form__group--inline .form__label,.form__group--inline>label{margin-right:1.4285714286rem}@media screen and (min-width:48em){.form__group--inline .form__label,.form__group--inline>label{width:25%;text-align:right}}.form__group--emphasized{padding:.8571428571rem;background-color:#ddd}.form__group--emphasized input,.form__group--emphasized textarea{background-color:#f4f4f4;border:0}.form__group--emphasized .button,.form__group--emphasized .mail-share-button,.form__group--emphasized button,.form__group--emphasized input{margin-bottom:0}.form__controls:after{content:".";display:block;height:0;clear:both;visibility:hidden}label[for=message]+.form__controls:after{content:none}.form__controls--inline .form__label,.form__controls--inline input,.form__controls--inline label{margin-right:.4285714286rem;display:inline-block}fieldset:after{content:".";display:block;height:0;clear:both;visibility:hidden}.form__label,label{cursor:pointer}.article-comments .form__label,.article-comments label{margin-right:5.2857142857rem}@media screen and (min-width:48em){.form__actions{padding-left:25.5%}.form__actions>*{margin-left:20px}}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],textarea{font-size:14px;font-size:1rem;height:20px;height:1.4285714286rem;line-height:20px;padding:.2857142857rem .4285714286rem;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset;-moz-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset;box-shadow:rgba(0,0,0,.075) 0 1px 1px inset;-webkit-transition-property:border,-webkit-box-shadow;-moz-transition-property:border,-moz-box-shadow;transition-property:border,box-shadow;-webkit-transition-duration:.2s,.2s;-moz-transition-duration:.2s,.2s;transition-duration:.2s,.2s;background-color:#fff;border:1px solid #ccc;color:#666;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;margin-left:0;vertical-align:middle}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus,textarea:focus{border-color:#44c4d1;outline:0;z-index:2;-webkit-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(68,196,209,.6) 0 0 8px;-moz-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(68,196,209,.6) 0 0 8px;box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(68,196,209,.6) 0 0 8px}.theme-archive .main-container input[type=color],.theme-archive .main-container input[type=date],.theme-archive .main-container input[type=datetime-local],.theme-archive .main-container input[type=datetime],.theme-archive .main-container input[type=email],.theme-archive .main-container input[type=month],.theme-archive .main-container input[type=number],.theme-archive .main-container input[type=password],.theme-archive .main-container input[type=search],.theme-archive .main-container input[type=tel],.theme-archive .main-container input[type=text],.theme-archive .main-container input[type=time],.theme-archive .main-container input[type=url],.theme-archive .main-container input[type=week],.theme-archive .main-container textarea,.theme-morningedition .main-container input[type=color],.theme-morningedition .main-container input[type=date],.theme-morningedition .main-container input[type=datetime-local],.theme-morningedition .main-container input[type=datetime],.theme-morningedition .main-container input[type=email],.theme-morningedition .main-container input[type=month],.theme-morningedition .main-container input[type=number],.theme-morningedition .main-container input[type=password],.theme-morningedition .main-container input[type=search],.theme-morningedition .main-container input[type=tel],.theme-morningedition .main-container input[type=text],.theme-morningedition .main-container input[type=time],.theme-morningedition .main-container input[type=url],.theme-morningedition .main-container input[type=week],.theme-morningedition .main-container textarea{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}input,select,textarea{width:206px;margin-bottom:.8571428571rem}.archive-search input,.archive-search select,.archive-search textarea,[type=checkbox],[type=radio]{margin-bottom:0}.form__group--full-width input,.form__group--full-width textarea,.input--full-width,.textarea--full-width{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:99.9%}.form__group--full-width textarea,.textarea--full-width{min-height:120px;min-height:8.5714285714rem}.input--large{width:210px}.input--small{width:120px}.input--xsmall{width:80px}.input--mini{width:52px}input[type=button],input[type=checkbox],input[type=file],input[type=image],input[type=radio],input[type=reset],input[type=submit]{width:auto}.input-append{font-size:0;white-space:nowrap}.input-append input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;position:relative;vertical-align:top}.input-append .button:last-child,.input-append .mail-share-button:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;margin-left:-1px}.radio--custom{width:auto!important;text-align:left;min-width:1px!important;padding:.0714285714rem .7142857143rem 0;-webkit-border-radius:999px;-moz-border-radius:999px;border-radius:999px;display:inline-block;white-space:nowrap}.form__group .radio--custom,.radio--custom{margin-bottom:12px;margin-right:0}.radio--custom.checked{color:#fff;background-color:#aaa}.form__append{display:inline-block;vertical-align:top}.form__help{margin-bottom:.4285714286rem;color:#aaa;display:block}.form__help--inline{margin-left:1.4285714286rem;display:inline-block;vertical-align:text-top}.form__header{font-size:20px;margin-bottom:.8571428571rem}.error *{color:#9d261d}.error input,.error textarea{border-color:#9d261d;outline:0;z-index:2;-webkit-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(157,38,29,.6) 0 0 8px;-moz-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(157,38,29,.6) 0 0 8px;box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(157,38,29,.6) 0 0 8px}.navbar-search{margin:0}.navbar-search fieldset{position:relative}@media screen and (min-width:48em){.navbar-search{margin-bottom:.8571428571rem}}input.search-query{height:30px;height:2.1428571429rem;line-height:30px;-webkit-border-radius:999px;-moz-border-radius:999px;border-radius:999px;-webkit-box-shadow:rgba(0,0,0,.25) 0 1px 1px 0 inset;-moz-box-shadow:rgba(0,0,0,.25) 0 1px 1px 0 inset;box-shadow:rgba(0,0,0,.25) 0 1px 1px 0 inset;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:1px solid #d4d4d4;margin:0}.navbar-search input.search-query{-webkit-transition:width .4s;-moz-transition:width .4s;transition:width .4s;background-color:#eee;border:1px solid #eee;float:right;width:99%;padding:0 12px}.navbar-search input.search-query:focus{width:210%}@media screen and (min-width:48em){.navbar-search input.search-query:focus{width:99%}}.content-search input.search-query{width:73%}.no-boxshadow .navbar-search input.search-query{border-color:#ddd}.search-submit{background:0 0;border:0;color:#aaa;line-height:1;margin-top:-7px;padding:0;position:absolute;right:9px;top:50%}.search-submit:focus,.search-submit:hover{color:#666}.content-search .button,.content-search .mail-share-button{width:25%}.archive-search{margin-bottom:.8571428571rem}.archive-search input[type=text]{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form--flag{padding:2.8571428571rem;margin-top:5.7142857143rem;max-width:500px;max-width:35.7142857143rem;background:#fff;margin-left:auto;margin-right:auto}.form--flag:focus{outline:0}.form--register .form__group--inline .form__label,.form--register .form__group--inline>label{min-width:200px;min-width:14.2857142857rem}@media screen and (max-width:47.9em){.form--register .form__help--inline{display:block;margin-left:0}}@media screen and (min-width:48em){.form--register .form__help--inline{max-width:200px;max-width:14.2857142857rem;vertical-align:top}}@media screen and (min-width:62.1875em){.form--register .form__help--inline{max-width:350px;max-width:25rem;vertical-align:top}}@media screen and (min-width:48em){.form--register .form__controls--inline{vertical-align:top}}.form--register .form__col{float:left;width:100%}@media screen and (min-width:40em){.form--register .form__col{width:33%}}.form--register .form__col__cell{padding-right:1.4285714286rem}@media screen and (min-width:48em){.form--register .form__disclaimer{width:60%}}.form--login .button,.form--login .mail-share-button{height:40px;height:2.8571428571rem;font-weight:700;border-color:transparent!important}.form--login input[type=password],.form--login input[type=text]{height:45px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.form--login .icon-lock,.form--login .icon-user-blank{position:relative}.form--login .icon-lock.padder--y0:before,.form--login .icon-user-blank.padder--y0:before{top:27px}.form--login .icon-lock:before,.form--login .icon-user-blank:before{position:absolute;top:15px;left:15px}.form--login .icon-lock input,.form--login .icon-user-blank input{padding-left:40px}.form--login .validation-summary-errors ul,.form--login .validation-summary-valid ul{list-style:none;margin:0}.form--login .validation-summary-errors li,.form--login .validation-summary-valid li{color:#9d261d}.gallery{margin:1.4285714286rem 0;cursor:pointer;cursor:-webkit-zoom-in;position:relative}@media screen and (min-width:40em){.gallery.i-1k,.gallery.i-1k+blockquote{max-width:33%}.gallery.i-2k,.gallery.i-2k+blockquote{max-width:50%}.l-1k2k1k .gallery.i-2k{width:auto}.l-2k2k .gallery.i-2k,.l-2k2k .gallery.i-2k+blockquote{max-width:50%}.l-2k2k .secondary-col .gallery.i-2k,.l-2k2k .secondary-col .gallery.i-2k+blockquote{max-width:100%}.gallery.i-1k,.gallery.i-1k+blockquote,.gallery.i-2k,.gallery.i-2k+blockquote{float:left;margin-right:1.4285714286rem}.right-col .gallery.i-1k,.right-col .gallery.i-1k+blockquote,.right-col .gallery.i-2k,.right-col .gallery.i-2k+blockquote{margin-left:1.4285714286rem}.gallery.i-1k+blockquote,.gallery.i-2k+blockquote{margin-top:0}}@media screen and (min-width:62.1875em){.left-col .gallery,.left-col .gallery+blockquote{margin-left:-1.4285714286rem}.right-col .gallery,.right-col .gallery+blockquote{margin-right:-1.4285714286rem;float:right}}.article-full--eyewitness .gallery{background-color:transparent!important;margin-left:0}@media screen and (min-width:48em){.article-full--poster .gallery{float:left;width:74%;margin-top:0}}.gallery figure{margin:0}.gallery img{display:block;margin:0 auto}.gallery figcaption{font-size:12px;font-size:.8571428571rem;padding:.5714285714rem 0 0;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.gallery figcaption span{font-size:11px;font-size:.7857142857rem;color:#aaa;white-space:nowrap}.gallery .label{position:absolute;top:12px;top:.8571428571rem}.left-col .gallery .label{right:12px;right:.8571428571rem;left:auto}.gallery .label,.right-col .gallery .label{left:12px;left:.8571428571rem;right:auto}.article__col .gallery{margin:0}.gallery .slideshow__image__inner:hover:after{background-color:#444;padding:10px 11px;margin:-21px 0 0 -21px;opacity:.8;color:#fff;font-family:Dso-icons;font-size:18px;content:"\e60f";position:absolute;left:50%;top:50%}.heading{display:block;font-size:16px;font-size:1.1428571429rem}.heading--framed{display:inline-block;padding:.3571428571rem .5714285714rem .1428571429rem;font-size:14px;font-size:1rem;background-color:#666;color:#fff;line-height:1}.main-container .heading--framed a{text-decoration:none;color:#fff}.main-container .heading--framed a:visited{color:#fff}.main-container .heading--framed a:focus,.main-container .heading--framed a:hover{color:#fff;text-decoration:none}.heading--framed--inverted{background-color:#fff!important;color:#444}.heading--framed--inverted a{text-decoration:none;color:#444}.heading--framed--inverted a:visited{color:#444}.heading--framed--inverted a:focus,.heading--framed--inverted a:hover{color:#444;text-decoration:none}.section-logo{font-size:17px;font-size:1.2142857143rem;font-weight:700;height:87px;margin:0;position:absolute;top:20px;left:0;z-index:99;width:87px;text-transform:uppercase}.section-logo a{height:87px;height:6.2142857143rem;padding-left:.5714285714rem;color:#fff;display:block}.section-logo span{padding-left:.5714285714rem;bottom:0;left:0;position:absolute}.section-heading{margin-bottom:.4285714286rem;font-size:24px;font-size:1.7142857143rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:400;text-transform:uppercase;line-height:1.2}.island,.islet{margin-bottom:1.4285714286rem;margin-top:1.4285714286rem;background-color:#eee;display:block}.island:after,.islet:after{content:".";display:block;height:0;clear:both;visibility:hidden}.widget .island,.widget .islet{margin-top:0}.island{padding:1.4285714286rem}.island article{padding-top:0;padding-bottom:0}.island>:last-child,.islet>:last-child{margin-bottom:0}.islet{padding:.8571428571rem}.islet--tight{padding:0}.islet .flush-full{margin-left:-.8571428571rem;margin-right:-.8571428571rem}[class*=" icon-"],[class^=icon-]{display:inline-block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-family:Dso-icons;font-style:normal;speak:none;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased}.icon-lightbulb:before{content:"\e637"}.icon-notdef:before{content:"\e600"}.icon-clock:before{content:"\e601"}.article-media-photoset .article-media__helper:after,.icon-photoset:before{content:"\e602"}.icon-video:before{content:"\e603"}.icon-home:before{content:"\e604"}.icon-search:before{content:"\e605"}.icon-road:before{content:"\e606"}.icon-stats:before{content:"\e607"}.icon-weather:before{content:"\e608"}.icon-rss:before{content:"\e609"}.icon-mail:before{content:"\e60a"}.icon-twitter:before{content:"\e60b"}.icon-facebook:before{content:"\e60c"}.icon-chevron-right:before{content:"\e60d"}.icon-chevron-left:before{content:"\e60e"}.icon-expand:before{content:"\e60f"}.icon-circle-close:before{content:"\e610"}.icon-arrow-right:before{content:"\e611"}.icon-arrow-left:before{content:"\e612"}.icon-circle-close-invert:before{content:"\e613"}.icon-star:before{content:"\e614"}.icon-reply:before{content:"\e618"}.icon-forward:before{content:"\e619"}.icon-share:before{content:"\e61a"}.icon-grid:before{content:"\e61b"}.article-media-video .article-media__helper:after,.icon-caret-right:before,.ui-datepicker .ui-datepicker-next:before{content:"\e61c"}.icon-caret-left:before,.ui-datepicker .ui-datepicker-prev:before{content:"\e61d"}.icon-caret-down:before{content:"\e61e"}.icon-caret-up:before{content:"\e61f"}.icon-obituary:before{content:"\e620"}.icon-immo:before{content:"\e621"}.icon-briefcase:before{content:"\e032"}.icon-cloud:before{content:"\e622"}.icon-google-plus:before{content:"\e623"}.icon-linkedin:before{content:"\e624"}.icon-flickr:before{content:"\e625"}.icon-globe:before{content:"\e626"}.icon-chat:before{content:"\e627"}.icon-user:before{content:"\e628"}.icon-ribbon:before{content:"\e629"}.icon-info:before{content:"\e62a"}.icon-alert-invert:before{content:"\e042"}.icon-phone:before{content:"\e62b"}.icon-desktop:before{content:"\e62c"}.icon-page:before{content:"\e62d"}.comment .comment:before,.icon-comment:before{content:"\e62e"}.icon-mail-alt:before{content:"\e62f"}.icon-print:before{content:"\e630"}.icon-ds:before{content:"\e049"}.icon-plusbullet:before{content:"\e631"}.icon-plusimage:before{content:"\e632"}.icon-plustitle:before{content:"\e633"}.icon-pencil:before{content:"\e634"}.icon-user-blank:before{content:"\e635"}.icon-lock:before{content:"\e636"}.icon-alert .path1:before{content:"\e615";color:#13110c}.icon-alert .path2:before{content:"\e616";margin-left:-.9931640625em;color:#13120d}.icon-alert .path3:before{content:"\e617";margin-left:-.9931640625em;color:#13120d}.icon--white{color:#fff!important}.icon-home{font-size:12px;font-size:.8571428571rem}.icon-search{font-size:17px;font-size:1.2142857143rem;top:-1px;position:relative}.icon-weather{font-size:16px;font-size:1.1428571429rem}.icon-road{font-size:15px;font-size:1.0714285714rem}.icon-stats{font-size:16px;font-size:1.1428571429rem}.icon-rss{font-size:11px;font-size:.7857142857rem;min-width:14px;min-width:1rem;top:-1px;display:inline-block;position:relative}.icon-share{font-size:11px;font-size:.7857142857rem;top:-1px;position:relative}.icon-caret-left,.icon-caret-right{font-size:70%}.icon-caret-down,.icon-caret-up{font-size:8px}.icon-chevron-left,.icon-chevron-right{top:-1px;font-size:.7em;position:relative}.icon-arrow-close,.icon-arrow-left,.icon-arrow-right{font-size:36px;font-size:2.5714285714rem}.infographic-container{height:600px}.jobat{max-width:362px;max-width:25.8571428571rem;padding:0 0 1.4285714286rem;margin:0 auto}.jobat__inner{padding-top:55.2486187845%}.jobat--narrow{max-width:177px;max-width:12.6428571429rem}.jobat--narrow .jobat__inner{padding-top:144.0677966102%}.link{white-space:nowrap}.article__header+.link{margin-top:-.4285714286rem;display:block}.link--proceed{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:600}.link--proceed:after{content:' >'}a.link--register{margin-top:12px;font-size:12px;text-decoration:underline}a.link--mediaid{display:block;text-align:center;color:#2c84cb}a.link--mediaid:visited{color:#2c84cb}a.link--mediaid:hover{color:#1e5b8c}.author-info,.carousel ol,.child__list,.comments-list,.currently,.ekrant__previous-attachments,.history-list,.inline-list,.list--ellipsis,.list--history,.nav-tabs,.slideshow__pager,.star-rating,.stock-bar,.unstyled,.widget__list{list-style:none;padding-left:0}.expanded li{margin:.2857142857rem 0}.custom-list li{margin-bottom:.2857142857rem}.custom-list li>*{color:#444}.custom-list a{text-decoration:none;color:#444}.custom-list a:visited{color:#aaa}.custom-list a:focus,.custom-list a:hover{color:#44c4d1;text-decoration:none}.article-breaking-news .custom-list{margin-left:1.4285714286rem;margin-right:1.4285714286rem}.article-chapeau-square .custom-list{clear:both;padding-left:0}.article-chapeau-square .custom-list li{margin-left:16px}.tab-pane .custom-list{margin-top:0;margin-bottom:0}article .custom-list:last-child{margin-bottom:0}ul.custom-list{list-style:square inside;padding-left:0}ol.custom-list{padding-left:0;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:600}ol.custom-list li>*{font-family:Georgia,Cambria,Times New Roman,Times,sans-serif;font-weight:400}.list-bullets-inside{list-style-position:inside}.inline-list>li{display:inline-block;padding-left:6px;padding-right:6px}.history-list,.history-list.widget__list,.list--history,.list--history.widget__list{margin-bottom:.8571428571rem}.history-list>li,.list--history>li{margin-bottom:.8571428571rem;border:0!important;padding-bottom:0!important}.history-list time,.list--history time{width:115px;width:8.2142857143rem;display:inline-block}.list--ellipsis li{max-width:100%}.list--ellipsis li>*{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#444;display:block}.list--ellipsis a{text-decoration:none;color:#444}.list--ellipsis a:visited{color:#aaa}.list--ellipsis a:focus,.list--ellipsis a:hover{color:#44c4d1;text-decoration:none}.list--paco li>*{color:#444}.list--paco a{text-decoration:none;color:#444}.list--paco a:visited{color:#aaa}.list--paco a:focus,.list--paco a:hover{color:#dd2727;text-decoration:none}.list--decimal{counter-reset:decimal}.list--decimal a:before{counter-increment:decimal;content:counter(decimal) ".";color:#aaa;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:700;margin-right:.6em}.list--narrow li,.list--narrow>li{padding-top:4px!important;padding-bottom:6px!important}.list--high li,.list--high>li{padding-top:6px!important;padding-bottom:6px!important}.list--striped li,.list--striped>li{border-top:1px solid #ccc;margin:0;padding-left:.8571428571rem}.list--striped li:nth-child(odd),.list--striped>li:nth-child(odd){background-color:#eee}.list-visuals>li{margin-bottom:2.8571428571rem!important}.list-visuals figure{position:relative}.list-visuals img{margin-left:auto;margin-right:auto}.list-visuals figcaption{position:absolute;width:100%;left:0;top:-20px;text-align:center;z-index:10}.list-visuals figcaption .heading--framed{display:block;max-width:304px;margin-left:auto;margin-right:auto}.intro--list{margin-bottom:.8571428571rem;margin-top:.8571428571rem}.intro--list li{color:#444}.article-chapeau-square .intro--list li{margin-left:0}.author-info>li{padding:1.4285714286rem 0;margin-bottom:0!important;border-bottom:0!important}.author-info>li:after{content:".";display:block;height:0;clear:both;visibility:hidden}.author-info .avatar{float:left}.author-info h3,.author-info p,.author-info ul{margin-left:116px}.author-info ul{margin-bottom:0}.author-info--full{padding-top:1.4285714286rem;padding-bottom:1.4285714286rem;margin-bottom:1.4285714286rem;border-bottom:1px dashed #ededed}.author-info--full:after{content:".";display:block;height:0;clear:both;visibility:hidden}.author-info--full h1{font-size:28px;font-size:2rem}.content-list{border-bottom:1px solid #ededed;padding-bottom:.8571428571rem}.content-list>li{padding-bottom:0!important;margin-bottom:.5714285714rem}.child__list{margin:.4285714286rem 0}.related-list{font-size:90%}.related-list:before{content:'';width:25%;height:0;display:block;border-top:1px solid #ededed;padding-bottom:.4285714286rem}.limit-chars{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:10.5em}.logo{margin-bottom:.8571428571rem;display:inline-block;max-width:100%;text-decoration:none}@media screen and (min-width:40em){.logo{float:left;display:block}}.logo img{background-color:#44c4d1;min-width:90px}@media screen and (min-width:48em){.logo img{max-width:126px}}.logo--small{display:block;float:none}.logo--small img{max-width:90px}.label{font-weight:700;line-height:1;text-transform:uppercase}.label.alt-family,.label.article-lsc,.label.conversion__header,.label.form,.label.form--flag,.label.interactive__count,.label.interactive__label,.label.magazines-header,.label.pullquote,.label.session-expired{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:400}.label--framed{font-size:11px;font-size:.7857142857rem;padding:.4285714286rem .4285714286rem .2142857143rem;display:inline-block;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#ddd;color:#000}.gallery .label--framed{background-color:rgba(221,221,221,.7)}.label--pill{-webkit-border-radius:999px;-moz-border-radius:999px;border-radius:999px}.magazines-header{padding:1.4285714286rem 0 0 2.8571428571rem}p.magazines-header{padding-top:0}.content-magazine,.intro-box{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.content-magazine .left,.content-magazine .right,.intro-box .left,.intro-box .right{float:left}.content-magazine ul,.intro-box ul{list-style:none}.content-magazine nav ul li,.intro-box nav ul li{border-right:1px solid #000;float:left;padding:0 10px}.content-magazine nav ul li:first-child,.intro-box nav ul li:first-child{padding-left:0}.content-magazine nav ul li a,.intro-box nav ul li a{color:#9f0222!important;display:block}.content-magazine nav ul li a:focus,.content-magazine nav ul li a:hover,.intro-box nav ul li a:focus,.intro-box nav ul li a:hover{color:#000!important}.intro-box{background-color:#f5f5f5;margin:20px 20px 0;overflow:hidden;padding:20px}.intro-box .left{width:20%;border-right:1px solid #c1c1c1;margin-right:2%;min-height:80px;padding:0 10px}.intro-box .left h3{padding-top:1.4285714286rem;color:#9e021e}.intro-box form.archive{margin:0}.intro-box .right{width:70%}.intro-box .right p:first-child{padding-top:1.4285714286rem}@media screen and (max-width:48em){.intro-box .left,.intro-box .right{float:none;width:100%}.intro-box .left{border-right:none;margin-right:0;margin-top:20px;min-height:20px;padding-right:0}}.content-magazine{border-bottom:10px solid #eee;clear:left;overflow:hidden;padding:20px 40px}.content-magazine .left,.content-magazine .right{float:left}.content-magazine .left{margin-right:5%;width:30%}.content-magazine .right{width:65%}.content-magazine h2{color:#9f0222;font-size:1.4em;padding:5px 0 20px;text-transform:uppercase}.content-magazine img.big-thumb{background-color:#00f}.content-magazine .date,.content-magazine .day{display:block}.content-magazine .day{color:#9f0222;font-weight:500;padding-bottom:3px;padding-top:8px}.content-magazine .today p .day{font-size:1.6em;padding-top:12px}.content-magazine a .date{color:#444}.content-magazine a:focus img,.content-magazine a:hover img{opacity:.9}.content-magazine a:focus .date,.content-magazine a:hover .date{color:#e76969}.content-magazine .today .date{font-size:1.2em}.content-magazine .list-magazine{padding:0;margin:0}.content-magazine .list-magazine li{float:left;margin-right:6%}.content-magazine .list-magazine li img{border:1px solid #e0e0e0;padding:2px}.content-magazine input{max-width:150px}@media screen and (max-width:48em){.content-magazine{padding:20px 30px}.content-magazine .left{margin-right:6%;width:39%}.content-magazine .right{width:55%}.content-magazine .list-magazine li{margin-right:10%}.content-magazine .right .list-magazine li:nth-child(2n+2){margin-right:0}.content-magazine .list-magazine.attach li{margin-right:3.5%}.content-magazine .list-magazine.attach li:nth-child(4){margin-right:0}}@media screen and (min-width:59em){.content-magazine .list-magazine li:nth-child(3n+1){clear:left}}@media screen and (min-width:62.1875em){.content-magazine .clear{clear:left}.content-magazine .list-magazine li.end-row{margin-right:0}}.magnifier-image{max-width:100%;height:auto;margin:0 auto;position:relative}.magnifier-image .magnifier-image__small{max-width:100%;display:block}.magnifier-image .magnifier-image__large{background-repeat:no-repeat;width:175px;height:175px;-webkit-border-radius:100%;-moz-border-radius:100%;border-radius:100%;-webkit-box-shadow:0 0 0 7px rgba(255,255,255,.85),0 0 7px 7px rgba(0,0,0,.25),inset 0 0 40px 2px rgba(0,0,0,.25);-moz-box-shadow:0 0 0 7px rgba(255,255,255,.85),0 0 7px 7px rgba(0,0,0,.25),inset 0 0 40px 2px rgba(0,0,0,.25);box-shadow:0 0 0 7px rgba(255,255,255,.85),0 0 7px 7px rgba(0,0,0,.25),inset 0 0 40px 2px rgba(0,0,0,.25);display:none;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);transform:translateZ(0);position:absolute;top:0;left:0}.modalbox-active{overflow-y:hidden}.modalbox-active.modalbox-article-active{overflow-y:scroll}.modalbox-active.modalbox-article-active body{position:relative}.modalbox-active body{-ms-touch-action:none}.modal-photos{margin-bottom:.8571428571rem;position:relative}.modal-photos .label{left:10px;left:.7142857143rem;top:10px;top:.7142857143rem;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:rgba(255,255,255,.4);color:#000;position:absolute;text-transform:none;font-weight:700;display:none}.js .modal-photos .label{display:block}.modal--full-bleed{margin-left:-1.4285714286rem;margin-right:-1.4285714286rem}.ad--splash,.ad--xlsplash,.modalbox{background-color:#000;position:fixed;min-height:100%;z-index:1030;top:0;left:0;right:0}.ad--splash,.modalbox--opaque,.modalbox-article{background-color:rgba(0,0,0,.7)}.ad--xlsplash,.modalbox--invert{background-color:#fff}.modalbox--invert--opaque{background-color:rgba(255,255,255,.7)}.modalbox-article{padding:2.8571428571rem;position:absolute}.modalbox-article .modalbox__inner{background-color:#fff;position:relative;padding:1.4285714286rem}@media screen and (min-width:62.1875em){.modalbox-article .modalbox__inner{margin-left:50px;margin-right:50px}}@media screen and (min-width:68.4375em){.modalbox-article .modalbox__inner{width:955px;margin-left:auto;margin-right:auto}}.modalbox-slideshow{z-index:1090}.modalbox-base{height:100%;overflow-y:auto}.modalbox__content:focus{outline:0}.modalbox-slideshow .modalbox__content{padding:0}.modalbox-slideshow .modalbox__content .slideshow__next,.modalbox-slideshow .modalbox__content .slideshow__next:focus,.modalbox-slideshow .modalbox__content .slideshow__next:hover,.modalbox-slideshow .modalbox__content .slideshow__prev,.modalbox-slideshow .modalbox__content .slideshow__prev:focus,.modalbox-slideshow .modalbox__content .slideshow__prev:hover{background-color:transparent;outline:0}#campaign-modal{background-color:#000;background-color:rgba(0,0,0,.85)}.matrix{list-style:none;margin:0;padding-left:0;width:100%}.matrix:after{content:".";display:block;height:0;clear:both;visibility:hidden}.matrix>li{float:left;width:100%}.nav:after{content:".";display:block;height:0;clear:both;visibility:hidden}.nav li{float:left}.nav a{display:block;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;text-decoration:none;color:#4d4d4d}.nav a:visited{color:#4d4d4d}.nav a:focus,.nav a:hover{color:#44c4d1;text-decoration:none}.main-header .col-1--bp0.col-1--bp1a.col-1.arrange__item{margin-left:33.33%}@media screen and (min-width:30em){.main-header .col-1--bp0.col-1--bp1a.col-1.arrange__item{margin-left:0}}.main-header .col-2--bp0.col-4--bp1a.col-3.arrange__item,.main-header .editions-navbar,.main-header .secondary-nav{display:none}@media screen and (min-width:30em){.main-header .col-2--bp0.col-4--bp1a.col-3.arrange__item,.main-header .secondary-nav{display:inline-block}}@media screen and (min-width:30em){.main-header .editions-navbar{display:block}}.primary-nav{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;position:relative;text-align:center;width:100%}@media screen and (min-width:48em){.primary-nav{margin-bottom:.8571428571rem}}.primary-nav ul{width:100%}.primary-nav li{display:inline-block;width:49%}@media screen and (min-width:30em){.primary-nav li{margin:0 2%;width:auto}}@media screen and (min-width:55em){.primary-nav li{margin:0 3%}}.primary-nav a{font-size:17px;font-size:1.2142857143rem;padding:.3571428571rem .2142857143rem 0;display:block;line-height:1;text-align:center;text-transform:uppercase;text-decoration:none}@media screen and (min-width:42em){.primary-nav a{font-size:18px;font-size:1.2857142857rem}}@media screen and (min-width:48em){.primary-nav a{font-size:20px;font-size:1.4285714286rem;text-align:left}}.primary-nav .nav-live a{text-decoration:none;color:#444}.primary-nav .nav-live a:visited{color:#444}.primary-nav .nav-live a:focus,.primary-nav .nav-live a:hover{color:#44c4d1;text-decoration:none}.primary-nav .nav-live.current a{background-color:#44c4d1;text-decoration:none;color:#fff}.primary-nav .nav-live.current a:visited{color:#fff}.primary-nav .nav-live.current a:focus,.primary-nav .nav-live.current a:hover{color:#fff;text-decoration:none}.primary-nav .nav-paco a{text-decoration:none;color:#444}.primary-nav .nav-paco a:visited{color:#444}.primary-nav .nav-paco a:focus,.primary-nav .nav-paco a:hover{color:#dd2727;text-decoration:none}.primary-nav .nav-paco.current a{background-color:#dd2727;text-decoration:none;color:#fff}.primary-nav .nav-paco.current a:visited{color:#fff}.primary-nav .nav-paco.current a:focus,.primary-nav .nav-paco.current a:hover{color:#fff;text-decoration:none}.primary-nav .nav-eveningedition{position:relative}.theme-conversion-evening .primary-nav .nav-eveningedition a:after{height:19px;height:1.3571428571rem;line-height:23px;width:19px;width:1.3571428571rem;background:#dd2727;-webkit-border-radius:100%;-moz-border-radius:100%;border-radius:100%;color:#fff;content:'1';display:block;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:12px;position:absolute;right:-9px;text-align:center;top:-7px}.secondary-nav{margin:0;font-weight:400;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;line-height:1;padding:.8571428571rem 1.4285714286rem .8571428571rem .8571428571rem}@media screen and (min-width:40em){.secondary-nav{padding-left:0}}.secondary-nav li{float:left;margin-left:.2857142857rem}.secondary-nav li:first-child{margin:0}.secondary-nav a{padding:2px 2px 1px;display:block;text-decoration:none}@media screen and (min-width:40em){.secondary-nav a{padding:2px 4px 1px}}.secondary-nav .current a{background-color:#666;text-decoration:none;color:#fff}.secondary-nav .current a:visited{color:#fff}.secondary-nav .current a:focus,.secondary-nav .current a:hover{color:#fff;text-decoration:none}.meta-nav{margin-bottom:.8571428571rem;padding:.8571428571rem;background-color:#eee;text-align:right;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;position:relative}.meta-nav:after{content:".";display:block;height:0;clear:both;visibility:hidden}.meta-nav li{display:inline-block;margin-left:.8571428571rem;margin-right:.8571428571rem}@media screen and (min-width:40em){.meta-nav{padding:.8571428571rem 1.4285714286rem;text-align:right;z-index:500}.meta-nav ul{display:block;width:100%;text-align:right}.meta-nav li{margin-right:0}}@media screen and (min-width:48em){.meta-nav{padding-top:1.4285714286rem;margin-bottom:-1.0714285714rem;background-color:transparent;margin-left:15%;padding-bottom:0}.meta-nav li{margin-left:1.4285714286rem}}.meta-nav a{display:inline-block;font-size:13px;font-size:.9285714286rem}.meta-nav [href="/zoeken"]{text-decoration:none!important}.meta-nav span{color:#aaa}.meta-nav .nav-paco a{text-decoration:none;color:#dd2727!important}.meta-nav .nav-paco a:visited{color:#dd2727!important}.meta-nav .nav-paco a:focus,.meta-nav .nav-paco a:hover{color:#dd2727!important;text-decoration:underline}.meta-nav .nav-paco a:active{text-decoration:underline}.index-nav a{padding:.5714285714rem}.editions-navbar{padding:.5357142857rem 0;background-color:#fff;border-color:#000;border-style:solid;border-width:1px 0 2px;letter-spacing:-.31em;margin:0;text-align:center}@media screen and (min-width:40em){.editions-navbar{padding:.5357142857rem 1.4285714286rem}}.editions-navbar .hasChildren{position:relative}.editions-navbar>div,.editions-navbar>nav{display:block;letter-spacing:normal;word-spacing:normal;width:100%}@media screen and (min-width:40em){.editions-navbar>div,.editions-navbar>nav{display:inline-block}}.editions-navbar>div{left:auto;position:relative;text-align:left;top:2px}@media screen and (min-width:40em){.editions-navbar>div{width:20%}}@media screen and (min-width:62.1875em){.editions-navbar>div{width:15%}}@media screen and (min-width:40em){.editions-navbar>nav{width:80%}}@media screen and (min-width:62.1875em){.editions-navbar>nav{width:70%}}.editions-navbar .editions-navbar__page{display:none;text-align:right}@media screen and (min-width:62.1875em){.editions-navbar .editions-navbar__page{display:inline-block}}.editions-navbar .data,.editions-navbar .link{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;line-height:1.25}.editions-navbar .data{font-size:11px!important;font-size:.7857142857rem!important;color:#666!important;display:none;font-weight:400!important;text-transform:uppercase}@media screen and (min-width:40em){.editions-navbar .data{display:block}}.editions-navbar .link{font-size:13px!important;font-size:.9285714286rem!important;display:none;text-decoration:none!important}@media screen and (min-width:40em){.editions-navbar .link{display:block}}.editions-navbar,.opera:-o-prefocus{word-spacing:-.43em}.subnav-editions{margin:0;padding:0;text-align:center}.subnav-editions ul{display:inline-block;width:100%}@media screen and (min-width:40em){.subnav-editions ul{width:auto}}.subnav-editions li{text-align:left;width:100%}@media screen and (min-width:40em){.subnav-editions li{text-align:center;width:auto}}.subnav-editions li>a{padding:.5714285714rem .5714285714rem .2857142857rem;font-size:15px;font-size:1.0714285714rem;font-weight:400;line-height:1;text-transform:uppercase;text-decoration:none;color:#666}.subnav-editions li>a:visited{color:#666}.subnav-editions li>a:focus,.subnav-editions li>a:hover{color:#000;text-decoration:none;background:#ddd}@media screen and (min-width:48em){.subnav-editions li>a{font-size:14px;font-size:1rem}}@media screen and (min-width:62.1875em){.subnav-editions li>a{font-size:14px;font-size:1rem}}.subnav-editions .current>a{background:#ddd}@media screen and (min-width:62.1875em){.priority-nav .dropdown__toggle{display:none}.priority-nav .dropdown__list,.priority-nav .dropdown__list.is-offscreen,.priority-nav .slideshow__pager li span.dropdown__list,.slideshow__pager li .priority-nav span.dropdown__list{background-color:transparent;border:0;float:left;position:static}.priority-nav .dropdown__list li,.priority-nav .dropdown__list.is-offscreen li,.priority-nav .slideshow__pager li span.dropdown__list li,.slideshow__pager li .priority-nav span.dropdown__list li{float:left}}.nav--vertical a,.nav--vertical li{display:block}.nav--vertical li>*{line-height:1}.nav--vertical li ol,.nav--vertical li ul{padding-left:.4285714286rem}.nav--vertical a{padding:.4285714286rem 0 .2857142857rem}.nav--bordered>ol>li,.nav--bordered>ul>li{border-bottom:1px solid #ededed}.nav--bordered>ol>li.last,.nav--bordered>ul>li.last{border-bottom:0}.editions-attachments{background-color:#fff;border:1px solid #ededed;position:absolute;top:60px;right:-20px;width:550px}.editions-attachments li{display:inline-block;width:31%;margin-right:0;padding-right:2%}.editions-attachments li:after{content:".";display:block;height:0;clear:both;visibility:hidden}.editions-attachments li img{float:left}.editions-attachments li p{font-size:14px;font-size:1rem;margin-left:72px;text-align:left}.dropdown{position:relative;text-align:left;z-index:999}.dropdown__list{background-color:#fff;border:1px solid #ededed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;position:absolute;left:0;top:20px;z-index:1000}.dropdown__list li{float:none;display:block}.dropdown__list li a{padding:6px 4px 2px}.secondary-nav .dropdown__list li a{padding:2px 4px 1px}.dropdown-toggle i{margin-left:5px}.dropdown-menu,.ui-autocomplete{text-align:left;position:absolute;top:100%;left:0;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;z-index:1000;list-style-type:none;background-color:#fff;border:1px solid #aaa;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.dropdown-menu>li,.ui-autocomplete>li{display:block}.dropdown-menu>li>a,.ui-autocomplete>li>a{display:block;padding:3px 20px;clear:both}.dropdown-menu>li>a.ui-state-focus,.dropdown-menu>li>a.ui-state-hover,.dropdown-menu>li>a:active,.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover,.ui-autocomplete>li>a.ui-state-focus,.ui-autocomplete>li>a.ui-state-hover,.ui-autocomplete>li>a:active,.ui-autocomplete>li>a:focus,.ui-autocomplete>li>a:hover{background-color:#666;color:#fff!important;text-decoration:none!important}.dropdown-menu>.dropdown__divider,.ui-autocomplete>.dropdown__divider{height:1px;padding:0;overflow:hidden;background-color:#ddd;border-bottom:1px solid #fff;margin:6px 0}.overlay,.slideshow__overview article{position:relative}.article-lsc .article__body,.overlay__content,.slideshow__overview .article__header{background-image:url(../img/black-transp-bg.png);background-image:-webkit-gradient(linear,left top,left bottom,from(transparent),color-stop(50%,rgba(0,0,0,.8)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.8) 50%);background-image:-moz-linear-gradient(transparent,rgba(0,0,0,.8) 50%);background-image:linear-gradient(transparent,rgba(0,0,0,.8) 50%);bottom:0;display:block;left:0;position:absolute;right:0}.js-sbt-visibility-full,.js-sbt-visibility-light,.js-sbt-visibility-nonlight,.js-sbt-visibility-nonsubscriber,.js-sbt-visibility-subscriber{display:none}.promo{padding-bottom:1.4285714286rem}.promo:after{content:".";display:block;height:0;clear:both;visibility:hidden}.promo img{margin-left:auto;margin-right:auto}.promo article{padding-bottom:0}.promo.divider{padding-top:1.4285714286rem}.last .promo.divider{border-bottom:none;margin-bottom:0;border-top:1px solid #ededed}.promo .form{float:left}.pagination ol,.pagination ul{padding:1.4285714286rem 0;margin:0}.pagination ol:after,.pagination ul:after{content:".";display:block;height:0;clear:both;visibility:hidden}.pagination a{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:700;display:block;line-height:1;padding:.5714285714rem .7142857143rem .4285714286rem}.pagination .current a{background-color:#666;text-decoration:none;color:#fff}.pagination .current a:visited{color:#fff}.pagination .current a:focus,.pagination .current a:hover{color:#fff;text-decoration:none;background-color:#000}.pagination--bordered ol,.pagination--bordered ul{border-top:1px solid #ededed}.pagination--centered{text-align:center}.pagination--centered li{display:inline-block}.prev-page{float:left}.prev-page a{padding-left:0}.next-page{float:right}.next-page a{padding-right:0}.paywall-deco{display:block;float:right;width:40%;max-width:100%;margin-left:12px;margin-bottom:12px}.paywall--wordcount{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:16px;font-size:1.1428571429rem;font-style:italic;display:block}.paywall--wordcount:before{content:'';background:url(../img/plus/bullet.png) no-repeat;background:0 0,url(../img/plus/bullet.svg) no-repeat;width:10px;height:10px;display:inline-block(baseline);margin-right:5px}.popup{position:absolute;top:100%;width:100%;z-index:1010}.popup__inner{padding:1.4285714286rem;-webkit-box-shadow:0 2px 10px rgba(0,0,0,.4);-moz-box-shadow:0 2px 10px rgba(0,0,0,.4);box-shadow:0 2px 10px rgba(0,0,0,.4);background-color:#fff;margin:0 auto;max-width:955px;width:90%}.popup__arrow{position:absolute;top:-12px}.popup__arrow:after,.popup__arrow:before{border-bottom:12px solid #fff;border-left:12px solid transparent;border-right:12px solid transparent;content:'';display:block;position:absolute;left:0;height:0}.popup__arrow:before{border-bottom-color:rgba(0,0,0,.1);top:-1px;z-index:-1}.popup__arrow:after{top:0;z-index:1011}.regionals .appended-row>.primary-col{width:80%}.regionals .appended-row>.secondary-col{width:20%}.regionals form label{width:auto}.regionals form button{display:none!important}.regionals .brand--rondom{display:none}#viewport{min-height:600px;min-height:42.8571428571rem;max-width:1200px;max-width:85.7142857143rem;background-color:#fff;height:90%;margin-bottom:0;margin-left:auto;margin-right:auto;min-width:0!important;overflow:hidden;position:relative;width:100%}.span{display:block;float:left}.span--half{width:50%}.push--half{margin-left:50%}.pull--half{margin-right:50%}.span--third{width:33%}.push--third{margin-left:33%}.pull--third{margin-right:33%}.span--two-thirds{width:66%}.push--two-thirds{margin-left:66%}.pull--two-thirds{margin-right:66%}.span--quarter{width:25%}.push--quarter{margin-left:25%}.pull--quarter{margin-right:25%}.span--three-quarter{width:75%}.push--three-quarter{margin-left:75%}.pull--three-quarter{margin-right:75%}.span--fifth{width:20%}.push--fifth{margin-left:20%}.pull--fifth{margin-right:20%}.span--two-fifth{width:40%}.push--two-fifth{margin-left:40%}.pull--two-fifth{margin-right:40%}.span--three-fifth{width:59%}.push--three-fifth{margin-left:59%}.pull--three-fifth{margin-right:59%}.span--four-fifth{width:80%}.push--four-fifth{margin-left:80%}.pull--four-fifth{margin-right:80%}.span--sixth{width:16%}.push--sixth{margin-left:16%}.pull--sixth{margin-right:16%}.span--eight{width:12%}.push--eight{margin-left:12%}.pull--eight{margin-right:12%}.span--inline-block,.theme-morningedition .l-front article+article .article__header,.theme-morningedition .l-front article+article .article__header+p{display:inline-block;float:none}.l-spotlight{padding-bottom:.8571428571rem;margin-bottom:1.4285714286rem;border-bottom:1px solid #ededed}.l-spotlight article{padding-top:0;padding-bottom:0}.l-spotlight .col-1 .col__cell,.l-spotlight .col-2 .col__cell{border-right:1px solid #ededed}.l-spotlight .col-last .col__cell{border-right:none}.social-media:after{content:".";display:block;height:0;clear:both;visibility:hidden}.no-js .social-media{display:none}.social-media>*{float:left!important;margin-right:20px!important;margin-bottom:20px}.social-media>[data-social]{height:18px}.breaker+.social-media{margin-left:1.4285714286rem;margin-right:1.4285714286rem}@media screen and (min-width:48em){.breaker+.social-media{margin-left:16%}}.social-media--alt{min-height:87px;min-height:6.2142857143rem;padding-top:1.4285714286rem;border-bottom:1px solid #ededed}@media screen and (min-width:48em){.social-media--stacked .interactive,.social-media--stacked>*{margin-bottom:12px!important;display:block!important;float:none!important;margin-right:0}}.social-media--stacked .button,.social-media--stacked .mail-share-button{width:80px}.share{min-height:87px;min-height:6.2142857143rem;max-width:270px;max-width:19.2857142857rem;float:left;margin:0!important;position:relative}.share>[data-social]{position:absolute;top:0}.share>[data-social=twitter]{left:62px}.share>[data-social=facebook]{left:144px}@media screen and (min-width:40em){.share>[data-social=twitter]{left:70px}.share>[data-social=facebook]{left:160px}}.share>iframe[data-twttr-rendered]{left:70px;position:absolute!important}.interactive{padding-top:1.4285714286rem;border-top:1px solid #ededed;clear:left;margin-right:0!important;width:100%}@media screen and (min-width:30em){.interactive{border-top:0;clear:none;float:right!important;padding-top:0;width:auto}}.interactive__item{margin-left:1.4285714286rem;float:left}.interactive__item:first-child{margin-left:0}@media screen and (min-width:30em){.interactive__item{margin-left:.8571428571rem;padding-left:.8571428571rem;border-left:1px solid #ededed;text-align:center}.interactive__item:first-child{border-left:0;padding-left:0}.interactive__item i{font-size:28px;font-size:2rem;display:block;line-height:1}}@media screen and (min-width:40em){.interactive__item{margin-left:1.4285714286rem;padding-left:1.4285714286rem}.interactive__item:first-child{margin-left:0;padding-left:0}}.interactive__item--comment i{position:relative}@media screen and (min-width:30em){.interactive__item--comment i{font-size:36px;font-size:2.5714285714rem;line-height:1;margin-bottom:0}.interactive__item--comment .interactive__label{margin-top:.4285714286rem}}.interactive__count{padding-left:.3em}@media screen and (min-width:30em){.interactive__count{font-size:20px;font-size:1.4285714286rem;color:#fff;bottom:0;left:0;line-height:1.5;right:0;padding-left:0;position:absolute;top:0;width:100%}}@media screen and (min-width:30em){.interactive__label{margin-top:1rem;display:block}}.fb-share-button>span{border:1px solid #3b5998;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;padding:.15em .25em;vertical-align:middle!important}.comment-share{margin:1.4285714286rem 0}@media screen and (min-width:40em){.comment-share{margin-top:0;text-align:right}}.comment-share a{display:block;text-decoration:none;color:#fff}.comment-share a:visited{color:#fff}.comment-share a:focus,.comment-share a:hover{color:#fff;text-decoration:none}.no-js .comment-share{display:none}.comment-share__totals{font-size:13px;font-size:.9285714286rem;margin-left:1.4285714286rem;padding-left:.4285714286rem;background-color:#aaa;color:#fff!important;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;line-height:1.8;position:relative;text-align:center;text-decoration:none!important}.comment-share .comment-share__totals{display:inline-block}.comment-share__totals:after{bottom:-10px;border-top:10px solid #aaa;border-right:10px solid transparent;content:'';left:10px;position:absolute}@media screen and (min-width:40em){.comment-share__totals{padding:.5rem 0 .2857142857rem;font-size:18px;font-size:1.2857142857rem;max-width:59px;max-width:4.2142857143rem;line-height:1;margin-left:15%;width:40%}}@media screen and (min-width:48em){.comment-share__totals{font-size:21px;font-size:1.5rem;margin-left:10%}}.comment-share__totals:first-child{margin-left:0}.comment-share__totals span{display:inline-block;margin-left:.4285714286rem;padding-left:.4285714286rem;background:#fff;color:#aaa;text-transform:uppercase}@media screen and (min-width:40em){.comment-share__totals span{background:0 0;bottom:-2em;font-size:.666667em;left:0;margin:0;padding:0;position:absolute}}.comment-share__totals:focus,.comment-share__totals:hover{background:#666}.comment-share__totals:focus:after,.comment-share__totals:hover:after{border-top-color:#666}.comment-share__totals:focus span,.comment-share__totals:hover span{color:#666}.star-rating{clear:both}.star-rating li{display:inline-block}.slideshow{padding:0 1.4285714286rem;position:relative}.article-full .slideshow{margin-top:-1.4285714286rem;padding:0}.slideshow .article-picture-credits{color:#aaa}.ad--splash .slideshow .article-picture-credits,.ad--xlsplash .slideshow .article-picture-credits,.modalbox .slideshow .article-picture-credits{color:#666}.slideshow figure{background-color:transparent}.slideshow--mini{margin:1.4285714286rem 0;padding:0}.slideshow--mini figure{position:relative}.slideshow__container{margin:1.4285714286rem 0 .8571428571rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.modalbox-slideshow .slideshow__container{margin:0}.slideshow__image{margin-bottom:1.7142857143rem;height:0;overflow:hidden;padding:60% 0 0;position:relative}.slideshow__image .slideshow__image__inner{bottom:0;left:0;position:absolute;right:0;top:0;width:100%!important}.slideshow__image .slideshow__image__inner img{display:inline-block;max-height:100%!important;width:auto!important}.old-safari .slideshow__image .slideshow__image__inner.center{height:auto}.slideshow--3k .slideshow__image{background-color:transparent}@media screen and (min-width:40em){.slideshow--3k .slideshow__image{float:left;padding-top:36%;width:61%}}.modalbox-slideshow .slideshow__image{background-color:transparent;padding-bottom:50%}.modalbox-slideshow .slideshow__image .slideshow__image__inner{position:fixed}.slideshow--mini .slideshow__image{padding-top:50%;margin-bottom:0}@media screen and (min-width:40em){.article-full .slideshow__image{padding-top:74%}}.slideshow__overview{height:100%;overflow:auto;width:100%}.slideshow__overview ol{height:100%}.slideshow__overview li{width:33.33%}@media screen and (min-width:40em){.slideshow__overview li{width:25%}}@media screen and (min-width:48em){.slideshow__overview li{width:20%}}@media screen and (min-width:40em){.slideshow--3k .slideshow__overview li{width:33.33%}}.slideshow__overview article{padding-right:0;padding-top:0}.slideshow__overview .article__body{margin-top:0}.slideshow__overview .article__header{padding:.8571428571rem;bottom:20px;bottom:1.4285714286rem;font-size:13px;color:#fff;font-family:Georgia,Cambria,Times New Roman,Times,sans-serif;text-align:left;text-shadow:0 1px 0 #000;-webkit-font-smoothing:antialiased}.slideshow__overview a:focus .article__header,.slideshow__overview a:hover .article__header{color:#fff}.slideshow__meta{margin-bottom:1.4285714286rem;position:relative}.slideshow__meta:after{content:".";display:block;height:0;clear:both;visibility:hidden}@media screen and (min-width:40em){.slideshow--3k .slideshow__meta{float:left;width:39%}}.modalbox-slideshow .slideshow__meta{background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.3)),color-stop(75%,#000));background-image:-webkit-linear-gradient(rgba(0,0,0,.3),#000 75%);background-image:-moz-linear-gradient(rgba(0,0,0,.3),#000 75%);background-image:linear-gradient(rgba(0,0,0,.3),#000 75%);bottom:0;margin:0;position:fixed;width:100%}.slideshow--mini .slideshow__meta{position:absolute;bottom:0;left:0;background-color:rgba(0,0,0,.5);width:100%;margin:0}.slideshow__caption{margin-right:10.7142857143rem;max-width:805px;max-width:57.5rem;float:left;margin-bottom:0}.modalbox-slideshow .slideshow__caption{color:#aaa;padding:1.4285714286rem 0;margin:0 17.8571428571rem 0 1.4285714286rem;display:none}@media screen and (min-width:40em){.modalbox-slideshow .slideshow__caption{display:block}}@media screen and (min-width:75em){.modalbox-slideshow .slideshow__caption{max-width:992px;max-width:70.8571428571rem;float:none;margin:0 auto;text-align:center;width:100%}}.slideshow--mini .slideshow__caption{padding:1.4285714286rem;color:#fff;float:none;font-family:Georgia,Cambria,Times New Roman,Times,sans-serif;text-transform:uppercase;margin:0}.slideshow__controls{position:absolute;right:0;top:-.3em}.modalbox-slideshow .slideshow__controls{position:static}.no-js .slideshow__controls{display:none}.slideshow__next,.slideshow__prev{height:30px;height:2.1428571429rem;width:30px;width:2.1428571429rem;top:-2px;top:-.1428571429rem;font-size:18px;font-size:1.2857142857rem;line-height:1.85;display:inline-block;background:#aaa;position:relative;text-align:center;text-decoration:none;color:#fff}.slideshow__next:visited,.slideshow__prev:visited{color:#fff}.slideshow__next:focus,.slideshow__next:hover,.slideshow__prev:focus,.slideshow__prev:hover{color:#fff;text-decoration:none;background:#666}.slideshow__next i,.slideshow__prev i{vertical-align:middle}.modalbox-slideshow .slideshow__next,.modalbox-slideshow .slideshow__prev{opacity:.6;color:#fff!important;display:inline-block;vertical-align:middle;margin-right:0;margin-left:0;position:fixed;z-index:1091;width:50%;left:0;top:0;min-height:100%;background:0 0}.modalbox-slideshow .slideshow__next i,.modalbox-slideshow .slideshow__prev i{position:fixed;left:20px;top:50%;margin-top:-14px}.modalbox-slideshow .slideshow__next:focus,.modalbox-slideshow .slideshow__next:hover,.modalbox-slideshow .slideshow__prev:focus,.modalbox-slideshow .slideshow__prev:hover{opacity:1}.slideshow__prev{margin-right:.5em}.slideshow__next{margin-left:.5em}.modalbox-slideshow .slideshow__next{left:50%;margin-left:0}.modalbox-slideshow .slideshow__next i{left:auto;right:20px}.slideshow__thumbs{margin-bottom:1.4285714286rem}.slideshow__thumbs ol li{height:50px;width:50px}.slideshow__thumbs ol a{position:relative}.slideshow__thumbs ol a:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:5px solid transparent;content:'';height:100%;left:0;position:absolute;top:0;width:100%}.slideshow__thumbs ol img{display:block;height:auto!important;width:100%!important}.slideshow__thumbs ol .is-active a:after,.slideshow__thumbs ol a:focus:after,.slideshow__thumbs ol a:hover:after{border-color:#aaa}.slideshow__teasers.widget{border-bottom:0}.slideshow__teasers .widget__list li{float:left;width:50%}@media screen and (min-width:40em){.slideshow__teasers .widget__list li{width:100%}}@media screen and (min-width:62.1875em){.slideshow__teasers .widget__list li{width:50%}}.slideshow__teasers article{padding-top:0}.slideshow__teasers article img{width:90px;width:6.4285714286rem;float:left}.slideshow__teasers .article__body{margin-left:7.8571428571rem;margin-top:0}.slideshow__teasers .article__header{font-size:18px;font-size:1.2857142857rem}.slideshow__pager{margin-bottom:1.4285714286rem;right:20px;right:1.4285714286rem;bottom:0;margin-left:0;position:absolute}.slideshow__pager li{display:inline-block;border-left:9px solid #444;border-top:5px solid transparent;border-bottom:5px solid transparent;margin:0 2px 0 0}.slideshow__pager li.is-active{border-left-color:#fff}.modalbox-slideshow .slideshow__pager{position:static;text-align:center}@media screen and (min-width:40em){.modalbox-slideshow .slideshow__pager{position:fixed}}.slideshow__intro{padding-right:1.4285714286rem;padding-top:1.4285714286rem;padding-bottom:1.4285714286rem;font-weight:700}[class*=" thumb-"],[class^=thumb-]{background-position:0 0;background-repeat:no-repeat}.thumb-paper{background-image:url(../img/krantje.png);padding-left:87px;-webkit-background-size:75px 63px;-moz-background-size:75px 63px;background-size:75px 63px;min-height:63px}.theme-morningedition .thumbnail-author{margin-bottom:1.4285714286rem}@media screen and (min-width:40em){.main-topic .topic__heading{float:left;width:66.6666%}}@media screen and (min-width:40em){.main-topic .topic__body{float:left;width:33.3333%}}.tag{font-size:12px;font-size:.8571428571rem;line-height:12px;color:#aaa;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:700;text-transform:uppercase}.intro .tag{margin:0 .2857142857rem 0 0}.article-tags .tag{font-weight:400}.tag:empty:before{display:none;visibility:hidden;font-weight:400;color:#000;margin-left:3px}.article-full--edition .tag,.author-info--full .tag{color:#000!important;font-weight:700}a.tag{font-size:14px;font-size:1rem;text-transform:none;display:inline-block}a.tag:first-letter{text-transform:uppercase}.tag-list{display:inline-block;margin:12px 0;color:#aaa}.tag-list:before{display:inline-block;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:700}.tag-list+.custom-list{margin-top:0}.search-results .tag-list:before{content:'Tags: '}.tag-list a.tag{font-weight:400}.article--plus>.tag-list a.tag,.tag-list a.tag.tag--live,.tag-list a.tag.tag--plus{color:#aaa!important;font-weight:400}.article-teaser .tag-list:before{content:'Tags: '}.article-teaser .tag-list a{color:#aaa!important}.talkbubble{padding:1.4285714286rem;margin:0 0 4.2857142857rem;font-size:21px;font-size:1.5rem;background-color:#ddd;position:relative}.talkbubble:after{left:20px;left:1.4285714286rem;bottom:-16px;bottom:-1.1428571429rem;content:"";position:absolute;border-top:16px solid #ddd;border-right:16px solid transparent}.talkbubble.inverted{background-color:#fff;color:#444;-webkit-font-smoothing:subpixel-antialiased!important}.talkbubble.inverted:after{border-top-color:#fff}.callout .talkbubble.inverted{color:#7ba2cc}.talkbubble__meta{left:20px;left:1.4285714286rem;bottom:-46px;bottom:-3.2857142857rem;color:#aaa;position:absolute}.callout .inverted .talkbubble__meta{color:#fff}.table{width:100%;margin-bottom:1.4285714286rem}.table td,.table th{padding:.5714285714rem .4285714286rem}.table--bordered{border:1px solid #ddd;border-collapse:separate;border-left:0}.table--bordered td,.table--bordered th{border-left:1px solid #ddd;border-top:1px solid #ddd}.table--bordered thead th{border-top:0}.table--striped tbody>tr:nth-child(odd)>td,.table--striped tbody>tr:nth-child(odd)>th{background-color:#eee}.table--striped tbody td a,.table--striped tbody th a{text-decoration:none;color:#444}.table--striped tbody td a:visited,.table--striped tbody th a:visited{color:#444}.table--striped tbody td a:focus,.table--striped tbody td a:hover,.table--striped tbody th a:focus,.table--striped tbody th a:hover{color:#000;text-decoration:none}.table--dividers tbody>tr>td{border-bottom:1px solid #ddd}.table--expanded td,.table--expanded th{padding:.8571428571rem}.table--condensed td,.table--condensed th{padding-:6px 4px;padding-:.4285714286rem .2857142857rem}.table--hover tbody tr:hover td,.table--hover tbody tr:hover th{background-color:#ddd}.table--clicker tbody tr:hover td,.table--clicker tbody tr:hover th{cursor:pointer}@media screen and (max-width:39.9375em){.table--rwd thead{display:none;visibility:hidden}.table--rwd tbody,.table--rwd td,.table--rwd th,.table--rwd tr{display:block;border:0;padding:0;text-align:left;white-space:normal}.table--rwd td[data-title]:before,.table--rwd th[data-title]:before{content:attr(data-title) ":\00A0";font-weight:700}.table--rwd th:not([data-title]){font-weight:700}.table--rwd td:empty{display:none}.table--rwd.table--bordered tbody th,.table--rwd.table--bordered td,.table--rwd.table--striped tbody th,.table--rwd.table--striped td{padding:.1428571429rem .4285714286rem}}caption{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:17px;font-size:1.2142857143rem;text-align:left}caption:after{content:".";display:block;height:0;clear:both;visibility:hidden}.latest-issues caption{margin-bottom:.8571428571rem;padding:.8571428571rem .5714285714rem .1428571429rem;line-height:1;font-size:14px;font-weight:400;border-bottom:1px solid #ededed}th{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;color:#aaa;vertical-align:bottom;font-weight:400}.latest-issues th{vertical-align:top;text-transform:none}th[scope=row]{text-align:left;font-weight:400;font-family:inherit;text-transform:none;color:inherit;font-size:14px;font-size:1rem;vertical-align:middle}.latest-issues td{width:14.28571%;text-align:center}.latest-issues td img{border:1px solid rgba(0,0,0,.25);-webkit-box-shadow:rgba(0,0,0,.35) 2px 2px 2px;-moz-box-shadow:rgba(0,0,0,.35) 2px 2px 2px;box-shadow:rgba(0,0,0,.35) 2px 2px 2px}.latest-issues tfoot td{text-align:left}.latest-issues{margin-bottom:0}.attachment-today{background-color:#eee}.table--big .key{width:89px;max-width:89px;overflow:hidden}.value{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;color:#aaa;text-align:right}.pos{color:#0cae00}.neg{color:#fc0000}.graph-bars{width:100%}.graph-bars td{width:50%;padding:0}.graph-bars div{display:inline-block;height:14px;height:1rem}.graph-bars .pos{background-color:#0cae00}.graph-bars .neg{background-color:#fc0000}.sort-header{cursor:pointer;text-align:left!important}.sort-header div{position:relative}.sort-header div:after,.sort-header div:before{content:'';height:0;font-size:0;position:absolute;top:50%;right:-3px;border-style:solid;border-color:#aaa transparent;opacity:.4}.sort-header div:before{margin-top:-6px;border-width:0 4px 4px}.sort-header div:after{margin-top:0;border-width:4px 4px 0}.sort-header div:hover:after,.sort-header div:hover:before{opacity:.7}.sort-up div:before,.sort-up div:hover:before{opacity:.4}.sort-down div:before,.sort-down div:hover:before,.sort-up div:after,.sort-up div:hover:after{opacity:1}.sort-down div:after,.sort-down div:hover:after{opacity:.4}.tabs{margin-bottom:1.4285714286rem}.nav-tabs{padding:0 0 .8571428571rem;margin:0;width:100%}.nav-tabs:after{content:".";display:block;height:0;clear:both;visibility:hidden}.nav-tabs li{margin-left:.5714285714rem;margin-right:.5714285714rem;float:left;position:relative}.nav-tabs li.first{margin-left:0}.nav-tabs li:after{top:-1px;top:-.0714285714rem;right:-11px;right:-.7857142857rem;content:"∙";font-weight:700;position:absolute}.nav-tabs li.last:after{content:''}.nav-tabs li a{font-weight:400;text-transform:uppercase}.nav-tabs li.active a{text-decoration:none;color:#666}.nav-tabs li.active a:visited{color:#666}.nav-tabs li.active a:focus,.nav-tabs li.active a:hover{color:#222;text-decoration:none}.js .tab-content{overflow:hidden}.js .tab-content>.tab-pane{display:none}.js .tab-content>.active{display:block}.alt-family,.article-lsc,.conversion__header,.form,.form--flag,.interactive__count,.interactive__label,.magazines-header,.pullquote,.session-expired{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.alt-family.button,.alt-family.mail-share-button,.alt-family.tag,.article-lsc.mail-share-button,.button.article-lsc,.button.conversion__header,.button.form,.button.form--flag,.button.interactive__count,.button.interactive__label,.button.magazines-header,.button.pullquote,.button.session-expired,.conversion__header.mail-share-button,.form--flag.mail-share-button,.form.mail-share-button,.interactive__count.mail-share-button,.interactive__label.mail-share-button,.magazines-header.mail-share-button,.mail-share-button.pullquote,.mail-share-button.session-expired,.tag.article-lsc,.tag.conversion__header,.tag.form,.tag.form--flag,.tag.interactive__count,.tag.interactive__label,.tag.magazines-header,.tag.pullquote,.tag.session-expired{line-height:1}.alt-family-2{font-family:Georgia,Cambria,Times New Roman,Times,sans-serif;line-height:1}h1.alt-family,h1.article-lsc,h1.conversion__header,h1.form,h1.form--flag,h1.interactive__count,h1.interactive__label,h1.magazines-header,h1.pullquote,h1.session-expired,h2.alt-family,h2.article-lsc,h2.conversion__header,h2.form,h2.form--flag,h2.interactive__count,h2.interactive__label,h2.magazines-header,h2.pullquote,h2.session-expired,h3.alt-family,h3.article-lsc,h3.conversion__header,h3.form,h3.form--flag,h3.interactive__count,h3.interactive__label,h3.magazines-header,h3.pullquote,h3.session-expired,h4.alt-family,h4.article-lsc,h4.conversion__header,h4.form,h4.form--flag,h4.interactive__count,h4.interactive__label,h4.magazines-header,h4.pullquote,h4.session-expired,h5.alt-family,h5.article-lsc,h5.conversion__header,h5.form,h5.form--flag,h5.interactive__count,h5.interactive__label,h5.magazines-header,h5.pullquote,h5.session-expired,h6.alt-family,h6.article-lsc,h6.conversion__header,h6.form,h6.form--flag,h6.interactive__count,h6.interactive__label,h6.magazines-header,h6.pullquote,h6.session-expired{text-transform:uppercase}h1.alt-family,h1.article-lsc,h1.conversion__header,h1.form,h1.form--flag,h1.interactive__count,h1.interactive__label,h1.magazines-header,h1.pullquote,h1.session-expired{font-size:34px}h2.alt-family,h2.article-lsc,h2.conversion__header,h2.form,h2.form--flag,h2.interactive__count,h2.interactive__label,h2.magazines-header,h2.pullquote,h2.session-expired{font-size:26px}h3.alt-family,h3.article-lsc,h3.conversion__header,h3.form,h3.form--flag,h3.interactive__count,h3.interactive__label,h3.magazines-header,h3.pullquote,h3.session-expired,h4.alt-family,h4.article-lsc,h4.conversion__header,h4.form,h4.form--flag,h4.interactive__count,h4.interactive__label,h4.magazines-header,h4.pullquote,h4.session-expired{font-size:18px}h5.alt-family,h5.article-lsc,h5.conversion__header,h5.form,h5.form--flag,h5.interactive__count,h5.interactive__label,h5.magazines-header,h5.pullquote,h5.session-expired{font-size:16px}h6.alt-family,h6.article-lsc,h6.conversion__header,h6.form,h6.form--flag,h6.interactive__count,h6.interactive__label,h6.magazines-header,h6.pullquote,h6.session-expired{font-size:14px}.h1{font-size:36px}.h2{font-size:28px}.h3,.h4{font-size:20px}.h5,.theme-morningedition .l-front article+article .article__header{font-size:18px}.h6{font-size:16px}.conversion__header,.edition-nav .current-page,.index-nav a,.latest-issues caption,.theme-archive .author-info h3,.theme-biz th,.theme-morningedition .info .info__header,.theme-morningedition .info__data dt,.theme-morningedition .island .widget__header,.theme-morningedition .islet .widget__header,.theme-morningedition .l-front .article__header,.theme-morningedition .label-section--large,.uc,.widget.stockteaser .currency,caption,th{text-transform:uppercase}.smaller{font-size:.85em}.x-small{font-size:.6em;vertical-align:text-bottom}.blend-in{color:inherit!important;font-size:inherit!important;font-family:inherit!important}.pullquote{margin:.8571428571rem 0 .8571428571rem 1.2857142857rem;padding:0 0 0 1.2857142857rem;font-size:21px;font-size:1.5rem;border-left:1px solid #000;color:#9d261d;line-height:1.2;width:33%}.pullquote.pull-left{margin-right:1.2857142857rem;padding-right:1.2857142857rem;margin-left:0;padding-left:0;border-left:none;border-right:1px solid #000;text-align:right}.link--paco,.link--paco:visited{color:#dd2727!important}.link--paco:active,.link--paco:focus,.link--paco:hover{color:#dd2727!important;text-decoration:underline!important}li .link--paco,li .link--paco:visited{text-decoration:none!important}li .link--paco:active,li .link--paco:focus,li .link--paco:hover{color:#dd2727!important;text-decoration:underline!important}.session-expired{-webkit-transition:max-height .4s ease-out;-moz-transition:max-height .4s ease-out;transition:max-height .4s ease-out;max-height:0;overflow:hidden;text-align:center}.session-expired .alert{margin-top:1.4285714286rem}.session-expired button:focus,.session-expired button:hover{opacity:.8}.layout-session-expired .session-expired{max-height:500px;max-height:35.7142857143rem}@media screen and (min-width:48em){.layout-session-expired .session-expired{max-height:300px;max-height:21.4285714286rem}}.session-expired__inner{max-width:700px;max-width:50rem;margin:0 auto}.session-expired__header{font-size:16px;font-size:1.1428571429rem;color:#dd2727;text-transform:uppercase}.session-expired__header a{text-decoration:none;color:#dd2727}.session-expired__header a:visited{color:#dd2727}.session-expired__header a:focus,.session-expired__header a:hover{color:#e76969;text-decoration:none}.session-expired__header i+i{margin-right:.8em}.alert .session-expired__link{text-decoration:underline;color:#dd2727}.alert .session-expired__link:visited{color:#dd2727}.alert .session-expired__link:focus,.alert .session-expired__link:hover{color:#e76969;text-decoration:underline}.alert .session-expired__link:active{text-decoration:underline}.icon-pinit{background:url(../img/pinit.png) no-repeat;background:0 0,url(../img/pinit.svg) no-repeat;width:50px;height:24px;display:inline-block;position:absolute;left:10px;top:10px;cursor:pointer;opacity:1}.pin-container{position:relative;clear:left}.article-full figure{position:relative}.slideshow__overview.center__item+.icon-pinit{display:none}.slideshow__overview.center__item.is-offscreen+.icon-pinit,.slideshow__pager li span.slideshow__overview.center__item+.icon-pinit{display:block}html.no-touch .video,html.touch .video:not(.video--dsokaltura){padding-top:61.9718309859%}.article-full--video .video{margin-bottom:1.4285714286rem}html .video--vimeo,html .video--youtube{padding-top:62.323943662%}html .video--vmma{padding-top:56.161971831%}html .video--zoomin{padding-top:66.9014084507%}html .video--humo{padding-top:103.1690140845%}#jwplay_wrapper{height:auto!important;width:100%!important}html .video--rob,html .video--vier,html .video--vijf,html .video--vrt,html .video--vt4{padding-top:56.338028169%}html .video--vrt #jwplay_wrapper{position:static!important}.kWidgetIframeContainer{position:relative;padding-bottom:61.9718309859%;height:0!important;overflow:hidden;width:100%!important}html .video .kWidgetIframeContainer{position:static}.kWidgetIframeContainer iframe{position:absolute;top:0;left:0;width:100%;height:100%}#Kaltura_Embed{max-width:100%}.widget{padding:1.4285714286rem 0 0 1.4285714286rem;display:block}.widget:after{content:".";display:block;height:0;clear:both;visibility:hidden}.primary-col .cols-3 .widget,.primary-col aside .widget,.widget{border-bottom:1px solid #ededed}.callout>.widget,.primary-col .widget,.regionals .widget,.widget.last{border-bottom:none}.row .widget,.slideshow .widget,.slideshow__teasers .widget__list .widget{padding-left:0}.widget.article-tags{padding-bottom:1.4285714286rem}.topic .widget{padding:1.4285714286rem 2.8571428571rem}.island .widget,.islet .widget{padding-top:0}.col-3 .cols-2 .widget.photo-special,.col-3 .cols-2 .widget.video-special{padding-right:0!important}.widget.simple-list a{text-decoration:none;color:#444}.widget.simple-list a:visited{color:#444}.widget.simple-list a:focus,.widget.simple-list a:hover{color:#44c4d1;text-decoration:none}.widget.simple-list a time{color:#44c4d1}.widget.simple-list a span{font-size:20px;font-size:1.4285714286rem;display:block}.widget.simple-list li+li:before{padding-bottom:1.4285714286rem;border-top:1px solid #d3d3d3;content:'';display:block;margin:0 auto;width:39%}.widget.simple-list:last-child{margin-bottom:1.4285714286rem}.widget.archive-list{position:relative}.widget.archive-list:first-child{margin-top:0}.widget.archive-list .plustitle{position:relative;float:left;background:url(../img/plus/logo_naasttitel.png) no-repeat;background:0 0,url(../img/plus/logo_naasttitel.svg) no-repeat;width:40px;width:2.8571428571rem;height:22px;height:1.5714285714rem;display:inline-block;margin-right:.3571428571rem}.widget.archive-list .plustitle #ds_popup{top:-55px}.widget.archive-list #ds_popup{position:absolute;top:-50px;min-width:180px;background-color:#fff;z-index:1030;font-size:13px;font-size:.9285714286rem;color:#dd2727;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;border:1px solid #eee;padding:.3571428571rem}.widget.archive-list #ds_popup:after,.widget.archive-list #ds_popup:before{content:"";position:absolute;width:0;height:0;border-style:solid;border-color:transparent;border-bottom:0}.widget.archive-list #ds_popup:before{bottom:-10px;left:11px;border-top-color:#eee;border-width:10px}.widget.archive-list #ds_popup:after{bottom:-9px;left:12px;border-top-color:#fff;border-width:9px}.widget.archive-list.archive--abo h3{display:inline-block}.widget.archive-list.archive--abo h3:before{content:url(../img/plus/logo_naasttitel.png);content:url(../img/plus/logo_naasttitel.svg);display:inline-block(middle)}.widget.archive-list.archive--abo .plustitle{float:none;vertical-align:bottom}.widget.archive-list.archive--abo a img.pull-left{margin-right:.7142857143rem;margin-top:.3571428571rem}.widget.archive-list.archive--abo a p{font-size:14px;font-size:1rem;line-height:1.5;color:#444}.widget.archive-list.archive--abo a p.link--paco{font-size:19px;font-size:1.3571428571rem}.widget.archive-list.archive--abo #ds_popup{position:absolute;top:-50px;min-width:180px;background-color:#fff;z-index:1030;font-size:13px;font-size:.9285714286rem;text-transform:none;color:#dd2727;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;border:1px solid #eee;padding:.3571428571rem}.widget.archive-list.archive--abo #ds_popup:after,.widget.archive-list.archive--abo #ds_popup:before{content:"";position:absolute;width:0;height:0;border-style:solid;border-color:transparent;border-bottom:0}.widget.archive-list.archive--abo #ds_popup:before{bottom:-10px;left:11px;border-top-color:#eee;border-width:10px}.widget.archive-list.archive--abo #ds_popup:after{bottom:-9px;left:12px;border-top-color:#fff;border-width:9px}.widget.archive-list.archive--abo .widget__list{margin:0}.widget.archive-list.archive--abo .widget__list li{clear:both}.widget.archive-list.archive--abo .widget__list li:first-child{margin-bottom:1.4285714286rem}.widget.archive-list.archive--abo .widget__list li a time{font-size:11px;font-size:.7857142857rem;text-transform:uppercase}.widget.archive-list.archive--abo .widget__list li a .tag{display:inline;font-size:11px;font-size:.7857142857rem;text-transform:uppercase}.widget.archive-list.archive--abo .widget__list li a .tag:before{content:"|";padding-right:.2142857143rem}.widget.archive-list.archive--abo .widget__list li a .tag:empty:before{content:""}.widget.archive-list .widget__list{margin-left:2.1428571429rem}.widget.archive-list a{text-decoration:none;color:#dd2727}.widget.archive-list a:visited{color:#dd2727}.widget.archive-list a:focus,.widget.archive-list a:hover{color:#e76969;text-decoration:none}.widget.archive-list p{font-size:16px;margin-bottom:0}.widget.archive-list .tag,.widget.archive-list time{color:#444;display:block}@media screen and (min-width:40em){.widget.archive-list .tag,.widget.archive-list time{display:inline-block}}.widget.archive-list .tag{font-weight:500;line-height:1}.widget.stockteaser .currency{font-size:14px;font-size:1rem;margin:.5rem 0 1.4285714286rem;background:#f7f3f7;color:#666;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;float:left;padding:2%;width:92%}.widget.stockteaser .currency dd,.widget.stockteaser .currency dt{padding:.2142857143rem 0 0;float:left;margin:0}.widget.stockteaser .currency dt{margin-right:.3571428571rem;width:115px;width:8.2142857143rem;clear:both}.widget.stockteaser .currency dd{font-size:12px;font-size:.8571428571rem;padding-top:.3571428571rem}.widget.stockteaser .currency dd:last-of-type{margin-left:1.0714285714rem}.widget.external-links h6{margin-bottom:.3571428571rem}.widget.external-links ul{margin:0}.widget.related-articles .article-teaser a .article-teaser__text .article__header{font-size:21px;font-size:1.5rem}.widget.widget__popup-message{margin-left:8.5%;margin-right:8.5%;opacity:0;padding:.3571428571rem .7142857143rem;margin-bottom:1.4285714286rem;display:block;border:1px solid #dd2727;border-bottom:1px solid #dd2727!important;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.widget.widget__popup-message .icon-lightbulb{color:#dd2727;font-size:35px;font-size:2.5rem;margin-left:.7142857143rem}.widget.widget__popup-message a .message__container{display:inline-block;vertical-align:middle;max-width:60%;margin-left:1.4285714286rem;line-height:1.5}.widget.widget__popup-message a .message__container .widget__header{margin:.7142857143rem 0 .3571428571rem;font-weight:700}.widget.widget__popup-message a .message__container p{margin-bottom:.7142857143rem;color:#444}.widget--has-dividers .widget__list>li{border-bottom:1px solid #ededed!important;margin-bottom:20px}.widget--has-dividers .widget__list{margin-bottom:0}.widget.simple-list{text-align:center}.col-3 .cols-2 .widget.photo-special,.col-3 .cols-2 .widget.video-special,.widget.archive-list,.widget.simple-list{margin-top:1.4285714286rem;padding-left:1.4285714286rem;padding-right:1.4285714286rem;background-color:#eee}.widget__header{margin:0 0 1.4285714286rem;line-height:1;text-transform:uppercase;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.widget__header:after{content:".";display:block;height:0;clear:both;visibility:hidden}.widget__header>*{margin:0}.widget__header>h1{font-size:34px}.widget__header>h2{font-size:26px}.widget__header>h3,.widget__header>h4{font-size:18px}.widget__header>h5{font-size:16px}.widget__header>h6{font-size:14px}.widget__footer{padding-bottom:1.4285714286rem}.widget__footer:after{content:".";display:block;height:0;clear:both;visibility:hidden}.widget__list{margin:0}.widget__list:after{content:".";display:block;height:0;clear:both;visibility:hidden}.widget__list>li{display:block;padding-bottom:20px}.photo-special .widget__list>li,.video-special .widget__list>li{float:left;width:20%;padding-bottom:0}.secondary-col .photo-special .widget__list>li,.secondary-col .video-special .widget__list>li{padding-bottom:20px}.col-3 .cols-2 .photo-special .widget__list>li,.col-3 .cols-2 .video-special .widget__list>li{width:50%}.widget__list>li article{padding-top:0;padding-bottom:0}.secondary-col .widget__list>li{float:none;width:100%;border-bottom:0}.l-zone-transformer .widget__list>.list__item-1,.l-zone-transformer .widget__list>.list__item-2{float:left;width:30%}.l-zone-transformer .widget__list>.list__item-3,.l-zone-transformer .widget__list>.list__item-4,.l-zone-transformer .widget__list>.list__item-5{border-left:1px solid #ededed;float:right;clear:right;width:39.8%}.l-zone-transformer .widget__list>.list__item-3 article,.l-zone-transformer .widget__list>.list__item-4 article,.l-zone-transformer .widget__list>.list__item-5 article{margin-left:1.4285714286rem;margin-right:1.4285714286rem;padding-right:0}.l-zone-transformer .widget__list>.list__item-3 article,.l-zone-transformer .widget__list>.list__item-4 article{border-bottom:1px solid #ededed}.widget--sport{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.widget--sport th{text-align:left}.widget--sport .table:first-child{margin-top:1em}.widget--sport .table time{color:#aaa}.widget--agenda .article-media__helper{float:left}.widget--agenda .article__body{margin-left:105px}.widget--agenda .link--proceed{display:block}.lsc-soccer__event__inner,.lsc-soccer__wrapper{display:block;font-size:0;list-style:none;margin:0 -10px;padding:0}.lsc-soccer__event__inner>.lsc-soccer__event__inner,.lsc-soccer__event__inner>.lsc-soccer__wrapper,.lsc-soccer__wrapper>.lsc-soccer__event__inner,.lsc-soccer__wrapper>.lsc-soccer__wrapper{margin:0}.lsc-soccer__aside,.lsc-soccer__main,.lsc-soccer__meta,.lsc-soccer__team{display:inline-block;font-size:14px}.lsc-soccer__aside__inner,.lsc-soccer__main__inner,.lsc-soccer__meta__inner,.lsc-soccer__team__inner{padding:0 10px}.lsc-soccer__aside__inner{white-space:nowrap}.lsc-soccer__aside__inner:before{content:"";height:100%;display:inline-block;vertical-align:middle}.lsc-soccer{font-size:14px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;text-transform:uppercase}.lsc-widget-header{background-color:#44c4d1}.lsc-widget-logo span{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:.8em}.lsc-section-title{margin-top:15px;border-bottom:1px solid #aaa;color:#000;font-weight:900;font-size:18px}.lsc-section-title a{margin-top:3px;float:right;color:#000;text-transform:none;text-decoration:none;font-size:12px}.lsc-section-title a:hover{color:#000}.lsc-soccer__header{margin-top:20px;margin-bottom:5px;overflow:hidden}.lsc-soccer__header a,.lsc-soccer__header h2,.lsc-soccer__header h3{margin:0;color:#fff}.lsc-soccer__header h2{float:left;font-size:19px;font-weight:700;line-height:toEm(22px,19px)}.lsc-soccer__header a{float:right;font-size:1em;font-weight:300;line-height:22px;text-transform:none}.lsc-soccer__events{list-style:none;margin:0;padding:0}.lsc-soccer__event{border:none;height:60px;border-bottom:1px solid #aaa}.lsc-soccer__event__inner{text-align:center}.lsc-soccer__event__inner:before{content:'';display:inline-block;margin-left:-1px;height:60px;vertical-align:middle;width:1px}.lsc-soccer__aside,.lsc-soccer__main{vertical-align:middle}.lsc-soccer__main{width:80%}.lsc-soccer__aside{vertical-align:top!important;width:20%}.lsc-soccer__wrapper{text-align:center}.lsc-soccer__meta,.lsc-soccer__team{vertical-align:middle}.lsc-soccer__meta{padding:0;width:20%}.lsc-soccer__meta .unibet-odds{margin-top:1px;display:block}.lsc-soccer__meta .unibet-odds span{font-size:13px}.lsc-soccer__meta__inner{padding:0;margin-left:-50%;width:200%}.lsc-soccer__meta__inner .lsc-soccer__status{font-size:11px}.lsc-soccer__progress,.lsc-soccer__status{vertical-align:middle;display:inline-block}.lsc-soccer__status .pill-live{display:none}.lsc-soccer__status .pill-gedaan,.lsc-soccer__status .pill-uitgesteld{font-size:11px}.lsc-soccer__team{width:40%}.lsc-soccer__team>a{-webkit-box-align:center;-webkit-align-items:center;-moz-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-moz-box-pack:center;-ms-flex-pack:center;justify-content:center;overflow:hidden;display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-ms-flexbox;display:flex;color:transparent;text-decoration:none}.lsc-soccer__team img{height:auto;margin:4px auto;max-width:100%;width:36px;display:inline-block}.lsc-soccer__team abbr{border-bottom:0;display:inline-block;-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-ms-flex:1;flex:1;color:transparent;font-weight:500;font-size:14px;line-height:1.1;text-transform:uppercase}.lsc-soccer__team abbr[title]:before{content:attr(title)}.lsc-soccer__team abbr[title] span{display:none}.lsc-soccer__home>a{float:none}.lsc-soccer__home img{float:left}.lsc-soccer__away img{-webkit-order:1;-ms-flex-order:1;-webkit-box-ordinal-group:2;-moz-box-ordinal-group:2;order:1}.lsc-soccer__away>a{float:none}.lsc-soccer__away img{float:right}.lsc-soccer__status{color:transparent;font-weight:900;font-size:18px}.lsc-soccer__result{font-size:24px;font-weight:900;line-height:1.2}.lsc-soccer__result a{color:transparent;text-decoration:none}.lsc-soccer__cta-live,.lsc-soccer__cta-video{background-color:#ececec;color:#444;display:block;font-size:10px;font-weight:800;margin:.3em 0;padding:.5em .3em;text-transform:uppercase}.lsc-soccer__cta-live:focus,.lsc-soccer__cta-live:hover,.lsc-soccer__cta-video:focus,.lsc-soccer__cta-video:hover{background-color:#dfdfdf}.lsc-soccer__cta-live span,.lsc-soccer__cta-video span{display:none}.lsc-soccer__result .pill-gedaan:before,.lsc-soccer__result .pill-live:before,.lsc-soccer__result .pill-uitgesteld:before{display:block;color:red;font-size:11px;text-transform:uppercase}.lsc-soccer__result .pill-live:before{content:"Live"}.lsc-soccer__result .pill-gedaan:before{content:"Einde"}.lsc-soccer__result .pill-uitgesteld:before{content:"Uitgesteld"}.lsc-soccer__next{display:none}.lsc-widget .lsc-soccer,.lsc-widget .lsc-soccer__aside,.lsc-widget .lsc-soccer__main,.lsc-widget .lsc-soccer__meta,.lsc-widget .lsc-soccer__team,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__aside,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__main,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__meta,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__team{font-size:12px}.lsc-widget .lsc-soccer__header,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__header{margin-left:10px;margin-right:10px}.lsc-widget .lsc-soccer,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer{font-size:14px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;text-transform:uppercase;border:2px solid transparent;border-top:none}.lsc-widget .lsc-soccer__event,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__event{border-bottom:none}.lsc-widget .lsc-soccer__event:nth-child(even),section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__event:nth-child(even){background-color:#ddd}.lsc-widget .lsc-soccer__aside__inner,.lsc-widget .lsc-soccer__cta-video,.lsc-widget .lsc-soccer__event,.lsc-widget .lsc-soccer__event__inner:before,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__aside__inner,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__cta-video,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__event,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__event__inner:before{height:50px}.lsc-widget .lsc-soccer__event__inner,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__event__inner{margin:0}.lsc-widget .lsc-soccer__aside__inner,.lsc-widget .lsc-soccer__main__inner,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__aside__inner,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__main__inner{padding:0;position:relative}.lsc-widget .lsc-soccer__main,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__main{width:82%}.lsc-widget .lsc-soccer__main__inner,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__main__inner{margin-right:10px}.lsc-widget .lsc-soccer__team img,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__team img{width:28px;display:none}.lsc-widget .unibet-odds .icon-unibet,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .unibet-odds .icon-unibet{height:9px;width:60px}.lsc-widget .unibet-odds span,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .unibet-odds span{background:#31a065;padding:0 4px;border-right:1px solid #444;display:inline-block;color:#fff;font-size:9px}.lsc-widget .unibet-odds span:last-child,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .unibet-odds span:last-child{border-right:0;margin-right:0}.lsc-widget .lsc-soccer__aside,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__aside{margin-right:3%;width:15%}.lsc-widget .pill-gedaan:before,.lsc-widget .pill-live:before,.lsc-widget .pill-uitgesteld:before,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .pill-gedaan:before,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .pill-live:before,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .pill-uitgesteld:before{display:none}.lsc-widget .lsc-soccer__meta .pill-gedaan,.lsc-widget .lsc-soccer__meta .pill-live,.lsc-widget .lsc-soccer__meta .pill-uitgesteld,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__meta .pill-gedaan,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__meta .pill-live,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__meta .pill-uitgesteld{display:block}.lsc-widget .lsc-soccer__status.lsc-soccer__status,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__status.lsc-soccer__status{font-size:12px}.lsc-widget .lsc-soccer__cta-video,.lsc-widget .lsc-soccer__progress,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__cta-video,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__progress{width:100%;font-weight:900}.lsc-widget .lsc-soccer__progress,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__progress{margin-left:-4px}.lsc-widget .lsc-soccer__progress span,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__progress span{margin-top:-5px;font-size:80%;display:block}.lsc-widget .lsc-soccer__progress.lsc-soccer__progress-extra+.lsc-soccer__live-loader,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__progress.lsc-soccer__progress-extra+.lsc-soccer__live-loader{max-width:45px;top:50%;left:50%;margin-left:-23px;margin-top:-20px}.lsc-widget .lsc-soccer__result,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__result{display:block}.lsc-widget .lsc-soccer__live-loader,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__live-loader{max-width:40px;position:absolute;top:50%;left:50%;margin-left:-20px;margin-top:-20px}.lsc-widget .lsc-soccer__cta-video,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__cta-video{background-color:#eee;font-weight:700;display:inline-block;color:transparent;line-height:50px;margin:0;padding:0;position:absolute;top:0;left:0;-webkit-transition:all .3s ease-in-out;-moz-transition:all .3s ease-in-out;transition:all .3s ease-in-out;text-decoration:none}.lsc-widget .lsc-soccer__cta-video:after,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__cta-video:after{content:'>';margin-left:-2px}.lsc-widget .lsc-soccer__cta-video:focus,.lsc-widget .lsc-soccer__cta-video:hover,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__cta-video:focus,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__cta-video:hover{background-color:red;color:#fff;text-decoration:none}.lsc-widget .lsc-soccer__cta-video .lsc-soccer__status,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__cta-video .lsc-soccer__status{color:#fff}.lsc-widget .lsc-soccer__event:nth-child(even) .lsc-soccer__cta-video,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__event:nth-child(even) .lsc-soccer__cta-video{background-color:#ddd}.lsc-widget .lsc-soccer__event:nth-child(even) .lsc-soccer__cta-video:hover,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__event:nth-child(even) .lsc-soccer__cta-video:hover{background-color:red}.lsc-widget .lsc-soccer__prolsc-soccer__statusess span:after,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__prolsc-soccer__statusess span:after{content:'"'}.lsc-widget .lsc-soccer__progress,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__progress{color:#666}.lsc-widget .lsc-soccer__result a,.lsc-widget abbr[title],section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__result a,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync abbr[title]{color:#44c4d1!important}.lsc-widget abbr[title],section.sportwereld section.sportwereld .js-lsc-matchcenter-sync abbr[title]{cursor:pointer}.lsc-widget abbr[title] span,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync abbr[title] span{display:none}.lsc-widget .lsc-soccer__home abbr,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__home abbr{text-align:left}.lsc-widget .lsc-soccer__away abbr,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc-soccer__away abbr{text-align:right}.lsc-widget .lsc_soccer__custom-event,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc_soccer__custom-event{text-align:left}.lsc-widget .lsc_soccer__custom-event__inner,section.sportwereld section.sportwereld .js-lsc-matchcenter-sync .lsc_soccer__custom-event__inner{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;border-bottom:0;display:inline-block;margin-left:10px;font-weight:500;font-size:12px!important;text-transform:uppercase;line-height:23px}.lsc-widget{margin-bottom:20px}.live-sports-coverage .lsc-widget .lsc-soccer__header{margin-top:0;margin-left:10px;margin-right:10px}.live-sports-coverage .lsc-widget .lsc-soccer__header a,.live-sports-coverage .lsc-widget .lsc-soccer__header h3{margin-top:10px;margin-bottom:0}.live-sports-coverage .lsc-widget .lsc-soccer__header h3{float:left}.live-sports-coverage .lsc-widget .lsc-soccer__events{border-top:1px solid #aaa}.lsc-widget .lsc-soccer__team abbr{font-size:12px}.lsc-widget .lsc-soccer__team abbr:before{display:inline-block}.lsc-widget .lsc-soccer__team abbr span{display:none}.lsc-widget-header{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;text-transform:uppercase;font-size:18px}.lsc-widget-header .lsc-widget-logo{line-height:18px}.lsc-widget-header a{font-weight:700;font-size:18px}.lsc-widget-header span{font-size:18px}.lsc-widget .live-sports-coverage a,.lsc-widget .lsc-soccer__result a,.lsc-widget .lsc-soccer__status.lsc-soccer__status,.lsc-widget .lsc-soccer__team abbr{color:#444}.lsc-widget .lsc-soccer__event__inner{padding:0}.social--share{position:relative;margin-left:-20px}.social--share .social--share-left{background-color:#e4e4e4;margin-left:-1.0714285714rem;padding:.7142857143rem 2.1428571429rem;margin-bottom:1.4285714286rem;display:inline-block;vertical-align:top;width:100%;min-height:72px}@media screen and (min-width:62.1875em){.social--share .social--share-left{width:58%}}.social--share .social--share-left p{line-height:24px;padding-top:.8571428571rem;margin:0}.social--share .social--share-left p span{font-style:italic;color:#dc2323}.social--share .social--share-left p.from{font-style:normal;color:#dc2323}@media screen and (min-width:62.1875em){.social--share .social--share-right{display:inline-block;vertical-align:top;width:33%;margin-bottom:0;margin-left:.5714285714rem}}.social--share:after{width:0;height:0;border-left:15px solid transparent;border-top:15px solid #b8b8b9;position:absolute;left:-15px;bottom:5px;content:"";display:none}@media screen and (min-width:48em){.social--share:after{display:block}}.share_lines{margin-bottom:1.4285714286rem;margin-top:.8571428571rem;padding-bottom:.7142857143rem}.share_lines h3{margin-bottom:0;margin-top:.4em}.share_lines ul{margin:0}.share_lines ul li{padding-top:.7142857143rem;position:relative;display:inline-block;width:100%;border-top-color:#ddd;border-top-style:solid;border-top-width:1px;margin-bottom:.5714285714rem}.share_lines ul li i.icon-twitter{padding:0 .3571428571rem;margin-right:-.3571428571rem;color:#4099FF;border:1px solid #eee;cursor:pointer;position:relative}.share_lines ul li i.icon-facebook{padding:0 .3571428571rem;color:#3B5998;border:1px solid #eee;cursor:pointer;position:relative}.share_lines ul li span.share_lines-text{font-size:14px;font-size:1rem;float:left;margin-left:4.2857142857rem;color:#aaa;cursor:pointer}.share_lines ul li span.share_lines-icons{width:60px;position:absolute;left:0;top:10px}.share_lines ul li #sl_popup{margin-bottom:.8571428571rem;position:absolute;bottom:100%;left:0;z-index:1030;width:100px;color:#444;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:12px;font-size:.8571428571rem;font-weight:700;border:1px solid #eee;background-color:#fff;padding:.3571428571rem}.share_lines ul li #sl_popup:after,.share_lines ul li #sl_popup:before{content:"";position:absolute;width:0;height:0;border-style:solid;border-color:transparent;border-bottom:0}.share_lines ul li #sl_popup:before{bottom:-10px;left:4px;border-top-color:#eee;border-width:10px}.share_lines ul li #sl_popup:after{bottom:-9px;left:5px;border-top-color:#fff;border-width:9px}.share_lines h3,.share_lines-text.share_lines-text.share_lines-text{font-size:16px;font-size:1.1428571429rem}.ntm{padding-left:1.4285714286rem}.ntm .widget__header h2:before{background:url(../img/plus/logo_artdetail.png) no-repeat;background:0 0,url(../img/plus/logo_artdetail.svg) no-repeat;content:'';display:inline-block(sub);height:27px;height:1.9285714286rem;width:52px;width:3.7142857143rem;margin-right:.3571428571rem}.ntm .widget__header h2 a{color:#000!important}@media screen and (min-width:68.4375em){.ntm .widget__list li{float:left;width:25%}}.ntm .widget__list li article{padding-right:1.4285714286rem}@media screen and (min-width:68.4375em){.ntm .widget__list li a img{width:100%!important}}@media screen and (min-width:68.4375em){.ntm .widget__list li a .article-media__helper{width:100%!important}}.scribble-live{background:#fff;border:1px solid #ccc;overflow:auto}.scribble-live .item{padding:15px 12px;overflow:hidden;border-bottom:1px solid #ededed;color:#666;text-align:left}.scribble-live ul.RecentPostsWidget{width:100%;margin:0;padding:0;border-bottom:0;overflow:hidden;list-style-type:none}.scribble-live .post-time{background:#00387b;margin-bottom:3px;padding:0 7px;display:inline-block;color:#fff;font-size:12px}.scribble-live .Content{position:relative;display:block;width:100%;margin:0;border-top:1px solid #F0F0F0;list-style-type:none}.scribble-live .Content img{max-width:100%;margin:0 auto;display:block}.scribble-live .Content .Caption{background:rgba(0,0,0,.5);width:90%;margin:0 5%;padding:15px 20px;position:absolute;bottom:0;left:0;color:#fff;font-size:14px}.scribble-live .Content .Caption a{color:#ddd}.scribble-live .LinkTitle{margin-top:10px;color:#005494}.scribble-live .Meta{margin:10px 0 0;float:right;color:#555;font-size:11px}.scribble-live .Meta img{margin-left:10px}.scribble-live a{color:#444}.scribble-live a:hover{color:#318f98}.scribble-live .SL_SlideShow{position:relative;margin:5px -12px;clear:both}.scribble-live .SL_SlideShow_Slide{width:100%;overflow:hidden;visibility:visible;opacity:1;-webkit-transition:opacity .5s ease-in-out;-moz-transition:opacity .5s ease-in-out;transition:opacity .5s ease-in-out}.scribble-live .SL_SlideShow_Slide.HideSlide{opacity:0;position:absolute;left:-9999em;top:-9999em}.scribble-live .SL_SlideShow_Slide .sltc-twitter{width:auto!important;margin:0 60px;right:0}.scribble-live .SL_SlideShow_Slide .sltc-twitter>a{display:none}.scribble-live .SL_SlideShow_Slide .sltc-twitter .sltc-avatar{background:url(http://cdn.scribblelive.com/liveblog/display/content/default/images/post_sprite.png) -22px -255px no-repeat;width:35px;height:35px;margin:0 10px 0 0;float:left;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.scribble-live .SL_SlideShow_Slide .sltc-lower{display:none}.scribble-live .SL_SlideShow_Counter{text-align:center}.scribble-live .SlideShowNav{background:rgba(0,0,0,.3);width:40px;height:85px;margin-top:-43px;display:block;cursor:pointer;text-indent:-9999em;position:absolute;z-index:1}.scribble-live .SlideShowNav:before{background:url(http://cdn.scribblelive.com/liveblog/display/content/default/images/post_sprite.png) no-repeat;width:13px;height:20px;content:'';position:absolute;top:32px;left:0}.scribble-live .SlideShowNav.SlideShowPrev{left:0;-webkit-border-top-right-radius:2px;-moz-border-radius-topright:2px;border-top-right-radius:2px;-webkit-border-bottom-right-radius:2px;-moz-border-radius-bottomright:2px;border-bottom-right-radius:2px}.scribble-live .SlideShowNav.SlideShowPrev:before{background-position:-22px -14px;left:11px}.scribble-live .SlideShowNav.SlideShowNext{right:0;-webkit-border-top-left-radius:2px;-moz-border-radius-topleft:2px;border-top-left-radius:2px;-webkit-border-bottom-left-radius:2px;-moz-border-radius-bottomleft:2px;border-bottom-left-radius:2px}.scribble-live .SlideShowNav.SlideShowNext:before{background-position:-22px -34px;left:17px}.theme-live .scribble-live{border:0}.theme-live .scribble-live .RecentPostsWidget .item-text .post-time{background-color:#44c4d1;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:600;padding:2px 6px;margin-bottom:0;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-text .Content{border-top:1px solid #44c4d1;line-height:1.5;padding-top:10px}.theme-live .scribble-live .RecentPostsWidget .item-text .Content strong{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;font-weight:600}.theme-live .scribble-live .RecentPostsWidget .item-text .Meta{float:none;position:relative;height:50px;width:100%}.theme-live .scribble-live .RecentPostsWidget .item-text .Meta .avatar{position:absolute;left:0;bottom:0;border:1px solid #eee;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.theme-live .scribble-live .RecentPostsWidget .item-text .Meta .post-author{position:absolute;top:16px;left:70px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-live .scribble-live .RecentPostsWidget .item-html .post-time{background-color:#44c4d1;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:600;padding:2px 6px;margin-bottom:0;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-html .Content{border-top:1px solid #44c4d1;line-height:1.5;padding-top:10px}.theme-live .scribble-live .RecentPostsWidget .item-html .Content .scrbbl-sitePreview .LinkTitle{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;font-weight:600;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-html .Content .scrbbl-sitePreview .Media.SL_Top.LinkImage .Meta{display:none}.theme-live .scribble-live .RecentPostsWidget .item-html .Meta{float:none;position:relative;height:50px;width:100%}.theme-live .scribble-live .RecentPostsWidget .item-html .Meta .avatar{position:absolute;left:0;bottom:0;border:1px solid #eee;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.theme-live .scribble-live .RecentPostsWidget .item-html .Meta .post-author{position:absolute;top:16px;left:70px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-live .scribble-live .RecentPostsWidget .item-image .post-time{background-color:#44c4d1;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:600;padding:2px 6px;margin-bottom:0;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-image .Content{border-top:1px solid #44c4d1;line-height:1.5;padding-top:10px}.theme-live .scribble-live .RecentPostsWidget .item-image .Content .scrbbl-sitePreview .LinkTitle{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;font-weight:600;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-image .Content .scrbbl-sitePreview .Media.SL_Top.LinkImage .Meta{display:none}.theme-live .scribble-live .RecentPostsWidget .item-image .Meta{float:none;position:relative;height:50px;width:100%}.theme-live .scribble-live .RecentPostsWidget .item-image .Meta .avatar{position:absolute;left:0;bottom:0;border:1px solid #eee;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.theme-live .scribble-live .RecentPostsWidget .item-image .Meta .post-author{position:absolute;top:16px;left:70px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-live .scribble-live .RecentPostsWidget .item-embed .post-time{background-color:#44c4d1;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:600;padding:2px 6px;margin-bottom:0;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-embed .Content{border-top:1px solid #44c4d1;line-height:1.5;padding-top:10px}.theme-live .scribble-live .RecentPostsWidget .item-embed .Content .scrbbl-sitePreview .LinkTitle{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;font-weight:600;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-embed .Content .scrbbl-sitePreview .Media.SL_Top.LinkImage .Meta{display:none}.theme-live .scribble-live .RecentPostsWidget .item-embed .Meta{float:none;position:relative;height:50px;width:100%}.theme-live .scribble-live .RecentPostsWidget .item-embed .Meta .avatar{position:absolute;left:0;bottom:0;border:1px solid #eee;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.theme-live .scribble-live .RecentPostsWidget .item-embed .Meta .post-author{position:absolute;top:16px;left:70px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-live .scribble-live .RecentPostsWidget .item-video .post-time{background-color:#44c4d1;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:600;padding:2px 6px;margin-bottom:0;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-video .Content{border-top:1px solid #44c4d1;line-height:1.5;padding-top:10px}.theme-live .scribble-live .RecentPostsWidget .item-video .Content .scrbbl-sitePreview .LinkTitle{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;font-weight:600;line-height:1.5}.theme-live .scribble-live .RecentPostsWidget .item-video .Content .scrbbl-sitePreview .Media.SL_Top.LinkImage .Meta{display:none}.theme-live .scribble-live .RecentPostsWidget .item-video .Meta{float:none;position:relative;height:50px;width:100%}.theme-live .scribble-live .RecentPostsWidget .item-video .Meta .avatar{position:absolute;left:0;bottom:0;border:1px solid #eee;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.theme-live .scribble-live .RecentPostsWidget .item-video .Meta .post-author{position:absolute;top:16px;left:70px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.widget--sport div[id*=ranking] .section-header{display:none}.widget--sport div[id*=ranking] a{text-decoration:none;color:#444;cursor:default}.widget--sport div[id*=ranking] tfoot{display:none}.live-color{background-color:#44c4d1}.secondary-col .live-color{padding-left:1.4285714286rem;padding-right:1.4285714286rem}.secondary-col .live-color:first-child{margin-top:1.4285714286rem}.live-color .article__body,.live-color .article__header,.live-color .widget__footer{color:#fff!important}.paco-color{color:#dd2727}.theme-live .main-container{margin-top:20px}.theme-live .breadcrumb{padding:.8571428571rem 0;text-transform:uppercase}.theme-live .article-comment .form__label,.theme-live .article-comments label,.theme-live .article-opinion blockquote:before,.theme-live .comment-share__totals span,.theme-live .custom-list,.theme-live .heading--framed--inverted,.theme-live .link,.theme-live .list--decimal a:before,.theme-live .tag,.theme-live article>a:active .article__header,.theme-live article>a:focus .article__header,.theme-live article>a:hover .article__header,.theme-live time{color:#44c4d1}.theme-live .article__subheader{font-size:14px;font-size:1rem;line-height:1.2857142857;color:#666;font-family:Georgia,Cambria,Times New Roman,Times,sans-serif}.theme-live .article__content-info{font-size:12px;font-size:.8571428571rem;line-height:1.5;color:#aaa;margin-bottom:0;text-transform:uppercase}.theme-live .nav-tabs a,.theme-live .pagination--simple a{text-decoration:none;color:#444}.theme-live .nav-tabs a:visited,.theme-live .pagination--simple a:visited{color:#444}.theme-live .nav-tabs a:focus,.theme-live .nav-tabs a:hover,.theme-live .pagination--simple a:focus,.theme-live .pagination--simple a:hover{color:#44c4d1;text-decoration:none}.theme-live .secondary-nav{float:left}.theme-live .secondary-nav a{text-decoration:none;color:#666}.theme-live .secondary-nav a:visited{color:#666}.theme-live .secondary-nav a:focus,.theme-live .secondary-nav a:hover{color:#44c4d1;text-decoration:none}.theme-live .main-footer li a{text-decoration:none;color:#666}.theme-live .main-footer li a:visited{color:#666}.theme-live .main-footer li a:focus,.theme-live .main-footer li a:hover{color:#44c4d1;text-decoration:underline}.theme-live .main-footer li a:active{text-decoration:underline}.theme-live .pagination .current a,.theme-live .secondary-nav .current a{text-decoration:none;color:#fff}.theme-live .pagination .current a:visited,.theme-live .secondary-nav .current a:visited{color:#fff}.theme-live .pagination .current a:focus,.theme-live .pagination .current a:hover,.theme-live .secondary-nav .current a:focus,.theme-live .secondary-nav .current a:hover{color:#fff;text-decoration:none}.theme-live .callout article>a:focus .article__header,.theme-live .callout article>a:hover .article__header{color:#fff}.theme-live .button--primary,.theme-live .callout,.theme-live .comment-share__totals,.theme-live .dropdown-menu>li>a:focus,.theme-live .dropdown-menu>li>a:hover,.theme-live .heading--framed,.theme-live .pagination .current a,.theme-live .secondary-nav .current a,.theme-live .slideshow__next,.theme-live .slideshow__prev,.theme-live .ui-autocomplete>li>a:focus,.theme-live .ui-autocomplete>li>a:hover{background-color:#44c4d1}.theme-live .list--paco time{color:#dd2727}.theme-live .slideshow__thumbs ol .is-active a:after,.theme-live .slideshow__thumbs ol a:focus:after,.theme-live .slideshow__thumbs ol a:hover:after{border-color:#44c4d1}.theme-live .meta-nav a{text-decoration:none;color:#aaa}.theme-live .meta-nav a:visited{color:#aaa}.theme-live .meta-nav a:focus,.theme-live .meta-nav a:hover{color:#44c4d1;text-decoration:underline}.theme-live .meta-nav a:active{text-decoration:underline}.theme-live .callout .tag{color:#222}.theme-live .article--plus .custom-list,.theme-live .article--plus .link,.theme-live .article--plus .tag,.theme-live .article--shared .custom-list,.theme-live .article--shared .link,.theme-live .article--shared .tag{color:#dd2727!important}.theme-live .article--plus>a:focus .article__header,.theme-live .article--plus>a:hover .article__header,.theme-live .article--shared>a:focus .article__header,.theme-live .article--shared>a:hover .article__header{color:#dd2727}.theme-live .article--plus .article__header:after,.theme-live .article--plus .article__header:before,.theme-live .article--shared .article__header:after,.theme-live .article--shared .article__header:before{background:#dd2727;color:#fff}.theme-live .article--plus .custom-list,.theme-live .article--shared .custom-list{list-style:none}.theme-live .article--plus .custom-list a:focus,.theme-live .article--plus .custom-list a:hover,.theme-live .article--shared .custom-list a:focus,.theme-live .article--shared .custom-list a:hover{color:#dd2727}.theme-live .article--plus .custom-list li:before,.theme-live .article--shared .custom-list li:before{content:'';background:url(../img/plus/bullet.png) no-repeat;background:0 0,url(../img/plus/bullet.svg) no-repeat;width:10px;height:10px;display:inline-block(baseline);margin-right:5px}.theme-live .button--primary{border-color:#2da9b5}.theme-live .button--primary:hover{background-color:#2da9b5;border-color:#23838c}.theme-live .article__meta a,.theme-live .breadcrumb a,.theme-live .button--link,.theme-live .carousel__next,.theme-live .carousel__prev,.theme-live .heading--framed--inverted a,.theme-live .nav-tabs .active a,.theme-live .pagination a,.theme-live a.tag{text-decoration:none;color:#44c4d1}.theme-live .article__meta a:visited,.theme-live .breadcrumb a:visited,.theme-live .button--link:visited,.theme-live .carousel__next:visited,.theme-live .carousel__prev:visited,.theme-live .heading--framed--inverted a:visited,.theme-live .nav-tabs .active a:visited,.theme-live .pagination a:visited,.theme-live a.tag:visited{color:#44c4d1}.theme-live .article__meta a:focus,.theme-live .article__meta a:hover,.theme-live .breadcrumb a:focus,.theme-live .breadcrumb a:hover,.theme-live .button--link:focus,.theme-live .button--link:hover,.theme-live .carousel__next:focus,.theme-live .carousel__next:hover,.theme-live .carousel__prev:focus,.theme-live .carousel__prev:hover,.theme-live .heading--framed--inverted a:focus,.theme-live .heading--framed--inverted a:hover,.theme-live .nav-tabs .active a:focus,.theme-live .nav-tabs .active a:hover,.theme-live .pagination a:focus,.theme-live .pagination a:hover,.theme-live a.tag:focus,.theme-live a.tag:hover{color:#318f98;text-decoration:none}.theme-live .comment-share__totals:after{border-top-color:#44c4d1}.theme-live .comment-share__totals:focus,.theme-live .comment-share__totals:hover{background:#2896a1}.theme-live .comment-share__totals:focus:after,.theme-live .comment-share__totals:hover:after{border-top-color:#2896a1}.theme-live .comment-share__totals:focus span,.theme-live .comment-share__totals:hover span{color:#318f98}.theme-live .article-comments{padding:1.4285714286rem 1.4285714286rem 0;margin-left:-1.3571428571rem;margin-right:-1.3571428571rem;background-color:#f8f8f8}.theme-live .article-comments:after{content:".";display:block;height:0;clear:both;visibility:hidden}.theme-live .article__body a{text-decoration:underline;color:#44c4d1}.theme-live .article__body a:visited{color:#44c4d1}.theme-live .article__body a:focus,.theme-live .article__body a:hover{color:#318f98;text-decoration:none}.theme-live .author-info--full .social-media{margin-left:116px}.theme-live .nav-biz a{text-decoration:none;color:#666}.theme-live .nav-biz a:visited{color:#666}.theme-live .nav-biz a:focus,.theme-live .nav-biz a:hover{color:#ad9a0a;text-decoration:none}.theme-live .nav-biz.current a{background-color:#ad9a0a}.theme-live .nav-lifestyle a{text-decoration:none;color:#666}.theme-live .nav-lifestyle a:visited{color:#666}.theme-live .nav-lifestyle a:focus,.theme-live .nav-lifestyle a:hover{color:#f7516d;text-decoration:none}.theme-live .nav-lifestyle.current a{background-color:#f7516d}.theme-live .nav-mobilia a{text-decoration:none;color:#666}.theme-live .nav-mobilia a:visited{color:#666}.theme-live .nav-mobilia a:focus,.theme-live .nav-mobilia a:hover{color:#5c52e6;text-decoration:none}.theme-live .nav-mobilia.current a{background-color:#5c52e6}.theme-live .ntm{margin-left:-1.4285714286rem}.theme-live .list__item--plus{position:relative;list-style:none}.theme-live .list__item--plus,.theme-live .list__item--plus .tag,.theme-live .list__item--plus a,.theme-live .list__item--plus a:active,.theme-live .list__item--plus a:focus,.theme-live .list__item--plus a:hover{color:#dd2727}.theme-live .list__item--plus:before{left:-21px;left:-1.5rem;display:inline-block;vertical-align:baseline;content:'';background:url(../img/plus/bullet.png) no-repeat;background:0 0,url(../img/plus/bullet.svg) no-repeat;height:10px;height:.7142857143rem;width:10px;width:.7142857143rem;margin-left:-.2142857143rem;margin-right:.2857142857rem}.theme-live .list__item--plus #ds_popup{position:absolute;top:-45px;min-width:180px;background-color:#fff;z-index:1030;font-size:13px;font-size:.9285714286rem;color:#dd2727;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;border:1px solid #eee;padding:.3571428571rem}.theme-live .list__item--plus #ds_popup:after,.theme-live .list__item--plus #ds_popup:before{content:"";position:absolute;width:0;height:0;border-style:solid;border-color:transparent;border-bottom:0}.theme-live .list__item--plus #ds_popup:before{bottom:-10px;left:11px;border-top-color:#eee;border-width:10px}.theme-live .list__item--plus #ds_popup:after{bottom:-9px;left:12px;border-top-color:#fff;border-width:9px}@media screen and (min-width:62.1875em){.layout-wideskyscraper .theme-live{max-width:1170px;max-width:83.5714285714rem;margin-left:auto;margin-right:auto}.layout-wideskyscraper .theme-live .container,.layout-wideskyscraper .theme-live .main-footer,.layout-wideskyscraper .theme-live .main-header,.layout-wideskyscraper .theme-live .session-expired{margin-left:0}.layout-wideskyscraper .theme-live .l-zone{margin-right:172px}}@media screen and (min-width:75em){.layout-wideskyscraper .theme-live .l-zone{width:100%;margin-right:0}}@media screen and (max-width:75em){.layout-wideskyscraper .theme-live{max-width:100%}.layout-wideskyscraper .theme-live .container,.layout-wideskyscraper .theme-live .main-footer,.layout-wideskyscraper .theme-live .main-header,.layout-wideskyscraper .theme-live .session-expired{margin-left:auto}}.zone-biz .article-opinion blockquote:before,.zone-biz .custom-list,.zone-biz .custom-list a:focus,.zone-biz .custom-list a:hover,.zone-biz .link,.zone-biz .list--decimal a:before,.zone-biz .tag,.zone-biz article>a:active .article__header,.zone-biz article>a:focus .article__header,.zone-biz article>a:hover .article__header{color:#ad9a0a}.zone-biz a.tag{text-decoration:none;color:#ad9a0a}.zone-biz a.tag:visited{color:#ad9a0a}.zone-biz a.tag:focus,.zone-biz a.tag:hover{color:#736607;text-decoration:none}.zone-biz .section-logo{background-color:#ad9a0a}.theme-biz .article-comment .form__label,.theme-biz .article-comments label,.theme-biz .article-opinion blockquote:before,.theme-biz .bc__divider,.theme-biz .comment-share__totals span,.theme-biz .custom-list,.theme-biz .heading--framed--inverted,.theme-biz .link,.theme-biz .list--decimal a:before,.theme-biz .tag,.theme-biz .widget__header,.theme-biz article>a:active .article__header,.theme-biz article>a:focus .article__header,.theme-biz article>a:hover .article__header,.theme-biz caption,.theme-biz time{color:#ad9a0a}.theme-biz .custom-list li a,.theme-biz .list--ellipsis li a,.theme-biz .nav-tabs a,.theme-biz .pagination--simple a{text-decoration:none;color:#444}.theme-biz .custom-list li a:visited,.theme-biz .list--ellipsis li a:visited,.theme-biz .nav-tabs a:visited,.theme-biz .pagination--simple a:visited{color:#444}.theme-biz .custom-list li a:focus,.theme-biz .custom-list li a:hover,.theme-biz .list--ellipsis li a:focus,.theme-biz .list--ellipsis li a:hover,.theme-biz .nav-tabs a:focus,.theme-biz .nav-tabs a:hover,.theme-biz .pagination--simple a:focus,.theme-biz .pagination--simple a:hover{color:#ad9a0a;text-decoration:none}.theme-biz .custom-list .list__item--plus a.link-live,.theme-biz .custom-list .list__item--plus a.link-live:hover{color:#dd2727}.theme-biz .nav-biz a{text-decoration:none;color:#666}.theme-biz .nav-biz a:visited{color:#666}.theme-biz .nav-biz a:focus,.theme-biz .nav-biz a:hover{color:#ad9a0a;text-decoration:none}.theme-biz .button--primary,.theme-biz .callout,.theme-biz .comment-share__totals,.theme-biz .heading--framed,.theme-biz .pagination .current a,.theme-biz .slideshow__next,.theme-biz .slideshow__prev,.theme-biz .stock-bar li.current{background-color:#ad9a0a}.theme-biz .slideshow__next:focus,.theme-biz .slideshow__next:hover,.theme-biz .slideshow__prev:focus,.theme-biz .slideshow__prev:hover{background-color:#736607}.theme-biz .slideshow__thumbs ol .is-active a:after,.theme-biz .slideshow__thumbs ol a:focus:after,.theme-biz .slideshow__thumbs ol a:hover:after{border-color:#ad9a0a}.theme-biz .meta-nav a{text-decoration:none;color:#aaa}.theme-biz .meta-nav a:visited{color:#aaa}.theme-biz .meta-nav a:focus,.theme-biz .meta-nav a:hover{color:#ad9a0a;text-decoration:underline}.theme-biz .meta-nav a:active{text-decoration:underline}.theme-biz .button--primary{border-color:#7d6f07}.theme-biz .button--primary:hover{background-color:#7d6f07;border-color:#4d4404}.theme-biz .button,.theme-biz .mail-share-button{text-transform:uppercase}.theme-biz .button-link{text-transform:none}.theme-biz .table tfoot a{text-decoration:underline;color:#ad9a0a}.theme-biz .table tfoot a:visited{color:#ad9a0a}.theme-biz .table tfoot a:focus,.theme-biz .table tfoot a:hover{color:#736607;text-decoration:underline}.theme-biz .table tfoot a:active{text-decoration:underline}.theme-biz .article__meta a,.theme-biz .button--link,.theme-biz .carousel__next,.theme-biz .carousel__prev,.theme-biz .heading--framed--inverted a,.theme-biz .nav-tabs .active a,.theme-biz .pagination a,.theme-biz .table a,.theme-biz .widget__footer a,.theme-biz .widget__header a,.theme-biz a.tag,.theme-biz nav a{text-decoration:none;color:#ad9a0a}.theme-biz .article__meta a:visited,.theme-biz .button--link:visited,.theme-biz .carousel__next:visited,.theme-biz .carousel__prev:visited,.theme-biz .heading--framed--inverted a:visited,.theme-biz .nav-tabs .active a:visited,.theme-biz .pagination a:visited,.theme-biz .table a:visited,.theme-biz .widget__footer a:visited,.theme-biz .widget__header a:visited,.theme-biz a.tag:visited,.theme-biz nav a:visited{color:#ad9a0a}.theme-biz .article__meta a:focus,.theme-biz .article__meta a:hover,.theme-biz .button--link:focus,.theme-biz .button--link:hover,.theme-biz .carousel__next:focus,.theme-biz .carousel__next:hover,.theme-biz .carousel__prev:focus,.theme-biz .carousel__prev:hover,.theme-biz .heading--framed--inverted a:focus,.theme-biz .heading--framed--inverted a:hover,.theme-biz .nav-tabs .active a:focus,.theme-biz .nav-tabs .active a:hover,.theme-biz .pagination a:focus,.theme-biz .pagination a:hover,.theme-biz .table a:focus,.theme-biz .table a:hover,.theme-biz .widget__footer a:focus,.theme-biz .widget__footer a:hover,.theme-biz .widget__header a:focus,.theme-biz .widget__header a:hover,.theme-biz a.tag:focus,.theme-biz a.tag:hover,.theme-biz nav a:focus,.theme-biz nav a:hover{color:#736607;text-decoration:none}.theme-biz .breadcrumb a{text-decoration:none;color:#ad9a0a}.theme-biz .breadcrumb a:visited{color:#ad9a0a}.theme-biz .breadcrumb a:focus,.theme-biz .breadcrumb a:hover{color:#736607;text-decoration:none}.theme-biz .table--striped a{text-decoration:none;color:#444}.theme-biz .table--striped a:visited{color:#666}.theme-biz .table--striped a:focus,.theme-biz .table--striped a:hover{color:#000;text-decoration:none}.theme-biz .comment-share__totals:after{border-top-color:#ad9a0a}.theme-biz .comment-share__totals:focus,.theme-biz .comment-share__totals:hover{background:#655a06}.theme-biz .comment-share__totals:focus:after,.theme-biz .comment-share__totals:hover:after{border-top-color:#655a06}.theme-biz .comment-share__totals:focus span,.theme-biz .comment-share__totals:hover span{color:#736607}.theme-biz .stock-bar li.current:focus,.theme-biz .stock-bar li.current:hover{background-color:#736607}.theme-biz .article__body a{text-decoration:underline;color:#ad9a0a}.theme-biz .article__body a:visited{color:#ad9a0a}.theme-biz .article__body a:focus,.theme-biz .article__body a:hover{color:#736607;text-decoration:underline}.theme-biz .article__body a:active{text-decoration:underline}.theme-biz th{font-size:10px;font-size:.7142857143rem;text-align:right}.theme-biz th[scope=row]{text-align:left;font-weight:400;text-transform:none;font-size:14px;font-size:1rem}.zone-lifestyle .article-opinion blockquote:before,.zone-lifestyle .custom-list,.zone-lifestyle .custom-list a:focus,.zone-lifestyle .custom-list a:hover,.zone-lifestyle .link,.zone-lifestyle .list--decimal a:before,.zone-lifestyle .tag,.zone-lifestyle article>a:active .article__header,.zone-lifestyle article>a:focus .article__header,.zone-lifestyle article>a:hover .article__header{color:#f7516d}.zone-lifestyle a.tag{text-decoration:none;color:#f7516d}.zone-lifestyle a.tag:visited{color:#f7516d}.zone-lifestyle a.tag:focus,.zone-lifestyle a.tag:hover{color:#a8374a;text-decoration:none}.zone-lifestyle .section-logo{background-color:#f7516d}.theme-lifestyle .article-comment .form__label,.theme-lifestyle .article-comments label,.theme-lifestyle .article-opinion blockquote:before,.theme-lifestyle .bc__divider,.theme-lifestyle .comment-share__totals span,.theme-lifestyle .custom-list,.theme-lifestyle .heading--framed--inverted,.theme-lifestyle .link,.theme-lifestyle .list--decimal a:before,.theme-lifestyle .tag,.theme-lifestyle .widget__header,.theme-lifestyle article>a:active .article__header,.theme-lifestyle article>a:focus .article__header,.theme-lifestyle article>a:hover .article__header,.theme-lifestyle time{color:#f7516d}.theme-lifestyle .breadcrumb a,.theme-lifestyle .custom-list li a,.theme-lifestyle .list--ellipsis li a,.theme-lifestyle .nav-tabs a,.theme-lifestyle .pagination--simple a{text-decoration:none;color:#444}.theme-lifestyle .breadcrumb a:visited,.theme-lifestyle .custom-list li a:visited,.theme-lifestyle .list--ellipsis li a:visited,.theme-lifestyle .nav-tabs a:visited,.theme-lifestyle .pagination--simple a:visited{color:#444}.theme-lifestyle .breadcrumb a:focus,.theme-lifestyle .breadcrumb a:hover,.theme-lifestyle .custom-list li a:focus,.theme-lifestyle .custom-list li a:hover,.theme-lifestyle .list--ellipsis li a:focus,.theme-lifestyle .list--ellipsis li a:hover,.theme-lifestyle .nav-tabs a:focus,.theme-lifestyle .nav-tabs a:hover,.theme-lifestyle .pagination--simple a:focus,.theme-lifestyle .pagination--simple a:hover{color:#f7516d;text-decoration:none}.theme-lifestyle .custom-list .list__item--plus a.link-live,.theme-lifestyle .custom-list .list__item--plus a.link-live:hover{color:#dd2727}.theme-lifestyle .nav-lifestyle a{text-decoration:none;color:#666}.theme-lifestyle .nav-lifestyle a:visited{color:#666}.theme-lifestyle .nav-lifestyle a:focus,.theme-lifestyle .nav-lifestyle a:hover{color:#f7516d;text-decoration:none}.theme-lifestyle .button--primary,.theme-lifestyle .callout,.theme-lifestyle .comment-share__totals,.theme-lifestyle .heading--framed,.theme-lifestyle .pagination .current a,.theme-lifestyle .slideshow__next,.theme-lifestyle .slideshow__prev{background-color:#f7516d}.theme-lifestyle .slideshow__next:focus,.theme-lifestyle .slideshow__next:hover,.theme-lifestyle .slideshow__prev:focus,.theme-lifestyle .slideshow__prev:hover{background-color:#a8374a}.theme-lifestyle .slideshow__thumbs ol .is-active a:after,.theme-lifestyle .slideshow__thumbs ol a:focus:after,.theme-lifestyle .slideshow__thumbs ol a:hover:after{border-color:#44c4d1}.theme-lifestyle .meta-nav a{text-decoration:none;color:#aaa}.theme-lifestyle .meta-nav a:visited{color:#aaa}.theme-lifestyle .meta-nav a:focus,.theme-lifestyle .meta-nav a:hover{color:#f7516d;text-decoration:underline}.theme-lifestyle .meta-nav a:active{text-decoration:underline}.theme-lifestyle .button--primary{border-color:#f52044}.theme-lifestyle .button--primary:hover{background-color:#f52044;border-color:#d80a2d}.theme-lifestyle .article__meta a,.theme-lifestyle .breadcrumb a,.theme-lifestyle .button--link,.theme-lifestyle .carousel__next,.theme-lifestyle .carousel__prev,.theme-lifestyle .heading--framed--inverted a,.theme-lifestyle .nav-tabs .active a,.theme-lifestyle .pagination a,.theme-lifestyle .table a,.theme-lifestyle .widget__footer a,.theme-lifestyle .widget__header a,.theme-lifestyle a.tag,.theme-lifestyle nav a{text-decoration:none;color:#f7516d}.theme-lifestyle .article__meta a:visited,.theme-lifestyle .breadcrumb a:visited,.theme-lifestyle .button--link:visited,.theme-lifestyle .carousel__next:visited,.theme-lifestyle .carousel__prev:visited,.theme-lifestyle .heading--framed--inverted a:visited,.theme-lifestyle .nav-tabs .active a:visited,.theme-lifestyle .pagination a:visited,.theme-lifestyle .table a:visited,.theme-lifestyle .widget__footer a:visited,.theme-lifestyle .widget__header a:visited,.theme-lifestyle a.tag:visited,.theme-lifestyle nav a:visited{color:#f7516d}.theme-lifestyle .article__meta a:focus,.theme-lifestyle .article__meta a:hover,.theme-lifestyle .breadcrumb a:focus,.theme-lifestyle .breadcrumb a:hover,.theme-lifestyle .button--link:focus,.theme-lifestyle .button--link:hover,.theme-lifestyle .carousel__next:focus,.theme-lifestyle .carousel__next:hover,.theme-lifestyle .carousel__prev:focus,.theme-lifestyle .carousel__prev:hover,.theme-lifestyle .heading--framed--inverted a:focus,.theme-lifestyle .heading--framed--inverted a:hover,.theme-lifestyle .nav-tabs .active a:focus,.theme-lifestyle .nav-tabs .active a:hover,.theme-lifestyle .pagination a:focus,.theme-lifestyle .pagination a:hover,.theme-lifestyle .table a:focus,.theme-lifestyle .table a:hover,.theme-lifestyle .widget__footer a:focus,.theme-lifestyle .widget__footer a:hover,.theme-lifestyle .widget__header a:focus,.theme-lifestyle .widget__header a:hover,.theme-lifestyle a.tag:focus,.theme-lifestyle a.tag:hover,.theme-lifestyle nav a:focus,.theme-lifestyle nav a:hover{color:#a8374a;text-decoration:none}.theme-lifestyle .comment-share__totals:after{border-top-color:#f7516d}.theme-lifestyle .comment-share__totals:focus,.theme-lifestyle .comment-share__totals:hover{background:#f00b32}.theme-lifestyle .comment-share__totals:focus:after,.theme-lifestyle .comment-share__totals:hover:after{border-top-color:#f00b32}.theme-lifestyle .comment-share__totals:focus span,.theme-lifestyle .comment-share__totals:hover span{color:#a8374a}.theme-lifestyle .article__body a{text-decoration:underline;color:#f7516d}.theme-lifestyle .article__body a:visited{color:#f7516d}.theme-lifestyle .article__body a:focus,.theme-lifestyle .article__body a:hover{color:#a8374a;text-decoration:underline}.theme-lifestyle .article__body a:active{text-decoration:underline}.zone-mobilia .article-opinion blockquote:before,.zone-mobilia .custom-list,.zone-mobilia .custom-list a:focus,.zone-mobilia .custom-list a:hover,.zone-mobilia .link,.zone-mobilia .list--decimal a:before,.zone-mobilia .tag,.zone-mobilia article>a:active .article__header,.zone-mobilia article>a:focus .article__header,.zone-mobilia article>a:hover .article__header{color:#5c52e6}.zone-mobilia a.tag{text-decoration:none;color:#5c52e6}.zone-mobilia a.tag:visited{color:#5c52e6}.zone-mobilia a.tag:focus,.zone-mobilia a.tag:hover{color:#2117a1;text-decoration:none}.zone-mobilia .section-logo{background-color:#5c52e6}.theme-mobilia .article-comment .form__label,.theme-mobilia .article-comments label,.theme-mobilia .article-opinion blockquote:before,.theme-mobilia .bc__divider,.theme-mobilia .comment-share__totals span,.theme-mobilia .custom-list,.theme-mobilia .heading--framed--inverted,.theme-mobilia .link,.theme-mobilia .list--decimal a:before,.theme-mobilia .tag,.theme-mobilia .widget__header,.theme-mobilia article>a:active .article__header,.theme-mobilia article>a:focus .article__header,.theme-mobilia article>a:hover .article__header,.theme-mobilia time{color:#5c52e6}.theme-mobilia .breadcrumb a,.theme-mobilia .custom-list li a,.theme-mobilia .list--ellipsis li a,.theme-mobilia .nav-tabs a,.theme-mobilia .pagination--simple a{text-decoration:none;color:#444}.theme-mobilia .breadcrumb a:visited,.theme-mobilia .custom-list li a:visited,.theme-mobilia .list--ellipsis li a:visited,.theme-mobilia .nav-tabs a:visited,.theme-mobilia .pagination--simple a:visited{color:#444}.theme-mobilia .breadcrumb a:focus,.theme-mobilia .breadcrumb a:hover,.theme-mobilia .custom-list li a:focus,.theme-mobilia .custom-list li a:hover,.theme-mobilia .list--ellipsis li a:focus,.theme-mobilia .list--ellipsis li a:hover,.theme-mobilia .nav-tabs a:focus,.theme-mobilia .nav-tabs a:hover,.theme-mobilia .pagination--simple a:focus,.theme-mobilia .pagination--simple a:hover{color:#5c52e6;text-decoration:none}.theme-mobilia .custom-list .list__item--plus a.link-live,.theme-mobilia .custom-list .list__item--plus a.link-live:hover{color:#dd2727}.theme-mobilia .nav-mobilia a{text-decoration:none;color:#666}.theme-mobilia .nav-mobilia a:visited{color:#666}.theme-mobilia .nav-mobilia a:focus,.theme-mobilia .nav-mobilia a:hover{color:#5c52e6;text-decoration:none}.theme-mobilia .button--primary,.theme-mobilia .callout,.theme-mobilia .comment-share__totals,.theme-mobilia .heading--framed,.theme-mobilia .pagination .current a,.theme-mobilia .slideshow__next,.theme-mobilia .slideshow__prev{background-color:#5c52e6}.theme-mobilia .slideshow__next:focus,.theme-mobilia .slideshow__next:hover,.theme-mobilia .slideshow__prev:focus,.theme-mobilia .slideshow__prev:hover{background-color:#9b95f0}.theme-mobilia .slideshow__thumbs ol .is-active a:after,.theme-mobilia .slideshow__thumbs ol a:focus:after,.theme-mobilia .slideshow__thumbs ol a:hover:after{border-color:#5c52e6}.theme-mobilia .meta-nav a{text-decoration:none;color:#aaa}.theme-mobilia .meta-nav a:visited{color:#aaa}.theme-mobilia .meta-nav a:focus,.theme-mobilia .meta-nav a:hover{color:#5c52e6;text-decoration:underline}.theme-mobilia .meta-nav a:active{text-decoration:underline}.theme-mobilia .button--primary{border-color:#3225e0}.theme-mobilia .button--primary:hover{background-color:#3225e0;border-color:#251bb7}.theme-mobilia .article__meta a,.theme-mobilia .breadcrumb a,.theme-mobilia .button--link,.theme-mobilia .carousel__next,.theme-mobilia .carousel__prev,.theme-mobilia .heading--framed--inverted a,.theme-mobilia .nav-tabs .active a,.theme-mobilia .pagination a,.theme-mobilia .table a,.theme-mobilia .widget__footer a,.theme-mobilia .widget__header a,.theme-mobilia a.tag,.theme-mobilia nav a{text-decoration:none;color:#5c52e6}.theme-mobilia .article__meta a:visited,.theme-mobilia .breadcrumb a:visited,.theme-mobilia .button--link:visited,.theme-mobilia .carousel__next:visited,.theme-mobilia .carousel__prev:visited,.theme-mobilia .heading--framed--inverted a:visited,.theme-mobilia .nav-tabs .active a:visited,.theme-mobilia .pagination a:visited,.theme-mobilia .table a:visited,.theme-mobilia .widget__footer a:visited,.theme-mobilia .widget__header a:visited,.theme-mobilia a.tag:visited,.theme-mobilia nav a:visited{color:#5c52e6}.theme-mobilia .article__meta a:focus,.theme-mobilia .article__meta a:hover,.theme-mobilia .breadcrumb a:focus,.theme-mobilia .breadcrumb a:hover,.theme-mobilia .button--link:focus,.theme-mobilia .button--link:hover,.theme-mobilia .carousel__next:focus,.theme-mobilia .carousel__next:hover,.theme-mobilia .carousel__prev:focus,.theme-mobilia .carousel__prev:hover,.theme-mobilia .heading--framed--inverted a:focus,.theme-mobilia .heading--framed--inverted a:hover,.theme-mobilia .nav-tabs .active a:focus,.theme-mobilia .nav-tabs .active a:hover,.theme-mobilia .pagination a:focus,.theme-mobilia .pagination a:hover,.theme-mobilia .table a:focus,.theme-mobilia .table a:hover,.theme-mobilia .widget__footer a:focus,.theme-mobilia .widget__footer a:hover,.theme-mobilia .widget__header a:focus,.theme-mobilia .widget__header a:hover,.theme-mobilia a.tag:focus,.theme-mobilia a.tag:hover,.theme-mobilia nav a:focus,.theme-mobilia nav a:hover{color:#9b95f0;text-decoration:none}.theme-mobilia .comment-share__totals:after{border-top-color:#5c52e6}.theme-mobilia .comment-share__totals:focus,.theme-mobilia .comment-share__totals:hover{background:#2a1ece}.theme-mobilia .comment-share__totals:focus:after,.theme-mobilia .comment-share__totals:hover:after{border-top-color:#2a1ece}.theme-mobilia .comment-share__totals:focus span,.theme-mobilia .comment-share__totals:hover span{color:#9b95f0}.theme-mobilia .article__body a{text-decoration:underline;color:#5c52e6}.theme-mobilia .article__body a:visited{color:#5c52e6}.theme-mobilia .article__body a:focus,.theme-mobilia .article__body a:hover{color:#9b95f0;text-decoration:underline}.theme-mobilia .article__body a:active{text-decoration:underline}.zone-beroemdenbizar{background-color:#333}.zone-beroemdenbizar h3{color:#44c4d1}.zone-beroemdenbizar article{border-top:0;padding-top:0}.zone-beroemdenbizar a{text-decoration:none;color:#fff}.zone-beroemdenbizar a:visited{color:#fff}.zone-beroemdenbizar a:focus,.zone-beroemdenbizar a:hover{color:#fff;text-decoration:none}.zone-beroemdenbizar .article__header{color:#fff}.zone-beroemdenbizar .article__content-info,.zone-beroemdenbizar .article__subheader,.zone-beroemdenbizar .credentials,.zone-beroemdenbizar .custom-list,.zone-beroemdenbizar .link--proceed,.zone-beroemdenbizar .tag{display:none}.theme-morningedition{background-color:#fff}.theme-morningedition .custom-list,.theme-morningedition .l-3k2k .label-section,.theme-morningedition .section-header,.theme-morningedition blockquote,.theme-morningedition time{color:#004e86}.theme-morningedition .article__subheader,.theme-morningedition .content-list .tag{color:#8bbcdb}.theme-morningedition a{text-decoration:underline;color:#004e86}.theme-morningedition a:visited{color:#004e86}.theme-morningedition a:focus,.theme-morningedition a:hover{color:#8bbcdb;text-decoration:underline}.theme-morningedition a:active{text-decoration:underline}.theme-morningedition .article-full li a,.theme-morningedition .button--link,.theme-morningedition .content-list .more-list li a{text-decoration:none;color:#004e86}.theme-morningedition .article-full li a:visited,.theme-morningedition .button--link:visited,.theme-morningedition .content-list .more-list li a:visited{color:#004e86}.theme-morningedition .article-full li a:focus,.theme-morningedition .article-full li a:hover,.theme-morningedition .button--link:focus,.theme-morningedition .button--link:hover,.theme-morningedition .content-list .more-list li a:focus,.theme-morningedition .content-list .more-list li a:hover{color:#8bbcdb;text-decoration:none}.theme-morningedition .content-list li a,.theme-morningedition .pagination--simple a{text-decoration:none;color:#444}.theme-morningedition .content-list li a:visited,.theme-morningedition .pagination--simple a:visited{color:#444}.theme-morningedition .content-list li a:focus,.theme-morningedition .content-list li a:hover,.theme-morningedition .pagination--simple a:focus,.theme-morningedition .pagination--simple a:hover{color:#004e86;text-decoration:none}.theme-morningedition .secondary-nav li>a{text-decoration:none;color:#000}.theme-morningedition .secondary-nav li>a:visited{color:#000}.theme-morningedition .secondary-nav li>a:focus,.theme-morningedition .secondary-nav li>a:hover{color:#000;text-decoration:none}.theme-morningedition .link,.theme-morningedition .today a{text-decoration:none;color:#004e86}.theme-morningedition .link:visited,.theme-morningedition .today a:visited{color:#004e86}.theme-morningedition .link:focus,.theme-morningedition .link:hover,.theme-morningedition .today a:focus,.theme-morningedition .today a:hover{color:#8bbcdb;text-decoration:none}.theme-morningedition .editions-navbar__date a,.theme-morningedition .editions-navbar__page a{text-decoration:none;color:#000}.theme-morningedition .editions-navbar__date a:visited,.theme-morningedition .editions-navbar__page a:visited{color:#000}.theme-morningedition .editions-navbar__date a:focus,.theme-morningedition .editions-navbar__date a:hover,.theme-morningedition .editions-navbar__page a:focus,.theme-morningedition .editions-navbar__page a:hover{color:#000;text-decoration:none}.theme-morningedition .custom-list li>*,.theme-morningedition .tag{color:#000}.theme-morningedition .article-full--eyewitness .label-section,.theme-morningedition .button--primary,.theme-morningedition .heading--framed,.theme-morningedition .island .label-section,.theme-morningedition .island .widget__header,.theme-morningedition .islet .label-section,.theme-morningedition .islet .widget__header,.theme-morningedition .pagination .current a{background-color:#004e86}.theme-morningedition .callout{background-color:#8bbcdb}.theme-morningedition .callout a{text-decoration:none;color:#004e86}.theme-morningedition .callout a:visited{color:#004e86}.theme-morningedition .callout a:focus,.theme-morningedition .callout a:hover{color:#519ac9;text-decoration:none}.theme-morningedition .callout .button,.theme-morningedition .callout .mail-share-button{border:none;text-align:left}.theme-morningedition .callout .button [class^=icon-],.theme-morningedition .callout .mail-share-button [class^=icon-]{color:#0056b5!important;padding-right:.3em}.theme-morningedition .callout .button:focus [class^=icon-],.theme-morningedition .callout .button:hover [class^=icon-],.theme-morningedition .callout .mail-share-button:focus [class^=icon-],.theme-morningedition .callout .mail-share-button:hover [class^=icon-]{color:#519ac9!important}.theme-morningedition .logo img{background-color:#dd2727}.theme-morningedition .meta-nav a{text-decoration:none;color:#aaa}.theme-morningedition .meta-nav a:visited{color:#aaa}.theme-morningedition .meta-nav a:focus,.theme-morningedition .meta-nav a:hover{color:#004e86;text-decoration:underline}.theme-morningedition .meta-nav a:active{text-decoration:underline}.theme-morningedition .main-footer{z-index:501}.theme-morningedition .main-footer li a{text-decoration:none;color:#666}.theme-morningedition .main-footer li a:visited{color:#666}.theme-morningedition .main-footer li a:focus,.theme-morningedition .main-footer li a:hover{color:#dd2727;text-decoration:underline}.theme-morningedition .main-footer li a:active{text-decoration:underline}.theme-morningedition .pagination .current a{text-decoration:none;color:#fff}.theme-morningedition .pagination .current a:visited{color:#fff}.theme-morningedition .pagination .current a:focus,.theme-morningedition .pagination .current a:hover{color:#fff;text-decoration:none}.theme-morningedition .crossheading,.theme-morningedition .history-list,.theme-morningedition .list--history,.theme-morningedition .more-list li,.theme-morningedition .section-header,.theme-morningedition blockquote{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-morningedition .article-teaser--quote blockquote,.theme-morningedition .article__header,.theme-morningedition .content-list .tag{font-family:Georgia,Cambria,Times New Roman,Times,sans-serif}.theme-morningedition .main-container{position:static;padding-top:.8571428571rem}.theme-morningedition .main-footer{border-top:1px dotted #ccc}.theme-morningedition .l-zone{margin-bottom:0}.theme-morningedition .l-reversed .secondary-col .col__cell{padding-left:1.4285714286rem}.theme-morningedition .l-spotlight{margin-bottom:1.4285714286rem}.slideshow__teasers .theme-morningedition .l-1k1k1k1k .widget__list,.slideshow__teasers .theme-morningedition .l-1k2k1k .widget__list,.theme-morningedition .l-1k1k1k1k .row,.theme-morningedition .l-1k1k1k1k .slideshow,.theme-morningedition .l-1k1k1k1k .slideshow__teasers .widget__list,.theme-morningedition .l-1k2k1k .row,.theme-morningedition .l-1k2k1k .slideshow,.theme-morningedition .l-1k2k1k .slideshow__teasers .widget__list{padding-left:0}.theme-morningedition .l-1k1k1k1k [class*=" col-"] .col__cell,.theme-morningedition .l-1k1k1k1k [class^=col-] .col__cell,.theme-morningedition .l-1k2k1k [class*=" col-"] .col__cell,.theme-morningedition .l-1k2k1k [class^=col-] .col__cell{padding-left:20px}@media screen and (min-width:40em){.theme-morningedition .l-2k2k .cols-4 .primary-col{width:65%}.theme-morningedition .l-2k2k .cols-4 .secondary-col{width:35%}}@media screen and (min-width:40em){.theme-morningedition .l-2k2k--real .cols-4 .primary-col,.theme-morningedition .l-2k2k--real .cols-4 .secondary-col{width:50%}}@media screen and (min-width:40em){.theme-morningedition .l-3k2k .cols-5 .col-3{width:65%}.theme-morningedition .l-3k2k .cols-5 .col-2{width:35%}}.theme-morningedition .l-4k--wide .col__cell{padding-left:13px;padding-right:13px}@media screen and (min-width:62.1875em){.theme-morningedition .l-front{padding:0 1.4285714286rem;border-color:#000;border-style:solid;border-width:0 1px}}.theme-morningedition .l-front .article__header{max-width:100%;margin-left:0}.theme-morningedition .l-front .article__header,.theme-morningedition .l-front .article__header+p{margin-bottom:0}.theme-morningedition .l-front img+.article__header{margin-top:1.4285714286rem}.theme-morningedition .l-comment .article__body,.theme-morningedition .l-opinie .article__body{position:relative}@media screen and (min-width:48em){.theme-morningedition .l-comment blockquote{left:-33.33%;position:absolute;top:0}}@media screen and (min-width:62.1875em){.theme-morningedition .l-comment blockquote{left:-37%}}@media screen and (min-width:48em){.theme-morningedition .l-opinie blockquote{right:-33,33%;position:absolute;top:0}}@media screen and (min-width:62.1875em){.theme-morningedition .l-opinie blockquote{right:-37%}}.theme-morningedition .article,.theme-morningedition article{color:#000;font-size:15px;font-size:1.0714285714rem}.theme-morningedition .article>a,.theme-morningedition article>a{text-decoration:none;color:#000}.theme-morningedition .article>a:visited,.theme-morningedition article>a:visited{color:#000}.theme-morningedition .article>a:focus,.theme-morningedition .article>a:hover,.theme-morningedition article>a:focus,.theme-morningedition article>a:hover{color:#000;text-decoration:none}.theme-morningedition .article>a:focus .article__header,.theme-morningedition .article>a:hover .article__header,.theme-morningedition article>a:focus .article__header,.theme-morningedition article>a:hover .article__header{color:#004e86}.theme-morningedition .author{display:inline-block;margin-bottom:1.4285714286rem;border-bottom:1px solid #000}.theme-morningedition .article-teaser--2k .article__header,.theme-morningedition .article-teaser--2k .article__subheader,.theme-morningedition .article-teaser--2k .label-section{margin-left:0}.theme-morningedition .article__header{margin-bottom:1.4285714286rem;max-width:90%}.theme-morningedition .article__body .intro{font-size:15px;font-size:1.0714285714rem;margin-bottom:1.4285714286rem;font-weight:700}.theme-morningedition .article__body .intro .byline{display:none}.theme-morningedition .article__body a{text-decoration:underline;color:#004e86}.theme-morningedition .article__body a:visited{color:#004e86}.theme-morningedition .article__body a:focus,.theme-morningedition .article__body a:hover{color:#8bbcdb;text-decoration:none}.theme-morningedition .article__body p{margin-bottom:0}.theme-morningedition .tag{display:inline-block(baseline);color:#aaa;font-weight:400}.theme-morningedition .tag:after{content:'|';padding-left:.4em}.theme-morningedition .article__author{margin-bottom:0;overflow:hidden}.theme-morningedition .article__author .tag{line-height:1.2}.theme-morningedition .article__author .tag span{color:#666;font-weight:500;white-space:nowrap}.theme-morningedition .article__author .tag:after{display:none}.theme-morningedition .crossheading{margin-top:1.4285714286rem}.theme-morningedition .crossheading,.theme-morningedition .title-text{font-size:14px;font-size:1rem}.theme-morningedition .hnd{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:12px}.theme-morningedition .hnd:after,.theme-morningedition .hnd:before{font-family:sans-serif}.theme-morningedition .hnd:before{content:'('}.theme-morningedition .hnd:after{content:')'}.theme-morningedition .info{margin-bottom:1.4285714286rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-morningedition .info,.theme-morningedition .info .info__header{font-size:13px;font-size:.9285714286rem}.theme-morningedition .info .info__header{font-weight:700;margin:0}.theme-morningedition .info__data{margin:0}.theme-morningedition .info__data dt{float:left;margin-right:.3em}.theme-morningedition .info__data dt:after{content:':'}.theme-morningedition .info__data dd{margin:0;padding:0}.theme-morningedition .info--sport{max-width:300px;max-width:21.4285714286rem}.theme-morningedition .article-teaser .intro{font-size:15px;font-size:1.0714285714rem;margin-bottom:0}.theme-morningedition .article-full{max-width:625px;max-width:44.6428571429rem}.theme-morningedition .article-full .article__header{line-height:1.1}.theme-morningedition .article-full figure{background-color:transparent}.theme-morningedition .l-4k .article-full .article__body p,.theme-morningedition .l-4k .article-full>*{max-width:625px;max-width:44.6428571429rem}.theme-morningedition .l-4k .article-full,.theme-morningedition .l-4k .article-full .article__body,.theme-morningedition .l-4k .article-full .gallery{max-width:none}.theme-morningedition .article-full--eyewitness .article__header{color:#444}.theme-morningedition .label{font-weight:400;margin-bottom:6px}.theme-morningedition .col-1 .article-full .article__header{font-size:24px;font-size:1.7142857143rem}.theme-morningedition .secondary-col .article-teaser .article__body{margin-left:0}.theme-morningedition .article__meta{font-size:14px;font-size:1rem;color:inherit}.theme-morningedition .article-teaser .article__header{font-size:21px;font-size:1.5rem}.theme-morningedition .article-teaser .article__subheader{font-size:14px;font-size:1rem}.theme-morningedition .article-teaser.active{background-color:#ddd}.theme-morningedition .l-4k-flow .figure--4k .article-teaser{padding-bottom:0}.theme-morningedition .l-4k-flow .figure--4k .article-teaser .article__header{font-size:18px;font-size:1.2857142857rem;margin-left:0}.theme-morningedition .l-4k-flow .figure--4k .article-teaser .article__subheader{font-size:12px;font-size:.8571428571rem;margin-left:0;margin-bottom:0}.theme-morningedition .l-4k-flow .figure--4k .article-teaser article+article{border-top:0}.theme-morningedition .l-4k-flow .article--aside{padding-left:.7142857143rem;padding-right:.7142857143rem;background-color:#F6F3EF;border-top-width:0}.theme-morningedition .l-4k-flow .article--aside .article__header{font-size:18px;font-size:1.2857142857rem;margin-left:0;font-weight:700}.theme-morningedition .l-4k-flow .article--aside+.article--aside{margin-top:20px}.theme-morningedition .l-4k-flow .secondary-col>.col__cell{border-right:dotted 2px #aaa}.theme-morningedition .l-4k-flow .secondary-col article{margin-bottom:1.4285714286rem;border-top:0;border-bottom-style:solid;border-bottom-color:#000;border-bottom-width:3px}.theme-morningedition .l-4k-flow .secondary-col article.article--aside,.theme-morningedition .l-4k-flow .secondary-col article:last-child{margin-bottom:0;border-bottom:0}.theme-morningedition .l-4k-flow .secondary-col blockquote{margin-left:0}.theme-morningedition .l-4k-flow .secondary-col blockquote span{margin-top:2.8571428571rem;font-size:192px;font-size:13.7142857143rem;display:inline-block;line-height:1.5rem;color:#000}.theme-morningedition .l-4k-flow .secondary-col blockquote span:first-child{height:5rem;display:inline-block}.edition-nav .theme-morningedition .l-4k-flow .secondary-col blockquote span+span.bold.current-page,.theme-morningedition .info .l-4k-flow .secondary-col blockquote span+span.bold.info__header,.theme-morningedition .island .l-4k-flow .secondary-col blockquote span+span.bold.widget__header,.theme-morningedition .islet .l-4k-flow .secondary-col blockquote span+span.bold.widget__header,.theme-morningedition .l-4k-flow .secondary-col blockquote .edition-nav span+span.bold.current-page,.theme-morningedition .l-4k-flow .secondary-col blockquote .info span+span.bold.info__header,.theme-morningedition .l-4k-flow .secondary-col blockquote .island span+span.bold.widget__header,.theme-morningedition .l-4k-flow .secondary-col blockquote .islet span+span.bold.widget__header,.theme-morningedition .l-4k-flow .secondary-col blockquote .l-front span+span.bold.article__header,.theme-morningedition .l-4k-flow .secondary-col blockquote .widget.stockteaser span+span.bold.currency,.theme-morningedition .l-4k-flow .secondary-col blockquote span+span.bold.conversion__header,.theme-morningedition .l-4k-flow .secondary-col blockquote span+span.bold.label-section--large,.theme-morningedition .l-4k-flow .secondary-col blockquote span+span.uc.bold,.theme-morningedition .l-front .l-4k-flow .secondary-col blockquote span+span.bold.article__header,.widget.stockteaser .theme-morningedition .l-4k-flow .secondary-col blockquote span+span.bold.currency{font-size:18px;font-size:1.2857142857rem;margin-top:-5.7142857143rem;color:gray!important}.theme-morningedition .l-4k-flow .crossheading{font-weight:700}.theme-morningedition .l-4k-flow .article-stock .article__header,.theme-morningedition .l-4k-flow .center-aligned .article__header,.theme-morningedition .l-4k-flow .l-front .article__header,.theme-morningedition .l-front .l-4k-flow .section-header .article__header{margin-bottom:.8571428571rem}.theme-morningedition .l-4k-flow .article-stock .article__subheader,.theme-morningedition .l-4k-flow .center-aligned .article__subheader,.theme-morningedition .l-4k-flow .l-front .article__subheader,.theme-morningedition .l-front .l-4k-flow .section-header .article__subheader{margin-top:.8571428571rem;font-size:12px;font-size:.8571428571rem;font-family:Georgia,Cambria,Times New Roman,Times,sans-serif;letter-spacing:4px;color:#999}.theme-morningedition .l-4k-flow .article-stock .intro,.theme-morningedition .l-4k-flow .center-aligned .intro,.theme-morningedition .l-4k-flow .l-front .intro,.theme-morningedition .l-front .l-4k-flow .section-header .intro{margin-left:3.5714285714rem;margin-right:3.5714285714rem;color:#737373;line-height:1.3rem}.theme-morningedition .article-teaser--2k .article__header,.theme-morningedition .article-teaser--editorial .article__header{font-size:22px;font-size:1.5714285714rem}.theme-morningedition .article-teaser--2k .article__header{color:#444;font-weight:400;-webkit-font-smoothing:antialiased}.theme-morningedition .article-teaser--quote blockquote{font-size:21px;font-size:1.5rem;border:none;float:none;font-weight:500;line-height:1.2;margin:0;max-width:none;padding:0}.theme-morningedition .article-teaser--quote blockquote p{padding-left:0;padding-right:0}.theme-morningedition .article-teaser--quote .article__body{font-size:13px;font-size:.9285714286rem}.theme-morningedition .article-teaser .article__body .intro{font-weight:400}.theme-morningedition .article-teaser--medior .article__header,.theme-morningedition .article-teaser--minor .article__header{margin-bottom:0}.theme-morningedition .article-teaser--major .article__header{font-size:24px;font-size:1.7142857143rem}.theme-morningedition .article-teaser--major figcaption{padding-bottom:1.4285714286rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;text-align:left}.theme-morningedition .article-teaser--major figcaption span{font-size:11px;font-size:.7857142857rem;color:#aaa}.theme-morningedition .article-spotlight{background-color:#fff;padding:0!important}.theme-morningedition .article-spotlight a>img{float:none}.theme-morningedition .article-spotlight .article__header{color:#004e86;font-size:16px;font-size:1.1428571429rem}.theme-morningedition .article-spotlight .article__body{color:inherit;margin-left:0;text-align:left}.theme-morningedition .article-spotlight .label-section{font-size:14px;font-size:1rem;color:#004e86;font-weight:700;padding-left:1.4285714286rem}.theme-morningedition .article-spotlight .label-section:before{content:"";padding-left:0}.theme-morningedition .col-last .article-spotlight{border-right:none}.theme-morningedition .col-last .article-spotlight .article__body{padding-right:0}.theme-morningedition .article-stock--neg .article-stock__inner:after{border-color:#000 transparent transparent;border-width:8px 8px 0;margin-bottom:-4px;margin-top:0;top:auto;bottom:10%}.theme-morningedition .article-stock__inner{position:relative}.theme-morningedition .article-stock__inner:after,.theme-morningedition .article-stock__inner:before{content:"";left:50%;position:absolute;top:30%}.theme-morningedition .article-stock__inner:before{background-color:#000;bottom:10%;margin-left:-100px;width:4px}.theme-morningedition .article-stock__inner:after{border-color:transparent transparent #000;border-style:solid;border-width:0 8px 8px;margin-left:-106px;margin-top:-4px}.theme-morningedition .article-stock__inner>div{color:#8bbcdb}.theme-morningedition .widget article{padding-bottom:1.4285714286rem}.theme-morningedition .widget article:after{content:" ";display:block;width:50%;height:0;border-bottom:1px solid #aaa}.theme-morningedition .widget article:last-child{border-bottom:none;padding-bottom:0}.theme-morningedition .article-full--scroll .article__header{font-size:52px;font-size:3.7142857143rem;text-transform:uppercase}.theme-morningedition .article-full--scroll img+.article__header{margin-top:1.4285714286rem}.theme-morningedition .article-full.article--comment .article__header{text-transform:uppercase;color:#444;font-size:30px;font-size:2.1428571429rem}.theme-morningedition .article-full.article--comment .avatar{margin-left:1.4285714286rem;margin-bottom:.8571428571rem}.theme-morningedition .avatar{margin-bottom:1.4285714286rem;display:block;margin-left:0}.theme-morningedition .banner{border-color:#ccc;border-style:dotted;border-width:0 0 1px}.theme-morningedition .banner:after{content:".";display:block;height:0;clear:both;visibility:hidden}.theme-morningedition .banner .logo{float:none;margin-right:5%}.theme-morningedition .banner .logo img{max-width:200px;width:100%}.theme-morningedition .banner .logo,.theme-morningedition .banner time{display:inline-block;margin-bottom:1.4285714286rem}.theme-morningedition .banner time{font-size:14px;font-size:1rem;border-color:#ccc;border-style:dotted;border-width:0 0 0 1px;color:#aaa;font-family:Georgia,Cambria,Times New Roman,Times,sans-serif;padding:5% 0 5% 5%;text-align:center;text-transform:uppercase}.theme-morningedition blockquote{font-size:16px;font-size:1.1428571429rem;margin:.8571428571rem 1.4285714286rem .8571428571rem 0;padding:.8571428571rem 0;max-width:160px;max-width:11.4285714286rem;border-color:#444;border-style:solid;border-width:1px 0;clear:both;float:left;color:#444;font-weight:700;line-height:1.4;width:100%}.theme-morningedition blockquote .source,.theme-morningedition blockquote p{padding:0 .8571428571rem;color:#444!important}.theme-morningedition blockquote .source{font-size:12px;font-size:.8571428571rem;color:#aaa;display:block;font-weight:400}.theme-morningedition .button,.theme-morningedition .mail-share-button{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.theme-morningedition .button--primary{border-color:#003053}.theme-morningedition .button--primary:focus,.theme-morningedition .button--primary:hover{background-color:#c5deed;border-color:#004e86;color:#004e86!important}.theme-morningedition input:focus,.theme-morningedition textarea:focus{border-color:#004e86;-webkit-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(0,78,134,.6) 0 0 8px;-moz-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(0,78,134,.6) 0 0 8px;box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(0,78,134,.6) 0 0 8px}.theme-morningedition .gallery{margin-top:.3571428571rem;background-color:#ddd}.article-full--eyewitness .theme-morningedition .gallery{margin-left:0}.article-full--poster .theme-morningedition .gallery{margin-top:0}@media screen and (min-width:62.1875em){.article-full--poster .theme-morningedition .gallery{float:left;width:73.2%;margin-right:40px;margin-bottom:0}}.theme-morningedition .gallery:hover{opacity:.9}@media screen and (min-width:40em){.theme-morningedition .gallery.i-2k{max-width:100%}.theme-morningedition .gallery.i-1k{max-width:60%}}.theme-morningedition figcaption{padding:.4285714286rem .5714285714rem;font-size:13px;font-size:.9285714286rem;line-height:1.3;position:relative}.theme-morningedition figcaption:before{top:6px;top:.4285714286rem;background-color:#aaa;content:'';height:1em;left:0;position:absolute;width:4px}.theme-morningedition figcaption span{white-space:nowrap}.theme-morningedition .modalbox-slideshow figcaption:before{display:none}.theme-morningedition .island .widget__header,.theme-morningedition .islet .widget__header{display:inline-block;padding:.3571428571rem .4285714286rem .1428571429rem;font-size:14px;font-size:1rem;margin-bottom:1.4285714286rem;color:#fff;font-weight:700;line-height:1}.theme-morningedition .label-section{display:inline-block;font-size:16px;font-size:1.1428571429rem;color:#e8c75d;margin-bottom:0;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;line-height:1;text-transform:uppercase}.theme-morningedition .label-section:before{content:'> ';padding-left:.55em}.theme-morningedition .label-section:first-child{margin-top:1.4285714286rem}.main-container .island .theme-morningedition .label-section,.main-container .islet .theme-morningedition .label-section{padding:.3571428571rem .4285714286rem .1428571429rem;background-color:#666;color:#fff}.theme-morningedition .island{background-color:#fff;padding:0}.theme-morningedition .island .label-section{color:#e8c75d;background-color:#fff;margin-top:0}.theme-morningedition .island .label-section:first-child{margin-top:0}.theme-morningedition .island article{padding:1.4285714286rem 0}.theme-morningedition .island article .label-section{color:#8bbcdb;font-size:14px;font-size:1rem}.theme-morningedition .island article .label-section:before{content:"";padding-left:1.4285714286rem}.theme-morningedition .secondary-col article+.label-section{padding-top:1.4285714286rem;border-top:1px solid #ededed;width:100%}.theme-morningedition .l-3k2k .label-section:before{padding-left:0}.theme-morningedition .link--proceed{font-size:12px;font-size:.8571428571rem}.theme-morningedition .link--proceed:before{content:'> '}.theme-morningedition .link--proceed:after{display:none}.theme-morningedition .content-list{font-weight:700;border-color:#8bbcdb}.theme-morningedition .more-list li{font-weight:400}.theme-morningedition .related-list:before{border-color:#8bbcdb}.theme-morningedition .list-visuals figcaption{text-align:center}.theme-morningedition .secondary-nav li{margin-right:0}.theme-morningedition .section-header{border-bottom:1px dotted #004e86}.theme-morningedition .section-header__title{font-size:30px;font-size:2.1428571429rem;position:relative;text-transform:uppercase;top:2px}.theme-morningedition .section-header--alt{border-bottom:0;margin-top:-.8571428571rem}.theme-morningedition .section-header--alt .section-header__title{font-size:20px;font-size:1.4285714286rem;margin-bottom:.4285714286rem;display:inline-block;border-color:#004e86;border-style:solid;border-width:0 1px;padding:.5em .75em 0}.theme-morningedition .l-front .section-header .section-header__title{font-size:72px;font-size:5.1428571429rem;font-weight:100;text-indent:0}.theme-morningedition .slideshow--mini .slideshow__image{padding-top:73%}.theme-morningedition .widget{border-bottom:0}.theme-morningedition .article__body .intro,.theme-morningedition .crossheading,.theme-morningedition .section-header__title,.theme-morningedition .tag{text-indent:20px;text-indent:1.4285714286rem}.theme-morningedition .article-teaser--quote blockquote,.theme-morningedition .article-teaser--quote.article-teaser .article__body,.theme-morningedition .article__author .tag,.theme-morningedition .article__header,.theme-morningedition .article__subheader,.theme-morningedition .author,.theme-morningedition .banner .logo,.theme-morningedition .info,.theme-morningedition .link--proceed,.theme-morningedition .section-header--alt .section-header__title{margin-left:1.4285714286rem;text-indent:0;width:auto}.theme-morningedition .popup__inner a{display:inline-block;margin-left:1.4285714286rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;text-decoration:none}.theme-morningedition .popup__inner a:first-child{margin-left:0}.theme-morningedition .popup__inner a img{display:block}.theme-morningedition .label-section--large{display:inline-block;font-size:36px;font-size:2.5714285714rem;color:#004e86;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:100;line-height:1;vertical-align:baseline;-webkit-font-smoothing:antialiased}@media screen and (min-width:40em){.theme-morningedition .label-section--large{font-size:48px;font-size:3.4285714286rem}}@media screen and (min-width:48em){.theme-morningedition .label-section--large{-webkit-transform:rotate(-90deg) translateY(0.5em);-moz-transform:rotate(-90deg) translateY(0.5em);-ms-transform:rotate(-90deg) translateY(0.5em);transform:rotate(-90deg) translateY(0.5em);margin-top:-1em;white-space:nowrap;position:relative;z-index:0}.theme-morningedition .label-section--large:after{content:'';display:block;padding-top:100%}}.no-csstransforms .theme-morningedition .label-section--large{white-space:normal;margin-top:20px;font-size:20px}.no-csstransforms .theme-morningedition .label-section--large:after{padding-top:0}.theme-archive .tag{font-weight:700;font-size:14px;font-size:1rem;text-transform:none}.theme-archive .article-comment .form__label,.theme-archive .article-comments label,.theme-archive .custom-list,.theme-archive .interactive span,.theme-archive blockquote{color:#444}.theme-archive .section--title:before,.theme-archive .section-title:before{height:27px;height:1.9285714286rem;width:52px;width:3.7142857143rem;background:url(../img/plus/logo_artdetail.png) no-repeat;background:0 0,url(../img/plus/logo_artdetail.svg) no-repeat;content:'';display:inline-block(baseline)}.theme-archive.theme-archive-overview .primary-col .plustitle{display:none}.theme-archive .button--link,.theme-archive .main-container a{text-decoration:none;color:#dd2727}.theme-archive .button--link:visited,.theme-archive .main-container a:visited{color:#dd2727}.theme-archive .button--link:focus,.theme-archive .button--link:hover,.theme-archive .main-container a:focus,.theme-archive .main-container a:hover{color:#e76969;text-decoration:none}.theme-archive .main-header{margin-bottom:1.4285714286rem}.theme-archive .article-full .article__header,.theme-archive blockquote{font-family:Georgia,Cambria,Times New Roman,Times,sans-serif}.theme-archive .article__subheader{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-archive .breadcrumb{margin-bottom:1.4285714286rem;margin-right:-1.4285714286rem;margin-left:-1.4285714286rem;font-size:13px;font-size:.9285714286rem;font-weight:700;padding:0;color:#aaa;border-bottom:1px solid #ededed}.theme-archive .breadcrumb li>*{display:block;padding:.8571428571rem 1.1428571429rem .8571428571rem .8571428571rem;margin:0}.theme-archive .breadcrumb li>a{background:url(../img/breadcrumb-arrow.png) 100% 50% no-repeat}@media screen and (min-width:40em){.theme-archive .breadcrumb{margin-left:0;margin-right:0}}@media screen and (min-width:48em){.theme-archive .breadcrumb{font-size:16px;font-size:1.1428571429rem}.theme-archive .breadcrumb li>*{padding:.8571428571rem 2.8571428571rem .8571428571rem 1.7142857143rem}}.theme-archive .breadcrumb a{text-decoration:none;color:#aaa}.theme-archive .breadcrumb a:visited{color:#aaa}.theme-archive .breadcrumb a:focus,.theme-archive .breadcrumb a:hover{color:#e76969;text-decoration:none}.theme-archive .ad--leaderboard,.theme-archive .ad--tvleaderboard,.theme-archive .ad--xlleaderboard{margin-left:-20px;margin-right:-20px}.theme-archive.theme-archive-overview .breadcrumb{margin-right:-1.4285714286rem;margin-left:-1.4285714286rem}.theme-archive.theme-archive-overview .theme-archive-overview--tile .breadcrumb{margin-right:0;margin-left:0}.theme-archive.theme-fs .paywall--wordcount{clear:both}.theme-archive.theme-fs article{margin-left:1.4285714286rem;margin-right:1.4285714286rem}.theme-archive.theme-fs article .col__cell{padding-right:1.4285714286rem}.theme-archive .secondary-nav{float:left;padding-top:0;width:100%}.theme-archive .secondary-nav li{margin-right:1.1428571429rem}.theme-archive .secondary-nav .pull-right{float:right}.theme-archive .pagination--simple a,.theme-archive .secondary-nav a{text-decoration:none;color:#444}.theme-archive .pagination--simple a:visited,.theme-archive .secondary-nav a:visited{color:#444}.theme-archive .pagination--simple a:focus,.theme-archive .pagination--simple a:hover,.theme-archive .secondary-nav a:focus,.theme-archive .secondary-nav a:hover{color:#dd2727;text-decoration:none}.theme-archive .button--primary,.theme-archive .callout,.theme-archive .logo img,.theme-archive .pagination .current a,.theme-archive .secondary-nav .current a{background-color:#dd2727}.theme-archive .pagination .current a,.theme-archive .secondary-nav .current a{text-decoration:none;color:#fff}.theme-archive .pagination .current a:visited,.theme-archive .secondary-nav .current a:visited{color:#fff}.theme-archive .pagination .current a:focus,.theme-archive .pagination .current a:hover,.theme-archive .secondary-nav .current a:focus,.theme-archive .secondary-nav .current a:hover{color:#fff;text-decoration:none}.theme-archive .meta-nav a{text-decoration:none;color:#aaa}.theme-archive .meta-nav a:visited{color:#aaa}.theme-archive .meta-nav a:focus,.theme-archive .meta-nav a:hover{color:#dd2727;text-decoration:underline}.theme-archive .meta-nav a:active{text-decoration:underline}.theme-archive .main-footer li a{text-decoration:none;color:#666}.theme-archive .main-footer li a:visited{color:#666}.theme-archive .main-footer li a:focus,.theme-archive .main-footer li a:hover{color:#dd2727;text-decoration:underline}.theme-archive .main-footer li a:active{text-decoration:underline}.theme-archive blockquote{margin:1.4285714286rem 0 5.7142857143rem;padding:0 0 0 1.4285714286rem;font-size:21px;font-size:1.5rem;font-weight:400;line-height:1.2857;float:none;border-left:1px solid #dd2727}.article-teaser--quote .theme-archive blockquote{margin:.8571428571rem 0;float:none;padding:0;border:none;max-width:100%}.theme-archive blockquote .source{font-size:21px;font-size:1.5rem;font-weight:400;line-height:1.2857;text-transform:none}.theme-archive blockquote.avatar img{margin-left:0}.theme-archive blockquote.avatar p{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:16px;font-size:1.1428571429rem;margin-top:.7142857143rem}.theme-archive .button,.theme-archive .mail-share-button{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.theme-archive .button--primary{font-size:14px;font-size:1rem}.theme-archive .button--small,.theme-archive .mail-share-button{font-size:13px;font-size:.9285714286rem;padding-top:5px;padding-bottom:3px}.theme-archive .button--large{font-size:20px;font-size:1.4285714286rem}.theme-archive .promo .button,.theme-archive .promo .mail-share-button{white-space:nowrap}.theme-archive .button--primary{border-color:#b51c1c}.theme-archive .button--primary:hover{background-color:#b51c1c;border-color:#891515}.theme-archive .button--archive,.theme-archive .top-mail-share-button{-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;background-color:#fff;border-color:#dd2727;border-style:solid;border-width:1px;color:#dd2727;min-width:4em}.theme-archive .button--archive:focus,.theme-archive .button--archive:hover,.theme-archive .top-mail-share-button:focus,.theme-archive .top-mail-share-button:hover{border-color:#e76969}.theme-archive input:focus,.theme-archive textarea:focus{border-color:#dd2727;-webkit-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(221,39,39,.6) 0 0 8px;-moz-box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(221,39,39,.6) 0 0 8px;box-shadow:rgba(0,0,0,.075) 0 1px 1px inset,rgba(221,39,39,.6) 0 0 8px}.theme-archive .gallery{float:none}.theme-archive .gallery img{margin:0 auto}@media screen and (min-width:48em){.theme-archive .modalbox-article .gallery{margin-right:0}}.theme-archive .interactive .interactive__count,.theme-archive .interactive .interactive__label{color:#dd2727}@media screen and (min-width:30em){.theme-archive .interactive .interactive__count{color:#fff}}.theme-archive .interactive div{float:left}.theme-archive .social-media--alt{border:0;padding-bottom:0}.theme-archive .l-zone{overflow:hidden}.theme-archive .zone-info-search{margin-top:-1.4285714286rem;padding-top:.8571428571rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.slideshow__teasers .theme-archive .zone-info-search .widget__list,.theme-archive .zone-info-search .row,.theme-archive .zone-info-search .slideshow,.theme-archive .zone-info-search .slideshow__teasers .widget__list{padding-left:1.4285714286rem}.theme-archive .widget{border-bottom:none}.theme-archive .widget__list .intro,.theme-archive .widget__list>li article{margin-bottom:0}.theme-archive .widget__list--live a{text-decoration:none;color:#44c4d1}.theme-archive .widget__list--live a:visited{color:#44c4d1}.theme-archive .widget__list--live a:focus,.theme-archive .widget__list--live a:hover{color:#318f98;text-decoration:none}.theme-archive .widget__footer{padding-bottom:0}.carousel .theme-archive .widget__footer ol,.theme-archive .widget__footer .author-info,.theme-archive .widget__footer .carousel ol,.theme-archive .widget__footer .child__list,.theme-archive .widget__footer .comments-list,.theme-archive .widget__footer .currently,.theme-archive .widget__footer .ekrant__previous-attachments,.theme-archive .widget__footer .history-list,.theme-archive .widget__footer .inline-list,.theme-archive .widget__footer .list--ellipsis,.theme-archive .widget__footer .list--history,.theme-archive .widget__footer .nav-tabs,.theme-archive .widget__footer .slideshow__pager,.theme-archive .widget__footer .star-rating,.theme-archive .widget__footer .stock-bar,.theme-archive .widget__footer .unstyled,.theme-archive .widget__footer .widget__list{margin-bottom:0;margin-top:0}.theme-archive .main-container article{color:#000;padding-top:0;padding-bottom:0}.theme-archive .main-container article>a{text-decoration:none;color:#000}.theme-archive .main-container article>a:visited{color:#000}.theme-archive .main-container article>a:focus,.theme-archive .main-container article>a:hover{color:#000;text-decoration:none}.theme-archive .main-container article>a:focus .article__header,.theme-archive .main-container article>a:hover .article__header{color:#e76969}.theme-archive.theme-archive-overview .main-container article{color:#000;padding-top:0;padding-bottom:0}.theme-archive.theme-archive-overview .main-container article>a{text-decoration:none;color:#000}.theme-archive.theme-archive-overview .main-container article>a:visited{color:#000}.theme-archive.theme-archive-overview .main-container article>a:focus,.theme-archive.theme-archive-overview .main-container article>a:hover{color:#000;text-decoration:none}.theme-archive.theme-archive-overview .main-container article>a .tag,.theme-archive.theme-archive-overview .main-container article>a time,.theme-archive.theme-archive-overview .main-container article>a:focus .article__header,.theme-archive.theme-archive-overview .main-container article>a:hover .article__header{color:#44c4d1}.theme-archive.theme-archive-overview .main-container article.article--plus>a{text-decoration:none;color:#000}.theme-archive.theme-archive-overview .main-container article.article--plus>a:visited{color:#000}.theme-archive.theme-archive-overview .main-container article.article--plus>a:focus,.theme-archive.theme-archive-overview .main-container article.article--plus>a:hover{color:#000;text-decoration:none}.theme-archive.theme-archive-overview .main-container article.article--plus>a:focus .article__header,.theme-archive.theme-archive-overview .main-container article.article--plus>a:hover .article__header{color:#e76969}.theme-archive.theme-archive-overview .main-container article.article--plus>a .tag,.theme-archive.theme-archive-overview .main-container article.article--plus>a time{color:#dd2727}.theme-archive .article__header{font-size:21px;font-size:1.5rem}.theme-archive .article-full{font-size:16px;font-size:1.1428571429rem;line-height:1.5}.theme-archive .article-full header:before{margin-bottom:1.4285714286rem;height:27px;height:1.9285714286rem;width:52px;width:3.7142857143rem;background:url(../img/plus/logo_artdetail.png) no-repeat;background:0 0,url(../img/plus/logo_artdetail.svg) no-repeat;content:'';display:block}.theme-archive .article-full header.header--opinion:before{content:'opinie';text-indent:60px;font-size:36px;font-size:2.5714285714rem;text-transform:uppercase;line-height:1;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;color:#444;margin-bottom:2.8571428571rem}.theme-archive .article-full header.header--column:before{content:'column';text-indent:60px;font-size:36px;font-size:2.5714285714rem;text-transform:uppercase;line-height:1;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;color:#444;margin-bottom:2.8571428571rem}.theme-archive .article-full header.header--comment:before{content:'commentaar';text-indent:60px;font-size:36px;font-size:2.5714285714rem;text-transform:uppercase;line-height:1;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;color:#444;margin-bottom:2.8571428571rem}.theme-archive .article-full .intro{font-size:21px;font-size:1.5rem;margin-bottom:1.4285714286rem;margin-top:1.4285714286rem;padding-bottom:1.4285714286rem;border-bottom-color:#ddd;border-bottom-style:solid;border-bottom-width:1px;color:#444;font-weight:400}.theme-archive .article-full .article__header{font-size:40px;font-size:2.8571428571rem;margin-bottom:.2em}.theme-archive .article-full .article__header .plustitlexl{background:url(../img/plus/logo_artdetail.png) no-repeat;background:0 0,url(../img/plus/logo_artdetail.svg) no-repeat;width:52px;width:3.7142857143rem;height:27px;height:1.9285714286rem;display:inline-block(baseline);margin-right:.3571428571rem}.theme-archive .article-full .article__header .plustitlexl #ds_popup{top:-20px}.theme-archive .article-full .article__content-info{font-size:14px;font-size:1rem}.theme-archive .article-full .article__content-info time{text-transform:uppercase}.theme-archive .article-full .article__content-info .article__content-info-avatar{max-width:80px;max-width:5.7142857143rem;-webkit-border-radius:40px;-moz-border-radius:40px;border-radius:40px;overflow:hidden}.theme-archive .article-full .article__content-info .article__content-info-location{text-transform:uppercase;font-weight:700;margin-right:.2142857143rem}.theme-archive .article-full #ds_popup{position:absolute;top:0;min-width:180px;background-color:#fff;z-index:1030;font-size:13px;font-size:.9285714286rem;color:#dd2727;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;border:1px solid #eee;padding:.3571428571rem}.theme-archive .article-full #ds_popup:after,.theme-archive .article-full #ds_popup:before{content:"";position:absolute;width:0;height:0;border-style:solid;border-color:transparent;border-bottom:0}.theme-archive .article-full #ds_popup:before{bottom:-10px;left:11px;border-top-color:#eee;border-width:10px}.theme-archive .article-full #ds_popup:after{bottom:-9px;left:12px;border-top-color:#fff;border-width:9px}.theme-archive .article-full .article__body{padding-bottom:1.4285714286rem;font-size:18px;font-size:1.2857142857rem;line-height:1.5;position:relative}.theme-archive .article-full .article__body a{text-decoration:underline;color:#dd2727}.theme-archive .article-full .article__body a:visited{color:#dd2727}.theme-archive .article-full .article__body a:focus,.theme-archive .article-full .article__body a:hover{color:#e76969;text-decoration:underline}.theme-archive .article-full .article__body a:active{text-decoration:underline}.theme-archive .article-full .tag{color:#dd2727}.theme-archive .article-full .slideshow{margin-top:0}.theme-archive .article-full .slideshow__container{margin-left:-.8571428571rem;margin-right:-.8571428571rem;margin-top:0;position:relative}@media screen and (min-width:40em){.theme-archive .article-full .slideshow__container{margin-left:0;margin-right:0}}.theme-archive .article-full .slideshow__container .slideshow__controls{opacity:.1}.theme-archive .article-full .slideshow__container:hover .slideshow__controls{opacity:1}.theme-archive .article-full .slideshow__image{margin-bottom:.8571428571rem;background-color:#ddd;padding-top:60%}.theme-archive .article-full .slideshow__meta{position:static}@media screen and (min-width:40em){.theme-archive .article-full .slideshow__meta{float:left}}.theme-archive .article-full .slideshow__caption{max-width:655px;max-width:46.7857142857rem;margin-right:0}@media screen and (min-width:40em){.theme-archive .article-full .slideshow__thumbs{width:260px;width:18.5714285714rem;float:right}}.theme-archive .article-full .slideshow__thumbs ol li{margin-right:.4285714286rem;height:40px;width:40px}.theme-archive .article-full .slideshow__thumbs ol a:after{border-width:3px}.theme-archive .article-full .slideshow__thumbs ol .is-active a:after,.theme-archive .article-full .slideshow__thumbs ol a:focus:after,.theme-archive .article-full .slideshow__thumbs ol a:hover:after{border-color:#dd2727}.theme-archive .article-full .slideshow__controls{margin-top:-1.7857142857rem;padding-top:30%;pointer-events:none;position:absolute;top:0;width:100%}.theme-archive .article-full .slideshow__next,.theme-archive .article-full .slideshow__prev{height:50px;height:3.5714285714rem;line-height:50px;width:50px;width:3.5714285714rem;background-color:#dd2727;pointer-events:auto}.theme-archive .article-full .slideshow__next:focus,.theme-archive .article-full .slideshow__next:hover,.theme-archive .article-full .slideshow__prev:focus,.theme-archive .article-full .slideshow__prev:hover{background-color:#fff}.theme-archive .article-full .slideshow__next.slideshow__next,.theme-archive .article-full .slideshow__next.slideshow__prev,.theme-archive .article-full .slideshow__prev.slideshow__next,.theme-archive .article-full .slideshow__prev.slideshow__prev{color:#fff}.theme-archive .article-full .slideshow__next.slideshow__next:focus,.theme-archive .article-full .slideshow__next.slideshow__next:hover,.theme-archive .article-full .slideshow__next.slideshow__prev:focus,.theme-archive .article-full .slideshow__next.slideshow__prev:hover,.theme-archive .article-full .slideshow__prev.slideshow__next:focus,.theme-archive .article-full .slideshow__prev.slideshow__next:hover,.theme-archive .article-full .slideshow__prev.slideshow__prev:focus,.theme-archive .article-full .slideshow__prev.slideshow__prev:hover{color:#dd2727}.theme-archive .article-full .slideshow__next.slideshow__prev,.theme-archive .article-full .slideshow__prev.slideshow__prev{float:left}@media screen and (min-width:40em){.theme-archive .article-full .slideshow__next.slideshow__prev,.theme-archive .article-full .slideshow__prev.slideshow__prev{margin-left:3.5714285714rem}}.theme-archive .article-full .slideshow__next.slideshow__next,.theme-archive .article-full .slideshow__prev.slideshow__next{float:right}@media screen and (min-width:40em){.theme-archive .article-full .slideshow__next.slideshow__next,.theme-archive .article-full .slideshow__prev.slideshow__next{margin-right:3.5714285714rem}}.theme-archive .article-full .slideshow__next [class^=icon],.theme-archive .article-full .slideshow__prev [class^=icon]{top:1px}.theme-archive .article-full .slideshow__divider,.theme-archive .article-full .slideshow__index,.theme-archive .article-full .slideshow__total{display:none}.theme-archive .article__subheader{font-size:16px;font-size:1.1428571429rem;color:#dd2727}.theme-archive.theme-archive-overview .article__subheader{color:#aaa}.theme-archive .article__body{padding:0}@media screen and (min-width:48em){.theme-archive .article__meta{position:absolute;left:78%;top:0;width:22%}}.theme-archive .crossheading{font-size:21px;font-size:1.5rem;margin-top:2.1428571429rem;margin-bottom:1.4285714286rem;line-height:1.2857}.theme-archive .information-text{padding:1.4285714286rem;border-color:#ddd;border-style:solid;border-width:1px}.theme-archive .author-info>li{border-bottom:1px solid #ededed}.theme-archive .author-info>li.first{padding-top:0}.theme-archive .author-info>li.last{border-bottom:none}.theme-archive .author-info h3{font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-archive .author-info.profile-text{padding:.7142857143rem;border-color:#ddd;border-style:solid;border-width:1px}.theme-archive .link-live{color:#44c4d1!important}.theme-archive .link-live:focus,.theme-archive .link-live:hover{color:#318f98!important}@media screen and (min-width:62.1875em){.theme-archive .modalbox-article .modalbox__inner{width:780px;margin-left:auto;margin-right:auto}}.theme-archive .modalbox-article .article-full{padding-right:50px;padding-left:0;margin-right:0}.theme-archive .modalbox-article .article__meta{position:static;width:auto}.theme-archive .search-results article{margin-bottom:20px}.comment__footer menu .theme-archive .search-results li,.theme-archive .search-results .comment__footer menu li,.theme-archive .search-results .inline{display:inline-block!important;margin-top:12px;color:#aaa!important}.comment__footer menu .theme-archive .search-results li:before,.theme-archive .search-results .comment__footer menu li:before,.theme-archive .search-results .inline:before{content:'Tags: ';display:inline-block;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:700}.comment__footer menu .theme-archive .search-results .article-archive li .tag,.comment__footer menu .theme-archive .search-results .article-live li .tag,.theme-archive .search-results .article-archive .comment__footer menu li .tag,.theme-archive .search-results .article-archive .inline .tag,.theme-archive .search-results .article-live .comment__footer menu li .tag,.theme-archive .search-results .article-live .inline .tag{color:#aaa!important;font-weight:400}.theme-archive .search-results .tag__search{margin-bottom:1.4285714286rem;border-bottom:1px solid #eee}.theme-archive .search-results .tag__search .tag__search__item{margin-bottom:20px;background-color:#eee;padding:12px}.theme-archive .search-results .tag__search .tag__search__item.tag--live a .tag__search__item--tagformat:before{content:"\e629";font-family:Dso-icons;display:inline-block;vertical-align:middle}.theme-archive .search-results .tag__search .tag__search__item.tag--live a .tag__search__item--tagformat:after{content:'>';display:inline-block;margin-left:.3571428571rem}.theme-archive .search-results .tag__search .tag__search__item.tag--live a .tag__search__item--title{font-size:20px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;color:#444}.theme-archive .search-results .tag__search .tag__search__item.tag--live a .tag__search__item--title:hover{color:#44c4d1}.theme-archive .search-results .tag__search .tag__search__item.tag--live a .tag__search__item--intro{color:#444}.theme-archive .search-results .tag__search .tag__search__item.tag--live a .tag__search__item--intro img{display:none}.theme-archive .search-results .tag__search .tag__search__item.tag--live a .tag__search__item--intro:after{content:'>';display:inline-block;margin-left:.3571428571rem}.theme-archive .search-results .tag__search .tag__search__item.tag--plus a .tag__search__item--tagformat:before{content:"\e629";font-family:Dso-icons;display:inline-block;vertical-align:middle}.theme-archive .search-results .tag__search .tag__search__item.tag--plus a .tag__search__item--tagformat:after{content:'>';display:inline-block;margin-left:.3571428571rem}.theme-archive .search-results .tag__search .tag__search__item.tag--plus a .tag__search__item--title{font-size:20px;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;color:#444}.theme-archive .search-results .tag__search .tag__search__item.tag--plus a .tag__search__item--title:hover{color:#dd2727}.theme-archive .search-results .tag__search .tag__search__item.tag--plus a .tag__search__item--intro{color:#444}.theme-archive .search-results .tag__search .tag__search__item.tag--plus a .tag__search__item--intro img{display:none}.theme-archive .search-results .tag__search .tag__search__item.tag--plus a .tag__search__item--intro:after{content:'>';display:inline-block;margin-left:.3571428571rem}.theme-archive .alert{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.theme-archive .ui-datepicker-calendar td{border-color:#dd2727;background-color:#fceded}.theme-archive .ui-datepicker-calendar td>a{color:#dd2727!important}.theme-archive .ui-datepicker-calendar td>.ui-state-hover{background-color:#dd2727;color:#fff!important}.theme-archive .ui-datepicker-calendar .ui-datepicker-unselectable{border-color:#ddd;background-color:#fff;color:#aaa}.theme-archive .ui-datepicker-calendar .ui-datepicker-other-month{border:0;background-color:#fff}.theme-archive .ui-datepicker-calendar .ui-datepicker-current-day{background-color:#fff}.theme-archive .ui-datepicker-calendar .ui-datepicker-today{border-color:#9f1919;background-color:#dd2727}.theme-archive .ui-datepicker-calendar .ui-datepicker-today>a{color:#fff!important}.theme-archive form.archive img.ui-datepicker-trigger{padding-bottom:.8571428571rem}.theme-archive .ekrant__header .datepicker-wrapper{visibility:hidden}.theme-archive .ekrant__header .datepicker-wrapper.is-visible a{width:180px;width:12.8571428571rem;display:block;position:relative;top:5px;visibility:visible}.theme-archive .article-live .tag,.theme-archive .article-live>a:focus .article__header,.theme-archive .article-live>a:hover .article__header{color:#44c4d1!important}.theme-archive .article-live.tag--live{color:#44c4d1!important;font-weight:400!important}.theme-archive .article-biz .tag,.theme-archive .article-biz>a:focus .article__header,.theme-archive .article-biz>a:hover .article__header{color:#ad9a0a!important}.theme-archive .article-lifestyle .tag,.theme-archive .article-lifestyle>a:focus .article__header,.theme-archive .article-lifestyle>a:hover .article__header{color:#f7516d!important}.theme-archive .article-mobilia .tag,.theme-archive .article-mobilia>a:focus .article__header,.theme-archive .article-mobilia>a:hover .article__header{color:#5c52e6!important}.theme-archive .article-morningedition .tag,.theme-archive .article-morningedition>a:focus .article__header,.theme-archive .article-morningedition>a:hover .article__header{color:#004e86!important}.theme-archive .article-archive .tag,.theme-archive .article-archive>a:focus .article__header,.theme-archive .article-archive>a:hover .article__header{color:#dd2727!important}.theme-archive .article-archive h1:before{content:'';display:inline-block(middle);width:40px;width:2.8571428571rem;height:21px;height:1.5rem;background:url(../img/plus/logo_naasttitel.png) no-repeat;background:no-repeat,url(../img/plus/logo_naasttitel.svg) no-repeat;margin-right:.3571428571rem}.theme-archive .article-archive.tag--plus{color:#dd2727!important}.theme-archive .reeks{border-color:#ddd;border-style:solid;border-width:1px;padding:.8571428571rem}.theme-archive .reeks h2{font-size:21px;font-size:1.5rem;text-transform:uppercase;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;margin-bottom:.2857142857rem}.theme-archive .reeks h2 .reeks__bigheader__prefix{color:#ddd;font-weight:400}.theme-archive .reeks .reeks__intro{font-size:16px;font-size:1.1428571429rem}.theme-archive .reeks .reeks__articles .reeks__articles__list{padding:0;font-size:18px;font-size:1.2857142857rem;list-style:none}.theme-archive .reeks .reeks__articles .reeks__articles__list .reeks__articles__list__item{border-top-color:#ddd;border-top-style:solid;border-top-width:1px;line-height:1.8;padding:.4285714286rem 0;font-size:18px;font-size:1.2857142857rem}.theme-archive .reeks .reeks__articles .reeks__articles__list .reeks__articles__list__item .reeks__articles__list__item__link__subtitle{font-size:14px;font-size:1rem;color:#666;display:block;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-archive .reeks .reeks__articles .reeks__cta{padding:0;margin:0;text-align:right;font-size:16px;font-size:1.1428571429rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:700}.theme-archive .reeks .reeks__articles .reeks__cta a:after{content:'\e013';font-family:Dso-icons}.theme-archive .tagrelated{border-color:#ddd;border-style:solid;border-width:1px;padding:.8571428571rem}.theme-archive .tagrelated h2{font-size:21px;font-size:1.5rem;text-transform:uppercase;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;margin-bottom:.2857142857rem}.theme-archive .tagrelated h2 .reeks__bigheader__prefix{color:#ddd;font-weight:400}.theme-archive .tagrelated .tagrelated__intro{font-size:16px;font-size:1.1428571429rem}.theme-archive .tagrelated .tagrelated__articles .tagrelated__articles__list{margin-top:.7142857143rem;padding:0;font-size:18px;font-size:1.2857142857rem;list-style:none}.theme-archive .tagrelated .tagrelated__articles .tagrelated__articles__list .tagrelated__articles__list__item{border-top-color:#ddd;border-top-style:solid;border-top-width:1px;clear:both;line-height:1.8;padding:.4285714286rem 0;font-size:18px;font-size:1.2857142857rem}.theme-archive .tagrelated .tagrelated__articles .tagrelated__articles__list .tagrelated__articles__list__item .tagrelated__articles__list__item__link{display:block;margin-top:.3571428571rem}.theme-archive .tagrelated .tagrelated__articles .tagrelated__articles__list .tagrelated__articles__list__item .tagrelated__articles__list__item__link .tagrelated__articles__list__item__link__subtitle{text-transform:uppercase;font-size:14px;font-size:1rem;color:#666;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif}.theme-archive .tagrelated .tagrelated__articles .tagrelated__articles__list .tagrelated__articles__list__item .tagrelated__articles__list__item__link .tagrelated__articles__list__item__link__subtitle:after{display:block;content:'';width:100%}.theme-archive .tagrelated .tagrelated__articles .tagrelated__articles__list .tagrelated__articles__list__item .tagrelated__articles__list__item__link time{text-transform:uppercase}.theme-archive .tagrelated .tagrelated__articles .tagrelated__articles__list .tagrelated__articles__list__item .tagrelated__articles__list__item__link time:after{content:'|';margin:0 .2142857143rem}.theme-archive .tagrelated .tagrelated__articles .tagrelated__articles__list .tagrelated__articles__list__item .tagrelated__articles__list__item__link img{margin:0;float:left;padding:0 .7142857143rem .7142857143rem 0}.theme-archive .tagrelated .tagrelated__articles .tagrelated__cta{padding:0;margin:0;text-align:right;font-size:16px;font-size:1.1428571429rem;font-family:Din,'Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:700}.theme-archive .tagrelated .tagrelated__articles .tagrelated__cta a:after{content:'\e013';font-family:Dso-icons}.theme-archive .share>[data-social=facebook]{top:39px}.theme-archive-no-blocks .l-zone{overflow:visible}.theme-archive-no-blocks .l-zone .breadcrumb{margin-left:-20px;margin-right:-20px}.conversion--evening-theme,.theme-conversion-evening .conversion--auto-theme{border-color:#628226}.conversion--evening-theme .conversion__header,.theme-conversion-evening .conversion--auto-theme .conversion__header{color:#628226}.conversion--morning-theme,.theme-conversion-morning .conversion--auto-theme{border-color:#004e86}.conversion--morning-theme .conversion__header,.theme-conversion-morning .conversion--auto-theme .conversion__header{color:#004e86}.theme-conversion-evening .conversion__ad--evening,.theme-conversion-evening .conversion__title--evening{display:block}.theme-conversion-evening .conversion--auto-hide.conversion--morning-theme,.theme-conversion-evening .conversion--auto-hide.conversion--morning-theme .ad--mediumrectangle2,.theme-conversion-evening .conversion--auto-hide.conversion--morning-theme .ad--mediumrectangle3,.theme-conversion-evening .conversion--auto-hide.conversion--morning-theme .ad--mediumrectangle4,.theme-conversion-evening .conversion__ad--morning,.theme-conversion-evening .conversion__title--morning{display:none}.theme-conversion-evening .conversion--auto-hide.conversion--evening-theme{display:block}.theme-conversion-morning .conversion__ad--evening,.theme-conversion-morning .conversion__title--evening{display:none}.theme-conversion-morning .conversion--auto-hide.conversion--morning-theme,.theme-conversion-morning .conversion__ad--morning,.theme-conversion-morning .conversion__title--morning{display:block}.theme-conversion-morning .conversion--auto-hide.conversion--evening-theme,.theme-conversion-morning .conversion--auto-hide.conversion--evening-theme .ad--mediumrectangle2,.theme-conversion-morning .conversion--auto-hide.conversion--evening-theme .ad--mediumrectangle3,.theme-conversion-morning .conversion--auto-hide.conversion--evening-theme .ad--mediumrectangle4{display:none}@media print{*{background:0 0!important;color:#000!important;-webkit-box-shadow:none!important;-moz-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important;font-family:Georgia,Cambria,Times New Roman,Times,sans-serif!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}article img{max-height:400px!important}.ad,.ad-group,.main-footer,.main-header,.social-media{display:none!important}.breadcrumb,.widget{display:none}.theme-live .primary-col aside,.theme-live .secondary-col,.theme-morningedition .edition-nav,.theme-morningedition .l-latest-issues,.theme-morningedition .l-spotlight{display:none!important}.theme-archive .breadcrumb{display:block}.theme-archive .paywall,.theme-archive .zone-info-search{display:none!important}.theme-archive .gallery img{margin-left:auto;margin-right:auto}.theme-archive .breadcrumb{margin:.5cm}.theme-archive .breadcrumb li>a,.theme-archive .breadcrumb li>strong{background:0 0;padding:6px}.theme-archive .article__sharelinks,.theme-archive .reeks,.theme-archive .share_lines,.theme-archive .slideshow__controls,.theme-archive .slideshow__thumbs.carousel{display:none!important}} \ No newline at end of file diff --git a/codeview/src/main/assets/training-set/css/new 8.txt b/codeview/src/main/assets/training-set/css/new 8.txt new file mode 100755 index 0000000..ed93fc4 --- /dev/null +++ b/codeview/src/main/assets/training-set/css/new 8.txt @@ -0,0 +1 @@ +@keyframes spin{to{transform:rotate(360deg)}}@-webkit-keyframes spin{to{-webkit-transform:rotate(360deg)}}.c-hidden{display:none}.c-clearfix:before,.c-clearfix:after{content:" ";display:table}.c-clearfix:after{clear:both}.c-pull-right{float:right}.c-pull-left{float:left}.c-hide-text{text-indent:100%;white-space:nowrap;overflow:hidden}.c-hidden{display:none}.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;transition:opacity 0.15s linear}.fade.in{opacity:1}.c-form-control{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;display:block;width:100%;font-size:14px;height:34px;line-height:20px;padding:6px 12px;background-image:none;border:1px solid #ccc;border-radius:4px;box-shadow:inset 1px 1px 2px -1px rgba(0,0,0,0.15);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-moz-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-ms-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.c-form-control:focus{border-color:#3c80d3;outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 4px #3c80d3}.c-form-control::-moz-placeholder{color:#a6a6a6;opacity:1}.c-form-control:-ms-input-placeholder{color:#a6a6a6}.c-form-control::-webkit-input-placeholder{color:#a6a6a6}textarea.c-form-control{height:auto;resize:vertical}.c-form-group{margin-bottom:10px;position:relative}.c-form-inline .c-form-group{display:inline-block;vertical-align:top;margin-bottom:0;vertical-align:middle}.c-form-inline .c-form-control{display:inline-block;vertical-align:middle}.c-submit-group{margin-top:34px}.c-radio,.c-checkbox{position:relative;display:block;font-size:12px;margin-top:10px;margin-bottom:10px}.c-radio label,.c-checkbox label{font-weight:normal;cursor:pointer}.c-radio.c-input-height,.c-checkbox.c-input-height{min-height:34px}.c-checkbox label{max-width:90%;display:inline-block;vertical-align:top}.c-radio input[type="radio"],.c-checkbox input[type="checkbox"]{margin-right:.5em;line-height:normal}.c-radio input[type="radio"]:focus,.c-checkbox input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.c-help-block{display:block}.c-checkbox .c-help-block{margin-top:5px}.c-help-block.c-help-block-toggle{display:none}.c-btn{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;display:inline-block;margin-bottom:0;text-align:center;text-transform:uppercase;font-weight:bold;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:4px 12px 3px;font-size:12px;line-height:20px;border-radius:3px;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}.c-btn:hover,.c-btn:focus{color:#fff;text-decoration:none}.c-btn:active,.c-btn.active{outline:0;background-image:none}.c-btn.disabled,.c-btn[disabled],fieldset[disabled] .c-btn{cursor:not-allowed;pointer-events:none;opacity:0.65;filter:alpha(opacity=65);box-shadow:none}.c-btn-primary{background-color:#4f86b5;border-bottom:2px solid #4270a2;color:#ffffff}.c-btn-primary:hover,.c-btn-primary:focus,.c-btn-primary:active,.c-btn-primary.disabled,.c-btn-primary[disabled]{background-color:#4980ae;color:#ffffff}.c-btn-primary:focus{outline-offset:1px}.c-btn-primary:active,.c-btn-primary.active{border-bottom-width:1px;margin-top:1px}.c-btn-secondary{background-color:#c6c6c6;border-bottom:2px solid #b8b8b8;color:#ffffff}.c-btn-secondary:hover,.c-btn-secondary:focus,.c-btn-secondary:active,.c-btn-secondary.disabled,.c-btn-secondary[disabled]{background-color:#c0c0c0;color:#ffffff}.c-btn-secondary:focus{outline-offset:1px}.c-btn-secondary:active,.c-btn-secondary.active{border-bottom-width:1px;margin-top:1px}.c-btn-highlight{background-color:#dc6431;border-bottom:2px solid #c9532b;color:#ffffff}.c-btn-highlight:hover,.c-btn-highlight:focus,.c-btn-highlight:active,.c-btn-highlight.disabled,.c-btn-highlight[disabled]{background-color:#da5c26;color:#ffffff}.c-btn-highlight:focus{outline-offset:1px}.c-btn-highlight:active,.c-btn-highlight.active{border-bottom-width:1px;margin-top:1px}.c-tooltip{position:absolute;z-index:1002;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.c-tooltip .tooltip-inner{padding:2px 8px 3px;color:#ffffff;text-decoration:none;background-color:#000000;border-radius:2px}.c-tooltip .tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;border-width:8px}.c-tooltip.in{opacity:1;filter:alpha(opacity=100)}.c-tooltip.top{padding:8px 0}.c-tooltip.right{padding:0 8px}.c-tooltip.bottom{padding:8px 0}.c-tooltip.left{padding:0 8px}.c-tooltip.top .tooltip-arrow{bottom:2px;left:50%;margin-left:-8px;border-bottom-width:0;border-top-color:#000000}.c-tooltip.top-right .tooltip-arrow{bottom:-8px;left:auto;right:2px;border-bottom-width:0;border-top-color:#000000}.c-tooltip.right .tooltip-arrow{top:50%;left:2px;margin-top:-8px;border-left-width:0;border-right-color:#000000}.c-tooltip.left .tooltip-arrow{top:50%;right:2px;margin-top:-8px;border-right-width:0;border-left-color:#000000}.c-tooltip.bottom .tooltip-arrow{top:2px;left:50%;margin-left:-8px;border-top-width:0;border-bottom-color:#000000}.c-has-feedback{position:relative}.c-has-error .c-tooltip.right .tooltip-arrow{border-right-color:#d4473f}.c-has-error .c-tooltip.left .tooltip-arrow{border-left-color:#d4473f}.c-has-error .c-tooltip.top-right .tooltip-arrow,.c-has-error .c-tooltip.top .tooltip-arrow{border-top-color:#d4473f}.c-has-error .c-tooltip.bottom .tooltip-arrow{border-bottom-color:#d4473f}.c-has-error .tooltip-inner{background-color:#d4473f}.c-has-success .c-tooltip.right .tooltip-arrow{border-right-color:#6ec02a}.c-has-success .c-tooltip.left .tooltip-arrow{border-left-color:#6ec02a}.c-has-success .c-tooltip.top-right .tooltip-arrow,.c-has-success .c-tooltip.top .tooltip-arrow{border-top-color:#6ec02a}.c-has-success .c-tooltip.bottom .tooltip-arrow{border-bottom-color:#6ec02a}.c-has-success .tooltip-inner{background-color:#6ec02a}.c-form-control-feedback-wrapper{width:calc(125%);width:110%;position:absolute;left:100%;top:0}.c-form-control-feedback-wrapper.inside-input{margin-left:-30px}.c-form-control-feedback{display:none;position:absolute;left:5px;top:7px;height:20px;width:20px;vertical-align:middle}.c-form-control-feedback-throbber,.c-form-throbber:after{background-image:url('data:image/gif;base64,R0lGODlhFAAUAIQAAFxeXMTCxISGhOTm5NTS1JyenHRydPT29MzKzJSSlOzu7Nza3KSmpHx6fGxubPz+/GRiZMTGxIyOjOzq7NTW1KSipHR2dPz6/MzOzJSWlPTy9Nze3KyqrHx+fP///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJBwAeACwAAAAAFAAUAAAFj6AnjuMwkWgqBgAUqOMTFJQoQYA0ahfKQpCB5/fycACC3qiAAyBEA6Go0dKQKECHNYVoMFKDyBaGOiwOZNXGAXFs0p7LppfAQRLwCqDiyQD+GXl7Hmttb2lySmZjcCQTCRYVSo0PVDhfKRcIjApNEBYqCACYIhdsLTopBxWHIxhsDSceFXxwFwoPrgSNvCQhACH5BAkHAB0ALAAAAAAUABQAhFxeXLSytNza3IyOjOzu7HR2dMTGxGxqbOTm5JyenPz6/Ly+vGRmZOTi5JSWlPT29MzOzGRiZLy6vNze3JSSlPTy9ISChGxubOzq7KyqrPz+/MTCxNTS1P///wAAAAAAAAWRYCeOo6KQaCpOxyWoZLNUYgYAGSw2EVCcgsthsrJsUItIDyN6nGoAC4pQAAw0qkqGiFJgnrpuWPUYRAaPcQfbkfQikjHkAGnfAPHwvF4+p8dgHYFqIxoSCRyEIzY9iSoEbCMFbwkdAg4OLx0EEQYoFAA9CxgMPQdMGgZ/IwQUBRkKG6E3R4QCsxGahAEMDAEwIQAh+QQJBwAhACwAAAAAFAAUAIVcXly0srTc2tyEhoTs7ux0dnScmpzExsRsamzk5uT8+vy8vryMjoysqqxkZmTk4uT09vSEgoSkoqTU0tRkYmS0trTc3tyMioz08vR8enycnpxsbmzs6uz8/vzEwsSUkpTU1tT///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGnMCQcEgsGo8KjUZxJEIsHaGAAhA0hZAC5SNMLrGNRNFCdUSNE0CjqPg4As0OiGk8X+/4YScQCdjzAgAAFFZ3HBccIWSChVccA4l7fX95lVcPHgRHHRUXEhhEE1QbmkUBggAMRAaDAAchEAsLECEXrRR0IQuDFA8dEVQDChKtGUQdCwYTIQlUVBwYDBQZFlcKCIMItCG5VwIXF41FQQAh+QQJBwAcACwAAAAAFAAUAIRcXly8uryMiozc3tx0dnTMysxsamz08vScnpzEwsTU0tRkZmTs7uyEhoR0cnT8/vysrqxkYmS8vryMjozk5uR8enzMzsxsbmz09vSkpqTExsTU1tT///8AAAAAAAAAAAAFiyAnjmRpnpxVoOxjGA8rQoQyFutoYSYRIagDwGJSICisg2zJPFESSM4GsVlqIoCI5rCILJSsShZQ4QK+MjG2IkXYZNespjl6RkUYSuw0gORGDA4RAnskAxFYASQSAI1RAwMzWBENhogOPBCIEBwFkxklAxIMHA8OjRcPDwENGTwsAlgTdCIHEBBgJiEAIfkECQcAGgAsAAAAABQAFACEXF5ctLK0jIqM3Nrc7O7sbG5snJ6cxMbE/Pr8ZGZkzM7MlJaU7Ors9Pb0dHZ0rKqsZGJkjI6M3N7c9PL0dHJ0pKKkzMrM/P78bGps1NLU////AAAAAAAAAAAAAAAAAAAABY6gJo5kaZ4aw6CsJghiUxUCUQ7GNKpiAEAAGMkAOZwWP0ChNDlcTgcgxNAyHRYBRPWEYDw1jUyjynAAHKsFZFGtQN4VDZLdqgDucYSY7ICgtyRdWoEsYTaBERgPJw19CRIkA3cJgw2DGUmLIw0UEBEiGQkYGSkJQBZMA18RQJ8aEg+oLT4QAYAjFwoKXyYhACH5BAkHAB8ALAAAAAAUABQAhFxeXLSytNza3JSSlHRydOzu7MTGxGxqbKyqrPz6/Ly+vOTm5JyanHx+fMzOzGRmZPT29GRiZLy6vOTi5JSWlHx6fPTy9MzKzGxubPz+/MTCxOzq7JyenISChNTS1P///wWL4CeOolFVBqmuUwQA0bTOn+K62ncNQaZaGl8LFhO8IgGVBrApnVISGICiyjRniwPsQqNtFIKu+OMbJcafBAPDOBseKbHhlnrHu5dj/DxWs/loI2WBIgWDIw4MMjMMERUQJBkEUzMFLgBcJAgEDiILHQ1NCRUABwsrgwgwCCIQF6diDhERnYQiG1czIQAh+QQJBwAcACwAAAAAFAAUAIRcXly0trSEhoTc3tz08vR0dnScmpzU1tTEwsTs6uz8+vx8fnykoqRsbmyMjoxkYmS8vrzk5uT09vR8enycnpzc2tzExsTs7uz8/vyEgoSkpqSUkpT///8AAAAAAAAAAAAFjCAnjmJCMRGpisrFFsBTKOt4NM+SRA8Qp4lAhaTAxTaKQm9GaMQOo0tvyYkwUJxBDBAYYRZTxkqRATQSpMRmoqGNB4SafE5XIRwIUSSTovN+VXx1CT4PfXUjd3mIjI0kFwhuKxANFBgqBgAWckaHIhUULhwYAQGXHAYPExJ0Aw8PQ6MRrHQSAgK0jnUhACH5BAkHABwALAAAAAAUABQAhFxeXLSytNze3JSWlPTy9Hx6fMTGxGxqbOzq7KyqrLy+vPz6/GRmZOTm5KSipNTS1GRiZLS2tOTi5JyanPT29ISGhGxubOzu7KyurMTCxPz+/NTW1P///wAAAAAAAAAAAAWPICeO4mIYC6mu3ARAAzsSQ5Fo2vEeGrdsF9UA8lK0AIAJR1OBWIKjwgvg4FBOKQrj9SAlkJDuysGopEYahUPMovRGDwxbpgpMA3SRICHgMIgQDHkLOhYLf0gHeRQWAAcLdkR4eXt9HHFzeZqbIhoNdAgOGysZAAgyLgUrBApvHBISIxsFEZqEPJwkEbW5uSEAOw==');background-repeat:no-repeat}@media only screen and (min-resolution:2dppx),only screen and (-webkit-min-device-pixel-ratio:2){.c-form-control-feedback-throbber,.c-form-throbber:after{background-image:url('data:image/gif;base64,R0lGODlhKAAoAKUAAFxeXLS2tIyKjNze3JyenPTy9HRydMzKzGxqbJSWlOzq7KyqrLy+vPz6/NTW1GRmZJSSlOTm5KSmpHx6fGRiZLy6vIyOjOTi5KSipPT29NTS1GxubJyanOzu7KyurMTCxPz+/Nza3Hx+fP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJBwAjACwAAAAAKAAoAAAG/sCRcEgsGo/IpHIYqVQuy2iUQQEAHgyp1nh5VClg6PaYCUWMFcDXWhkXGwsvQDQgptVqSqAIUgwyUQt4YBsKQ11rD2JCDRxqBg5KGQ94VhQSdpRgbUQBlQaASCFVgwACRRcVAYtDFmsAIUkXpVUJW45fFGdJImtgB1sDCHgcIEoDG2sExsEcAgENUQoLAgkHzG7Z2tvcUiAhARUh2N1IBa5fFgXlSCCuVngQ0d0FDBXrQqOW+7HcHRNWJnQQ4glMHit7uKX5wimArzwJty20kmWEvlcU+m37p0Ygo3eDLJDTVu8ekXOkKAjAx+7IN1XjWsqUCWKAhGoMQs0cAmKBba8JrGZ+qERqgk6ZDZLRAlBRSgYJFjQcM/gQwhYMVRAYErW0yiktFvDUQdJBDlEAGLZooGRhHhIIZ9WM1eLHLRIFSnMtINdBgICB3RRY8EJhwwe7IzwBiNitQ4gBiIUMMLBh7k4jBVhe3szZSBAAIfkECQcAIwAsAAAAACgAKACFXF5cvLq8jIqM3N7cdHZ09PL0zM7MnJ6cbGps7OrshIKExMbElJaU/Pr81NbUrKqsZGZk5ObkfH58ZGJkxMLEjI6M5OLkfHp89Pb01NLUpKakdHJ07O7shIaEzMrMnJqc/P783NrcrK6s////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv7AkXBILBqPyKRyCOJwGstolFOZTCocqdYIEkwA3wp0S+Z8z5MsuZg4XAQUENEMBqfXxMSmPnkQQVV1AnJEBSIHDoRJBwCNXxAJeV4TAmpMAnYZSxdndR5FTU9GERBfAAdLHXyNDlsFCHYiSwudExcYZAsIEAIFSw0PpQAXFngFCWNRCR4OuHjP0NHSSyAYDYrTSQMCELwD2dqwZwjf2Q3JI12rAIPTHhsbBkMY4nwQ6HgYBF8EY/SrEyA4g9Zgz4QNY9TVaifNA4ENn4aEqAcAQQhwDQYO2QYBgYCL4JJUsxayZMgmISLgMzmiwAFxF+SxFNJAVR0AEGSypGAFgHydCf3IJMiwsggDnz3rFBMCIkSAAIlGQTi1xAtAACA5YEJaqUgGKxKwGdFw0xSCLBgk1AIgQWODAwpaKUnQqc4HOQHKIg0AbcHUMx18jQi0tkK0BBoEMKCQTMHVCQpmfrgK4MNMB6YyA5BrEoQGzRM0iA3ZgMI+AAQYkwkCACH5BAkHACQALAAAAAAoACgAhVxeXLSytNza3ISGhOzu7MTGxJyanHRydGxqbOTm5JSSlPz6/NTS1MTCxKyqrGRmZLy6vOTi5IyOjPT29MzOzKSipISChGRiZLS2tNze3IyKjPTy9MzKzJyenHR2dGxubOzq7JSWlPz+/NTW1P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJJwSCwaj8ikcslsHgkQDMFJNRIOgMthWu1CsllM1ygSYBoTI+YChoyJIgf74kkUr2wPt7gBiZgCYFkSVlF7RBlYHX9KGGBsH2lUBnMgSw2PAB4LVQFZHxtLE1hzblULGB0ZTQkSBwcYjG9UE5yzt7i5urtVIgwdFQy2vEUiFYIVssRCFGyPFLqoGMMkx3NZHboBbAFE1o8V2lndQ82ZDLoTGNNw3xcV1MskCxQVFRTx8vr7/E0iGRgcFAi1JEEFCxIa5EsygRKYA9CSjEDwKMRCMgYACLrwYNURER6czWnQJNC1ORqQCJhzjRCcBROUeTqZBYGkIgwysRmASAFzgg8KBAxxoFPjA4J3RGp8N4TBA0EI0JHAVPSAMm+ZENghMSHkUo2bSFzZOI7hsSwHRgxZ+egCG6EkKDy4BkDDxSEbGGRQZs4ZGKkkMvh8cCDA3YIsWW4dsmDD1S4iFGj8quDxLgIaBFk4JG8BB3scDh8JAgAh+QQJBwAmACwAAAAAKAAoAIVcXly0srSEhoTc2tx0cnScmpzs7uzExsRsamyUkpTk5uR8fnykpqT8+vzU0tRkZmS8vryMjozk4uR8enykoqT09vTMzsxkYmSMiozc3tx0dnScnpz08vTMysxsbmyUlpTs6uyEgoSsqqz8/vzU1tTEwsT///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG/kCTcEgsGo/IpHLJbCIbFacU2fEQOtOssKK5AAgN7XH0JAAuhKh42AiEIpljh+CxrIkBwNnDOVbCYyJwTCMhZ2d2UwNnGE0RehcXA1kGCAAiTRIeXhtiHBlkTRwWk3emp6ipqqtNICICGCIKRQ0ZGYCmFpZeFwiJJhkLZwtxdyAPXocACLMVE4cXGrhaDLzQlyYD1l6lYgLXyQLZ4N1aAttnFyEmztAaamLV12cMQsFeCxKmCpbXzGwDBsC7owvSMiysiLgSEEJWwodNKnCYlmSEhAMOBrb6gODBBAihkIyg8OCMhmJNFJiBhikJhG3vnHyYd0EfkgXoHIhCsM1LboAkXa6VIDKChAgRJEIaQKbMS8sjBQwCeGDTRIMNvC5sANTg2bwDSfgZpBASgrIzEIa8NIhGYxEFBTSEgICrUNYzIUI1EGGNQNUsXdkCmDBNQgAGHdxOSYAuAcRsJZMhKJfQQdAJvx43UACCYpMgACH5BAkHACYALAAAAAAoACgAhVxeXLSytIyKjNza3HR2dOzu7MTGxJyenGxqbLy+vOTm5ISChPz6/JSWlNTS1KyqrGRmZLy6vOTi5Hx+fPT29HRydGRiZLS2tJSSlNze3Hx6fPTy9MzKzKSmpGxubMTCxOzq7ISGhPz+/JyanNTW1KyurP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJNwSCwaj8ikcslsOp9QISUQoESvpgDAUjJOF5MGCVvUcosgwnZrCTApDgVyWiWKBJZ13jJOUhYAEAZPEnsAh3kYSiR7C08GeWyIBEqFWw1PDnp6E0sGCyMbTxsem3luZEoJhnkaoqlJDBGlFhYCcrBLGw4GEgy5wMFHGyQkr8JGDAEQeQgBv0MSHR0SwGZrAKgmEghbCNWpBd2bCK8dhh2wJKaHDkLnaw+wmqx57tvdFh7gZOKbAOWiTeOXqgSrbMiKKINwyBm0hESIOTgGsWJCERseQsnw4EACK0sUCEDgIYJGJhciWdBQQAkpRAidDGBY65CiJBFq5qkAkglrPFY9jZTY5IGiCQYgFIgocuCghZZIGMEUsHRIBkAWFmQgsgqmvqpHGMADUGHrkA0VsBE4tkEDNgsJloggESCC0Q968nwgUgAP2QRgr1wwpW0IhQKBsUg11KcigwbYGpxMyOBCCAERglqEFQQAIfkECQcAJQAsAAAAACgAKACFXF5ctLK03NrcjIqMdHZ07O7sxMbEpKKkbGps5ObkhIKE/Pr81NLUvL68nJqcrKqsZGZk5OLklJKUfH589Pb0zM7MZGJkvLq83N7cjI6MfHp89PL0zMrMpKakbG5s7OrshIaE/P781NbUxMLErK6s////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv7AknBILAoTHYWikzA6n9AhB2IBVBGGqDaaoAKsX0hzSyYewNX0ocwuKb5psIJIqRgibeMkHp8LDQhpGRtkIUYHfGBrJSJeglscGhIURF1VYABiQhKXnRhRCxpfWURTcQgcQgsEaGAjUSESVp9FCQdKB3hCIW9xVqlRFBy0bAGtFgiUeWQUCnEQpMvMAROSItJ5IQvY3N3S2t5kBR0TEx2ERRvo3gUacRoFRBceCBfhHccdQxsIXwjr39y1mrCtRAEPVwAuWzDhmAZDQi4g8GDPGz5f+ohsiBeuHRp44aCM06ChA8eQUMChXMmy5a4EGBSK5CACIpsCA6p4GGHziXEAhBYc9NSyIKeVKtdSDvhiJSmZBIkcwHKXJtoWDL4sZNBCAg6Ck6oaKABxoaCQDR7gfAlA9IGGAQKMPEDzoEiDOBNkOgkx1CBCMP+IhBDhYEAAvWw+dLLywaUQCqLSEDDrkkFaZAwcEykwogFYzd2CAAAh+QQJBwAnACwAAAAAKAAoAIVcXly0srTc2tyMiox0dnTExsTs7uycnpxsamy8vrzk5uSUlpTU0tT8+vyEgoSsqqxkZmS8urzk4uSUkpTMzsz09vR0cnRkYmS0trTc3tyMjox8fnzMysz08vSkpqRsbmzEwsTs6uycmpzU1tT8/vyEhoSsrqz///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG/sCTcEgsDg0MisHIbDqJDRPkAoA8Gs9s9gGgXqgmbbaTUWCP0y6ge1mKjYbF9EIoDCledZfzLhoseV8mJCccVGpfABRDURYQAwJPE4FsGScGaXkQHUINE4gQkUyYenoeQlyHXQ9DI3ldJU0Ch5QanQ9eVmcnGIhdEE0SbL4XE0RISkUgvgAWTQ0ExF0JYgYfgWFNIJQXGxVvDAhqE7tMARB6GyF9JyEgGALlTRkPGgsg8uz6+/z9/v9DFESIIAGglgSHIFAj0sGDB04AJWT6UnCIhy+nAEZYQwsDkYsAMv6L4MWLxyENHxqUqKmiQSYR0AFAEOHlEwkRMLi0ybOnZM+fQPdxcEDggJssIDZMOPqGAyIH355k8GKMnQNfDLLg6bJBH4FAdp502DCNCYkQCggVOUDrggItHSjsZLTgywJ5Bq5+WeivAKKwUCgUWAcwAKJsQTOkgWApqBAOJUosckz5ZxAAIfkECQcAIgAsAAAAACgAKACFXF5ctLK0jIqM3NrcnJ6cdHZ07O7sxMbEbGpslJaUrKqs/Pr85ObkfH581NLUZGZklJKUpKak9Pb0ZGJkvL68jI6M3N7cpKKkfHp89PL0zMrMbG5snJqcrK6s/P787OrshIKE1NbU////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv5AkXBILBIXC6NyyTQaLhjMxdCsWg0FgBZQoFq/xssEMCkDLuDlR1HhaDzDRWE8JmOSaaLmQdZWMkIeGFp0AHdEDAEXGnhLDA+FY2hCBJFnRCEIWwmNRgp9fRMPXliFXXGDhRpMFZZkFkMfFwVSH0QffIWTSgl1dGMMRUhGGRuFAB1MB66HX5V9CLZLCwKhAAirYAsRGw8NIVUSF5oTGA55QhkGnU0ZFgzs6FUecPJ5HgcgZSAH9fZNHsSEmnDB378FBgz4WwaK0IF/QgxUePCgghcQA/uAgLiglZkKSY7VIWMwjwFfZKhYKlMmHhgDkMiUodLAFYAGED0I8AVSBHpDaxMeQjQggKIALwFREiwpD2GGTvj0TWhwwCVEJfSuat3KtetWBgMkgJFwYIC9DmUKSAMI4RW6D4U4WJEzRmiaAaEEfNFQAILYPBJSAaCgjamQDwQIrEXEQQAFw3kWYJwAwmpXCeQQ/PVqJMKYCJyXeBgwAHLo06iDAAA7');background-size:100%}}.cssanimations .c-form-control-feedback-throbber,.cssanimations .c-form-throbber:after{background:none;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-webkit-animation:spin 0.75s linear infinite;-o-animation:spin 0.75s linear infinite;animation:spin 0.75s linear infinite;border:2px solid #606060;border-bottom-color:transparent;border-left-color:transparent;border-radius:100%}.c-form-control-feedback-success{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDEzQjBENEY0RTczMTFFNDgxRkFDMDlERTVEN0NFMEMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDEzQjBENTA0RTczMTFFNDgxRkFDMDlERTVEN0NFMEMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowMTNCMEQ0RDRFNzMxMUU0ODFGQUMwOURFNUQ3Q0UwQyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowMTNCMEQ0RTRFNzMxMUU0ODFGQUMwOURFNUQ3Q0UwQyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pinc9p8AAAHFSURBVHjaYvz//z8DOug8GcIGpAKg2BKIpYD4FxA/AeLzQLweiDeWm6/5ha6XEd1AoGGBQKoLiFUY8IM7QFwONHQdVgOBBjEDqTYgLmMgDYAsrwIa/BfEYUGSIMcwBiQ95XAXAl0XAmSvZqAMhAJduYax40QwKALuArEMhQY+BWIlJpDJpBrGzMjCEKxWzmAlHYIsLA3EYSzQpEGSYQGqJQwqgiYMn3+/R5cOALnQlFjDGBmZGHyU88CGnX+1i2HX/dnoSkxABkoQb1gug4awFZJhGJlCkgmaA+BAS8SWwUEuBmQEhmFawrb4DGOApcPnQMwLN1DYhkFZwJiBk4WPYcf9GWAxYg0DmQUy8BIQq8FE1t/qZvAGGqAn6sTAwczN8Of/L7Bhl17vI2QYCJwBGbgBiOHx//f/H4bNdycy/Pz7jcFAzBUsdu3tYahr/xMK6g0s0BzSgZwW////x7Dz/kyG738+M/CzizJsuTsZLEZEwl4Ny3qgxL2KwpwSBsx6q5nAuRrIAFLdFBjWDTWDgQlJsBKIp5Bh2FSoXpwFbDA0TIkpYCtBJQzeEhupCgCFK6j0NoZmfFjAn4VWAauxVQEAAQYANWanlYrZvd8AAAAASUVORK5CYII=');background-repeat:no-repeat}@media only screen and (min-resolution:2dppx),only screen and (-webkit-min-device-pixel-ratio:2){.c-form-control-feedback-success{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAA8FBMVEWIyFP///+IyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFOIyFSJyVWLyVeMyliNylqPy12SzWKd0nGe0nOz3JG94aC/4aK/4aPG5KzL57TO6LjO6bnT68DU68DV7MLW7MTb7srb7svc78zd787g8dLh8dPj8tfk89nm89vn9Nzo9N3p9d/2+/L///8c6ejyAAAALHRSTlMAAAIEBQYKExQVHB43OFZXWFlaeHmHiJWXmJmssbO0ttLT4uPk6+zt7vj5+jjkTi8AAAFzSURBVHjajdVrU4JAGIbhBVQMKTVBIbRQFBVetex8LjvYmf//b1rdadlYFrw/OM5wzTAgPiBpHSLJesNxh+Px0HUauoxoWLFQM3vA1DO1VKi2AkgUtFQe7gwgpUE1ARULBFkKC0sdENYpxVBpQ0ZthUIbMrP/YBVyqhOoDvLgcGsNLcjNXsFKmA/DCoYmCJu/nQHJlJDsid1HFF2Sr56M9EwX3QJJR0a2mwCpgRyBO3pnHTioK3BL7O6pgy7yxe5hCjQfBRs5CGJ4csE5FtJTn/5E1xOhA59ezBc+eDcVOejS23P8jQ8vDgUOHGTEPywGy/nslXPkhm/Hl/CCyecz/njiHOjsQzF7xGjlZpzz5H+P2fSGc/FjJmnsLb9Kd4GGodQCpvNFigOL/Ll8yMlX11Cq5cHdDQdgjy5FMXtSisxIHYjdfomdvYLw7HYhMaS19CGt89NctvhptsrpY9/ss6zf5Mc+fn0YjjsKw5HrGInXxy8kW+V8htKxOgAAAABJRU5ErkJggg==');background-size:100%}}.c-form-control-feedback-error{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MENFNzMxNjI0RTZBMTFFNDgxRkFDMDlERTVEN0NFMEMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MENFNzMxNjM0RTZBMTFFNDgxRkFDMDlERTVEN0NFMEMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowQ0U3MzE2MDRFNkExMUU0ODFGQUMwOURFNUQ3Q0UwQyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowQ0U3MzE2MTRFNkExMUU0ODFGQUMwOURFNUQ3Q0UwQyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Ps7I76YAAAFJSURBVHjaYrzibs+ABbABcQAUWwKxFBD/AuInQHweiNcD8UaoGApgwWJYIBB3AbEKFks0oDgSiO8AcTkQr0NWxITEZgbiTqgCFQbCAKRmLVQPMzYXtgFxGQPpAKanHNmFIfgM09y0E4wJGBoCMxAUNv34VDOxsYMxATABZBbIwFAglmGgHEgDcRgLNGngBX8/fSTW0ACQgaaEVP358IFYA01ABkoQNPDtG2INlGSBpna8If7nI9EuBKfD50DMi0/Rt+tXiTXvOcjAS0Cshk/Vp0MHiDXwDCjZbCCkSnnGPDAmAmwAGbgaWorgDsM3r8GYAHgKMosRWnyBEvcqChN2GMhAWF4GubKbAsO6oWagFF+VQDyFDMOmQvVilId/gTgXWmrcIcKgO9CgyoHqxVligwrNzVDFoNLbGJrxYQF/FloFrMZWBQAEGACBFk1x4OIHEAAAAABJRU5ErkJggg==');background-repeat:no-repeat}@media only screen and (min-resolution:2dppx),only screen and (-webkit-min-device-pixel-ratio:2){.c-form-control-feedback-error{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAw1BMVEXURz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/URz/VSkLVTETZXFXdbmjhf3nhgHrign3lkYznmJPpoJzts7Dut7TxwsD11dP44N/55OP66+r88fD9+Pf++vr///9+tlYRAAAAK3RSTlMAAgQFBgoTFBUcHjc4VldYWVp4eYeIlZeYmayxs7S20tPi4+Tr7O3u+Pn6TsJYOwAAAVFJREFUeNqNlelygkAQhId4BUnUKIpBE7wV1vu+7fd/qlQZU8GdQfx+dnXt1HQNDd1hWEXX6w0GPc8tWgZFYdpNFaJpmySRrvhKw6+kifHeUQKdnGZ7cVQEzguFSNVVJPVU6L2aekDt/82qekiVbuRUDIVbLtq+e2B/r/Rer0Z9YQCQhmeDeGOQJSJbxRuVTWS0njG2DLKUzhk4M9GiEtMOwIGJRXKZtgN2THSpwbQtsGVig7pMWwNrJnbJZ9oKWDHRF4wLYMGNwugpMOWjhWUmwIQvI8QzBsY8HiHw0XI5EgJ/U09hCUcxnM+H/CiEM9sAG+HMyNSTvAAXPcVruVQ09Qgc9Rb4/bi0zGen00xL+1ZBeRXDx5MF8El/JB9XSjJUUt/Rvq8UhUhETq8m6J68XKQFYmQcXs1ORi77cjtsa5dNisKwSq7XD4K+55a038cPcsbXlCLjXwQAAAAASUVORK5CYII=');background-size:100%}}.c-form-control-feedback-error:hover{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDEzQjBENDc0RTczMTFFNDgxRkFDMDlERTVEN0NFMEMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDEzQjBENDg0RTczMTFFNDgxRkFDMDlERTVEN0NFMEMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowQ0U3MzE2NDRFNkExMUU0ODFGQUMwOURFNUQ3Q0UwQyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowMTNCMEQ0NjRFNzMxMUU0ODFGQUMwOURFNUQ3Q0UwQyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PnmyIBwAAAFlSURBVHjaYvz//z8DDOx3tIIx2YA4AIotgVgKiH8B8RMgPg/E64F4I1QMDhz3H2NgYcAEgUDcBcQqaOIgSzSgOBKI7wBxORCvQ1bEhOQ6ZiDVCVWgwkAYgNSshephhgkiu7ANiMsYSAcwPeVwFwJdF4LPMPsd+8GYgKEhYAOBhoHCph+faiZ2djAmACaAzAK5MBSIZRgoB9JAHMYCTRp4we+PH4g1NABkoClBAz8QbaAJyEAJQqp+vnlNrIGSLNDUjjfEfxHvQnA6fA7EvPgUfbp2hVjznoMMvATEavhUvTqwj1gDz4CSzQZCqszmLgZjIsAGkIGroaUI7kh5/QqMCYCnILMYQcUXMIWDEvcqChN2GLD4Ws0ELcdAruymwLBuqE8RxRcQVALxFDIMmwrVi1oeAl35F0jlQkuNO0QYdAdaDuQA8V9s5SEMgArNzVDFoNLbGJrxYQF/FloFrEavAkAAIMAAA5hfgl/QBoUAAAAASUVORK5CYII=');background-repeat:no-repeat}@media only screen and (min-resolution:2dppx),only screen and (-webkit-min-device-pixel-ratio:2){.c-form-control-feedback-error:hover{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAxlBMVEW+QDn///++QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm+QDm/QzzART7FVlDMaGPSenXSe3bTfXnYjIjblJDdnJnksK3mtLHqwL7w1NL039724+L46un68O/8+Pf9+vr///8XCyvZAAAALHRSTlMAAAIEBQYKExQVHB43OFZXWFlaeHmHiJWXmJmssbO0ttLT4uPk6+zt7vj5+jjkTi8AAAFeSURBVHgBjZVrD5pAEEUXULFIq1ZRLNriW2F8v9/e//+nampqt7OLeD6Sk0zmZvYijBdCCNOtBOFwPB6GQcU1DRlZdLwOSXQ8Ryva9YgYUd1WxW990tAvMtHyKQHfksVcixJp5f6JVpPe0LReYoPe0vgrFimF8lO02b4n4ET/MfzyR+QL44E6XBiFOF2MCw/Ro3SRPEOY3U/Erilc4tyAG3FcUSXOGTgTpyIC4hyBI3EC0SbOATgQpy0GxNkBO+IMREScLbAlTqQR18BaI6qjF8BCM1pdZg7MNcuo8cyAmSYeNfDpZjPVBP6VPsLVHMVktZpojkI9sz2w15yZ4fAk78Cdp+g8RKPOvl6AC2+B5+NimS+v1yVL234+1xKl8P3DAvjxaors+0rJSiX1ixL5mZNrL5M4vZFhRVrSF2lZrea8r1azn9eXfa1HEr2aXPb891ENwlEcj8Kgyn4fvwFfDN3MnP/SlwAAAABJRU5ErkJggg==');background-size:100%}}.c-form-control-feedback-error:hover+.c-tooltip .tooltip-inner{background-color:#bf4039}.c-form-control-feedback-error:hover+.c-tooltip.right .tooltip-arrow{border-right-color:#bf4039}.c-form-control-feedback-error:hover+.c-tooltip.left .tooltip-arrow{border-left-color:#bf4039}.c-form-control-feedback-error:hover+.c-tooltip.top-right .tooltip-arrow,.c-form-control-feedback-error:hover+.c-tooltip.top .tooltip-arrow{border-top-color:#bf4039}.c-form-control-feedback-error:hover+.c-tooltip.bottom .tooltip-arrow{border-bottom-color:#bf4039}.c-has-throbber .c-form-control-feedback-throbber,.c-has-success .c-form-control-feedback-success,.c-has-error .c-form-control-feedback-error{display:block}.c-form-throbber{display:none;float:right;padding:5px 0;margin-right:-25px}.c-form-throbber:after{content:'';height:20px;width:20px;display:block}.working .c-form-throbber{display:block}.c-alert{padding:15px;margin:8px 0 19px;border:1px solid transparent;border-radius:2px}.c-alert-danger{background-color:#f9e7e6;border-color:#f7dfdd;color:#b73129!important}.strength-meter{background-color:#efefef;border-radius:5px;display:none;position:absolute;right:5px;top:50%;margin-top:-4px;width:50px;height:8px;overflow:hidden;pointer-events:none}.c-has-feedback .strength-meter{display:block}.strength-meter-fill{height:100%;width:0}.c-has-success .strength-meter-fill{background-color:#6ec02a}.c-has-error .strength-meter-fill{background-color:#d4473f}.c-has-throbber .strength-meter-fill{background-color:#606060}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:9999;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform 0.3s ease-out;-moz-transition:-moz-transform 0.3s ease-out;-o-transition:-o-transform 0.3s ease-out;transition:transform 0.3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}@media (min-width:768px){.modal-dialog{width:728px;margin:30px auto}}.modal-content{position:relative;background-color:#f8fbfd;border-radius:5px;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:3px 3px 13px rgba(0,0,0,0.35);box-shadow:3px 3px 13px rgba(0,0,0,0.35);background-clip:padding-box;outline:0}@media (min-width:768px){.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#000000;z-index:9998}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:0.5;filter:alpha(opacity=50)}.modal-header{position:absolute;top:12px;right:12px}.modal-title{color:#4270a2;display:block}h1.modal-title,h2.modal-title,h3.modal-title{font-size:18px;font-weight:normal;margin:12px 0 18px}h4.modal-title,h5.modal-title,h6.modal-title{font-size:12px;font-weight:bold;margin:4px 0 6px;text-transform:uppercase}.modal-body{padding:60px}.modal-footer{background:#e9f0f7;border-bottom-left-radius:5px;border-bottom-right-radius:5px;border-top:1px solid #e9eef1}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}.c-close{display:block;width:12px;height:12px;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RUE3QUNEMDM0RTc2MTFFNDgxRkFDMDlERTVEN0NFMEMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RUE3QUNEMDQ0RTc2MTFFNDgxRkFDMDlERTVEN0NFMEMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFQTdBQ0QwMTRFNzYxMUU0ODFGQUMwOURFNUQ3Q0UwQyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFQTdBQ0QwMjRFNzYxMUU0ODFGQUMwOURFNUQ3Q0UwQyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PpbI1BoAAADYSURBVHjarJQxCsMwDEWVaOrSIUupaeccIOfImjlHy9LFa89h6NYTlGwdupRulUABF+L4G/pBxI6sh2U+qrquOxBRL+FDCC8qkNTu5TNIXGuDnCRGS5RARqvtFeQlnhINCosgjdV6nuf545y7y6a1RKt7/Q9CJn0S1iQKS0E0x8uhHGwLoqqQq1sqCVkFJWC0BflpLdZKm7stiKqmP4nB1t45azD42LecNRjxCeIzRsyG+IwRCAJjFJKD1TZPIMgiOzNFU2NgoT1kcZS4lAy26GZnHWxfAQYAJpi61uKKvAUAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:100% 100%}@media only screen and (min-resolution:2dppx),only screen and (-webkit-min-device-pixel-ratio:2){.c-close{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAFVBMVEUAAAAzMzMzMzMzMzMzMzMzMzMzMzO27Uu7AAAAB3RSTlMAAS5KTH+AKP+CfAAAAGhJREFUeNrt1MsKQCEIRVEf5f9/co6cHNg4vXCbRLVIEdHMMwxWpLc5dQPMreOWVa3AVGVvoOZRlRpValSp0aMaUHy1/5zTBMNF4fKCGkNqDCkxqtAw4nCcOJv4e/UjvboaPashthqHD8GQB/lQzhwAAAAAAElFTkSuQmCC');background-size:100%}}.c-close:hover{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABHNCSVQICAgIfAhkiAAAAGJ6VFh0UmF3IHByb2ZpbGUgdHlwZSBBUFAxAAB4nFXIsQ2AMAwAwd5TeIR3HBwyDkIBRUKAsn9BAQ1XnuztbKOveo9r60cTVVVVz5JrrmkBZl4GbhgJKF8t/ExEDQ8rHgYgD0i2FMl6UPBzAAAA60lEQVQ4ja3SMQ7CMAwF0O+6Q+IhQxgqxMABYOQAnIiJUyAmxJWYOAIzI1k6ZGlSpi5V2xgJj7b1ZH2Zm6bZGWOu1tpnjLHFD+W934jI3Tn3YmPMteu6LREdReShxbz3m77vbymlNYA9W2ufRHTMOa+02IDknFdVVX0AnDnG2IrIQ4uNESI6hRDeDABabA4BAB6WStgSAgCkOR0AlpBJaCZMLCGz0BgDgCUEAKo56NfiqeZETrH0Gn8Lm0tICOGt+TMuIcO8hLEG0WCkRUoRsIjcU0prLTJ1GTMf2Dn3ArAHcNYgY4yZD3VdX76jYUTZ7/1DYgAAAABJRU5ErkJggg==');background-repeat:no-repeat}@media only screen and (min-resolution:2dppx),only screen and (-webkit-min-device-pixel-ratio:2){.c-close:hover{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAMAAADW3miqAAAAFVBMVEUAAAAAAAAfHx8eHh4gICAcHBweHh7Gc8KcAAAAB3RSTlMAAUFlZ5+gmsSnrQAAAGhJREFUeNrt1MsKQCEIRVEf5f9/co6cHNg4vXCbRLVIEdHMMwxWpLc5dQPMreOWVa3AVGVvoOZRlRpValSp0aMaUHy1/5zTBMNF4fKCGkNqDCkxqtAw4nCcOJv4e/UjvboaPashthqHD8GQB/lQzhwAAAAAAElFTkSuQmCC');background-size:100%}}.c-toggle:after{content:' [+]';font-family:monospace;font-size:10px;vertical-align:1px}.c-toggle.c-toggle-toggled:after{content:' [-]'}.c-toggle-content{display:none}.c-toggle-content.c-toggle-content-toggled{display:block}.read-next-container{font-size:small}.read-next{font-size:0.9230769230769231em;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none;background:#ffffff;border:1px solid #d9d9d9;box-sizing:border-box;color:#222222;display:none;height:100px;position:relative;width:300px;z-index:9998}.read-next.active{display:block}.read-next.fixed{border-bottom-width:0;bottom:0;position:fixed}.read-next .read-next-header{background-color:#eff7ff;border-bottom:1px solid #d6eaff;color:#808080;padding-left:10px;padding-right:10px;padding-top:5px}.read-next .read-next-header-title{font-size:1em;line-height:1.6666666666666667em;margin-left:40px;position:relative;top:-2px}.read-next .read-next-title{font-size:1em;line-height:1.25em;display:block;max-height:45px;overflow:hidden;text-overflow:ellipsis}.read-next .read-next-nav{font-size:0.8333333333333334em;line-height:1.5em;position:absolute;top:5px}.read-next .read-next-nav-right{right:5px}.read-next .read-next-nav-right>*{margin-left:5px}.read-next .read-next-nav-left{left:5px}.read-next .read-next-nav-left>*{margin-right:5px}.read-next .read-next-dismiss,.read-next .read-next-button{transform:scale(1,1) translateY(0px);-webkit-transform:scale(1,1) translateY(0px);-moz-transform:scale(1,1) translateY(0px);-o-transform:scale(1,1) translateY(0px);-ms-transform:scale(1,1) translateY(0px);-webkit-transition:all 0.2s ease 0s;-moz-transition:all 0.2s ease 0s;-o-transition:all 0.2s ease 0s;-ms-transition:all 0.2s ease 0s;transition:all 0.2s ease 0s;cursor:pointer;display:inline-block;height:15px;position:relative;text-align:center;width:15px}.read-next .read-next-dismiss:active,.read-next .read-next-button:active{transform:scale(1.01,1.01) translateY(1px);-webkit-transform:scale(1.01,1.01) translateY(1px);-moz-transform:scale(1.01,1.01) translateY(1px);-o-transform:scale(1.01,1.01) translateY(1px);-ms-transform:scale(1.01,1.01) translateY(1px)}.read-next .read-next-button{background-color:#3973ac;border-radius:50%;color:#ffffff}.read-next .read-next-button:active{background-color:#336699}.read-next .read-next-list{padding:10px;padding-top:5px}.read-next .read-next-link{display:none;float:left;height:60px;overflow:hidden;width:100%}.read-next .read-next-link.active{display:block}.read-next .read-next-link .read-next-thumbnail{display:block;float:left;height:45px;margin-right:5px;margin-top:3px;width:45px}.read-next .read-next-link .read-next-thumbnail img{height:auto;width:100%}.read-next .read-next-meta{font-size:0.8333333333333334em;line-height:1.5em;color:#808080}.md-container{font-size:small}.md{color:#222222;max-width:60em;overflow-wrap:break-word;word-wrap:break-word}.md .-headers,.md h1,.md h2,.md h3,.md h4,.md h5,.md h6{border:0;color:inherit;-webkit-font-smoothing:antialiased}.md .-headers code,.md h1 code,.md h2 code,.md h3 code,.md h4 code,.md h5 code,.md h6 code{font-size:inherit}.md blockquote,.md del{color:#4f4f4f}.md a{color:#0079d3;text-decoration:none}.md h6{text-decoration:underline}.md em{font-style:italic;font-weight:inherit}.md th,.md strong,.md .-headers,.md h1,.md h2,.md h3,.md h4,.md h5,.md h6{font-weight:600;font-style:inherit}.md h2,.md h4{font-weight:500}.md,.md h6{font-weight:400}.md *{margin-left:0;margin-right:0}.md tr,.md code,.md .-cells,.md .-lists,.md .-blocks,.md .-headers,.md h1,.md h2,.md h3,.md h4,.md h5,.md h6,.md th,.md td,.md ul,.md ol,.md .-lists,.md pre,.md blockquote,.md table,.md p,.md ul,.md ol{margin:0;padding:0}.md hr{border:0;color:transparent;background:#c5c1ad;height:2px;padding:0}.md blockquote{border-left:2px solid #c5c1ad}.md code,.md pre{border:1px solid #eeeed2;background-color:#fcfcf7;border-radius:2px}.md code{margin:0 2px;white-space:nowrap;word-break:normal}.md p code{line-height:1em}.md pre{overflow:auto}.md pre code{white-space:pre;background-color:transparent;border:0;display:block;padding:0!important}.md td,.md th{border:1px solid #e5e3da;text-align:left}.md td[align=center],.md th[align=center]{text-align:center}.md td[align=right],.md th[align=right]{text-align:right}.md img{max-width:100%}.md ul{list-style-type:disc}.md ol{list-style-type:decimal}.md blockquote{padding:0 8px;margin-left:5px}.md code{padding:0 4px}.md pre,.md .-cells,.md th,.md td{padding:4px 9px}.md .-lists,.md ul,.md ol{padding-left:40px}.md sup{font-size:0.86em;line-height:0}.md li li,.md li p{font-size:1em!important}.link .usertext .md{padding:5px 10px}.new-comment .md :not(pre)>code,.link .md :not(pre)>code,.usertext.border .md :not(pre)>code,.new-comment .md pre,.link .md pre,.usertext.border .md pre{background-color:#ffffff}.linklisting .md,.commentarea .md{margin-top:5px;margin-bottom:5px}textarea{background-color:white;color:black}code{font-family:monospace,monospace}.md{font-size:1.0769230769230769em}.md h1,.md h2{font-size:1.2857142857142858em;line-height:1.3888888888888888em;margin-top:0.8333333333333334em;margin-bottom:0.8333333333333334em}.md h3,.md h4{font-size:1.1428571428571428em;line-height:1.25em;margin-top:0.625em;margin-bottom:0.625em}.md h5,.md h6{font-size:1em;line-height:1.4285714285714286em;margin-top:0.7142857142857143em;margin-bottom:0.35714285714285715em}.md .-blocks,.md .-lists,.md pre,.md blockquote,.md table,.md p,.md ul,.md ol{margin-top:0.35714285714285715em;margin-bottom:0.35714285714285715em}.md textarea,.md .-text,.md p,.md pre>code,.md th,.md td,.md li{font-size:1em;line-height:1.4285714285714286em}.md-small,.side .md{font-size:0.9230769230769231em}.md-small h1,.side .md h1,.md-small h2,.side .md h2{font-size:1.5em;line-height:1.3888888888888888em;margin-top:0.5555555555555556em;margin-bottom:0.5555555555555556em}.md-small h3,.side .md h3,.md-small h4,.side .md h4{font-size:1.3333333333333333em;line-height:1.25em;margin-top:0.625em;margin-bottom:0.625em}.md-small h5,.side .md h5,.md-small h6,.side .md h6{font-size:1.1666666666666667em;line-height:1.4285714285714286em;margin-top:0.7142857142857143em;margin-bottom:0.35714285714285715em}.md-small .-blocks,.side .md .-blocks,.side .md .-lists,.side .md pre,.side .md blockquote,.side .md table,.side .md p,.side .md ul,.side .md ol{margin-top:0.4166666666666667em;margin-bottom:0.4166666666666667em}.md-small .-text,.side .md .-text,.side .md p,.side .md pre>code,.side .md th,.side .md td,.side .md li{font-size:1em;line-height:1.25em}.wiki-page-content .md h1{font-size:2.2857142857142856em;line-height:1.25em;margin-top:1.25em;margin-bottom:0.78125em}.wiki-page-content .md h2{font-size:1.7142857142857142em;line-height:1.25em;margin-top:1.25em;margin-bottom:0.625em}.wiki-page-content .md h3{font-size:1.4285714285714286em;line-height:1.25em;margin-top:1em;margin-bottom:0.5em}.wiki-page-content .md .-blocks,.wiki-page-content .md .-lists,.wiki-page-content .md pre,.wiki-page-content .md blockquote,.wiki-page-content .md table,.wiki-page-content .md p,.wiki-page-content .md ul,.wiki-page-content .md ol{margin-top:0.35714285714285715em;margin-bottom:0.7142857142857143em}.wiki-page-content .md h1,.wiki-page-content .md h6{color:#4f4f4f;font-weight:300}.wiki-page-content .md h2{color:#336699}.wiki-page-content .md h2,.wiki-page-content .md h3{font-weight:600}.wiki-page-content .md h4{font-style:italic}.wiki-page-content .md h5{text-decoration:underline}.wiki-page-content .md h4,.wiki-page-content .md h5{font-weight:400}.wiki-page-content .md h6{font-size:1em;line-height:1.4285714285714286em;margin-top:1.0714285714285714em;margin-bottom:0.35714285714285715em;text-decoration:none;text-transform:uppercase;letter-spacing:1px}.md>:first-child,.md .-cells>:first-child,.md .-lists>:first-child,.md .-blocks>:first-child,.md .-headers>:first-child,.md h1>:first-child,.md h2>:first-child,.md h3>:first-child,.md h4>:first-child,.md h5>:first-child,.md h6>:first-child,.md th>:first-child,.md td>:first-child,.md ul>:first-child,.md ol>:first-child,.md .-lists>:first-child,.md pre>:first-child,.md blockquote>:first-child,.md table>:first-child,.md p>:first-child,.md ul>:first-child,.md ol>:first-child{margin-top:0}.md>:last-child,.md .-cells>:last-child,.md .-lists>:last-child,.md .-blocks>:last-child,.md .-headers>:last-child,.md h1>:last-child,.md h2>:last-child,.md h3>:last-child,.md h4>:last-child,.md h5>:last-child,.md h6>:last-child,.md th>:last-child,.md td>:last-child,.md ul>:last-child,.md ol>:last-child,.md .-lists>:last-child,.md pre>:last-child,.md blockquote>:last-child,.md table>:last-child,.md p>:last-child,.md ul>:last-child,.md ol>:last-child{margin-bottom:0}.combined-search-page>.content{font-size:small}.combined-search-page .search-result-listing{font-size:0.9230769230769231em}.combined-search-page .search-result.visited .search-title,.combined-search-page .search-result.visited .search-link,.combined-search-page .search-result.visited .search-title>mark,.combined-search-page .search-result.visited .search-link>mark{color:#551a8b}.combined-search-page .search-result{margin-bottom:25px;margin-top:10px}.combined-search-page .search-result a,.combined-search-page .search-result a>mark{color:#006aba}.combined-search-page .search-result a:visited,.combined-search-page .search-result a:visited>mark{color:#551a8b}.combined-search-page .search-result.has-thumbnail{display:-webkit-flex;display:flex}.combined-search-page .search-result.has-thumbnail>*{-webkit-flex:1 1;flex:1 1}.combined-search-page .search-result.has-thumbnail>.thumbnail{-webkit-flex:0 0 70px;flex:0 0 70px;margin-right:10px;width:70px}.combined-search-page .search-result.has-thumbnail>.thumbnail img{display:block;height:auto;width:100%}.combined-search-page .search-result .search-result-meta,.combined-search-page .search-result .search-result-footer{font-size:1em;line-height:1.6666666666666667em;vertical-align:baseline}.combined-search-page .search-result .search-result-meta>*,.combined-search-page .search-result .search-result-footer>*{line-height:1em}.combined-search-page .search-result .search-result-header{font-size:1em;line-height:1.6666666666666667em}.combined-search-page .search-result .search-result-header *{vertical-align:top}.combined-search-page .search-result .search-result-header .search-title{font-size:16px;margin-right:5px}.combined-search-page .search-result .search-result-header .search-subreddit-link{color:#808080;display:inline-block;margin-bottom:0}.combined-search-page .search-result .search-result-meta{font-size:0.8333333333333334em;line-height:2em;color:#808080}.combined-search-page .search-result .search-result-meta .search-result-icon{vertical-align:text-bottom}.combined-search-page .search-result .search-score{font-size:1.2em;line-height:1em}.combined-search-page .search-result .search-score:after{content:' •'}.combined-search-page .search-result .search-comments{font-weight:bold;color:#808080}.combined-search-page .search-result .search-result-body{font-size:1em;line-height:1.25em;color:#4f4f4f;padding-right:40px}.combined-search-page .search-result .search-expando{overflow:hidden}.combined-search-page .search-result .search-expando.collapsed{max-height:45px;position:relative}.combined-search-page .search-result .search-expando.collapsed:before{bottom:0;content:'';height:15px;left:0;position:absolute;width:100%;background:rgba(255,255,255,0);background:-moz-linear-gradient(top,rgba(255,255,255,0) 0%,#ffffff 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,rgba(255,255,255,0)),color-stop(100%,#ffffff));background:-webkit-linear-gradient(top,rgba(255,255,255,0) 0%,#ffffff 100%);background:-o-linear-gradient(top,rgba(255,255,255,0) 0%,#ffffff 100%);background:-ms-linear-gradient(top,rgba(255,255,255,0) 0%,#ffffff 100%);background:linear-gradient(to bottom,rgba(255,255,255,0) 0%,#ffffff 100%)}.combined-search-page .search-result .search-expando-button{color:#006aba}.combined-search-page .search-result .search-expando-button:hover{cursor:pointer;text-decoration:underline}.combined-search-page .search-result .search-expando-button>span{display:none}.combined-search-page .search-result .search-expando-button.expanded .search-expando-button-label-expanded,.combined-search-page .search-result .search-expando-button.collapsed .search-expando-button-label-collapsed{display:inline}.combined-search-page .search-result .search-result-footer{font-size:1em;line-height:1.6666666666666667em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.combined-search-page .search-result .search-result-footer .search-link{margin-left:5px}.combined-search-page .search-result mark{background-color:transparent;color:inherit;font-weight:bold}.combined-search-page .search-result-subreddit .search-subscribe-button{display:inline-block;margin:0;margin-right:5px}.combined-search-page .search-result-subreddit .search-subscribe-button .remove{background:#b7001f;border-color:#840016}.combined-search-page .search-result-subreddit .search-subscribe-button .remove:active{background:#840016}.combined-search-page .search-result-subreddit .search-subscribe-button .add{background:#63b92b;border-color:#4d8f22}.combined-search-page .search-result-subreddit .search-subscribe-button .add:active{background:#4d8f22}.combined-search-page .search-result-subreddit .search-subscribe-button .add,.combined-search-page .search-result-subreddit .search-subscribe-button .remove{color:#ffffff;text-align:center;transform:scale(1,1);transition:all 0.15s;width:90px}.combined-search-page .search-result-subreddit .search-subscribe-button .add:focus,.combined-search-page .search-result-subreddit .search-subscribe-button .remove:focus{outline:none;box-shadow:0 0 0 1px #ffffff inset}.combined-search-page .search-result-subreddit .search-subscribe-button .add.active,.combined-search-page .search-result-subreddit .search-subscribe-button .remove.active{display:inline-block;line-height:13px}.combined-search-page .search-result-group{max-width:750px;min-width:600px;padding-left:30px;padding-right:20px}.combined-search-page .search-result-group .search-result-group-header{border-bottom:2px solid #e5e3da;color:#808080;margin-bottom:20px;margin-top:30px}.combined-search-page .search-result-group .search-header-label{font-size:1.1666666666666667em;line-height:1.4285714285714286em;font-weight:bold}.combined-search-page .search-result-group .search-header-menus{float:right}.combined-search-page .search-result-group .search-menu{font-size:1em;line-height:1.6666666666666667em;display:inline-block;margin-left:20px}.combined-search-page .search-result-group footer .nav-buttons{font-size:1em;line-height:1.6666666666666667em;margin-top:10px;margin-bottom:30px}.combined-search-page .search-result-group footer .nav-buttons *{font-size:inherit}.combined-search-page .search-result-group footer .info{color:#808080}.combined-search-page .author{margin-right:0}.combined-search-page .search-result-icon{background-position:center;background-repeat:no-repeat;display:inline-block;height:15px;vertical-align:middle;width:16px}.combined-search-page .search-result-icon-score{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAYAAABh2p9gAAAAAXNSR0IArs4c6QAAAgNJREFUSA3tVb9LAlEcvztFAm1ya3RoaWiqTQwCQYgg9QaDKJqStgrqn6i1tpBAB3+0CA0RJG41NdjQ4OjmdA4ievb5HJ6+O089rbYePN73x+f74fPuvfs+SXIxCoXCFacLqCTPAoHoRFGUW+J0XU8nk8m7aTVTCYvF4j6KH2RZVkjS7/d1LAeJRCJL32lMJMzn8zsej+cRRV5bYbfX6+2pqlq2xQ3XkRBkW9jmE5QtORVBaRvbj4H01Z4fI8Q2N0D0AuCyHWzzNRBvY/vvYtxCiANYg7IKAEERNMVuQmkEB1UzMUNCKAtBWRWJFTPpcm1AaRhK68Qbp5fL5UjyjDkvGTmM2gGHJGcymWAgEKhA3Rqziw6orLVarYjX7/cfg+wTRJziWIezKgYE+wv2h+BL4JAMLjEo2qVS6Rr+mRgT7Jt4PH4u+EPT+IZD7xeMf8Kff0QZp3kBmk0HqrmuzaD+zatp2j0u9tGcF5v303JHBxc7bfzL/G18Pl8VpCEHpTNDIKt3Op1wKpVq/E1zoAR2C7SiKMzmTEkjANtX1Ow0DFsuNvsa5McQ10Y1Ey022JjYC4m0EDLADow3YxfgNn2nwRwxxNrzY4QE8K3AVlSYXXsBY8w5vSfEOhIygYIylBxi8uk0Bm3GmDNj9nUiIYHYUhYEp2YRbcZMf+EVf9MlpxuCb2Tm3PaPmEoTAAAAAElFTkSuQmCC');background-size:10px 14px}.combined-search-page .search-result-icon-external{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAOCAYAAAA45qw5AAAAAXNSR0IArs4c6QAAAnhJREFUOBGVVE1IlFEUPfczmWaMyJpFkNK0ilnoEC4MXbXox0XtsoUK0cKCKIgMp59dVJqCtAj6gWhRLXSX0O+ilUJQDU4LLZAmMqiwFEmnmua7nTc/7/s239g8GDj3nHvufe+b967Av5KpGKTmHBS7SW+BSK1P/gnoe2qjmJ0ZwVjnn4J24lEIkcZeODjEOM7fRutRzRF/huA5NH8ZAzsyZU3KAP1vu2m+zni95YKAagpurgtXW6bRn74ARy4Gpfr4Jbg4jsGme4YrNk6mu3i6AuFLrAxVF5CVONxPi6hrmKJ/e2VDSVXtxkDzfcHpV1HUhqa5hajPOMFPOgm4K5YT2cx97mO81XKqYyzSiWS6l9p5iI5Ddd7qcCKs28a43XKKeeR+x4WfeIifuM8Krh7DYPNNG/tB31Qd1sgDnu6ApfP5VnxbSKM+JBhpy1reD/rTR/l33LCUi2GHu+ywhOrDwKYmaTixDMkeIeJFKy2npgN3d/0KbGrSzEEU42WL6ekwiFlC8cziIHCl9Ttv92tP1piHKyDVpz41ZhpXvxQfrEmwzeIqgGmcsfmCPRZXBOJ5IC04+3JTxXQjiuz15WQcqDy2hLk05iIErVOTYRx+sRZu3vMA66DhOzAXL2iZmoL9VmbPap5TlJukWS/xCd3iExrlKQ7aYsBHak/4nL54XKXnZLKqGSCq77A8l4DTuAFh5fuXeq/Rf6DSACleLk4SjrMe2pZWtZoJFWk4g2tNXzk223nC1KqeYoIZmT1mapnQu9VmhurfBD/XbRbL8GcGvH/9YDBB80mszA0VBDOrZ2d2MjdJ3xty3vs2CaaGqVWoydqlOW2kf1x25XNDvWyhAAAAAElFTkSuQmCC');background-size:15px 7px}.combined-search-page .search-result-icon-filter{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAYCAYAAAD+vg1LAAAAAXNSR0IArs4c6QAAAthJREFUSA2dlV1IVEEUx/8zq65aoCRUFFSCoEG6uBFFbwU99CGEgeVD0RdB0pdp7QZFCoGuRFpiQUqQPRgFShQI9VA9VJCWrUtmkBJEPWRGiEbq7pzOnbuX3fDeuu2FnY9z/uc35547Myvg9qkZLEIGqkDYyCErIMQ09x9AqhdTsTa0+seSUSJ54jgOhA9DyGYIeB00E1BUi1BJu+X/NzgY6WTgbh1ACAN0k7McgkQ6lPRz5gfYv8z0q3o0+uqM8d/BwfBBzrSdX58gKIQX4+fwZENUQ6wm0J8DmXGdURXapGg7Z37PGVz9Zim88i1nlAOoajT4WiyWbR8YvAEp9oHoC0aG86WtyDB6ZY2GEr1CQ88VR53lmJms5ff6xjFLUFBY6QwWotyMobNAnbLiHfvm9d+5/he1n8RWe/CJgVwWLGdhFFOfHzvC5jjUQ20SYp09OEss1ALCV7RuMfaru2c2+ikuzLEHR6MxLRAi0x0xrvKkm3oijz344yivzGUAFuB4ZJF7uFwZ147ag+9WzLDgqRZlY6drsKRdppae2YMNL9G1uKjeVdZnwmt5q+3VMaRuOYNH3t9n+BSfqFxkoQOH+rPNhWzaUy8Xs66DPZL3cidCpc+dwQVFlziDeRojsA153j7URkrmYAODm+HJ5DtErOLXHIP4edLQ2B/pYOQ8e+rmQAwDoY+bIfan88zPiCKtIxrl712OkJ8XsQMHw1V88bRpsdlM8l1xBCR3MKwsyZ4YEvXgV2w/Wkp/WMY/Mw5EKrhKXey0SjSDGJehqfiRDgi89gFpZbxAPv+MvT6M2Gwvmla/s4BWnwCfjmyCBw/YkRF3KihUIlR8xxL/T29mFhxYw9DuJCiXUR1NFWokkAbjvwyil8fzDYN+iD9co++qNU2l5z8YcZnrlZcIpjY0Ftcn5qmNJEMLk0Jvo6H7WNI85SGfFHWBoyf4lHVhfHqPq0vdxXK/Aa582Np22kTuAAAAAElFTkSuQmCC');background-size:11px 12px}.combined-search-page .search-result-icon-internal{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAUCAYAAACJfM0wAAAAAXNSR0IArs4c6QAAAm5JREFUOBGNVD1oU1EU/u5rYyoWUbK4iLvQuoqCJloQCViEVhwEQZzcFGNaRBxrbHUUh4JVXCSDdqiiKK0ORR0TKA66OLkExVYxjb7jd+5LbvJe7hPPkvO+853vnvvzxWC6LvCFyEt8b5zEncKGr4wLy8PYnnsMY8Z89cAHQvAInz4UU0W1SRdUjnI9kSIcPkX11KaHH4eUI+R6wi9sggVM1y55+HFIOcr1RCQs8geQ165uYABzi+IVhyUTWyPHcttFwQqsFqDCvxBiAjOjBZ7XbLzfXMFUbQH55UGHa64YWOsN7b0xUrBa1DQo1w6hMvrGcXR7Yubik8gSvjQmsDNrkB2u8iUUHV84jpHLHOy2w6jJLXuiXD+DQO5xqmhSCe+i1bqGTHaRCx5wHSItDnEOlZGHDmsnfmEtlmvHKVLl2c9xe/MYCJ4T3dvuIyw/OOskd/vMYT1JurCSSu93IRzagS3mBb92uz5BAyYsYmbfO4clku6lJAr2czC7h1tdYp5zZcFntOQYguY3h3kS/ztWoh6FmFc8jq4osIYwPIiMnMbA0EfL8Ygq5BfWyzPgRZltrk+wis3mYXZcpSmu25pylOuJfmHrJjxgY8bxhc+tuT6Gxjr/kEz3rJVjyPW4NH55kZsSD1/u423jPFYKv+1CapD9uXkufNYtbBO5ybdc7mCRcBo5clN8oajTYKpe4bSljlCk3R3C4OLq1v9yU0yh/ZHm0ubGJFeuPeG2xl3fP9zkOL1J0qVaE1nUy8trbiNy07jPoh1K36/aOcQJqv3sqeUD2rLEFb4SXOOfydE0i/Y09afW1nLEaqgWNf8CYx309EqyIbgAAAAASUVORK5CYII=');background-size:11px 10px}.combined-search-page .searchfacets{font-size:1em;line-height:1.6666666666666667em;border:1px solid #808080;margin:0;margin-left:30px;margin-top:20px;max-width:750px;min-width:600px;overflow:auto;padding:15px;white-space:pre-wrap}.combined-search-page .searchfacets>h4.title{color:#808080;margin-bottom:5px}.combined-search-page .searchfacets .facet:hover{text-decoration:underline}.combined-search-page li.searchfacet{display:inline-block;line-height:20px;min-width:32%}.combined-search-page .facet.count{color:#808080}.combined-search-page .facet.count:hover{text-decoration:none}.combined-search-page .searchpane{background:none;border:none;padding:10px;padding-left:30px}.combined-search-page #search{padding-right:120px}.combined-search-page #search input[type=text]{font-size:1.1666666666666667em;line-height:1.4285714285714286em;border-color:#808080;border-radius:2px;box-sizing:border-box;max-width:750px;min-width:375px;padding:5px;padding-left:10px;padding-right:25px;vertical-align:middle;width:100%}.combined-search-page .search-submit-button{margin-left:10px;font-size:1em;line-height:1.6666666666666667em;padding:5px 15px;vertical-align:middle}.combined-search-page .menuarea{font-size:1em;margin-left:20px}.combined-search-page .linkflairlabel{line-height:17px}.combined-search-page .stamp{text-transform:uppercase}.combined-search-page .searchfacets{background:transparent;box-shadow:none}.combined-search-page .searchfacets .list{margin:0}.combined-search-page .facet.count{font-weight:normal}.combined-search-page .search-icon{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAA5pJREFUWAnNmU1IVUEUx32aVMQrCyP7sCQTqQiJIsIWkRnRB7WPFi1a5CpatWpRm2grrQqiCNr0tYnAwoUIbfqOIiM0DPEjtLKyMtPX75RXj/Pu3Dfz3tXXgT9z5sw5//l373hn5pUocLBUKrWEtJ3j2EqbBHNAMegAL0EruJ5IJAZpZ8YQVgEugd/AxX6QdBWsmlaFTFAEzoFfIBv7TtEpUBi7UEhLQBOwWT8DT0EzeA4GgM3uMCDLIR6DTMS9DplNRJwBNWEzEd8EzoJBYNojAvPC6rxikBSCuyY7/UZQ4kJGXim4CEy7TSC31w3BaYP1J/3DLsLMHOqOgRGD74SZ59yHaDkQQdqyEhdMClGDJsOX1y+fK3+j8LxB1ujPkl4B5+WceSFYBPTT+0jfac2lS5oagacMfAOBCffsqVnRPVm4O4AuamQ3+Bxd5jYKTy+ZF1T2Qvz9qp/RFYF1RtZNo59r1+Tb5kXII38WPH/abq9ih2Q45fOlv4/NDmUTKfIE5bEH1hk4cbW85jG4uhRfpfIzuiJQTiWB9QVOzK3mLfLhNgXO9yn2yNW8CY+6AhHYowqWKT9OV/Pq+TLOIQJfqawqFvRi1c/Zha8CkqWKSM+nwuGuCHyshqS/T/XjcA8YJA+NfnSXf2El0PaEjtc6sc0AzyzwRpGP4pfZ8q1xih4oEnEPWZM9BuCRU422ex7lk6kw7NYs+J9A1WSGv0f9BqD3YbqpWn+m8QqKzcNqG7HybAipk2XzDmjL7ukFAmAqB72aEb8HeO2d5NcDubeYNkzA66AQaJtoIagFQqRtjM41sG4iMcRhvAbcAlEm3HtDyq2htL9WCOSCLieQBSFVbcRks5e9dQCUAlkGu8Aa4GLDJB1kj25ySQ7NQeR6EHa7I+xsUZd9ueDXh07uGoSgGJwEX4GPyRX1OJBfJd5GFMrlvs5VjzUPkiQ4ClqAkIaZPJH74AhIBmT4K0A7sNkQA9uD/LA2bQ2GJQUxyOSoVA1k3cm2mALy41E7a2qUNs2oWUmwBVSkDf4LDNHsob7VMj79YUTK6+4ENpNl5PU5i101AlaD9zaFxL8A+Wkvf4YA2WG6gM3k7rIlfwqZGQFy5uy2KSQu54DN+RZZjQjZRm0mF/yN+Ra5FhF9NoXEO8DcfIuUHetDhMh6+Zblzfj2yf1E9v5+i4gRS3xmwzxBOQnJFqntBR35X4T/wxAjn6AbQA4pV8Dfu8sfB3nUXzBvM7EAAAAASUVORK5CYII=');background-size:20px 20px;display:inline-block;height:20px;transform:translateY(-1px);vertical-align:middle;width:20px}.searchfacets{overflow:auto;font-size:small;white-space:pre-wrap;border:1px solid gray;padding:10px;margin-top:-6px;box-shadow:0 4px 6px -1px #cccccc inset;background:#fefefe}.searchfacets .title{margin:5px}.searchfacets .facet:hover{text-decoration:underline}.searchfacets .list{margin:0px 0px 0px 10px}li.searchfacet{display:inline-block;width:15em}.facet.count{color:#888888;font-weight:bold}.post-sharing{background:#fbfbfb;border:1px solid #e2e2e2;box-sizing:border-box;display:none;font-size:small;max-width:550px;padding:20px 40px;position:relative}.post-sharing .c-close{position:absolute;right:10px;top:10px}.post-sharing .post-sharing-form{font-size:1.0769230769230769em;display:none}.post-sharing .post-sharing-main{display:block}.post-sharing .post-sharing-main .c-form-group{-webkit-align-items:center;align-items:center;display:-webkit-flex;display:flex}.post-sharing .post-sharing-main .c-form-group>*{-webkit-flex:1 1 auto;flex:1 1 auto}.post-sharing .post-sharing-main .c-form-group>.post-sharing-label{-webkit-flex:0 0 20%;flex:0 0 20%;padding-right:10px;text-align:right}.post-sharing .post-sharing-email-form .c-form-group{margin-bottom:10px;margin-top:10px}.post-sharing .post-sharing-email-form.shared .post-sharing-shareplane{display:block}.post-sharing .post-sharing-email-form.shared .post-sharing-shareplane:before{-webkit-animation:post-sharing-shareplane 0.7s forwards;-o-animation:post-sharing-shareplane 0.7s forwards;animation:post-sharing-shareplane 0.7s forwards}.post-sharing .post-sharing-email-form.shared .post-sharing-buttons .c-btn{opacity:0}.post-sharing .post-sharing-label{font-size:1em;line-height:1.4285714285714286em;color:#808080}.post-sharing .post-sharing-option{background-size:26px 26px;cursor:pointer;display:inline-block;height:26px;margin-right:5px;margin-top:5px;position:relative;width:26px}.post-sharing .post-sharing-option:hover .c-tooltip{bottom:100%;opacity:1}.post-sharing .post-sharing-option .c-tooltip{transform:translate(-50%,-2px);-webkit-transform:translate(-50%,-2px);-moz-transform:translate(-50%,-2px);-o-transform:translate(-50%,-2px);-ms-transform:translate(-50%,-2px);-webkit-transition:all 0.15s ease 0s;-moz-transition:all 0.15s ease 0s;-o-transition:all 0.15s ease 0s;-ms-transition:all 0.15s ease 0s;transition:all 0.15s ease 0s;bottom:50%;left:50%;pointer-events:none}.post-sharing .post-sharing-option .c-tooltip .tooltip-inner{-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.08);box-shadow:0 1px 3px rgba(0,0,0,0.08);background:#ffffff;border:1px solid #e6e6e6;color:#222222;padding:10px;white-space:nowrap}.post-sharing .post-sharing-option .c-tooltip .tooltip-arrow{transform:translate(-50%,-1px);-webkit-transform:translate(-50%,-1px);-moz-transform:translate(-50%,-1px);-o-transform:translate(-50%,-1px);-ms-transform:translate(-50%,-1px);border-top-color:#ffffff;left:50%;top:100%}.post-sharing .post-sharing-option-facebook{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAA1CAYAAADh5qNwAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0JBNzU1RUZGODI1MTFFNEFFQjQ5M0QxQUE5RUE4MTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0JBNzU1RjBGODI1MTFFNEFFQjQ5M0QxQUE5RUE4MTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QkE3NTVFREY4MjUxMUU0QUVCNDkzRDFBQTlFQTgxNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QkE3NTVFRUY4MjUxMUU0QUVCNDkzRDFBQTlFQTgxNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqRdBrkAAAlsSURBVHjaxFp5iF7VFT9nZkwaSBgmKiGGMdHgqKilNFrirgiKGqK4kBAxbRWESZGigtj+UwouICjGJQMqWBuUCYK4kLZWjEvTmUBBBSWQaCGuZWpDHM04mUlmTs9733v3ne1+mchEJ3nf2+697579d869CLP4d+7aTb0AeBlfrgCg0/m8HAF7CKAbiH8RJvn+WwL6gm92IcBOvt7O7bYPD244MFvzwFkg5CQeZj0TsY7PfXwWg7eGp/Rbf66+Ts8m+HiD75/l88tM4MSPQtR5awdW8pTu4Ylc0wxF/lzRiFgTSInc4rq4opYUW9cAe/nVRj4eGx7s//oHIYols5RPj/KxOj8oJum0rsl8UtwLATb9ykej3O8P/OzxocH+qaNCFBPDvMY7+EP38u08TwS5SdfPUXyGrBQxp6rp731+t54J+2BWiWKCFvLpWR58FanJVN2F+kDOaspmlPrJDzdtmys1FtEBVt/bmbCnZ4Woc9dsOplb/Z0/slxzES1HG26nyWckye8LGyPjVMixQ0qwvH+EjzvZkdD3JooldBafXuNjsXcGks9y4ii4boivumoC6ufoJBqrJG7m618zYVk768gTNLCMB2WCcHE9uFYucpIC598k57GUjnQGSRJYs4Ecq8lpA9zMfQbaCaMzI6Ee7v42D7nM6n9LfcDZkFeARqIopTejvhB4TfW3ovfMq6c//3DrOzNSP7YhZii+yANeK4Ol/Ij3Zk73Q7uLxiAvN/GE4nYtxhSPrhjesuH1w6ofE/SbFkEQaDQGiiZb1pPAUBIkpEdB+yYgg1J4xYjK/qrbzWwmx7clitVuCQ/wQD1RHWNIEdhYjrSHWhKUJueVgRy7rfIoF0PavSMq1V7EDR48nKQe4mN+9NE4smju1+qCGe/YtEMDoyj9A8GU8l64fs2AhL9+xdI6XxLRJbzdT/m0Bp3/QvFBUIpBJqaAcOuW4BOX9MBVF58Ky3t74Cdz5sD09DSMHZiEofc+hVe37QyAVqOKBO0AWdnuPj5d4ojiV79PjENtIZEBEzXtGhQAqk/N31tv+AXcct2KyhT039j4wURUA24b1bYwS8OvxLiL2cGtZKexI6kfPziBX9yoNEQKnEiooYwtLZrQgFEp1ysvPA1uvT4mKAVa2R+ldjQEEGkF1epYTuJObVMIN6GwL2cX6L1YUkJE4cm0ciJz/LY157THaYhJqugiFZiAjAamSfuE1WxC3VL91lEQO1JcoYgwcAGWTMOlSxbComPnq37/2/cdbPnrB7BvdKxs+9nIaEa1UElKAucUN8sG6Ztz+fc6Pj/TxW688PM/a3XA0LVCcqPtdV1ntuxvj1vgJLNx8xBsG/44duVpDtLjKbEKIOADNve/oiCqULlL6w613oahk4R+G50u+xGZOAQw5xiPwj7/76gKuhJGNVIITECoXrIslICsvCk9YBffrLQ80VKouqHgjs2fUMOaGmVT4IunDk0LrfXxx6YvKAK6lhApD1sRtog1b1kH3/Y1aDlKx61ZYlNvUJIVaon5jIZCxNl4UlKeFhU887gSTIwsz32FpE4hE0jJSM3zVGKw5v28uV0w8MdrWwkgT27BvLmOqPt/ezkcOHioBX+43Z9feg/eGPqoNZaUOKIjziJ3S3Q1l1O7uNGiXOlKVXzUmZ+jL3t1dnRA39Lj2rrw3sXd6v7gwSlni1KFNWMpzBCMah7LLh3nSzwAdrDiP5LxSJpoEjHrSP8Kx6HLZz7zBRXUKUxphFp2F3GqU8aXWuyJUISYkwpjVApMdMREjXy136sZgqt1SG9o46hWSZhbEDXFLzvJ1Ad8vQFNsogupT80NQV/+ceuxILFCxfAz884QRGx/d1P4JuxVoV5klVvbHxSTdYnhegqIzlXX81tgh0F7Iei1m3qAw0X0Ik5V2SZmDwE927altpfdPbJjqgnX/gXfLznKw+EatCAjTdtqb1CeNnCqbD70SL4jpDKd9CDRWU/JvxSgKEymS8E8TC1xUbvvEqhzy9VqqPa7eU4BR/pTJUymY1NFtFJ1pp0uyxIZtQajaBDE+nb6IN9LQjB7l0d/Gg3RlksmYlSAC4t/wkyHkk3JCFhlcYEcRJMYNdENzNvNI12F4hiR5iSY5PHyA+j8JJgEnX5rOyLeeVD1NltrjAKNmwQBaAgJTwjw4Mb9hTe700wIVfpKXrEbFG6x9PVSJQ3q9ohRGXquBqcCoauViHm/FaZJDJlhSt633s1FA4RQwfQSNKVVdsmhTLYooTagAqkWjsDl+649Oc1WU16noTBJkebslpZ9qaMo5B1uXbhloJSckUokQHR6LysDfDifoKbvSiJeo6P6bgcTMJeTL5LGr4QUIhA9CT8ko8sh0X184TCRFqPBgHx1SvDWzaMJqJYBb/khy/IIocFivZD9SR0vQnbqp52MFE0k6qGIW/QAe1E88NBiQzuL+p+DUui1SIwa7QaxWv7Rti3fxze3fmlwnTjDIvIpXrok526Q8pRo+JpmufbQ4P9O8I6EWeNg/xoTR6QeEwGEINPyKQtuYU4qdyYKUfHiwbl3QVM1D/DsjO/voub7jd5rkIVUbRP9kB+sYAyKYLlONVpT2CNaIKsSUH+JAlyRPHLL/j0O1vMtOqiq6OxvURBVxYudc2XVDkBHMFesar+I/xz90xWEp/gxi+1hTrSOZCWWZQty3VeAHTLOGHxRbpuUbcg+UGAm6s4256oapH4Fh54N1ggRBq4SDdsuUiq2gMKCWAGtStGSqkjuuJPsceC5/r6ES1kF2u+/MGh1iI2uvJXnNdESSTA4TaRhKrsbFMx4Ckm6LYjXsgeHuzfw4MVFc//1OtIBE3tAI0KkltEoyzvFObLJClNqcxJaTMf/e2Y1dHuZbXL5AI+/t2Ec+t9xMI0URhW0a0UUgZOCW+LOohUEiv2UfzycNt6ZlT+OW/twEIqd3jhKlDFe+GaidJeCLvorDeC+H0VkKnpCcdQFDVuZ5Wb0Y6Xzpk0+uzDreMnnrmKAzN8U5Qe+IPHOPUyBKFKAMmFWBT7Kmz9w3jdIoO4ign620wrVN9jF9lAtYuMVse5VQ5FNNLMIRa9NNTaRcZXjw8frV1kwQaSlTyHe3iEa2LoE60P5/ZPKHC5l3828oPHWDo/zH6/QHIn8QTW81Dr+LYvArm5DFm46mpnJrLd0o+3MzMjvV4+XcbDpj20fPTwzLsrtRN7aGEXXx+VPbT/F2AA6Hc+PZ/VjbkAAAAASUVORK5CYII=')}.post-sharing .post-sharing-option-twitter{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAA1CAYAAADh5qNwAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0JBNzU1RjNGODI1MTFFNEFFQjQ5M0QxQUE5RUE4MTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0JBNzU1RjRGODI1MTFFNEFFQjQ5M0QxQUE5RUE4MTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QkE3NTVGMUY4MjUxMUU0QUVCNDkzRDFBQTlFQTgxNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QkE3NTVGMkY4MjUxMUU0QUVCNDkzRDFBQTlFQTgxNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pi9EJo4AAAj4SURBVHjaxFp7jFxlFT9nZjozu9t2tw62Ka3Ko9Ba6aqJEgINVZuKaIKEbYVoSA1BEkWUaOIDNcREo9GAJsbUgFHTJo3YriiRP5qGFF8tBp+tKbq4UmnYsrS77bLbfbAzc/zdO/fO/Z733u0O8CXf3tn7PL/zPuf7mDo4tu8fqzLzZvzcLCIbcVyPuYaYlpFQObptAvMs7hvGPc/g91+Y6Yl9A7WTnaKDOwCkgsOHQeROELkVvyva2yXl47guyfUhzL14Zvf+gdpzrwsogOkDUfeAqM8CUE1E0r8iGb/18WvMb+/fXnvqNQEFMEUcPo35dcxeJ+cjYg1JUB4JGu94DH8/A3D/e9VAAdAmHHZjvsNLaIbKOa+3mcAUSpyjU637ZnD+qzj/PYCTjoICoDtx+AFm1WEP2R+KCXZ9XTLtLRi/wdwJYOOLBgUwoIcfBEH3eqUSctZBdOfHMD7zfjiS/14wqMh+fop5+0IloqqSJokUNY2lo0nVvu8U5g2Q2DEfDYUMGnfFgIIPBh8LZtqIiVEBxc+ER/GonOIgNIlLAjgaqzEPbB8cu2TBoCClr+HwiYTY1seEJKfEVMINoC4dMcGy+3IbmNCBHYNjK3KrHwBtC7hxoXEs5qrXxFh9sa5qpm1mOKRf4fZbYGOSKikAeiPUZE8MKFXb2AYSc1UUG3NJRSQmVozz4v6IW8I345m786jfd/DiVXl8CWu25NaVkEjVLnxqxSk2qjoXe3wLgljjBYWL1+HBj5Py8ZhzqpPgPErpcgTkIE61JUMabSZIqtEsxf8PpEnqm86PhP8mTiKWimRkDm1PyYZOSsIk1ZuyiyHmb0lSsDaziW+FQPotUDh5DQ5bvNwWN8dMqTE77EPcahVPVYWZDRfvYZgoMTF6x30WKNzwuSzjsWKUJLGlxfWEEJeKetWWHR7TlwgrUo+DfDR2QDAXt0Hhn17ccJNTQopOe9OgOIaJ7ThU7yeGSheLTKtXFGndyjL19hSjAO+xHVWF2Q72IRamjwU/StGJW7TiLjPZ1GNJT7VA03MScY4McGIRFfy8/vIq3f7WKvVWErN+ZrxBP/rHeRoZr1MXzr/vsgo9PfIKvTTRsGswd/r1Ufz9LkeS+jkOt+atWE3A921ZTkfw8UPPzuYqEm/r76GBdRXnrXOgf/jlBm3oK9KfXpynBw9Pas8nuWVig6IDXhmz6T2a6EW3IactRC8s4A39tRJ9qr+bbtzQleneL7uo5AUUjApS6I1QyZHzTToMRn1oY3fLlCIi2h7YHx/fW9gRJIZMq+IIryafSbadxAzWbAygcKIYgb7jbV1077XLqbtS8Ep326XVXKnW2qUFunNTFx1+fs4d2MVwHgnjr8HX+Upy2ICoSWjMEdE5EwCsN4TOzjXb565bXaJdH+ijbeu7qLyEreT2ir5SLlAvnG/Ql347SWenGpGKiWXXTpBEVwKUrPfFmcykITLYQyfntfPdoPuuq7ro4Q/20V3vXkr9a+Hdulveba7RzAXq4PPzdAa2pakYux0Q6xpxBT7PNWa3y87KtjkSwaPHZ+j6tUvoomrBAMe07c3lcAajIfmYFYymq/QXTzjRveuqAoD0hgmQomZto5T0VCh4pqtcoPu3LKN/nqlnEhrYXrGQD9T4rHidjc9xxblgKYxPQkYHRzJjVTymYU8rKkzressdbUacPFdPV3t/rRXybc5MedreTnJUibjhseG5jgKahSmNTtTttIzdZmFkIQ14ZJ6wxMieOOAR+wEE3eNn6x0DdfjUPAX+RLNxI5SYklNqtanApsac+ik5aqToY42m0Dd+N0mPQmL15uJBHTwxq5ct5O48WSrZ0qzRQP3+7Uwe2VGKs+OF0ct6EHDXIGCenGosCtC/zjVo+KV5j6fVnRi5KmmhZwvRaoOe/SqpvVlTsSJnNY06h2AZSOnS5cVFgfrJ0emW1yUxvmlX4knBqEl1qLB/e+0Efox621Nsl9lx30CMqLjrz1N0fPzCJTX4n1l67sy8ox8oRoeJQ9Axf9t1Vcu2ngrZuvEjX3wXDldldV7VRNZK+8OUiej3yNVGUIaUChy6+iWFfF22v56u00NgiqT1IziFrmTcHYfCA66bVLE6y241wY3UtylMR07M0bGxOjLufICOInA/cGSSmk1Hxymlkm55aY0Lf4fmnS5FxP8SRAct5opOvLg7PpJ0huJLVWQWa1ADvXPlEroRmfjynLH4cTBgz9+mw7TIURu5W3DqLfr5vZpAUSj+IqjzM9eaWOfe1Zeggt1QpVXdhQXZzwkkqw8fm6GhF19ZlGNRFumaTPymfQNvGGGjm3QkZ7tXA1eCmm26uExb31KmfhSBXR61m4QPeHp0ng7B7oZwbDbTpZMJRG8vPALVu80yPQB70mqTtUMVeyO8mbWv7C1RHzL2nnJgY0QzdaHRl5s0Md2wMxSjyvaW6iogcmrS2wHqqNp4icdXMP/gTO3J0UDxNFlGkYyO5lmOEEd7OaNZ6tGeR2JAVocWF/4IQn/mcZUOQtROaXbia7Wc01w0+98Zr5VFtExhfj5rgeALAbO1tSRP3FIlJZ40yld2awtwbYzsbJSa8VD01ZEvQxgvpILaN1A7Ta3VQ0kv5cXW98gAxaNW7Fh4MDMVq2EqqQl1sD71wzxLOYEaHsThfs67wkGOXNHRchNRFwfscidTfUlbHAhy1jvMBTei7IXshyhaIrW2DORxv2yW4awlpN42Ntvlu7rAjeMpHK+N8lbKJSmFiE/isMfZR3esJ9krcY4FtDaRnj0VTmax+nwA6AYfoExQiM5Byr0T8/upRKdsybE8qS+oeypsQ6LDmJvTthsQLWLHCy2gP5i1wJCmzoqHzb3jJXfChpf9GMRcHWTCzpKfPSxit+e0JOhpgeHWmSgO3ZQH0IIkpUhM20UWF2wLytk43xIRxqu/i8wA14en76Fwvx/VXElpnAua+R6Tf5tOBOy13e9ngRts7cwEYTtB0FYQVNG47tubZI8hXNuLa7sB5vXZmekaOwbHqqB3MwgL9tEme2iJlmFqe2gjTxbuocV8AkA6tof2/wIMANo2Ww8r6WCbAAAAAElFTkSuQmCC')}.post-sharing .post-sharing-option-email{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAA1CAYAAADh5qNwAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RTlENzk2RjBGQ0MzMTFFNEE4RjFFRjk3NjY3NkJFNzkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RTlENzk2RUZGQ0MzMTFFNEE4RjFFRjk3NjY3NkJFNzkiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3QkE3NTVFRkY4MjUxMUU0QUVCNDkzRDFBQTlFQTgxNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3QkE3NTVGMEY4MjUxMUU0QUVCNDkzRDFBQTlFQTgxNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pprx0LMAAARJSURBVHja3JpfSFNRHMd/u9M0nRTh/FMRBbFFVga+SIMUZJrQmy+l/YFA8MkX/z4Jyl78R+CTIARKVg/6VA+pRBotFBLSMlR8yEjFKWG4bOaf9ftdz2SN3bu73XO3O3/w5W53599n59xzfvd3jgE4WvHzYjNeClD5KCvKgspEmVBG1B7KjVpFzaPmUOOoseG7w2u82mHgAEKNLkdVoPJUFDWJ6kc9Q8DVmEAhzGW8NDAYI8cO32NwrQj3NSpQCJOBlzbUAx49LWNeVB+qHuFcmkEh0CO8dKJOQvRsA1WDYE+4QiEMPejdbKjFymhIViGcWzUUAp3Gy2vUVYi9TaNKEWw5YigEuoiXEdR50I99Q9kRbCFsKNZDTp0B+YPZpHrMIPMMfdDJkJMbirZgz5ggkaFb50Bk11g7ISQUm7YrID6sgrVXevixhXUuyusQj3XM6r9AB/ZUW5wBAWtvW9CeYr7cF41dHy1dqis+X9G/pxriFMjXOQ3/9RR7fVji7G1H28i7P0OvLQnsRrkSIIPBAIXnCiFRSIxaS3f2d2D0+yh4vd5QSY2M47EPStEUnpWaBZ5dD9TaaiFBSNAcaHd/FxxOh1jvintF0RRPUAJ7BVf0xtpR1AGLvxbFiqjCaABRfVSvQssjHoHFFBRZ+vF0aC9q1xzMH4jqo3rDsAKBBUlAL2AqgcjyBRb1AT2AcQAisxKUJZKcvME4AZFZCCoz0ty8wDgCkWUSlElNCWrBOAORmQQeXkSkYBoAiYuwwNwL4AHmKHDAxPIENL9vFhdpOaPfKR2lp3ycgER3iaDcPEra3tuGro9d4uq/tLkE1SPVMO2aDv4ejvfpd0pH6Skf5edkbvJ1KG59Qi1Q07smcP12icMo2ZgMPZ96oPFtI2SbsiHHnANpx9Jg8+8mzKzNiC6P/YIdKq9XgmfPA3Vv6sT8LTdbIMmYpBZq1YBuxUv8cFtJ6qE7QyGB/IcR3XP+cML8z3lw77jBlGgCyykL2M7aICM14zDd+p91EYzuSYGVvChRCvWKoMixqokESg4oXAsFFgZUJz1T4zyGnNoH3TeDUnlUropnbJygxmINxBlsTGA7eJOxBuIENkk8vhhFvx6AOID1hx2jyM3IhbWtNU2Bgk0e5hQzTLmmFMco/ENkvXCwOygTsjFA2aUySE/RHugQbGsdBmcHwQshYxR9CPSQPvgHGlpR9+XCZFTwwOyAXuN+rb4vh3E/Fgjsi9PwWJ//pndg2LkeDmLT8WQbrN0QFIoF2WviDKomcPdeatPtKcTHdk4/At0LvCm16VaF+qxzoGnWTlAExbYcb8HB3qoejdpVKnX8QKqngG0S23UIRu2xyx07EORys219m46Gom/zekEukRCqFPaP3FDqH2o5KYDMMYOQs5+UxcvZJCGc0lnBFKbuZa6J1q4P1WMNByjsngrotaNz3i8I3NE5mSkBqIsztP8EGAB6RWM4xE5EngAAAABJRU5ErkJggg==')}.post-sharing .post-sharing-shareplane{font-size:0.8571428571428571em;line-height:1.6666666666666667em;bottom:0;color:#7cd344;display:none;font-weight:bold;padding:5px 15px;position:absolute;right:0;text-transform:uppercase}.post-sharing .post-sharing-shareplane:before{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAB/CAYAAACql41TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDBFQjY0RkRGQ0UwMTFFNDg5NUVCQjVCMDI1MjIxMzQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDBFQjY0RkVGQ0UwMTFFNDg5NUVCQjVCMDI1MjIxMzQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0MEVCNjRGQkZDRTAxMUU0ODk1RUJCNUIwMjUyMjEzNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0MEVCNjRGQ0ZDRTAxMUU0ODk1RUJCNUIwMjUyMjEzNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PlZuFdwAABnuSURBVHja7F0LeFRVfj8DCZAnIQ9CDMG8wASS8AjhFdAFzVYQkSJ2BSUKIkRWxaLSrvW1tdvP+qqKW2AVE5ZWd/lK7VrXz66s69YKioKwaOXzUVqF4icEJIQQCGR6fsP8ssfrZDKZuXfm3jvn/30387qZufec/+/83//jWbFx9zupqamNc+aUrK9NEJo0aVLIs/TZHYc6OzuHJCYmij59+oizZ88eTE5Obpo5c+R9f5IhvHqINMU1QJq93j53rtt+LiEhQaSlpYl+/fqJY8eOCbxub28X/fv3952I5/Kzl6qqqm6bXZ1wcJgeO03xABCv1ysaGnd5BwwYIFpaWkRmZqYPJEePHhVSsvikCs7B4fF4RN++fcWZM2dESkqKaGtre7eoqGjl9OnZ707uowdTk0sB8i8HRc0bb/xhx8mTJ32gAEDy8vLEuXPnxPHjx0VHR8f5kyVA8B6kC97Defh/qZb5jvT0dN+j/KxFnrdx3ryJd9VkizOD9ThrcjJAQMuf3+kFAKBSnT592geGgQMH+l4DOCdOnBA8l1IkKSnJdx7OJ+EzgIjPASQpnbxSEm2ZPLnijmnF4uBQPe6anAYQqFlgbDC9yvBQvSAZcB5A8c033/hAgQPSBkQ1rLeE35MA/Fh+/8pZs4pen9ZPT4gmmwKk/qf/+V8SHOVQn6AmkQACSILBgwd3qVPS9hCtra0+VQuE9/g8HIKUAvgAOgm2Fnkdt1966YgXZmaKDj1FmmwBEPxd9tx7XrwGIFSAwAUMEKSmpvqMc9ojMOoBFn7eW8JvAVi0bSC5ABZ8HwCI64BnDXYQ7B352SMlJSVNDRMHfKyFjaaoAgS0bMP7Xq7mAU+WjAwVLCMjo+scAAMMDMJ7YGp6u/AZ1C+rSIL3xbKyssYrpqa9XqbnUpPVAPl9uyjevHnP591JA0oXGN45OTm+VR3PCYpDhw51Padr2ErCb+Nak5OTfdIHEg7OBCl1zkjJdFd1dfnG64eLFj3NmkwBCGjxuu1eMH4gIjhop8B4B3PSWIdBD2kCJgVICCorAcIMAF4Tfu/UqVO+a1Eln7zWR7Kzs5tWX5LxsZ52TWEDZMn6d3x2CJgOzNcdg8NmwOcAh2Q8GthdYMHjkSNHukAFwuc4VA9YrElex8t5eXlNc64Y+tJ4zQ+aegLI6i2fvXX06NGpNJQhIYKpW1THEDOB5KHkoH2CGIoKEACDEfqY3rjfMYD7pHMAh5SAu+THTTfcMGnNJQM0g2iAGADy5ikx5IUX3j+kMnp3pEoRShK+Vr1h8HaBCVV7BeeE8htWEkCKa8IjwI1rg3oIdc2fSgOQH5bPGy+/vOJHFVmiU+egxTlAQHf/86dnpRTpCz3eaLDTAAeDg5EYNSfDgbKysnzP1c9AAAnsA9oOxs+jTQAEromqJCUbHuGtg/TDPapjhPHAuECySmnzcklJyR3Lpmfuz9S8FD8AWbPj9NK9e/c+CwYKx1YAkzEzWE10pGoGiQKg0B6JtSQxgwB2CZpd8p6b5swZsebi/pq5XAsQEGIiTEgMR78HsJimQmDQeGecpLm52bdKw35R01ucSAyW0sGB+4GU8b/XKu/352PHjrlzbpVoz9F85w6AhJtjRYnBzGCAhOoYVRh/Hpbv/C+//DIsINpqIOX94h4ACNgxsGFwn7hHvIfnkJp47ffmvVxZWXnH5dUJ+4s1HzoPILf9496X5Co4N1L1B8DAagqGQQQez8FIKMBS87fAQFC9GH2nl8nO6hftMTOIi4mU2p/IsVo5Z075a9OTNYPaFiAfCZH2Dz/f0xJOjpVKUNOYIYxINw4a6Ub7BtcC4MB7RC+YXeIlVhNralhuQAkkQdMqx2pVRcVFmxaPFO2aZW0CENDNz73XKlfzlEh+gK5UNfMXXi4mKhoBwkf8D+Iw8UIscca9w3ajdw0LCkqg8R7rcGDb+LOfHy8sLGxqmJr2YYrm5egD5MntbfP27NmzBZODVV1N3whH9aBtwmPQoEHf8QQZVSqkrvB9PNopjmI3gMnx2ZyTk9NYU1Pw2pxcPSaWAwR0+z996MVqhZVfTYOPVHen3g1pgu/GakkQqddErxAACo8XYxaqVNL0x5gOFjGMFxwCeA+qmhyrs/L4y5qacRuurxDfaA+0iQC5ce02X/JiuDUfgYCh/iakQm5uru+9QBJEzdsCKAAUesDw2kxD2WkOAHWsAAqqYPxfjBPTf6iyYQ5hE0p17vELL7yw6Z7Lcj7UcjgCgCx/fucG+bCExqOVDEGVi1LE6GamioaJhytVdRvzXLerXVbdH8YOAJIAe01K9cZFc4s2j9T46Bkg+6R6+/DabR1YnaxWafD9MEqDrZIEBQhuYUgRerzslCXsNICwtFptuOFfjPZI4DTNmFH15Lx8DZCAtHjd9q+kqM61euJ5LYzAU11Q1TE1/4vp89C3cVCCRFPlsuL3jCBQv98qgKgtnQgY1tXggHRBrzR40KDmSn5ob21t3VRXd/Gqy8pEa348A+QX+8XFW7fu+L1ZRnp3RMlAbxVULlUiqKoUdGsCiNnEtE/cJiWiARAmn8JGUccU72GsMa4Yb2Y+szUUeQKfSSC9VlpaemtNTcrnUxPjCCB+W8QbTQahyIcXBqtXT14rNddLBQptFLsb8m6znZgF7Xek7Jdz2VRXN+av//QCDRDTmIUp6FC34CQIFHk3vsb/AlAw4rHKUW0IlLoSC9DES+yGixpTh2gnQiuQqlq7nMtNY8aMWXX1+MTWIW4AyAOvHvy7r776anW0LozXpabDI5fLqBaojMfz/F3qfa8xSYhQUwIZvWIaINapywQHpTjDBHzPKPlRInHs2LG3UGMzu27wrjFOAsjn8nj4ufe8uAl4j6y2R7obdKhctD+MDN8d0MCUMDipN9MbFgtpoqP/oRHtUEn7s7Ky7pg69cKXZ2baGCCgW5o+2CdX44tY5xBtYrQYvw93MG2LYGn5aloKI/KMMncnTUJl4mC/GW0j221ENzNLopFFgcWRwJFzek4ukveMHTu28faJAw7bAiC/2C8q3nxz195YGbxqmS8GDSoXbYzu4h+q61I9F1JQA8S+BJsTCxl3EsAjXgMk1B6oxjGjQmoWayRPNN07t2hXSiwA4pciXqYt2MUYhBFPFzBtj1CJEXnaMG5MW3ETqfMTrDOO2oJK0mEJnpWTJo3avKBYnLMUIGgsB3TbgZFoS+B6sLKEEyhknhJrUIJJI0028zAFWQg5h8w/88dpqGqfk5/fU1JS0nhLberhJDMB8re/PfIXzc3ND9uhVkNNn8eAwDYx9uYKdUWi9ImnGhS3gcI4ryzKYyca2s101rCpCHsI4Hy5QG6U9u2GxVcVvjU8HICAlj67wxsLL1ZPRh2kCQYCN66mTPSWUIOiAofJkxxMTfZRpcywa9V+Apxj+V4btgMJ65fll9lOUacdAVUJ4hSvw1UDsU8j1DY1YKmmVWiKjqSIRksoOnzYhsqvsq9+ZlFVyqPzh38RlgR585S44MUXdx6026DSywVi1/dQqyC7W1kwYBg8FnW5IdfLTaqUGeTf8uPt0tLSaatqU78FiLDy17+XJP7vRRsOKpPtWDzECrtwVhXVnYyYCzOGdRWj66hTqlLjn1ww8oOAPBUJM2KVZeNnO3h+1KbYlIzsMI++wWpwM1AxlvoZJQi9YgxOwoinQUe1TruG7S01MG+wK2mo++ftx/X14x6c0oPWHDZAJFO8LpFXx7RouxIGBYEk1DIgXqLWw4dqLKolrBhslKyi0wjBqEFib8LGs0pg8dPKysqK2yb0PxMSaCOZWNSr4//BNLFIPQmFWKdNlx+kHaRBqE3pyPzGQCK9WtweOxYRcqeXGEfr2v0hgKl/f235273WlCK8wdOS0frbefVUcnd8r+HlgkRBP+BQMnuNgDBOMJI3AUD2tGJXSGPTbqcbspECWVVfrSIsgpgHaAp4hCqclZW1fsqU4oZw2yBFJEE+FCJ93aY/HOcGOXZYkXq6HyYpstUnI/DhjoMqXSBFub2Dmuat86+iA2qqUdJO/KKmpqa8YWyftoi/M5J/rhCihV4jO9ghoTA5VUF6uWinhDtxqrRg0wmABJJLLRHWoIjO/EsVev5TC0dtMQ10ZqDWSe5P1UhnOjUOSBK111Y436k2nQABgNwuWy0gcgsFy1K2ChQYW3gmEczlXMlx3TR7dnX9lYMtkEqRfoE0fl6UzLbAiQE0VSWj+5ZthyKViAACvF3Qi9VdtdyUCKmCIFpSAmUKTFCVKvLxoUOHjlg5Kelry+7RDPGPvUScqmcbqwqhesE2YdJjOOOj/p/q/YLHK14AYpVaiUVMGuH1Ty4YuSka92iKXiRXy28kqjNosDpJjTBOJFYnSBOIcHU/Ru6Gq6qSPXm+jM+hxtGQV5vc2cFOCfb7ocyn2deP7+NOAOx5Jsfr9fnzJ31/VlYUFwEzbmy3EInrmz44w12i4GJzOjFmAjVJrWpTJUC4Y8ctIWjMG8t/49XIVglueARjMebjx48etnik+DIW926KBBkjRAdR7pZcJTIx00zMKqSiOxiggL3DjivxCIJghHiVlB6r77uq8NGkWI6LWSvXug86p+/evfsNtXeuW8i/g21XBB5g8bffNFW3psdLlU5mqF/d/X8s5onXggWCHkT0ysL9U52trx/XZ4oUqrZYKM36ooaxfX5HT42biDYVJhAeFDxn+aaZBFWOu0iptpwZC5haWxGtOotuVRZ/qyZ2pIEaywYNRUVFY9ctHuexCzhMU7HUVdBsxrGDLcKVFqoRtq6mymUmcctt/0aePhDi0Qz7xE7qE9VL1onn5OQ03zu3KDtFFNly/k2d5fz8/C8kAw1zW+WduuJxL8He1r73ZmXF+AGE+B1jh3s3SGSoqdA0FiwY3396sjhj6+s103tyTH7fjxp3dboxtSLQPXHTH0y4un+iWffP72EypNpJMlDipJ2I9hnbMOGA+zwtLe2Vp6+ruNIp826qBBnkm7f4yTvCvaLWgB3oWRsTKbMa40m0T9Rmd3bP8WL2ANy1uNbjx4+3r22YnOQ0Bdxj9iBv3Ceqtm3buSceJIi6xTUAwtaYkQLEGN1XWxvhNdpwGoFoNwnCvRAHDx688t66wU87ViW0YhVqaNzlZW2EG1IrVLUmGCMCJGpmsHHLODOvh0a86kQwgspqwr0CrKzfZ2MLfweY959ZVFXj9Lm3JKpHfTmeekgxAIjaZ3ag76lvcKTMiQO/QYkS7fGGeknHAq5F3uvZJ+pHJ7ppm2lLACIZZLecuDFgDjX45XZ7BARDHcYoGIa5V2YyrnFzIUbkMc5qan007BPEL9hTasGCqtzaBPG12+bVkiVn1qzR8zmBTpUGgfZ0D0VtoSuYbUwpQahuBfu/UA/VBqI6RUAykNndvvPhkLpLF+wKtvPE6+Li4lsbGyZ73AgOy2wQvx3SKQfQ40SQGJsz9Ja4sqtbyHHTHzVGZGYAkKn6BBFSYcDEbKkZkZrhd0JAdWbPsR8vHOXJiAPNwLLMwqysrDulPv6EEwESSY061SyuumAo6OpY4dHggeNhdqsgBuAUNdcHDNSgRBr1Zy8p3NeCBZXlU/qKfXFjW1qpq0Zz408r7AmrPD/cPkItprIynUStQVHr59XFC6oTgIwIPs6DtPAb3gDGoceuGXGBiEOyNDfdSs+KU5u1gVHZGFstmIqGMQ2mp9vZaJ8wMMluL1QJn7i+MiFRiLhtSJxg8cT8tqOj41KnrfKWekXOR5W7NiQ1y+MULPWEQIR0ACGp1FiDwuIkSJvS0tJfrqpNvVZoslbFerVZZP/qVzsPO21QrBwTSg42mAPTmpGxa/x/VSoZwcJONKoLHq+zs7NbpSqVpmERJYCAlqx/53Q/bCjigBU/Gt0Qjb8HhoX+j4MMHK3fB0DgOCgoKLi5YWyf5zQcAkh8q3+gtnbSMui+du3dG9PVSQKB7lMWY0UzGu5PpZ+lwRFDgNxUITYyqU/Td4kFRDjQgT6a4+SvOTmhZyGGAAEh5ZkN2eysWhn19WgZ7WpBFtPE1Uh+oCi6WRJMAlRv6RtrgMiJ2GxHG8Rupah0s0LlglfJ6k1DYazLQ0uQWANk3ryyG9ko2m6Sw25gZXzH36VcRGHc9M4/sQbI1ERxql+/fi12Vq3sKM1wbZAm3HtEjYSboXpBakkJ0qJhEGOAgCoqKhbq4Q6P4G1C8qHZks/fXURLEDsA5Naafr+2k9RwUiSetglypZhRG6hZdG/vDd+TmJioJYgdAAKCz59uTavVFWMioNNAEchWYq0H7RK1Jj6chQD/KyWTliA2AshauHutZlSnA6KnVR8gYZktEhHDNeT9hVZagtgFIEuuLb+VDaGtZF43A4RbMRQUFHTtLhyuRGbxkyabAKRSzq9c+Q4wQc8KtcoNxOpAf3eQLoMalJ+fL4YNG+Z7jTyqUPZX7G7BYCGUJpsABDRjRu18Yyap2bq6G9QoppyQgfF40UUX+VLkmdDIct5wmRzjxSRJTTYByA1l4l0rkvLcplaxNgMgKCwsRI3Gt1qccgcm9uIK9zfcsp+LawACglFptooVSZMFu6lXYHyu7iUlJV0dRcjUlBgAByQNpEiYThOdRGpHgEgb5CEzdN9AUsOpdoixVU9xcTH2y/hO0qJabMXnOJAQ2ts2Pwg+sspQk40Acvd1FfebuTuTGwgSldIhLy+vqytJqBsS4XzGfYKBRF1Uol1/ogESIhUId2z0aTZAMjIy/nXjilrPQ7MLvnfgwAHRm+Z7ABNA0hsVE0BCHEVTkDGKlc7+y/8Rw7dufe8T/D6MzFB0YTcY4LhXNk2gsS3Vqa/uuTQ7z3juE2+3eiFp4fXDIyQMAoTBbC+kyav1JD2BcsSIUs/SSg0EW0kQ0A8Kxad4xAqG5mbxQtzjA/cNBpWAORAIHKBVtakeqQK1c8NLdEMJJg2gLiF4GKrUgd2TmalBEIxi6uODfk3d281Sw8iUkCKSmTt/Wj+6R1feiuqEpN+1pW7dubPl0p48f+yynim5PhiYVFC5bM9V90gQP7O8gwxVI0DcFtOgoc2NOvPz8x8PBRyk6cnisj+blr6aWb1sVm3MHqBnC9KJFYrBxhCA69QFt/a0QUAH5fHAszu8xpXRbVKD+VNyIdiz5vrKMRF81bCf7RH/6xu7gwcFEz8DjRdcuFh8mLLSnXSeObPMU5eugWBLCZJ/fhXrdHvCHO5PSo73IgQH6Itlo0UCGH/48PygJ0KK9OQiPi+BNAhsCxDQtddWD2FJqZPVKjAkg580qv0qVdv6JdWepxaOmmDST51bfUmG5+RJ7wG8gKqFiHsgKQFbRHUVG2MeUG3TdB9FewNE6teH3ZAwB+Mb9gWDbwBLaWnpD59ZVJVixe8tH+MpADjgAQwEDoAUEoSZwQCrMXsBr1M0BoKSLTLV3NB1EcwIkAAcEvCvSCPc8r3Ab5vQ3/ORyKl7+Y3m3wRSUwGAnJwc0dzc7JNwRvevz92sMWBvCeIX9a84fSAR/IMESUtL2/LYNSOujNbvjhLidQnO7YHsC4AW18TNPgMBSEuQ4OSxg86PypBbN7zvpU7tlDQUrtpgtMrKyjlyRf+3WF7P0++2exl1V+ttMMeHDh3qUrnU9x/8QZlHO7FsLkH6nVdR2jCBSJVwCiGDFmpLWVnZ5bEGB+jKiQNGIDvXWKNOSRJoDxFdDeIAgIBqa0fnYMKysrIcM3gSHE/BQ7WqNvXf7XA9RUJ8CruktDTzXvV9SBXYIkYbBJJPJ7s7BCALS0Qb0iPsZrDjeqjycSszMNrSm8YnP3J16R12nNT5BeInUv372qiqZmRkfMuVnqjzTHq2j+10MVjlDh8+bKs6aWbRst3OxInVY5eMErvtPrF3TUvPbRHpCRu2nexg13hE3tHvl2komhwkQfw68Ua7xUS4HQGOGTOqK5wADpI0vs/m5qbMgyoFcPhUKv8utizt1dQDT9otcr16y2depFLEkmDkQlpABcFKW1BQcPtDswvWOHmin3rnlBe1JAAJ7w+q4mPXjNDJJk5RsUBHjx49IpkyO6ZiVYICPaewwt69fFKfchdsEbByUpLnod+0nJWg74v7QgQeFYiaHKRige68ecIQO1zH7NnjL3h++SRPuYv2z7jv+7kJEvw7EGuCXeXGzpOuB0i5f9N6szr+BWMCMAnzlCg5YJTf0jA5d06uOOTGCV99ScZEqV49OmTIEKEbZzgQIKBOE6t4eurwQSDivKKioiueWVTlmSDE126e9Acuz1tdVpZTjkCnJofZIKDk5OQn5Kq+qjddPcKVLohtIF5w/5JqT34cTfzVQ8W+rQMzdd/RnhZYu+qhKzbu9obanaM3BM8UXLcAHozUuXNHp9SlizbNCpoco2KBTpw48ZkVG1hCWvh177P19aOTNDg0ORIgtbW1862I9p5vdZN5pumWKYkTJV40C2hypIoFWvnCR770bTPpZzeN14ExTc6XIKBwXb3sjk73LVLok5KS/mO9BoemXpKtywHS0tL+qrm5+Se9Rr2/+7k/W/X4g3fVDRrlooCfJq1i+ahVHqv8lYa9tTNA6enpR5++riJLT7MmV0qQ1PPSYEd7e/uEUKK+UK2QRoHYxprrK7U6pcndNgiosrJyPlQldAoMKgpRPpqQgNhGkwaHprhQsUg3rt3mhWQIFlWX0mP//csnFRfqOdUUTxIEhCIfpGcTIGyGBsmCYOLAgQOnPa/BoSnebBBSRkZGgwTFOhT8QJJA3cI2ZR0dHX+zcUXtfXoaNcW1BPnhVYXrETBEijZSRSBRJGDuf2rhKA0OTVqC5J9Xq15taWmZJcGxbd3icbV66jRpI12hXx8RGZ98cjLzz6ek/LeeNk3Rov8XYACXUa1qK8H1wgAAAABJRU5ErkJggg==');background-size:50px 32px;content:'';height:32px;position:absolute;transform:translate(0,0);width:50px}.post-sharing .post-sharing-buttons{overflow:auto}.post-sharing .post-sharing-buttons .c-btn{-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none;margin-left:5px;margin-right:0;padding:5px 15px}.post-sharing .post-sharing-buttons .c-btn:focus{box-shadow:0 0 0 1px #ffffff inset;outline:none}@keyframes post-sharing-shareplane{0%{opacity:0;transform:translate(0px,0px)}50%{opacity:1;transform:translate(20px,-10px)}60%{opacity:1;transform:translate(20px,-10px)}100%{opacity:0;transform:translate(-50px,-60px)}}@-o-keyframes post-sharing-shareplane{0%{opacity:0;transform:translate(0px,0px)}50%{opacity:1;transform:translate(20px,-10px)}60%{opacity:1;transform:translate(20px,-10px)}100%{opacity:0;transform:translate(-50px,-60px)}}@-webkit-keyframes post-sharing-shareplane{0%{opacity:0;transform:translate(0px,0px)}50%{opacity:1;transform:translate(20px,-10px)}60%{opacity:1;transform:translate(20px,-10px)}100%{opacity:0;transform:translate(-50px,-60px)}}.no-select{-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}.screenreader-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.basic-button,.sponsored-page .primary-button,.sponsored-page button{border-width:1px;border-style:solid;border-radius:5px}.basic-button:focus,.sponsored-page .primary-button:focus,.sponsored-page button:focus{outline:0;box-shadow:inset 0 0 0 1px rgba(255,255,255,0.35)}.basic-button:active,.sponsored-page .primary-button:active,.sponsored-page button:active{box-shadow:inset 0 1px 1px 1px rgba(0,0,0,0.09999999999999998)}.basic-button:disabled,.basic-button.disabled,.sponsored-page .primary-button:disabled,.sponsored-page .primary-button.disabled,.sponsored-page button:disabled,.sponsored-page button.disabled{background:#e9edf1!important;background:-moz-linear-gradient(top,#e9edf1 0%,#dce3ea 100%)!important;background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#e9edf1),color-stop(100%,#dce3ea))!important;background:-webkit-linear-gradient(top,#e9edf1 0%,#dce3ea 100%)!important;background:-o-linear-gradient(top,#e9edf1 0%,#dce3ea 100%)!important;background:-ms-linear-gradient(top,#e9edf1 0%,#dce3ea 100%)!important;background:linear-gradient(to bottom,#e9edf1 0%,#dce3ea 100%)!important;color:#999999!important;text-shadow:0 1px 0 #ffffff!important;border-color:#ccd6e0!important;box-shadow:none!important}html{height:100%}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td,iframe{margin:0;padding:0}table{border-collapse:collapse}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%}q:before,q:after{content:''}body{font:normal x-small verdana,arial,helvetica,sans-serif;background-color:white;z-index:1;min-height:100%}textarea{font:normal small verdana,arial,helvetica,sans-serif}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;padding:2px 6px 3px}button[disabled],html input[disabled]{cursor:default}input[type=hidden]{position:absolute}h1{font-size:18px;font-weight:normal;margin:10px 0}h2{color:#369;font-size:13px}h2 a{text-decoration:none}h2 a:visited{color:#336699}h2 a:hover{text-decoration:underline}h3{font-size:110%}a img{border:0 none}a{text-decoration:none;color:#369}[hidden]{display:none}.rounded{border-radius:7px}.rounded .morelink{border-top-right-radius:6px}div.autosize{display:table;width:1px}div.autosize>div{display:table-cell}input.txt{background-color:#f7f7f7;border:1px solid #369}label.disabled{color:gray}.wrong{color:red;font-weight:normal}.attention{font-weight:bold;border:solid 1px #ff6600;padding:3px;border-radius:7px}.subform input.text{width:25em}.subform textarea.text{width:25em}.subform label{margin:0 5px 0 5px}.subform td{padding:0px 5px 5px 0}.subform td.nopadding{padding:0px}.nowrap{white-space:nowrap}.leftpad{padding-left:1em}.nomargin{margin:0px}.nopadding{padding:0px}.fancybutton{padding:5px 10px;background:-webkit-gradient(linear,0% 0%,0% 100%,from(#d4e3f2),to(#adc9e6));background:-moz-linear-gradient(top,#d4e3f2,#adc9e6);background-color:#ADC9E6;border:1px solid #5E96CF;border-radius:7px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;color:#2E6399;text-shadow:0px 1px 0px rgba(255,255,255,0.7);-webkit-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8);-moz-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8);box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8);text-decoration:none;font-weight:bold}.fancybutton:hover{background:-webkit-gradient(linear,0% 0%,0% 100%,from(#e4edf7),to(#d4e3f2));background:-moz-linear-gradient(top,#e4edf7,#d4e3f2);background-color:#D4E3F2}.fancybutton:focus,.fancybutton:active{background:-webkit-gradient(linear,0% 0%,0% 100%,to(#d4e3f2),from(#adc9e6));background:-moz-linear-gradient(top,#adc9e6,#d4e3f2);background-color:#D4E3F2;-webkit-box-shadow:inset 0px -1px 0px rgba(255,255,255,0.7);-moz-box-shadow:inset 0px -1px 0px rgba(255,255,255,0.7);box-shadow:inset 0px -1px 0px rgba(255,255,255,0.7)}.fancybutton.disabled,.fancybutton.disabled:active{background:-webkit-gradient(linear,0% 0%,0% 100%,from(#e9edf1),to(#dce3ea));background:-moz-linear-gradient(top,#e9edf1,#dce3ea);background-color:#D4E3F2;border-color:#999;color:#999}.hover a:hover{text-decoration:underline}.selected,.choice.primary{font-weight:bold}.flat-list{list-style-type:none;display:inline}.flat-list li,.flat-list form{display:inline;white-space:nowrap}.flat-list li a.gold{color:#9a7d2e;font-weight:bold}.flat-list li.selected a{color:orangered}.link .flat-list{display:block;padding:1px 0}.link.compressed .flat-list{display:inline-block;padding:0 0 1px 0}ul.flat-vert{text-align:left}.flat-vert .separator{margin:0}.flat-vert.title{font-family:arial,verdana,helvetica,sans-serif;color:#777;font-size:18px;font-weight:normal;margin-bottom:5px}.separator{color:gray;margin:0px .7ex 0px .7ex;cursor:default}.pref-lang{font-weight:bold}.pref{font-weight:bold}#jumpToContent{position:absolute;left:135px;top:25px;font-weight:bold;margin-left:-1000px}#jumpToContent:focus{margin-left:0!important}#header{border-bottom:1px solid #5f99cf;position:relative;background-color:#cee3f8;z-index:99}#header-img{margin-top:2px;margin-right:5px}#header-img.default-header{text-indent:-9999px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -313px;background-repeat:no-repeat;height:40px;width:120px;display:inline-block;vertical-align:bottom;margin-bottom:3px}.hohoho-header{display:inline-block;width:35px;height:40px;overflow:hidden;text-indent:-4000px;background-image:url(../secret-santa-present.png);background-repeat:no-repeat;background-position:left center;background-size:35px;vertical-align:bottom}#header-top{position:absolute;right:5px}#header-bottom-left{font-size:larger}#header-bottom-right{position:absolute;right:0px;bottom:0px;background-color:#EFF7FF;padding:4px;line-height:12px;border-top-left-radius:7px}#mail{position:relative;top:2px;display:inline-block;text-indent:-9999px;overflow:hidden;width:15px;height:10px}#mail.havemail{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-40px -859px;background-repeat:no-repeat}#mail.nohavemail{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-61px -859px;background-repeat:no-repeat}.message-count{background-color:#FF7500;color:#FFF;font-size:8px;font-weight:bold;padding:0px 3px;margin-left:3px;border-radius:2px;display:inline-block}#modmail{position:relative;top:-2px;display:inline-block;text-indent:-9999px;overflow:hidden;width:16px;height:16px;margin-bottom:-6px}#modmail.havemail{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -730px;background-repeat:no-repeat}#modmail.nohavemail{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -730px;background-repeat:no-repeat}.user{color:gray}.user .userkarma{font-weight:bold}.beta-hint{position:absolute;cursor:inherit;height:24px;opacity:0.8}.beta-hint:hover{opacity:1}.beta-hint a{position:absolute;text-indent:24px;white-space:nowrap;overflow:hidden;margin-left:-24px;display:inline-block;width:20px;height:13px;background:transparent url('data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2266%22%20height%3D%2269%22%20viewBox%3D%220%200%2066%2069%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Ctitle%3E%EF%83%83%3C%2Ftitle%3E%3Cpath%20d%3D%22M1.156%2065.88c-1.027-1.89-.707-4.16.96-6.81l22.455-35.4V5.857h-2.856c-.774%200-1.443-.283-2.01-.848-.564-.567-.847-1.236-.847-2.01%200-.774.283-1.443.848-2.01.566-.564%201.235-.847%202.01-.847H44.57c.775%200%201.445.283%202.01.848.566.567.85%201.236.85%202.01%200%20.774-.284%201.443-.85%202.01-.565.564-1.235.847-2.01.847h-2.856V23.67l22.456%2035.4c1.666%202.65%201.986%204.92.96%206.81-1.027%201.89-3.118%202.834-6.273%202.834H7.43c-3.156%200-5.247-.945-6.274-2.835zM17.25%2045.856h31.786L36.893%2026.705%2036%2025.32V5.858h-5.714V25.32l-.893%201.385L17.25%2045.857z%22%20fill%3D%22%2346A508%22%20fill-rule%3D%22evenodd%22%2F%3E%3C%2Fsvg%3E') center left no-repeat;background-size:contain}.pagename{font-weight:bold;margin-right:1ex;font-variant:small-caps;font-size:1.2em;vertical-align:bottom}.pagename a{color:black}.newpagelink{padding:3px 5px;background-color:#ff9}.dropdown{cursor:default;display:inline;position:relative}.drop-choices.inuse{display:block}.drop-choices{position:absolute;left:0px;border:1px solid gray;z-index:100;background-color:white;white-space:nowrap;line-height:normal;margin-top:1px;display:none}.drop-choices a.choice{cursor:pointer;padding:2px 3px 1px 3px;display:block}.drop-choices a.choice:hover{background-color:#c7def7}.drop-choices a.choice.selected{display:none}.dropdown.lightdrop .selected{position:relative;background:none no-repeat scroll center right;background-image:url(../droparrowgray.gif);padding-right:21px;text-decoration:underline;color:gray}.drop-choices.lightdrop{margin-top:2px}.dropdown.tabdrop .selected{position:relative;background:#ffffff none no-repeat scroll center right;background-image:url(../droparrowgray.gif);padding:2px 21px 1px 5px;margin-left:3px;border:1px solid #5f99cf;border-bottom:none;color:orangered}.dropdown.tabdrop .selected.title{background-color:#eff7ff;color:#369;padding-bottom:0;border:none}.drop-choices.tabdrop{margin-top:2px}.dropdown-title.tabdrop{display:none}.drop-choices .choice.hidden{display:none}.tabmenu{list-style-type:none;white-space:nowrap;display:inline-block;margin-top:5px;vertical-align:bottom}.tabmenu li{display:inline;font-weight:bold;margin:0px 3px}.tabmenu li a{padding:2px 6px 0 6px;background-color:#eff7ff}.tabmenu li.selected a{color:orangered;background-color:white;border:1px solid #5f99cf;border-bottom:1px solid white;z-index:100}.tabpane-content{border:1px solid #5f99cf;padding:4px 4px 4px 4px}.content{z-index:1;margin:7px 5px 0px 5px}.content .spacer{margin-bottom:5px}.state-button{display:inline}.side{float:right;background-color:white;margin:0px 5px 0 5px;width:300px}.side .spacer{margin:7px 0 12px 0}.side .side-message{background:#faf2ce no-repeat 10px 10px;border:1px solid #edce42;border-radius:2px;padding:10px;line-height:1.75em}.side .side-message:before{content:'';display:inline-block;float:left;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -664px;background-repeat:no-repeat;width:16px;height:16px;margin-right:7px}.side .side-message p{font-size:.9em;margin:0}.side .side-message p strong{display:block;font-weight:normal;font-size:1.25em}.side .side-message p+p{margin-top:.25em}.side .side-message.gold{font-family:serif;border:1px solid #d5c9a9;box-shadow:0 0 10px #ebe5d5 inset;border-radius:0}.side .side-message.gold:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -839px;background-repeat:no-repeat;width:13px;height:14px;margin-top:1px}.morelink{display:block;text-align:center;position:relative;border:1px solid #c4dbf1;background:#ffffff none repeat-x scroll center left;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -278px;background-repeat:repeat;font-size:150%;font-weight:bold;letter-spacing:-1px;line-height:29px;height:29px}.morelink:hover,.mlh{border-color:#879eb4;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -243px;background-repeat:repeat}.morelink a{display:block;width:100%;height:100%;overflow:hidden;text-overflow:ellipsis;color:#369}.morelink:hover a{color:white}.morelink .nub{position:absolute;top:-1px;right:-1px;height:31px;width:24px;background:#ffffff none no-repeat scroll center left;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-30px -547px;background-repeat:no-repeat}.morelink:hover .nub,.mlhn{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -547px;background-repeat:no-repeat}.disabled .morelink,.disabled .morelink:hover{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -208px;background-repeat:repeat;border-color:#dadada}.disabled .morelink a{cursor:default;color:#aaa}.disabled .morelink .nub,.disabled .morelink:hover .nub{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-76px -491px;background-repeat:no-repeat}.raisedbox{padding:5px;background:#E0E0E0;border:1px solid gray}.raisedbox h4{margin-bottom:3px}.raisedbox li{margin-bottom:2px}.sidebox .spacer{position:relative;margin-top:10px;padding:5px 0 0 44px;min-height:41px;background:#ffffff none no-repeat scroll top left}.sidebox .spacer.no-icon{padding:0;min-height:0}.sidebox .spacer a{position:absolute;top:0;left:0px;display:block;height:40px;width:40px}.sidebox.create .spacer a{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-76px -359px;background-repeat:no-repeat}.sidebox.gold .spacer a{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-76px -435px;background-repeat:no-repeat}.sidebox.gold .morelink{border:none;background-color:transparent;background-image:url(../goldmorelink.png);background-position:0 0;background-repeat:no-repeat;height:31px}.sidebox.gold .morelink a,.sidebox.gold .morelink a:visited{color:#9a7d2e}.sidebox.gold .morelink:hover{background-position:0 -31px}.sidebox.gold .morelink:hover a{color:#ffffff;margin-top:1px}.sidebox.gold .morelink .nub{display:none}.submit.mod-override .morelink a:after{background-image:url("../shield.png");content:" ";position:absolute;height:16px;width:16px;margin:7px}.submit.mod-override .morelink:hover a:after{opacity:0.5}.sidebox .subtitle{margin-left:10px;color:dimgray;font-size:110%}.sidebox.hohoho .morelink a,.sidebox.holiday_shopping .morelink a{overflow:visible;color:#417142}.sidebox.hohoho .morelink a:before,.sidebox.holiday_shopping .morelink a:before{content:'';display:inline-block;background-image:url(../rg-santa-and-elves.png);background-repeat:no-repeat;background-size:46px;background-position:center left;width:46px;height:42px;vertical-align:top;margin-top:-7px;margin-left:-8px;margin-right:0px}.sidebox.holiday_shopping .morelink a:before{background-image:url(../rg-elf.png);background-size:36px}.account-activity-box{text-align:center}#account-activity table{margin:2em 0 0 2em;width:45em;font-size:larger}#account-activity th{font-weight:bold}#account-activity td{padding:.5em 0}.infotable{margin-top:5px;margin-bottom:10px}.infotable .small{font-size:smaller}.infotable td{padding-right:1em}.infotable a:hover{text-decoration:underline}.infotable .state-button a{background-color:#F0F0F0;color:gray}.infotable .bold{font-weight:bold}.infotable .invalid-user{background-color:#ffc0cb}.infotable .organic-vote{border:1px solid green}.profile-attr .label{font-weight:bold}.profile-attr .value{color:#404040;margin-right:5px}.profile-attr .md{margin-left:10px;margin-top:5px;border-color:#B2B2B2 #D0D0D0 #D0D0D0 #B2B2B2;border-style:solid;border-width:1px;padding:10px}.profile-attr .md ul{float:none;list-style-type:disc;margin-left:15px}.profile-attr .md p{margin-top:0px}.question{color:red}.question .yes{margin-left:5px;margin-right:3px}.question .no{margin:0px 3px 0px 3px}.preload{position:absolute;top:-1000px;left:-1000px}.arrow{margin:2px 0px 0px 0px;width:100%;height:14px;display:block;cursor:pointer;background-position:center center;background-repeat:no-repeat;width:15px;margin-left:auto;margin-right:auto;outline:none}.arrow.upmod{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-105px -818px;background-repeat:no-repeat}.arrow.downmod{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-63px -818px;background-repeat:no-repeat}.arrow.up{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-84px -818px;background-repeat:no-repeat}.arrow.down{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-42px -818px;background-repeat:no-repeat}.midcol{float:left;margin-right:7px;margin-left:7px;background:transparent;overflow:hidden}body>.content .link.compressed .midcol{width:15px;margin-right:5px}.entry{overflow:hidden;margin-left:3px;opacity:1}.domain{color:#888;font-size:x-small;white-space:nowrap}.domain a{color:#888;display:inline-block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;vertical-align:middle;max-width:19em}.domain a:hover{text-decoration:underline;max-width:none}.spam .domain,.spam .domain a{color:black}.link-note{background-color:white;color:#ff4444;font-size:x-small}.user-distinction{color:#888;font-size:x-small;margin:5px 5px 0px 5px}.user-distinction .admin{color:#ff0011;text-decoration:none;font-weight:bold}.tagline{color:#888;font-size:x-small}.tagline a{color:#369;text-decoration:none}.tagline .friend{color:#ff4500}.tagline .submitter{color:#0055df}.tagline .moderator,.green{color:#228822}.tagline .admin{color:#ff0011}.tagline .alum{color:#BE1337}.tagline a.author.admin{font-weight:bold}.tagline a:hover{text-decoration:underline}.tagline .edited-timestamp{cursor:default}.tagline .stickied-tagline{color:#228822}.tagline .userattrs .cakeday{display:inline-block;text-indent:-9999px;width:11px;height:8px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -876px;background-repeat:no-repeat;vertical-align:middle}a.author{margin-right:0.5em}a.banned-user{color:red}.thing .parent .author{margin-right:0.5em}.flair,.linkflairlabel{display:inline-block;margin-right:.5em;padding:0 2px;background:#f5f5f5;color:#555;border:1px solid #ddd;border-radius:2px}.collapsed .flair{display:none}.flair input{font-size:xx-small}.linkflairlabel{font-size:x-small;max-width:10em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.link .flair{font-size:x-small;margin-top:-1px}.flair-settings{margin-bottom:16px}.flairlist .flair-jump{margin-bottom:1em}.flairlist .flair-jump input[type="text"]{width:430px}.flair-jump button{font-size:100%}.flairlist.pretty-form{font-size:inherit}.flairlisthome,.flairlist .nextprev{display:inline-block;margin-top:10px}.flairlisthome{font-size:smaller}.flaircell,.flairlist .header{display:inline-block;text-align:center;width:30ex;margin-right:4ex}.flair-entry{display:inline-block}.flaircell.narrow,.flairlist .header.narrow{width:14ex}.flairsample-left{text-align:right!important}.flairsample-right{text-align:left!important}.flairrow .tagline{display:inline-block;margin-bottom:8px;margin-left:6px;text-align:left;width:36ex}.flairlist .flaircell input[type="text"]{width:28ex}.flairrow>form button{display:none}.flairrow .edited button{display:inline-block}.flairrow .flairdeletebtn{display:inline}.flairrow:hover .flairdeletebtn{opacity:1.0}.flairselector{box-shadow:4px 4px 4px #ccc;font-size:x-small;position:absolute;width:400px}.flairselector img{margin:none}.flairselector h2{background:#cee3f8;padding-bottom:2px;margin-bottom:4px;text-align:center}.flairselector.drop-choices.active{border:1px solid gray;display:block}.flairselector .error{text-align:center}.flairselector ul{display:inline-block;max-width:200px;overflow:hidden;vertical-align:top}.flairselector .selected,.flairselector.active li{display:block;font-weight:normal;text-decoration:none!important}.flairselector li{border:1px solid white;cursor:pointer;display:block!important;padding-left:4px}.flairselector li a{color:#369!important;font-weight:normal!important}.flairselector li:hover{background-color:#bbb;border:1px solid #bbb}.flairselector li a:hover{text-decoration:none}.flairselector li.selected{border:dashed 1px black}.flairselector .title{font-size:x-small!important}.flairselector form{border-top:solid 1px gray;clear:both;display:block;padding-top:4px;text-align:center}.flairselector form>div{margin:2px 0}.flairselector form button{margin-left:5px}.flairoptionpane{margin-bottom:4px;max-height:200px;overflow:auto;text-align:center}.flairselector .customizer{display:inline-block}.flairselector .customizer input{display:none}.flairselector .customizer button{display:inline!important}.flairselector .flairremove{display:none}.media-button .option{color:red}.media-button .option.active{background:none no-repeat scroll right center;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -859px;background-repeat:no-repeat;padding-right:15px;color:#336699}.embededmedia{margin-top:5px;margin-left:60px}.thing .title{color:blue;outline:none;margin-right:.4em;padding:0px;overflow:hidden}.thing .title:visited,.thing.visited .title{color:#551a8b}.thing.stickied a.title,.thing.stickied a.title:visited,.thing.stickied a.title.visited{font-weight:bold;color:#228822}body.with-listing-chooser.explore-page #header .pagename{position:static}.explore-header{font-weight:bold;margin-bottom:7px;padding:5px 0}.explore-header #explore-settings input{margin-left:5px}.explore-header #explore-settings button{color:#333;font-weight:bold;line-height:10px;margin-left:8px}.explore-header .explore-title{font-size:1.3em}.explore-item{margin-bottom:1em}.explore-item .explore-label{border-radius:2px;display:inline-block;margin:0 5px 1px 0;padding:1px 2px 2px}.explore-item .explore-label-type,.explore-item .explore-label-link{padding:0 5px}.explore-item .explore-sr-details{color:#777;display:inline-block;font-size:x-small;font-weight:normal;margin-left:3px}.explore-item .explore-feedback{display:inline-block}.explore-item .explore-feedback .fancy-toggle-button .add,.explore-item .explore-feedback .fancy-toggle-button .remove{background-color:transparent;background-image:none;border:none;color:#aaa;border:1px solid #ccc;border-radius:2px;margin-left:10px;padding-top:0}.explore-item .explore-feedback .fancy-toggle-button .add .option,.explore-item .explore-feedback .fancy-toggle-button .remove .option{line-height:7px}.explore-item .explore-feedback .fancy-toggle-button .add:hover,.explore-item .explore-feedback .fancy-toggle-button .remove:hover{color:white;border:1px solid #444}.explore-item .explore-feedback .fancy-toggle-button .add:hover{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px 0px;background-repeat:repeat}.explore-item .explore-feedback .fancy-toggle-button .remove:hover{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -182px;background-repeat:repeat}.explore-item .explore-feedback .subscribe-button{display:inline-block;margin:0 4px 0 0}.explore-item .explore-feedback-dismiss{cursor:pointer;display:inline-block;text-indent:-9999px;width:9px;height:9px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-110px -642px;background-repeat:no-repeat;opacity:.3;margin-left:4px;vertical-align:middle;border:3px solid transparent}.explore-item .explore-feedback-dismiss:hover{opacity:1}.explore-item .explore-sr{display:inline-block;font-size:1.1em;font-weight:bold;margin-bottom:3px;padding:2px 4px;line-height:13px;height:18px}.explore-item .midcol{display:none}.explore-item .rank{display:none}.explore-comment{}.explore-comment .explore-label{background-color:#cee3f8;border:solid thin #5f99cf}.explore-comment .tagline,.explore-comment .buttons,.explore-comment .thumbnail,.explore-comment .expando-button{display:none}.explore-comment .comment{border-left:solid 2px #eee;color:#888;margin:-3px 0 3px 5px;max-height:100px;overflow-x:hidden;overflow-y:hidden;position:relative}.explore-comment .comment .md{font-size:x-small;padding-bottom:2px}.explore-comment .comment .md p{margin:5px}.explore-comment .comment-fade{background:-moz-linear-gradient(bottom,#ffffff 0%,rgba(255,255,255,0) 100%);background:-webkit-gradient(linear,left bottom,left top,color-stop(0%,#ffffff),color-stop(100%,rgba(255,255,255,0)));bottom:0;border:none;height:10px;position:absolute;width:100%}.explore-comment .comment-link{color:#888;display:inline-block;font-weight:bold;padding:0 0 8px 5px}.explore-page.res-nightmode .comment-fade{display:none}.explore-hot .explore-label{background-color:#fff088;border:solid thin #c4b487}.explore-rising .explore-label{background-color:#d6fbcb;border:solid thin #485}.explore-discovery .explore-label{background-color:#dedede;border:solid thin #aaa}.explore-subscribe-bubble{margin-left:22px}.sitetable{list-style-type:none}.ajaxhook{position:absolute;top:-1000px;left:0px}.nextprev,.next-suggestions{color:gray;font-size:larger;margin-top:10px}.nextprev a,.next-suggestions a{padding:1px 4px;background:#eee;border:1px solid #ddd;border-radius:3px;font-weight:bold}.nextprev a:hover,.next-suggestions a:hover{background:#f0f0f0;border:1px solid #82A6C9}.nextprev a:active,.next-suggestions a:active{background:#e4e4e4}.nextprev .separator,.next-suggestions .separator{margin:0;margin-left:.5em;padding-left:.5em;border-left:1px solid #ccc}.next-suggestions{margin-left:0.75em}.next-suggestions a{background:none;font-weight:normal;margin-left:.5em}.next-suggestions .mark-all-read-container .throbber{position:absolute;margin-left:5px;margin-top:-2px;padding-left:22px;min-width:18px;width:auto;font-size:10px;line-height:16px}.help a.help{color:#808080;text-decoration:underline}.help.help-cover{position:relative;background-color:#F8F8F8;border:1px solid gray;display:none;padding:5px 10px 10px 10px;overflow:hidden}.help p,.help form{margin:5px;font-size:110%}.help form{display:inline}.help-hoverable{cursor:help}.hover-bubble{display:none;position:absolute;background:white;color:#333;border:1px solid gray;padding:3px;box-shadow:0 2px 10px rgba(0,0,0,0.25);z-index:100}.hover-bubble:before,.hover-bubble:after{position:absolute;display:block;content:''}.hover-bubble.anchor-top:before,.hover-bubble.anchor-top:after{right:8px;border:9px solid transparent}.hover-bubble.anchor-top:before{top:-19px;border-bottom-color:gray}.hover-bubble.anchor-top:after{top:-18px;border-bottom-color:white}.hover-bubble.anchor-top-left:before,.hover-bubble.anchor-top-left:after{left:8px;border:9px solid transparent}.hover-bubble.anchor-top-left:before{top:-19px;border-bottom-color:gray}.hover-bubble.anchor-top-left:after{top:-18px;border-bottom-color:white}.hover-bubble.anchor-top-centered:before,.hover-bubble.anchor-top-centered:after{left:50%;margin-left:-9px;border:9px solid transparent}.hover-bubble.anchor-top-centered:before{top:-19px;border-bottom-color:gray}.hover-bubble.anchor-top-centered:after{top:-18px;border-bottom-color:white}.hover-bubble.anchor-right:before,.hover-bubble.anchor-left:before,.hover-bubble.anchor-right:after,.hover-bubble.anchor-left:after{top:8px;border:9px solid transparent}.hover-bubble.anchor-right.anchor-right:before,.hover-bubble.anchor-left.anchor-right:before{right:-19px;border-left-color:gray}.hover-bubble.anchor-right.anchor-right:after,.hover-bubble.anchor-left.anchor-right:after{right:-18px;border-left-color:white}.hover-bubble.anchor-right.anchor-left:before,.hover-bubble.anchor-left.anchor-left:before{left:-19px;border-right-color:gray}.hover-bubble.anchor-right.anchor-left:after,.hover-bubble.anchor-left.anchor-left:after{left:-18px;border-right-color:white}.help-bubble{width:35em}.help-bubble p,.help-bubble form{margin:.5em}.help-bubble a{font-weight:bold}.help-bubble a:hover{text-decoration:underline}.hover-bubble.multi-selector{margin-top:-47px;min-width:130px;min-height:40px;padding:8px 0;-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none}.hover-bubble.multi-selector:before,.hover-bubble.multi-selector:after{top:48px}.hover-bubble.multi-selector strong,.hover-bubble.multi-selector a.sr{display:block;margin:3px 0;text-align:center}.hover-bubble.multi-selector strong{font-size:1.05em;font-weight:bold;color:#333}.hover-bubble.multi-selector .throbber{position:absolute;top:10px;right:8px}.hover-bubble.multi-selector .multi-list{margin-top:5px}.hover-bubble.multi-selector label{font-size:1.25em;display:block;padding:5px 12px}.hover-bubble.multi-selector label:hover{background:#eee}.hover-bubble.multi-selector label input[type="checkbox"]{margin-top:0;margin-right:5px;vertical-align:middle}.hover-bubble.multi-selector label a{float:right;margin-left:7px;width:12px;height:12px;line-height:12px;background:white;border:1px solid #6699cc;border-radius:2px;text-align:center;opacity:.65}.hover-bubble.multi-selector label a:hover{opacity:1}.hover-bubble.multi-selector .create-multi input[type="text"]{background:white;border:1px solid #ccc;padding:2px 5px}.infotext{border:1px solid #369;background-color:#EFF7FF;-webkit-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8),0px 1px 0px rgba(255,255,255,0.6);-moz-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8),0px 1px 0px rgba(255,255,255,0.6);box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8),0px 1px 0px rgba(255,255,255,0.6)}.infotext p{font-size:small;margin:5px}.wikiaction-revisions::before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -796px;background-repeat:no-repeat}.wikiaction-pages::before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -752px;background-repeat:no-repeat}.organic-listing{border:solid 1px gray;padding:0;overflow:hidden;position:relative;margin-bottom:7px}.organic-listing .link{background-color:#F8F8F8;padding-top:5px;padding-bottom:5px;min-height:72px}body.compressed-display .organic-listing .link{padding-top:7px;padding-bottom:7px;min-height:37px}.organic-listing.loading{display:block;height:82px;opacity:.5}body.compressed-display .organic-listing.loading{height:51px}.organic-listing.loading .help,.organic-listing.loading .throbber{display:none}.organic-listing .link,.organic-listing .link.compressed,.organic-listing .link.promotedlink{padding-right:7em;padding-left:2px;margin-bottom:0px}.organic-listing .nextprev{margin:0px;position:absolute;right:0px;top:0px;vertical-align:top;z-index:1}.organic-listing .nextprev .arrow,.organic-listing .nextprev .throbber{width:21px;height:21px;margin:5px 5px 2px 0px}.organic-listing .nextprev .throbber{vertical-align:top;background-position:center center}.organic-listing .nextprev .arrow{border:solid 1px #B3B3B3;display:inline-block;position:relative;text-indent:50px}.organic-listing .nextprev .arrow.prev{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-83px -613px;background-repeat:no-repeat}.organic-listing .nextprev .arrow.next{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-58px -613px;background-repeat:no-repeat}.organic-listing .nextprev .arrow:hover{cursor:pointer;border:solid 1px #336699}.organic-listing .nextprev .arrow:active{top:1px}.organic-listing .help{color:#336699;margin:0px 5px 5px 0;position:absolute;right:-1px;bottom:0px;z-index:1}.link.promotedlink{border:1px solid gray;padding:5px 0 5px 3px;overflow:hidden;position:relative}.link.promotedlink.unpaid{background-color:#FFC}.link.promotedlink.unseen{background-color:#FFC}.link.promotedlink.accepted{background-color:#9F9}.link.promotedlink.rejected{background-color:#FF9A9A}.link.promotedlink.accepted{background-color:#9F9}.link.promotedlink.pending{background-color:#BFC}.link.promotedlink.promoted{background-color:#EFF7FF}.link.promotedlink.finished{background-color:#DDD}#promo-form+form #img-preview-container{display:none}.profile-page .link.promotedlink.saved{background-color:white;border:none}.profile-page .link.promotedlink.saved .sponsored-tagline{display:none}.rejection-form textarea{width:40em;height:10em}.promoted-list{font-size:larger}.promoted-list .unpromote-button{display:inline}.promoted-list .unpromote-button a{color:gray}.help-cover.promoted{background-color:#EFF7FF}.organic-listing .promoted{background-color:#EFF7FF;border:none}.organic-listing .sponsored-tagline{right:6.8em}.sponsored-tagline{color:#808080;bottom:0;margin:0 5px 5px 0;position:absolute;font-weight:bold;right:0}.geotarget-notice{margin:5px 10px}.geotarget-notice .md p{font-size:smaller;margin:1px 0 0}.geotarget-notice div:before{content:"";float:left;height:16px;width:20px;background-repeat:no-repeat}.geotarget-notice.city div:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -664px;background-repeat:no-repeat}.geotarget-notice.country div:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -796px;background-repeat:no-repeat}.promote-pixel{position:absolute;top:-1000px;right:-1000px}.organic-help-button{padding:0 .5ex}.menuarea{border-bottom:1px dotted gray;padding:5px 10px;margin:5px;overflow:hidden;font-size:larger}.menuarea .spacer{display:inline;margin-right:15px}.panestack-title{margin:10px 310px 0px 10px;padding-bottom:3px;border-bottom:1px dotted gray}.panestack-title .title{font-size:16px;font-weight:normal;margin:10px 0}.panestack-title a.title-button{font-size:12px;margin-left:8px}.panestack-title a.title-button.gold{background-color:#fff088;color:#6a4d00;border:1px solid #9a7d2e;padding:1px 5px;border-radius:3px}.commentarea .menuarea{border:none;margin:0 310px 10px 10px;padding:0;color:gray}.commentarea .menuarea form.toggle{margin-left:8px}.commentarea .menuarea .toggle{display:inline-block}.commentarea .menuarea .toggle a{color:gray;font-weight:bold;font-size:x-small}.commentarea>.usertext{margin:0 0 10px 10px;overflow:auto}.infobar{background-color:#f6e69f;padding:5px 10px;margin:5px 305px 5px 0px;border:1px solid #ffa500;font-size:small}.infobar img{display:inline;vertical-align:middle}.infobar strong{font-weight:bold}.infobar.red{padding:5px;background-color:#FFAEAE;border-color:red}.infobar.red img{float:left;margin-right:5px}.infobar.mellow{background-color:#eff8ff;border:1px solid #93abc2}.infobar.gold{background-color:#fffdcc;border:1px solid #e1b000;color:#9a7d2e}.content .infobar.gold:before{margin-top:5px;margin-right:7px}.infobar.welcome{display:none;background:url(../welcome-lines.png) top center;border:1px solid #ff8b60;padding:0;height:80px;overflow:hidden;margin-right:0;white-space:nowrap}.infobar.welcome h1,.infobar.welcome h2{display:inline-block;font-weight:normal;margin:0}.infobar.welcome h1{margin-top:14px;margin-left:2%;padding:7px 16px;font-size:16px;background:white;border-bottom:2px solid #5f99cf}.infobar.welcome .button-row{position:relative;top:-8px;margin-left:10%}.infobar.welcome h2{padding:4px 14px;padding-left:38px;background:#ffffff url(../welcome-upvote.png) 12px center no-repeat;font-size:13px;color:#222;border-bottom:2px solid #ff4500}.infobar.welcome a{margin-left:2%;background:#e75018;font-size:11px;font-weight:bold;color:white;padding:5px 10px;border-radius:4px;border-bottom:2px solid #a73a11}.infobar.welcome a:hover{background:#f0571e;border-bottom-color:#c74514}.infobar.welcome a:active{position:relative;top:1px;background:#df531f;border-bottom:1px solid #a73a11}.infobar.newsletterbar{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;position:relative;overflow:hidden;min-height:80px;padding:15px 20px 20px 25px;border:none;border-radius:2px;background-color:#30659B}.infobar.newsletterbar header{float:left;height:45px;width:325px}.infobar.newsletterbar a.newsletter-close{position:absolute;right:3px;top:0;font-size:11px;color:#CCC}.infobar.newsletterbar form{margin:2px 150px 0 340px;max-width:400px;min-width:150px;line-height:45px;white-space:nowrap}.infobar.newsletterbar .subscribe-thanks{display:none}.infobar.newsletterbar.success header{padding-left:65px}.infobar.newsletterbar.success header:before{content:"✓";color:#80d654;font-weight:bold;font-size:60px;position:absolute;top:0;left:15px}.infobar.newsletterbar.success .subscribe-callout{display:none}.infobar.newsletterbar.success .subscribe-thanks{display:block}.infobar.newsletterbar h1{margin:0}.infobar.newsletterbar h1 a:hover{border-bottom:1px dotted #999}.infobar.newsletterbar h2{color:white;font-weight:normal;font-size:14px;margin-top:5px}.infobar.newsletterbar .c-form-group{width:100%}.infobar.newsletterbar .c-form-control-feedback-wrapper{top:5px}.infobar.newsletterbar button{padding:6px 12px 5px;font-size:12px;line-height:20px;border-radius:3px;margin-left:10px}@media screen and (max-width:992px){.infobar.newsletterbar header{float:none}.infobar.newsletterbar form{margin:10px 0 0}.infobar.newsletterbar .c-form-group{max-width:50%}}.locationbar{margin:5px}.locationbar .md,.locationbar .md p,.locationbar .options{color:#888888;font-weight:bold;font-size:11px;display:inline}.locationbar .options{margin-left:15px}a.star{text-decoration:none;color:#ff8b60}.entry .buttons li{display:inline-block;border:none;padding-right:4px;line-height:1.6em}.entry .buttons li+li{padding-left:4px}.entry .buttons li.stamp+li.stamp{margin-left:4px}.entry .buttons li a{color:#888;font-weight:bold;padding:0 1px}.entry .buttons li a.nonbutton{color:#369;font-weight:normal}.entry .buttons a:hover{text-decoration:underline}.entry .buttons .status-msg{display:none;margin-right:.5em}.toggle .error{font-size:x-small}.toggle .option{display:none}.toggle .option.active{display:inline}.thing .stub{display:none}.link.last-clicked{border:1px dashed gray;overflow:hidden}.link{margin:0;margin-bottom:8px;padding-left:3px}.link .score{text-align:center;color:#c6c6c6}.link .title{font-size:medium;font-weight:normal;margin-bottom:1px}.link .child h3{margin:15px;text-transform:none;font-size:medium}.rank{overflow:hidden}.profile-page .link .rank,.single-page .link .rank{display:none}.link .midcol{font-weight:bold;font-size:small}.link .score.likes{color:#FF8B60}.link .score.dislikes{color:#9494FF}.link .rank{float:left;margin-top:15px;color:#c6c6c6;font-family:arial;font-size:medium;text-align:right}.rank-spacer{font-size:medium}.midcol-spacer{font-size:small}.link.compressed{margin-bottom:5px}.link.compressed .rank{margin-top:10px}.link.compressed .title{margin:-2px 0 3px}.link.compressed .score{color:#888888}.link.compressed .score-placeholder{height:3px}.link.compressed .subreddit{font-weight:bold}.link.compressed .tagline{display:inline;margin-right:12px}.link.compressed .expando-button{display:none}.score.likes,.score.dislikes{display:none}.likes .score,.dislikes .score{display:none}.likes .score.likes{display:inline}.dislikes .score.dislikes{display:inline}.likes div.score.likes{display:block}.dislikes div.score.dislikes{display:block}.warm-entry .rank{color:#EDA179}.hot-entry .rank{color:#E47234}.cool-entry .rank{color:#A5ABFB}.cold-entry .rank{color:#4959F7}.gadget{font-size:x-small}.gadget .midcol{width:15px;margin:0}.gadget .reddit-link-end{clear:left;padding-top:10px}.gadget .click-gadget{font-size:small}.gadget small{color:gray}.gadget .reddit-entry{margin-left:20px}.gadget .right{text-align:right}.comment,.content .details{margin-left:10px}.comment.noncollapsed .numchildren{display:none}.comment.noncollapsed .usertext,.comment.noncollapsed .child,.comment.noncollapsed .buttons{display:block}.comment.noncollapsed .midcol{visibility:visible}body.show-controversial .comment.controversial>.entry .score:after{content:'†';position:relative;top:-2px}.comment.collapsed{padding-bottom:10px;line-height:14px}.comment.collapsed .numchildren{display:inline}.comment.collapsed .usertext,.comment.collapsed .child,.comment.collapsed .buttons{display:none}.comment.collapsed .midcol{visibility:hidden;height:1px}.comment.collapsed .tagline,.comment.collapsed .tagline a{color:gray}.comment.collapsed .tagline :not(.expand),.comment.collapsed .tagline a :not(.expand){font-style:italic}.comment.collapsed.collapsed-for-reason .collapsed-reason{display:inline}.comment.collapsed.collapsed-for-reason .score,.comment.collapsed.collapsed-for-reason .live-timestamp{display:none}.admin_takedown{background-color:#F7F7F7;color:#888888;padding:3px}.admin_takedown a:link{color:#326699}.comment .midcol{margin-left:0px;width:15px}.comment .title{font-size:small;margin-top:10px}.comment .author{font-weight:bold}.comment .expand{margin-right:3px;padding:1px}.comment .child,.comment .showreplies{margin-top:10px;margin-left:15px;border-left:1px dotted #DDF}.comment.collapsed-for-reason .collapsed-reason{display:none}.comment.deleted>.midcol{visibility:hidden}.comment .showreplies{display:block;margin-top:7px;margin-bottom:15px;padding:5px}textarea.gray{color:gray}.deepthread:after{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-82px -859px;background-repeat:no-repeat;content:" ";display:inline-block;width:25px;height:9px;margin:5px 0 0 5px}.deepthread a{font-size:larger;color:#336699}.deepthread a:hover{text-decoration:underline}.morecomments{font-size:larger}.morecomments a{color:#336699}.morecomments a:hover{text-decoration:underline}.morecomments .gray{font-weight:normal;color:#808080}.expand-btn{font-size:smaller;margin:0px 5px;margin-top:4px;display:inline-block}.message.noncollapsed .numchildren{display:none}.message.noncollapsed .child,.message.noncollapsed .buttons,.message.noncollapsed .md{display:block}.message.noncollapsed .midcol{visibility:visible}.message.collapsed>.entry .buttons,.message.collapsed>.entry .md{display:none}.message.collapsed .midcol{visibility:hidden;height:20px}.message{padding-left:5px;margin:10px 10px 20px 5px;padding:7px}.message.focal>.entry .md{background-color:#FFFFCC}.message .collapsed .head{color:#888888;font-style:italic}.message.message-parent .tagline,.message.message-reply .tagline{color:#485}.message.message-parent>.entry,.message.message-reply>.entry{color:#485}.message.message-parent>.entry .md,.message.message-reply>.entry .md,.message.message-parent>.entry blockquote,.message.message-reply>.entry blockquote,.message.message-parent>.entry del,.message.message-reply>.entry del{color:inherit}.message.recipient>.entry{color:black}.message.message-reply.recipient>.entry .head,.message.message-parent.recipient>.entry .head{color:black;font-weight:bold}.message .recipient a.author,.message .sender a.author,.message .subreddit{font-weight:bold}.message.new>.entry .head{color:orangered;font-weight:bold}.message.new>.entry{background-color:#F7F7F7;border:1px solid #E9E9E9;padding:6px}.message.new .unread{display:none}.message .child .message,.message .child .usertext{margin-top:10px;margin-left:12px}.message.was-comment .child .message,.message.was-comment .child .usertext{margin-top:0px;margin-left:0px}.message .expand{margin-right:3px;display:none}.message .entry{margin-left:0px}.message.message-parent .expand{display:inline}.message.message-parent .child,.message.message-reply .child{margin:0;padding:0}.message.message-parent .child .message,.message.message-reply .child .message{margin:0;padding:0}.message.message-parent .subject{margin-bottom:10px}.message.message-parent .message .subject{display:none}.message.message-reply .subject{display:none}.message.message-reply .entry,.message.message-parent .entry{margin-left:10px;padding-left:10px;padding-bottom:10px;border-left:2px dashed #E7E7E7}.message .buttons,.message .md{margin-left:15px}.message .entry .parent{border:1px solid #336699;max-width:60em;margin:3px 10px}.message .subject .correspondent{background-color:#EFF7FF;border:1px solid #336699;color:#336699;display:inline-block;margin-right:10px;padding:2px 5px}.message .subject .title{font-weight:normal;font-style:italic;margin-left:10px}.message .parent-link{margin-left:12px;padding:0 2px;font-weight:bold}.message.was-comment .midcol{margin-left:0px}.message.was-comment .buttons,.message.was-comment .parent-link{margin-left:0px}.message.was-comment .md{margin-left:2px}.message .subject{font-weight:bold;font-size:larger}.message.gold{font-family:"Bitstream Charter","Hoefler Text","Palatino Linotype","Book Antiqua",Palatino,georgia,garamond,FreeSerif,serif;background:url(../gold/tikkit-bg.png);max-width:80em;text-align:center;padding:20px;border-radius:4px;border:1px solid #555}.message.gold .insignia{float:left;margin:6em 20px 0 20px}.message.gold .subject{font-size:2.6em;line-height:1.5em;text-shadow:-1px -1px 0px rgba(255,255,255,0.8)}.message.gold .tagline,.message.gold .correspondent,.message.gold .expand-btn,.message.gold .unread-button,.message.gold .block-button,.message.gold .report-button,.message.gold ul.buttons li.first{display:none}.message.gold .entry{margin:0;border:0}.message.gold .md{margin:0;margin-bottom:10px;padding:15px;max-width:100%;text-shadow:0 0 2px #fff;border:0 dashed #000;border-width:1px 0}.message.gold .md blockquote{border:0;font-size:0.7em;font-style:italic}.message.gold .md p{font-size:1.2em;line-height:1.4em}.message.gold .usertext-edit{margin:0 auto}.message.gold .usertext-buttons{text-align:left}.message.gold ul.buttons li a{font-size:2em;text-shadow:0 0 3px #fff;color:#7a5d0e}.message.gold ul.buttons,.message.gold ul.buttons li{margin:0;padding:0}.message.gold.new>.entry{background-color:transparent;border:0;padding:0}.message.gold-auto blockquote{background-color:#fafafa;border:0;padding:4px;margin-left:0;margin-top:1em;font-style:italic;font-size:0.8em;color:#808080}.message.gold-auto blockquote p{margin:2px}.message.gold-auto blockquote strong{font-style:inherit}.clippy img{float:left}.clippy-bubble{background-color:#fffdd7;border:solid black 1px;width:350px;border-radius:5px;margin-left:5px;margin-bottom:15px;padding:7px;float:left}.clippy-headline{font-weight:bold;margin-bottom:0.5em}.clippy-bubble ul{list-style-type:disc;list-style-image:url(../clippy-bullet.png);padding-left:15px}.clippy-bubble li{margin-top:0.5em}.subreddit{margin-bottom:10px}.subreddit p{margin-top:0px;margin-bottom:1px}.subreddit .description{font-size:small;max-width:60em}.subreddit .key{display:block}.subreddit .title{font-size:medium;margin-right:5px}.subreddit .midcol{margin-right:5px;margin-top:5px;text-align:right;width:12em!important}.fancy-toggle-button{display:block;margin-bottom:5px}.fancy-toggle-button .active{border:1px solid #444;padding:1px 6px;background:#ffffff none repeat-x scroll center left;color:white;font-size:10px;font-weight:bold;line-height:20px;border-radius:3px}.fancy-toggle-button .remove{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -182px;background-repeat:repeat}.fancy-toggle-button .add{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px 0px;background-repeat:repeat}.fancy-toggle-button .banned{background-color:#666;padding:1px 1.9em}.commentbody.border{background-color:#ffc;padding-left:5px}.commentbody.grayed{color:gray;background-color:#E0E0E0;padding-left:5px}.fixedwidth{float:left;width:100px;height:0px}.clearleft{clear:left;height:0px}.clear{clear:both}.sharetable.preftable{margin-left:20px}.sharetable.preftable th{padding-bottom:5px;padding-top:5px}.sharetable.preftable button{margin-top:10px}.preftable.widget-preview{font-size:smaller}.preftable.widget-preview input[type="text"]{width:150px}.preftable #css-options input[type="text"]{margin-left:0px;width:6em}.share-summary{width:95%;margin-top:10px}.share-summary .head td{width:50%;font-size:large;text-align:center}.share-summary td{vertical-align:top}.share-summary>tbody>tr>td{padding-left:10px;padding-bottom:10px}.share-summary th{padding:5px;border-bottom:1px solid #000}.sponsored .entry{margin-right:20px}.sponsored .titlerow{background:#fcfcfc;padding:10px;border-top:#BCBCBC solid 1px;border-left:#BCBCBC solid 1px;border-bottom:#E0E0E0 solid 1px;border-right:#E0E0E0 solid 1px}.footer-parent{font-size:larger;padding-top:40px;clear:both;text-align:center}.footer{color:gray;padding:5px;margin:15px auto;border:1px solid #F0F0F0;display:flex;display:-webkit-flex;max-width:600px}.footer .col{display:inline-block;vertical-align:top;-webkit-flex:0 0 25%;flex:0 0 25%;margin:10px 0;padding:0 15px;border-left:1px solid #E0E0E0;box-sizing:border-box}.footer .col:first-child{border:none}.notes-button{margin-top:3px}.notes-status{font-size:larger}.load0{background-color:#FFFFFF}.load1{background-color:#f0f5FF}.load2{background-color:#E2ECFF}.load3{background-color:#d6f5cb}.load4{background-color:#CAFF98}.load5{background-color:#e4f484}.load6{background-color:#FFEA71}.load7{background-color:#ffdb81}.load8{background-color:#FF9191}.load9{background-color:#FF0000;color:#ffffff}.orangered{color:orangered}.logout{display:inline}.login-form-side{border:1px solid gray}.login-form-side input[type=text],.login-form-side input[type=password]{font-family:verdana;font-size:11px;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;border:1px solid #999;width:141px;margin:5px 0px 0px 5px;top:5px;padding:6px}.login-form-side input[type=password]{width:142px}.login-form-side #remember-me,.login-form-side .submit{margin:4px}.login-form-side .submit input[type=button]{margin:1px}.login-form-side #remember-me{float:left;line-height:24px;margin-left:5px}.login-form-side #remember-me *{vertical-align:middle}#rem-login-main{position:static;height:auto;width:auto;border:none;margin-right:5px;margin-top:0}.login-form-side label{padding:2px 0 2px 0;margin-right:5px;white-space:nowrap}.login-form-side .recover-password{margin-left:1em}.login-form-side .status{display:none}.login-form-side .submit{float:right}.login-form-side .submit *,.user-form .submit *{vertical-align:middle}.throbber{display:none;margin:0 2px;background:url(../throbber.gif) no-repeat;width:18px;height:18px}.working .throbber{display:inline-block}.working [type="submit"]{cursor:not-allowed;opacity:0.65;filter:alpha(opacity=65);pointer-events:none}.sr_style_toggle .throbber{position:absolute;margin-top:-2px;margin-left:4px}.status{margin:5px 0 0 5px;font-size:small}.error{color:red;font-size:small}.red{color:#ff0000}.buygold{color:#9A7D2E;font-weight:bold}.line-through{text-decoration:line-through}#noresults{margin-right:310px}#ad-frame,#ad_main{border:0px;overflow:hidden;width:300px;height:280px}#ad_sponsorship{border:0px;overflow:hidden;width:300px;height:120px}body.newsletter{background:#EEF7FF;font-size:12px}.newsletter-box{-webkit-box-shadow:0 3px 10px 4px rgba(0,0,0,0.1);box-shadow:0 3px 10px 4px rgba(0,0,0,0.1);margin:10% auto;background-color:white;width:90%;max-width:600px;border-radius:4px;padding:40px}.newsletter-box h1{margin:0;min-height:50px;font-size:15px}.newsletter-box .upvoted-weekly-logo{display:block;margin-top:15px;min-height:53px;background:transparent url(../upvoted-weekly-logo.svg) 0 0 no-repeat;background-size:contain}.newsletter-box .subscribe-thanks{display:none}.newsletter-box.success:before{content:"✓";display:block;text-align:center;color:#80d654;font-weight:bold;font-size:60px;line-height:1}.newsletter-box.success .result-message{display:block;margin:0 auto;text-align:center}.newsletter-box.success .subscribe-callout{display:none}.newsletter-box.success .subscribe-thanks{display:block;text-align:center;margin-top:25px}.newsletter-box.success form{display:none}.newsletter-box .result-message{margin-top:21px;line-height:1.5;font-size:14px;max-width:400px;color:#4f4f4f;font-weight:normal}.newsletter-box form{margin-top:40px;text-align:right}.newsletter-box .c-form-group{width:50%}.newsletter-box button{padding:6px 12px 5px;font-size:12px;line-height:20px;border-radius:3px;margin-left:10px}.newsletter-box .faq-toggle{position:absolute;margin-top:-13px;min-width:100px;font-size:11px;font-weight:bold;color:#79a6d2}.newsletter-box .faq-toggle:after{content:"â–¾";display:inline-block;height:15px;width:15px;text-align:center;position:absolute}.newsletter-box .faq-toggle.active:after{transform:rotate(180deg);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg)}.newsletter-box .faq{display:none}.newsletter-box .faq h3{margin-top:1.5em}.upvoted-gradient{position:fixed;bottom:0;width:100%;height:25%;background:transparent url(../upvoted-arrow-bg.png);z-index:-1}.upvoted-gradient:after{content:"";position:absolute;width:100%;height:100%;top:0;left:0;background:#eef7ff;background:-moz-linear-gradient(top,#eef7ff 0%,rgba(255,255,255,0) 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#eef7ff),color-stop(100%,rgba(255,255,255,0)));background:-webkit-linear-gradient(top,#eef7ff 0%,rgba(255,255,255,0) 100%);background:-o-linear-gradient(top,#eef7ff 0%,rgba(255,255,255,0) 100%);background:-ms-linear-gradient(top,#eef7ff 0%,rgba(255,255,255,0) 100%);background:linear-gradient(to bottom,#eef7ff 0%,rgba(255,255,255,0) 100%)}@media screen and (max-width:992px){.newsletter-box{position:static;transform:none;-webkit-transform:none;-moz-transform:none;-o-transform:none;-ms-transform:none;margin:10px auto;padding:15px;max-width:85%}.newsletter-box h1,.newsletter-box p{font-size:13px}.newsletter-box .faq-toggle{position:static;display:block;margin-top:20px;font-size:13px}.upvoted-gradient{display:none}}#searchmenu{margin:10px 0 0px 0;padding:2px 0 0 0;border-bottom:2px solid #369;background-color:#f5f5f5}#searchmenu .searchlabel{background-color:white;padding:2px 15px 0px 0px;font-weight:bold;color:#336699}#searchmenu .searchtime{font-weight:bold;display:inline;width:305px}#searchexpando{display:none;margin:5px 0 0 0;padding-top:10px;border-radius:3px}#searchexpando input,#searchexpando p{margin-bottom:10px}#searchexpando dl{margin:10px 0}#searchexpando dt{margin:0}#previoussearch p{margin:5px 0}#previoussearch label{display:block;margin:5px 0}#moresearchinfo{display:none;padding-top:5px;max-width:300px;border:0 solid orange;margin-top:-5px}label+#moresearchinfo{border-width:1px 0 0 0;margin-top:0px}#previoussearch #moresearchinfo{border-color:gray;margin:5px 0}#search_hidemore{float:right;margin-left:5px}.searchparams{margin:5px 20px 5px 20px}.searchparams .labels{text-align:right;margin-left:10px}.searchpane{margin:5px 305px 5px 0px;padding-left:96px;background:#e0e0e0 url(../search-large.png) 26px center no-repeat}.search-summary{float:right;text-align:right;margin:6px 8px 0 0}.search-summary .result-count{font-weight:bold}.searchfail{color:#c00000;font-size:larger;line-height:2em}.searchfail a{color:red;text-decoration:underline}#search{white-space:nowrap}#searchexpando,#moresearchinfo{white-space:normal}#search input[type=text]{border:1px solid gray;font-size:13px;font-family:verdana;width:300px;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;padding:6px;padding-right:25px;padding-left:9px;vertical-align:middle}#search input[type=submit]{background-color:transparent;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-91px -839px;background-repeat:no-repeat;height:13px;width:13px;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;border:none;margin:0;margin-left:-22px;vertical-align:middle}#search input[type=submit]:hover{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-107px -491px;background-repeat:no-repeat}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){#search input[type=submit]{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAAb1BMVEUAAACJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYm4Po3NAAAAJXRSTlMAAQIEDBAREhMUJS0uQ09QV19hZG1udHmbnJ64xMXGx8jOz9DUayO31AAAANNJREFUeAGF0fFugjAUhfGDg3W1blMEC2IV8Lz/My4nEnK7jOz3380nN7XFy0fdJzL1tUeujBMXUyxh7Acaw96UBzPj2sqBmtuDc6Edqe+0U6Km/v01VJ2muJxtUnnDYqc2e0itbRVWlXbWkJ5kC6MleYUkkgcYgWSCkKSD4Uiy+CdpYfi98Pb3MRqS3fbhzxA/61e77C8/vbmorrIXdcmvtwnOhWaknNZH0Zw7mqfcbGWcuXheTqaJr6+JvHVnDxzzJkUBUZNvZGy7Y7PZZH097p8/V4YmEaKXKKIAAAAASUVORK5CYII=');background-size:13px 13px;background-position:0 0}#search input[type=submit]:hover{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAAeFBMVEUAAACJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYl3r/6iAAAAJ3RSTlMAAQMFDhMUFhcYLC02N1FfYGlydXiDhIuRuru8vt3s7e7v8PH4+fpBQVyrAAAA1ElEQVR4AYXQcW+CMBBA8cPBuk7cpgiCiFUE3/f/hksuDbmakf3+uuSl5DhR8lH1AUJfeUnl7UQ0tbktnwPGsDXlTuKxtFzfjM3OubIZ9V0eUwvQv4sqOoA27jYB/ZtEmw6Yvc4VMBayKEag0rEHGjEa4KJTAHY2lUDQCcDZ5ACyf1IAytcPXv9eowbO68sfdfQz0G2SX356c6iusIc6peetS+fKegTgINH2wav90ob1lrcz0fN0SJv46hLgej56kb1pUZaJiu1HUqbdZLXZZH3fb1+/i3YpBcVhtqwAAAAASUVORK5CYII=');background-position:0 0}}.legal{color:#808080;font-family:serif;font-size:small;margin-top:20px}.legal a{text-decoration:underline}.divide{border-right:2px solid #D3D3D3;margin-right:-2px}.login-form-section{position:relative;float:left;overflow:hidden;padding-left:2%;padding-right:2%}.login-form-section.register{width:56%}.login-form-section.login{width:36%}.login-form-section>h3{margin-bottom:0;margin-top:10px;font-size:large;font-weight:bold;font-variant:small-caps;color:#404040}.login-form-section p{text-align:left;margin-bottom:10px;color:#606060;margin-bottom:20px}.login-form-section.register .registration-info{position:absolute;left:53%;width:40%;min-width:20em;margin-top:1.25em;color:#777}.login-form-section.register .registration-info .md{font-size:1.1em}.login-form-section.register .registration-info .md li{list-style-type:disc;margin-bottom:.5em}.user-form label{display:block;font-weight:bold;color:#606060}.user-form label.note{font-weight:normal}.user-form .error{display:inline-block;margin-top:2px;line-height:16px;color:inherit;font-size:inherit}.user-form .error.field-ratelimit,.user-form .error.field-vdelay{display:block}.user-form .remember{display:inline;margin-left:2px;text-transform:lowercase}.user-form input[type=checkbox]{vertical-align:bottom}.user-form ul{margin:7px}.user-form li{margin-top:5px}.user-form p .btn{margin-top:5px}.user-form input.logtxt{width:125px}.user-form input[type=text],.user-form input[type=password],.user-form input[type=email]{width:125px;border:1px solid #A0A0A0;margin-top:2px;margin-bottom:2px;margin-right:10px;padding:1px}.user-form #captcha{width:250px}.user-form .submit{margin-top:10px}#passform h1{margin-bottom:0px}#passform p{margin-bottom:5px;font-size:small}.register-form .name-entry *{vertical-align:middle}.notice-taken,.notice-available{display:none;line-height:16px}.register-form.name-taken .notice-taken,.register-form.name-available .notice-available{display:inline-block;margin-top:2px}.register-form .name-entry .throbber{display:none;margin-left:5px}.register-form.name-checking .name-entry .throbber{display:inline-block;margin-left:-1px;margin-top:2px}.login-page #login{margin-right:300px}@media (max-width:768px){.login-page #login{margin-right:0}.login-page .side{display:none}}#cover-msg{line-height:normal;margin:0 0 50px}#login .modal-title{margin:0 0 25px}#login .c-alert{display:none;font-size:11px}@media (max-width:480px){#login .c-btn{display:block;width:100%}}.login-disclaimer{color:#6a6a6a}.split-panel{margin-bottom:49px}.split-panel:before,.split-panel:after{content:" ";display:table}.split-panel:after{clear:both}.split-panel .split-panel-section{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;float:none;width:100%}.split-panel .split-panel-section:first-child{padding-right:0}.split-panel .split-panel-section:last-child{padding-left:0}.split-panel .split-panel-section.split-panel-divider:first-child{border:0;border-bottom:1px solid #e0e0e0;padding-bottom:60px;margin-bottom:60px}.split-panel .split-panel-section.split-panel-divider:last-child{border:0;border-top:1px solid #e0e0e0;padding-top:60px;margin-top:60px}@media (min-width:768px){.split-panel .split-panel-section{float:left;width:50%}.split-panel .split-panel-section:first-child{padding-right:60px}.split-panel .split-panel-section:last-child{padding-left:60px}.split-panel .split-panel-section.split-panel-divider:first-child{border:0;border-right:1px solid #e0e0e0;margin-bottom:0;padding-bottom:0}.split-panel .split-panel-section.split-panel-divider:last-child{border:0;border-left:1px solid #e0e0e0;margin-top:0;padding-top:0}}.login-page .split-panel .split-panel-section{float:none;width:100%}.login-page .split-panel .split-panel-section:first-child{padding-right:0}.login-page .split-panel .split-panel-section:last-child{padding-left:0}.login-page .split-panel .split-panel-section.split-panel-divider:first-child{border:0;border-bottom:1px solid #e0e0e0;padding-bottom:60px;margin-bottom:60px}.login-page .split-panel .split-panel-section.split-panel-divider:last-child{border:0;border-top:1px solid #e0e0e0;padding-top:60px;margin-top:60px}@media (min-width:992px){.login-page .split-panel .split-panel-section{float:left;width:50%}.login-page .split-panel .split-panel-section:first-child{padding-right:60px}.login-page .split-panel .split-panel-section:last-child{padding-left:60px}.login-page .split-panel .split-panel-section.split-panel-divider:first-child{border:0;border-right:1px solid #e0e0e0;margin-bottom:0;padding-bottom:0}.login-page .split-panel .split-panel-section.split-panel-divider:last-child{border:0;border-left:1px solid #e0e0e0;margin-top:0;padding-top:0}}.content>#login>.split-panel{padding-left:60px;padding-right:60px;padding-top:60px}.content>#login>p{margin-left:60px;margin-right:60px}.popup h1{font-size:large;font-weight:normal;margin-left:1em}.popup h2{text-align:center;font-size:small;margin-top:0px;color:black;font-weight:normal}.usertable{margin-left:10px}.usertable{font-size:larger}.usertable td,.usertable th{padding:0 0.7em}.usertable{white-space:nowrap}.usertable>.toggle{display:inline-block;margin:1em 0 .5em;padding:11px 15px;border:1px solid #bbb;border-radius:2px;background:#fdffe8}.usertable>.toggle .option.main:before{margin-right:7px}.usertable>.toggle .option{display:inline}.usertable>.toggle .togglebutton,.usertable>.toggle .error{display:none;font-size:inherit;border-left:1px solid #bbb;padding:4px 15px;padding-right:0;margin-left:10px}.usertable>.toggle .active .togglebutton{display:inline}.usertable>.toggle .error.active{display:inline}.usertable tr:hover{background-color:#e5efff}body.rulespage-body{overflow-y:scroll}.rulespage{margin:0 auto;position:relative;vertical-align:middle;width:600px}.rulespage h1{font-size:xx-large;text-align:center;margin-top:20px}.rulespage .info{font-size:larger;padding-top:10px}.rulespage .rule-list{margin:10px;padding:10px;font-size:medium}.rulespage li{border-bottom:1px solid #ddd;padding:10px;margin:10px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.rulespage li.first-rule{border-top:1px solid #ddd;padding-top:18px}.rulespage li#minors{padding-bottom:18px}.rulespage .expander{color:gray;cursor:help;padding:10px}.rulespage .examples{font-size:small}.rulespage li.example{border:none}.rulespage li.good-example{background:#bcf5a9}.rulespage li.bad-example{background:#f5a9a9}.rulespage em{font-weight:bold}.rulespage em.toggle{font-weight:normal}.rulespage .info{text-align:center}.rulespage img.bottom{margin-top:30px;text-align:center;padding-bottom:-40px}.aboutpage{margin-right:320px}.aboutpage p{margin:5px}.aboutpage h1,.aboutpage h2{margin:10px}.aboutpage .usertable{width:45%}.little a{font-size:x-small}.oldbylink a{background-color:#F0F0F0;margin:2px;color:#808080}.error-log{clear:both}.error-log a:hover{text-decoration:underline}.error-log .rest{display:none}.error-log:first-child .rest{display:block}.error-log,.error-log .exception{border:solid #aaa 1px;padding:3px 5px;margin-bottom:10px}.error-log .exception{background-color:#f0f0f8}.error-log .exception.new{border:dashed #ff6600 2px}.error-log .exception.severe{border:solid #ff0000 2px;background-color:#ffdfdf}.error-log .exception.interesting{border:dotted black 2px;background-color:#e0e0e8}.error-log .exception.fixed{border:solid #008800 1px;background-color:#e8f6e8}.error-log .exception span{font-weight:bold;margin-right:5px}.error-log .exception span.normal{margin-right:0;display:none}.error-log .exception span.new,.error-log .edit-area label.new{color:#ff6600}.error-log .exception span.severe,.error-log .edit-area label.severe{color:#ff0000}.error-log .exception span.interesting,.error-log .edit-area label.interesting{font-weight:normal;font-style:italic}.error-log .exception span.fixed,.error-log .edit-area label.fixed{color:#008800}.error-log .exception-name{margin-right:5px;display:inline-block;max-height:50px;overflow:hidden}.error-log .nickname{color:black;font-weight:bold;font-size:larger}.error-log .exception.fixed .nickname{text-decoration:line-through}.error-log a:focus{-moz-outline-style:none}.error-log .edit-area{border:solid black 1px;background-color:#eee}.error-log .edit-area label{margin-right:25px}.error-log .edit-area input[type=radio]{margin-right:4px}.error-log .edit-area input[type=text]{width:800px}.error-log .edit-area table td,.error-log .edit-area table th{padding:5px 0 0 5px}.error-log .save-button{margin:0 5px 5px 0;font-size:small;padding:0}.error-log .date{font-size:150%;font-weight:bold}.error-log .hexkey{color:#997700}.error-log .exception-name{font-size:larger;color:#000077}.error-log .frequency{font-size:larger;float:right;color:#886666}.error-log .occurrences{border:solid #003300 1px;margin:5px 0 2px;padding:2px}.error-log .occurrence{color:#003300;font-family:monospace;margin-right:3em;white-space:nowrap}.error-log table.stacktrace th,.error-log table.stacktrace td{border:solid 1px #aaa}.error-log table.stacktrace td{font-family:monospace}.error-log table.stacktrace td.col-1{text-align:right;padding-right:10px}.error-log .logtext.error{color:black;margin:0 0 10px 0}.error-log .logtext{margin-bottom:10px;border:solid #555 2px;background-color:#eeece6;padding:5px;font-size:small}.error-log .logtext *{color:black}.error-log .logtext.error .loglevel{color:white;background-color:red}.error-log .logtext.warning .loglevel{background-color:#ff6600}.error-log .logtext.info .loglevel{background-color:#00bbff}.error-log .logtext.debug .loglevel{background-color:#00ee00}.error-log .logtext .loglevel{padding:0 5px;margin-right:5px;border:solid black 1px}.error-log .logtext table{margin:8px 5px 2px 0;font-family:monospace}.error-log .logtext table,.error-log .logtext table th,.error-log .logtext table td{border:solid #aaa 1px}.error-log .logtext table th,.error-log .logtext table td{border:solid #aaa 1px}.error-log .logtext table .occ{text-align:right}.error-log .logtext table .dotdotdot{padding:0}.error-log .logtext table .dotdotdot a{margin:0;display:block;width:100%;height:100%;background-color:#e0e0e0}.error-log .logtext table .dotdotdot a:hover{background-color:#bbb;text-decoration:none}.error-log .logtext .classification{font-size:larger;font-weight:bold}.error-log .logtext .actual-text{max-width:600px;overflow:hidden}.details{font-size:x-small;margin-bottom:10px}.details span{margin:0 5px 0 5px}.details th{text-align:right;padding-right:5px;font-weight:bold}.details td{vertical-align:top}.ring{font-weight:bold;background-color:red;color:white;text-align:center;padding-left:3px;padding-right:4px!important;cursor:pointer}.vote-note{padding-left:3px;max-width:150px}.vote-a-notes{color:red}.vote-up{color:orangered}.vote-down{color:#336699}.vote-invalid{color:#888888!important;font-style:italic}.unvotable-message{border:solid 1px #ff6600;margin-top:4px;padding:1px 3px;border-radius:3px;display:none}.bottommenu{color:gray;font-size:smaller;clear:both}.bottommenu a{color:gray;text-decoration:underline}.bottommenu .updated{color:green}.debuginfo{text-align:right;padding:5px;color:gray;font-size:smaller;clear:both}.debuginfo .icon{color:#a0a0a0;font:1.5em serif;padding:0 2px}.debuginfo .content{display:none}.debuginfo:hover .content{display:inline}.button{border-collapse:collapse;color:gray;text-align:center;margin:1px;color:#369}button.button[disabled]{color:gray}.button #cover{position:relative}.button .cover{background:white}.button #popup{position:absolute;width:80%;z-index:1001;background:white;padding:1px;left:0px;top:0px;margin:0px;border-color:#B2B2B2 black black #B2B2B2;border-style:solid;border-width:1px}.button .arrow{width:15px}.num{font-weight:bold;font-size:larger}.button.thing{margin:0px;padding:0px}.button-body{background-color:transparent}.button .blog{border:1px solid #c7def7;color:gray;text-align:center;margin:0px;border-radius:4px;background-color:white}.button .blog .r{color:gray}.button .blog .score{white-space:nowrap}.button a:hover{text-decoration:underline}.button .blog1{font-size:x-small}.button .blog1 .arrow{float:left;margin-left:2px;margin-right:2px}.button .blog1 .headimgcell{background-color:#c7def7;width:18px;float:left}.button .blog1 .headimgcell a{display:inline-block}.button .blog1 .score{float:center;margin-top:2px;margin-right:5px}.button .blog2{font-size:small}.button .blog2 .arrow{width:15px;margin-left:auto;margin-right:auto}.button .blog2 .bottomreddit{color:black;background-color:#c7def7;font-size:small}.button .blog2 .score .submit{display:block;font-size:x-small;line-height:17px}.button .blog.blog3{font-size:small;border:none;background-color:transparent}.button .blog3 .left{float:left;width:50%}.button .blog2 .arrow{width:15px;margin-left:auto;margin-right:auto}.button .blog3 .right{float:right;margin-top:5px}.button .blog3 .score .submit{display:block;font-size:x-small;line-height:17px}.button .blog3 .snoo{margin-top:-1px}.blog5 .right{float:right}.blog5 .left{float:left;display:block;margin-top:10px}.blog5 .clearleft{clear:left}.button .blog.blog5{border:none;text-align:left;font-size:small}.blog5 a.bling{float:left}.blog5 .container{margin-left:35px;margin-top:2px;height:50px}.blog5 ul{display:inline}.blog5 ul a{color:#515481;font-weight:bold;text-decoration:underline}.blog5 li{display:inline;padding:1px 10px 1px 10px}.blog5 li.selected{background-color:#F8F8F1;color:#000;border-color:#CCC;border-style:solid solid none solid;border-width:1px}.blog5 .votes{height:25px;background-color:#F8F8F1;border:1px solid #CCC;padding-top:5px}.blog5 .arrow{margin-right:15px;margin-left:5px;color:black;cursor:pointer;display:inline;background-position:left center;background-repeat:no-repeat;padding-left:20px}.blog5 .votes.disabled .arrow{color:#888}.blog5 .arrow:hover{text-decoration:none}.blog5 .arrow b{font-size:larger}.blog5 .arrow.upmod b{color:#FF8B60}.blog5 .arrow.downmod b{color:#9494FF}.blog5 .right{margin-right:5px;font-size:medium;font-style:italic}.optional{color:#008000}.instructions{font-size:larger}.instructions h1,.instructions h2,.instructions h3{margin-top:20px;margin-bottom:20px}.instructions p{margin:10px;max-width:60em}.instructions pre{margin:5px;margin-right:10px}.instructions iframe{margin:5px 10px 5px 0px}.instructions input,.instructions select{margin:0 0.5em}.instructions a:focus{-moz-outline-style:none}.instructions strong{font-weight:bold}.instructions .buttons{margin-left:1em;max-width:50em}.instructions .buttons li{margin-top:1em;border-bottom:1px solid #e0e0e0;padding-bottom:1em}.instructions code{display:block;font-family:monospace;font-size:small;margin:5px;background-color:#FF9;padding:10px;max-width:50em}.self-service.instructions{margin-bottom:50px}.self-service.instructions p{margin:10px 0}.self-service.instructions ul{list-style-type:circle;margin-left:60px}.self-service.instructions li+li{padding-top:10px}.self-service .ad-launch-buttons{text-align:center}.self-service .ad-launch-buttons .button{font-size:22px;padding:10px 20px;margin-bottom:5px}.self-service .col-bottom-box{margin-right:20px}body.contact-us-page{overflow-y:scroll}.contact-us-page .content{width:600px;margin:0px auto}.contact-us-page h1{font-size:xx-large;text-align:center;margin:20px 0px}.contact-us-page .info{font-size:larger;text-align:center;margin-bottom:20px}.contact-us-page h2.button{background-color:#cee2f5;font-size:x-large;font-weight:bold;color:#369;text-align:center;border-radius:7px;border:2px solid #369;line-height:1.5em;margin:0px 10px 10px 10px}.contact-us-page h2.button:hover{background-color:#daeaf8;cursor:pointer}.contact-us-page .details{margin:0;display:none}.contact-us-page li:target .details{display:block}.contact-us-page .details li{background-color:#fafafa;font-size:small;border:1px solid #ccc;margin:0px 40px 10px 40px;padding:10px;width:500px}.contact-us-page img.space-snoo{display:block;margin:50px auto 0 auto}.button-demo a.view-code,.button-demo a.hide-code{float:right;margin-bottom:1em}.button-demo a.hide-code{display:none}.instructions .button-demo code{display:none}.button-demo.show-demo a.view-code{display:none}.button-demo.show-demo a.hide-code{display:inline}.button-demo.show-demo code{display:block}#preview{float:right;width:30em;margin:10px}#preview span{color:lightgray}#preview #previewbox{border-width:.2em;border-style:dashed;border-color:lightgray;padding:1em;font-size:larger}.bookmarklet{border:solid #888888 1px;padding:0px 2px}.toolbar{font-size:small;border-bottom:1px solid #336699;background-color:#CEE3F8}.toolbar .warning{height:20px;background-color:#fa8072}.toolbar .warning a{display:inline;border:none;text-decoration:underline}.toolbar .warning,.toolbar .warning a{color:#000;line-height:20px;font-weight:bold;text-align:center}.toolbar .left-side{height:19px;float:left;border-right:solid #336699 1px;background-color:#EFF7FF}.toolbar .middle-side{text-align:center;background-color:#EFF7FF;cursor:pointer}.toolbar .middle-side a,.toolbar .middle-side b{display:block;border-left:none}.toolbar .middle-side input[type=text]{font-size:14px;vertical-align:baseline;width:100%;height:18px;border:none;border-top:solid transparent 1px;margin-left:2px}.toolbar .middle-side .url{overflow:hidden}.toolbar .middle-side .domain{color:#888;font-size:small}.toolbar .right-side{float:right;background-color:#EFF7FF;height:19px}.toolbar a,.toolbar b{font-weight:normal;display:inline-block;height:18px;border-left:solid #336699 1px;white-space:nowrap;padding:1px 4px 0px;overflow:hidden;outline:none;-moz-outline:none}.toolbar .likes .score.likes{display:inline-block}.toolbar .dislikes .score.dislikes{display:inline-block}.toolbar a,.toolbar .clickable{cursor:pointer;color:#336699;text-decoration:none}.toolbar .clickable:active,.pushed-button{background-color:#cee3f8!important;color:orangered!important}.toolbar a img,toolbar b img{vertical-align:middle;padding-top:3px;vertical-align:-3px}.toolbar .content{float:left;vertical-align:middle}.toolbar .logo{margin:0px;padding:0 2px;border-left:none;vertical-align:top}.toolbar .title{padding-left:1em;padding-right:1em;color:black;display:block;overflow:hidden}.toolbar .title:active{color:orangered}.toolbar .controls{float:right}.toolbar .arrow{display:inline-block;width:auto;margin:0px;background-position:left center;padding-left:16px}.toolbar .arrow.upmod{background-image:url(../aminiupmod.gif)}.toolbar .arrow.downmod{background-image:url(../aminidownmod.gif)}.toolbar .arrow.up{background-image:url(../aminiupgray.gif)}.toolbar .arrow.down{background-image:url(../aminidowngray.gif)}.toolbar-status-bar{border-top:solid #336699 1px;border-bottom:solid #336699 1px;background-color:#F6E69F;padding:0px 2px;overflow:auto}.toolbar-status-bar .login-arrow-left{overflow:auto;background-image:url(../tb-loginarrow-left.png);background-position:top right}.toolbar-status-bar .login-arrow-right{float:right;margin-right:75px}.toolbar-status-bar .login-message{float:left;background-color:#F6E69F;padding-right:3px}.comments-panel .infobar{padding:3px 10px 7px;margin:5px 10px 10px 3px}#inner_toolbar #reddit_panel,#inner_toolbar #reddit_link_container,#inner_toolbar #reddit_link{position:absolute;height:100%;border:none}#inner_toolbar #reddit_panel{width:0}#inner_toolbar #reddit_link_container,#inner_toolbar #reddit_link{width:100%}#inner_toolbar.expanded #reddit_panel{width:400px}#inner_toolbar.expanded #reddit_link_container{left:400px;right:0;width:auto}.min-body{height:100%}.min-body .content{margin-top:0px;border-right:solid #369 1px;min-height:100%;max-width:60em;overflow:auto}.min-body .content h1,.min-body .content h2{padding-left:13px;display:inline-block;margin-bottom:15px}.min-body .content #noresults{margin:0 0 0 13px}.starkcomment+.clearleft+.starkcomment{margin-top:10px}.starkcomment .commentbox{color:black;background-color:#f0f0f0;padding:5px;margin-left:0px;margin-right:10px}.starkcomment .tagline{text-align:right}form .blurb{margin-bottom:5px}form .spacer+.spacer{margin:15px 0}form input[type=checkbox],form input[type=radio]{margin:2px .5em 0 0}.pretty-form{font-size:larger;vertical-align:top}.pretty-form p{margin:3px}.pretty-form input[type=checkbox],.pretty-form input[type=radio]{margin:2px .5em 0 0}.pretty-form img{margin:3px 0.5em}.pretty-form input[type=text],.pretty-form textarea,.pretty-form input[type=password],.pretty-form input[type=number]{border:1px solid gray;width:300px;padding:2px;-webkit-box-shadow:inset 0px 1px 1px rgba(0,0,0,0.3),0px 1px 0px rgba(255,255,255,0.6);-moz-box-shadow:inset 0px 1px 1px rgba(0,0,0,0.3),0px 1px 0px rgba(255,255,255,0.6);box-shadow:inset 0px 1px 1px rgba(0,0,0,0.3),0px 1px 0px rgba(255,255,255,0.6)}.pretty-form.short-text input[type=text].number{margin:0 0.5em}.pretty-form.short-text input[type=text].text{margin:0 0.5em 0 0;width:10em}.pretty-form .infobar{width:285px;margin:5px}.pretty-form input[type=text],.pretty-form input[type=file],.pretty-form input[type=password],.pretty-form input[type=number],.pretty-form select,.pretty-form b,.pretty-form textarea,.pretty-form button{margin:3px 5px}.pretty-form th{text-align:right}.pretty-form input[type=number]{width:75px}.white-field,.delete-field{background-color:white;padding:10px}.delete-field td{vertical-align:top}.pretty-form .delete-field{background:transparent}.pretty-form .delete-field td label+label{margin-left:2em}#pref-delete textarea#delete-message{font-size:smaller;height:5em}#pref-delete .md ul{margin-top:0;margin-bottom:0}#pref-delete .md ul li{margin:.5em 0}#pref-delete .credentials input{margin:.2em 0}#pref-delete .credentials .error,#pref-delete .error.RATELIMIT{margin-left:5px}.pretty-form.short-text input[type=text],.pretty-form.short-text textarea,.pretty-form.short-text input[type=password]{width:2em}#url-field #suggest-title{text-align:right}#url-field button{margin:10px 0 0 5px}#url-field .title-status{color:red;font-size:small}.content.submit .info-notice{background-color:#E4F2FB;border:1px solid #5F99CF;padding:9px;margin-bottom:12px;font-size:larger}.content.submit .info-notice a{font-weight:bold;text-decoration:underline}.opt-form{font-size:larger}.opt-form form{display:inline}.preftable th{padding:10px;font-weight:bold;vertical-align:top;text-align:right;white-space:nowrap}.preftable th label{display:block}.sharetable.preftable th label{display:inline}.preftable th span{display:block}.preftable td.prefright{padding:8px 0}.preftable select{margin:0 .5em 0 .5em}.preftable .spacer{margin-bottom:5px}.preftable .note{width:100%;vertical-align:top;padding-top:10px}.preftable .details{font-size:smaller;color:gray;margin:0}.preftable .details.reddit-gold{color:#9A7D2E}.preftable .reddit-themes-description{max-width:800px;margin-bottom:10px}.preftable .container.reddit-themes{max-width:800px;margin:5px 0;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-direction:row;-webkit-flex-direction:row;justify-content:flex-start;-webkit-justify-content:flex-start}.preftable .container.reddit-themes .theme{-webkit-flex:1 0 250px;flex:1 0 250px;padding:7px 0 11px 0;position:relative;max-width:270px}.preftable .container.reddit-themes .theme.selected{background-color:#a8c8ea;font-weight:normal}.preftable .container.reddit-themes .theme.select-custom-theme{-webkit-flex:1 0 100%;flex:1 0 100%;max-width:100%;width:100%;margin:7px;padding:7px}.preftable .container.reddit-themes .theme.select-custom-theme input{margin-left:2px}.preftable .container.reddit-themes .theme img{margin:0}.preftable .container.reddit-themes .theme .theme-thumbnail{display:block;margin:5px auto}.preftable .container.reddit-themes .theme .theme-container{max-width:240px;margin:0 auto}.preftable .container.reddit-themes .theme .theme-container p{display:inline}.preftable .container.reddit-themes .theme .theme-thumbnail{margin:5px auto}.preftable .container.reddit-themes .theme .theme-thumbnail:hover .theme-preview{visibility:visible;opacity:1}.preftable .container.reddit-themes .theme .theme-preview{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);-webkit-transform:translate(-50%,-50%);-moz-transform:translate(-50%,-50%);-o-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);visibility:hidden;opacity:0;z-index:100;-webkit-transition:opacity 0.2s ease 0.3s;-moz-transition:opacity 0.2s ease 0.3s;-o-transition:opacity 0.2s ease 0.3s;-ms-transition:opacity 0.2s ease 0.3s;transition:opacity 0.2s ease 0.3s;-webkit-box-shadow:0 0 5px #000000;box-shadow:0 0 5px #000000}.preftable .container.reddit-themes .theme .theme-preview img{margin:0;display:block}.over18 button{margin:0 10px 0 10px;padding:5px}.entry .buttons li.nsfw-stamp{font-size:x-small}.stamp{font-size:x-small;padding:0 2px;border:1px solid!important;border-radius:3px}.nsfw-stamp{color:#d10023}.nsfw-stamp acronym{text-decoration:none}.private-stamp{color:#e36e00}.restricted-stamp{color:#e36e00}.archived-stamp{color:#757575}.entry .buttons li.reported-stamp{border:1px solid black!important;padding:0 4px;background-color:#f6e69f}.suspicious{background-color:#f6e69f}.thing.spam{background-color:#fa8072}.comment.spam>.child,.message.spam>.child{background-color:white}.comment.spam>.child{margin-left:0;padding-left:15px}.message.spam>.child{}div.banned-user{overflow:hidden;opacity:.7;filter:alpha(opacity=70)}div.banned-user .title{text-decoration:line-through}.approval-checkmark{cursor:pointer;height:0.8em;vertical-align:baseline;margin-left:3px}.tagline .approval-checkmark{height:1em}.little{font-size:smaller}.gray{color:#808080}.stats{float:left;margin-right:2em;border-collapse:collapse;font-size:larger}.stats td.space{width:20px}.stats td.sec{padding-bottom:7px;font-size:18px;font-weight:normal}.stats a{color:#336699}.stats a:hover{text-decoration:underline}.stats td.k{color:#808080}.stats th{text-align:left;background-color:whitesmoke;color:#369;font-weight:bold}.stats td.ri{padding-left:20px;text-align:right}.thumbnail{float:left;font-size:0;margin:0;margin-right:5px;margin-bottom:2px;overflow:hidden;width:70px}.thumbnail.nsfw{height:70px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -359px;background-repeat:no-repeat}.thumbnail.self{height:50px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -491px;background-repeat:no-repeat}.thumbnail.default{height:50px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -435px;background-repeat:no-repeat}.stylesheet-customize-container textarea{font-family:"Bitstream Vera Sans Mono",Consolas,monospace;margin:0;padding:0px}.stylesheet-customize-container h2{margin-top:15px;margin-bottom:10px}.image-upload .new-image{margin-left:20px}.image-upload span{padding-left:5px}ul#image-preview-list{margin:20px 320px 20px 20px;font-size:larger}ul#image-preview-list li{padding-bottom:10px;margin-bottom:20px;vertical-align:top;width:45%;height:100px;float:left;position:relative}ul#image-preview-list .preview{width:100px;float:left;display:block;text-align:center;max-height:100px;overflow:hidden}ul#image-preview-list .preview img{max-width:100px;padding:auto}ul#image-preview-list .description{vertical-align:top;margin-left:105px}ul#image-preview-list .description pre{display:inline;padding:5px}.sheets{margin-right:315px}.sheets .col{width:100%}.sheets .col>div{margin:0 5px}.sheets .col textarea{width:100%}.sheets .buttons{margin-left:5px}.sheets .btn{margin-left:0px;margin-right:5px}.sheets .btn.right{float:right;margin-right:3px}#validation-errors{margin-left:40px;margin-top:10px;list-style-type:disc}#validation-errors a,#validation-errors li,.errors h2{color:#ff0000}#validation-errors a:hover{text-decoration:underline}#validation-errors pre{padding:10px;color:black}#preview-table{padding-right:15px}#preview-table>table{border-width:.2em;border-style:dashed;border-color:lightgray;padding:5px;margin:5px;width:900px}#preview-table>table>tbody>tr{padding-bottom:10px}#preview-table>table>tbody>tr>td{padding:5px;padding-right:15px}#preview-table>table>tbody>tr>th{padding:5px;padding-right:15px;font-weight:bold;vertical-align:top;font-size:larger;text-align:right}#img-preview-container{border-width:.2em;border-style:dashed;border-color:lightgray;padding:5px;margin:5px;float:left}#image-upload #img-preview-container img{max-width:160px}#icon-upload #img-preview-container img{width:60px;height:60px;margin:0}#banner-upload #img-preview-container img{width:160px;height:90px;margin:0}.linefield.mobile{width:512px;background-color:#EFF7FF;border:1px solid #CEE3F8}.private-feeds.instructions .prefright{line-height:2em}.private-feeds.instructions .feedlink{padding:2px 5px;font-weight:bold;margin-right:5px;border:1px solid #0000FF;color:white;padding-left:22px;background:#336699 none no-repeat scroll top left}.private-feeds.instructions .feedlink.rss-link{background-image:url(../rss.png)}.private-feeds.instructions .feedlink.json-link{background-color:#DDDDDD;background-image:url(../json.png);color:black}#sr-header-area{background-color:#f0f0f0;white-space:nowrap;text-transform:uppercase;border-bottom:1px solid gray;font-size:90%;height:18px;line-height:18px}#sr-header-area .width-clip{position:absolute;left:0;right:0}#sr-header-area .selected a{color:orangered}#sr-header-area .sr-list{overflow:hidden}#sr-header-area .dropdown.srdrop{float:left;padding-left:5px}#sr-header-area .drop-choices.srdrop{margin-top:0;margin-left:5px}.dropdown.srdrop .selected{background:none no-repeat scroll center right;background-image:url(../droparrowgray.gif);display:inline-block;vertical-align:bottom;padding-right:21px;padding-left:5px;color:black;font-weight:normal;margin-left:-5px;margin-right:10px;cursor:pointer}.srdrop .choice{padding-top:3px}.srdrop .choice.top-option{font-style:italic;border-bottom:1px dotted #369}.srdrop .choice.bottom-option{font-style:italic;border-top:1px dotted #369}.sr-bar .separator{color:gray}.sr-bar a{color:black}.sr-bar a.gold{color:#9a7d2e;font-weight:bold}#sr-more-link{color:black;background-color:#f0f0f0;position:absolute;right:0;top:0;padding:0 5px 0 15px;font-weight:bold;margin:0}#sr-more-link:hover{text-decoration:underline}.subscription-box li{clear:left;margin-bottom:10px}.subscription-box .fancy-toggle-button{margin-right:5px;float:left}.subscription-box .title{font-size:medium;color:blue;margin-right:5px}.subscription-box .title.banned{color:dimgray;text-decoration:line-through}.subscription-box .column{width:50%;float:left}.subscription-box .box-top{position:relative;height:20px}.subscription-box .box-separator{border-style:none none dotted none;border-width:1px;margin-bottom:5px}.subscription-box h1{text-align:center}.toggle.deltranslator-button{display:inline}#sr{margin-left:0px}#sr-list-wrapper{width:454px;height:200px;border:1px solid gray;border-top:none;margin:0 5px;font-size:smaller;position:relative}#sr-list-cover{position:absolute;background:#808080 none no-repeat scroll center center;background-color:url(../throbber.gif);height:100%;width:100%;opacity:.7;filter:alpha(opacity=70);z-index:1000;display:none}#sr-list{overflow:auto;position:absolute;height:100%;width:100%}#sr-searchfield{margin:0 5px}#sr-name-box{display:inline-block}#sr-name-box span{display:block;unicode-bidi:isolate}#sr-name-box .tooltip{border-bottom:1px dotted;margin-bottom:2px}.sr-name{font-size:small;vertical-align:top;padding:3px 3px 3px 0}.sr-description{padding:3px}.sr-row{cursor:default}.sr-row.sr-selected{background:#eff7ff none no-repeat scroll 0px 5px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-108px -613px;background-repeat:no-repeat}.sr-arrow{width:10px;height:12px}#sr-autocomplete-area{position:relative;z-index:100}#sr-drop-down{position:absolute;width:100%;margin:0;border:1px solid gray;background:white;display:none;left:0}#sr-drop-down table{width:100%}.sr-name-row{cursor:default}.sr-name-row.sr-selected{background-color:#369;color:white}.submit-header{font-size:larger;font-weight:bold}#suggested-reddits{margin-top:5px;font-size:small}#suggested-reddits h3{font-size:1em;font-weight:normal;margin-top:.5em}#suggested-reddits li{display:inline;padding-right:5px}.formtabs-content{width:520px;border-top:4px solid #5f99cf;padding-top:10px}.formtabs-content .infobar{margin:0;padding:5px}ul.tabmenu.formtab{display:block;padding-left:10px;font-size:larger}.tabmenu.formtab li{margin:0}.tabmenu.formtab a{font-weight:normal;outline:none;padding:0px 12px;vertical-align:bottom;border:1px solid #c1c1c1;border-bottom:none}.tabmenu.formtab .selected a{color:white;font-size:130%;background-color:#5f99cf;border:none}.expando{clear:left;margin:5px 0 5px 0}.expando-content{display:none}.expando-button{float:left;height:23px;width:23px;margin:2px 5px 2px 0;background:#ffffff none no-repeat scroll center center}.expando-button.selftext.collapsed{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-90px -547px;background-repeat:no-repeat}.expando-button.selftext.collapsed:hover,.eb-sch{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-61px -547px;background-repeat:no-repeat}.expando-button.selftext.expanded,.eb-se{margin-bottom:5px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-29px -584px;background-repeat:no-repeat}.expando-button.selftext.expanded:hover,.eb-seh{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -584px;background-repeat:no-repeat}.expando-button.video.collapsed{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-87px -584px;background-repeat:no-repeat}.expando-button.video.collapsed:hover,.eb-vch{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-58px -584px;background-repeat:no-repeat}.expando-button.video.expanded,.eb-ve{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-29px -613px;background-repeat:no-repeat}.expando-button.video.expanded:hover,.eb-veh{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -613px;background-repeat:no-repeat}.expando .psuedo-selftext{border-radius:7px;border:1px solid #369;overflow:hidden;max-width:710px;-webkit-mask-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC')}.expando .psuedo-selftext iframe{padding:0;margin:0;width:100%;border:0}.subreddit .usertext .md{padding:2px 5px;background-color:#fafafa;border:1px solid #CCC;border-radius:7px}.link .usertext-body .md{background-color:#fafafa;border:1px solid #369;border-radius:7px}.usertext{font-size:small}.usertext-edit{margin-top:5px;padding:0 1px;width:500px}.usertext-edit textarea{width:500px;height:100px}.usertext.border .usertext-body{background-color:#ffc;padding-left:5px}.usertext.grayed .usertext-body{color:gray;background-color:#f0f0f0;padding-left:5px;padding-right:5px;display:inline-block}.usertext button{margin:5px 5px 10px 0}.usertext .help-toggle,.usertext a.reddiquette{font-size:smaller;float:right;margin-top:5px;margin-left:10px}.usertext .bottom-area{overflow:hidden;width:100%}.usertext .markhelp{padding:4px;margin:5px 0px;border-top:1px dotted #c0c0c0}.usertext .markhelp table{width:100%;margin:5px 0px}.usertext .markhelp tr,.usertext .markhelp td{width:50%;border:1px solid #c0c0c0}.usertext .markhelp .spaces{background-color:#c0c0c0}.roundfield{width:500px;background-color:#cee3f8;border-radius:4px;padding:5px 10px 10px 10px;font-size:large}.roundfield-actions{width:520px}.roundfield .roundfield-content{margin-top:5px;border:none;vertical-align:top}.roundfield .usertext-edit{width:500px}.roundfield textarea,.roundfield input[type=text],.roundfield input[type=url],.roundfield input[type=password],.roundfield input[type=number]{font-size:100%;width:492px;padding:3px;margin:0;border:1px solid gray}.roundfield.captcha .capimage{margin-bottom:10px}.roundfield label{font-size:smaller;padding-right:2px}.linefield{width:514px;padding:7px 5px;font-size:large;background-color:#CEE3F8;margin-bottom:10px}.linefield .title{color:blue;font-weight:bold;padding:1px 10px}.linefield .title+.gray{font-size:x-small}.linefield .small-field,.linefield .delete-field{padding:0;font-size:smaller}.linefield span+span{margin-left:10px}ul.colors{overflow:auto}ul.colors li{float:left;width:140px;padding:5px 10px}ul.colors label{display:block}ul.colors .swatch{display:inline-block;width:20px;height:20px;margin-right:0.5em;vertical-align:middle}ul.colors li.custom-color{clear:left;width:auto}ul.colors li.custom-color p{margin:0 -10px 5px}ul.colors li.custom-color .swatch{border:1px solid #CEE3F8}ul.colors li.custom-color input[type=color]{width:100%;height:100%;overflow:hidden;cursor:default;opacity:0}ul.colors li.custom-color input[type=text]{width:60px;vertical-align:middle}.campaign .linefield span+span{margin-left:0}.linefield .info{font-style:italic;color:red;font-size:small}.linefield .linefield-content{padding:2px 7px 5px;vertical-align:top}.linefield.usertext .usertext-edit{font-size:small}.linefield.usertext .edit-usertext{font-size:x-small;float:right}.linefield .upload{font-size:small}.linefield .upload label{font-size:small}.linefield .upload>li{margin-top:10px}.linefield .upload>li:first-child{margin-top:0}.linefield.usertext .infobar{width:100%}.linefield.usertext .usertext-buttons{display:none}.linefield textarea,.linefield input[type=text],.linefield input[type=password]{font-size:100%;width:492px;padding:3px;margin:0;border:1px solid gray}.linefield select{margin:0}.linefield.captcha .capimage{margin-bottom:10px}.linefield label{font-size:smaller;margin-right:0.5em}.linefield span{font-size:smaller}.linefield input[type="text"].small-text{font-size:smaller;width:100%}.linefield .markhelp table{background:#FFFFFF}#kind-selector label{padding-right:20px}.campaign .status{font-size:x-small}.campaign-detail .existing-campaigns>table{width:auto;background-color:white;border:1px solid #cc9}.campaign-detail .existing-campaigns .campaign-spent,.campaign-detail .existing-campaigns .campaign-buttons,.campaign-detail .existing-campaigns button{display:none}.campaign-detail .hidden{display:none}.existing-campaigns>table{font-size:x-small;width:100%;margin:0px 0;border:none}.existing-campaigns td.campaign-bid span{display:inline-block;margin-right:5px;line-height:20px;margin-top:3px;vertical-align:top}.existing-campaigns td.campaign-bid.paid{background:url(../green-check.png) no-repeat scroll center right}.existing-campaigns tr.refund{color:red;font-weight:bold}.minimum-spend.error{font-weight:bold;color:red}.existing-campaigns>table{margin:10px 0}.existing-campaigns>table>tbody>tr>td{border-bottom:1px solid #d9d9d9;max-width:120px}.existing-campaigns>table>tbody>tr#edit-campaign-tr>td{text-align:left}.existing-campaigns>table>tbody>tr#edit-campaign-tr>td{padding:0}#edit-campaign-tr .campaign-editor>.linefield{border-radius:0;margin:0}.existing-campaigns>table>thead>tr>th{font-weight:bold;color:#737373;border-bottom:1px solid #a6a6a6}.existing-campaigns .campaign-target,.existing-campaigns .campaign-location{overflow:hidden;text-overflow:ellipsis;max-width:100px}.existing-campaigns .campaign-row>td,.existing-campaigns .campaign-header-row>td,.existing-campaigns .campaign-row>th,.existing-campaigns .campaign-header-row>th{padding:8px 2px 5px 8px}.existing-campaigns .campaign-start-date{text-align:right;padding-right:7px;padding-left:8px}.existing-campaigns .campaign-end-date,.existing-campaigns .campaign-buttons,.existing-campaigns .campaign-bid,.existing-campaigns .campaign-duration,.existing-campaigns .campaign-spent{text-align:right;padding-right:8px;padding-left:2px}.existing-campaigns>table>thead .campaign-start-date,.existing-campaigns>table>thead .campaign-end-date,.existing-campaigns>table>thead .campaign-spent{width:10%}.existing-campaigns>table>thead .campaign-spent,.existing-campaigns>table>thead .campaign-priority,.existing-campaigns>table>thead .campaign-duration{width:8%}.existing-campaigns>table>thead .campaign-bid{width:12%}.existing-campaigns>table>thead .campaign-buttons{width:15%}.campaign .bid-info{font-size:x-small}.campaign .bid-info.error{color:red}.campaign td.prefright{padding:8px 4px 4px}.campaign #bid,.campaign #impressions{text-align:right;width:auto;margin-bottom:5px}.campaign .subreddit-targeting input{width:95%;border-radius:7px}.campaign #suggested-reddits ul{margin:0 20px 10px 0}.campaign th{font-size:small;padding:4px;padding-top:8px;width:90px}.linefield-content .infotext{margin-top:5px}.linefield-content .infotext p{margin:5px}#campaign label,#campaign li{font-size:small}#campaign .geotarget-select{display:block;margin-top:2px}.geotargeting-disabled{font-size:13px;color:grey}.collection-selector{position:relative;width:100%;height:50px;z-index:100}.collection-selector .widget-container{width:100%;background:#fff;border:1px solid #CECECE;border-radius:5px;overflow:hidden;position:absolute;top:0;left:0}.collection-selector .form-group-list{position:relative;-webkit-transition:all 0.2s ease 0s;-moz-transition:all 0.2s ease 0s;-o-transition:all 0.2s ease 0s;-ms-transition:all 0.2s ease 0s;transition:all 0.2s ease 0s}.collection-selector .form-group-list .form-group{display:block;padding:0;margin:0}.collection-selector .form-group-list .form-group>input[type=radio]{display:none}.collection-selector .form-group-list .form-group>.label-group{height:50px;width:100%;padding:5px 10px;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;cursor:pointer;color:#404040}.collection-selector .form-group-list .form-group>.label-group:hover{background:#E4EDF7}.collection-selector .form-group-list .form-group>.label-group .label{font-size:15px}.collection-selector .form-group-list .form-group>.label-group .description{font-size:10px}.collection-selector .form-group-list .form-group>input[type=radio]:checked+.label-group{background:#FFFFFF;display:block}.collection-selector.expanded .form-group>input[type=radio]:checked+.label-group{background-color:#4A90E2;color:#FFF;box-shadow:none}.collection-selector.collapsed input[type=radio]:checked+.label-group{box-shadow:inset 0 -1px 0 1px #f2f2f2}.collection-selector.collapsed .widget-container:before{display:block;content:"";width:0;height:0;border-width:15px 10px 0;border-style:solid;border-color:#CCC transparent;position:absolute;top:18px;right:10px;z-index:100;pointer-events:none}.collection-selector.uninitialized .form-group>.label-group{display:none}.collection-selector.uninitialized .form-group>input[type=radio]:checked+.label-group{display:block}.collection-selector.uninitialized:hover .form-group>.label-group{display:block}.collection-selector.uninitialized:hover .form-group>input[type=radio]:checked+.label-group{background-color:#4A90E2;color:#FFF;box-shadow:none}.collection-subreddit-list{font-size:13px}.collection-subreddit-list .label{margin:5px 0;color:#404040;font-size:10px}.collection-subreddit-list ul li{display:inline-block;margin-right:5px}.traffic-table,.traffic-tables-side fieldset{margin:1.5em 2em;font-size:small;border:0}.traffic-table caption,.traffic-tables-side fieldset legend{font-weight:bold;text-align:left;font-size:medium;font-variant:small-caps}.traffic-table caption .normal{font-weight:normal;font-size:small;font-variant:normal;margin-left:.5em}.traffic-form{float:left;margin-right:10em}.traffic-form p{font-size:small;margin-bottom:1em;max-width:20em}.traffic-form textarea{display:block}.traffic-table a:hover{text-decoration:underline}.traffic-table thead th{font-weight:bold;text-align:center;padding-left:2em}.traffic-table thead th:first-child{text-align:left;padding-left:0}.traffic-table tbody th,.traffic-table tfoot th{text-align:left}.traffic-table td{padding:0 5px}.traffic-table td{text-align:right}.traffic-table tfoot tr{border-top:1px solid black}.traffic-table tfoot th,.traffic-table tfoot td{font-style:italic}.traffic-table tr.max{border-width:2px;border-style:solid}.traffic-table tr.min{border:2px solid #336699}.traffic-table tbody tr:nth-child(even){background-color:#E0E0E0}.traffic-table tr.mean{font-style:italic;border-top:1px solid}.traffic-table .dow-6 th,.traffic-table .dow-6 td{padding-bottom:1em}.traffic-table tr:nth-child(odd).dow-5 th,.traffic-table tr:nth-child(odd).dow-5 td{padding-top:1em}.traffic-table tr:nth-child(even).dow-6 th,.traffic-table tr:nth-child(even).dow-6 td{padding-bottom:0}.traffic-tables-side{float:left;min-height:50em}#promote-graph-table,#traffic-hour{display:none}div.timeseries{padding:10px;border:1px solid #B0B0B0;margin:10px 10px;display:inline-block;text-align:center}.timeseries-placeholder{width:350px;height:200px;font-family:verdana;font-size:small}div.timeseries span.title{font-weight:bold;font-size:medium;font-variant:small-caps}#timeseries-unprocessed{font-size:small;font-weight:bold;margin:1em 0;max-width:60em}#timeseries-unprocessed.slow{color:#900}.timeseries-tablebar{height:5px;margin:1px 0}.promoted-traffic .usertable{margin-left:0px}.promoted-traffic h1 a{font-size:small;margin-left:10px}.promoted-traffic tfoot th,.promoted-traffic tfoot td{font-style:normal;font-weight:bold;text-transform:uppercase;padding-top:.3em}.promocampaign-table td{white-space:nowrap}.traffic-table.promocampaign-table{margin:10px}.traffic-table.promocampaign-table thead th{text-align:right;padding:0 5px}.traffic-table.promocampaign-table tr.total{border-top:1px solid black}.traffic-table.promocampaign-table tr.active{background-color:pink;font-weight:bold;border:2px dotted red}.promo-traffic .content .tabmenu li{font-size:1.3em}.promo-traffic #helptext{font-size:1.2em;padding:3px 10px 6px}#promo-traffic-no-campaigns{padding:20px}.promo-traffic .tabpane-content{margin-right:305px;min-width:800px;position:relative}.promo-traffic #timeseries-unprocessed{font-size:1.2em;margin:0 .1em;padding:0px;position:absolute;right:1em;top:-1.3em}.promo-traffic-csv-link{font-size:1.1em;font-weight:bold;position:absolute;right:15px;top:11px}.promo-traffic-help{font-size:1.2em;margin:20px}.promo-traffic-help p{padding:5px}#promo-traffic-lifetime-stats{font-size:1.1em;font-weight:bold;margin:2px 10px;padding-top:5px}.promo-traffic-live{background-color:#EFF7FF}.promo-traffic-live td{max-width:150px;overflow:hidden;text-overflow:ellipsis}.promo-traffic-settings-instructions{font-size:small;margin:0px 15px 10px}.promo-traffic-settings{padding:20px}p.totals-are-preliminary{margin-left:10px}.award-square-container{max-width:1000px;overflow:hidden}.award-square{float:left;padding:10px 0px 30px 40px;white-space:nowrap;width:300px}.award-square.mini{width:100px;white-space:normal;text-align:center}.award-square img{float:left;margin:0 10px;width:70px;height:70px}.award-square.mini img{float:none;margin-bottom:7px}.award-square .award-name{color:black;font-size:22px;font-family:verdana,arial,helvetica,sans-serif;font-weight:bold;line-height:1em}.award-square.mini .award-name{font-size:18px;min-height:36px;display:block}.award-square .winner-info{line-height:15px;margin-top:15px;color:gray}.award-square .winner-name{font-size:18px;color:#336699}.lined-table{margin:5px}table.lined-table{margin:5px 3px}.lined-table th,.lined-table td{border:solid #cdcdcd 1px;padding:3px}.lined-table th{text-align:center;font-weight:bold}.sponsorshipbox{max-width:300px}.sponsorshipbox span{color:gray}.sponsorshipbox div{border:1px solid #D0D0D0;width:300px;font-size:0}.sponsorshipbox .promote-pixel{right:0}.sidecontentbox a.helplink{float:right;margin-top:4px}.confirm-award-claim .md{max-width:none;font-size:18px}.trophy-table{width:100%}.trophy-area .content{background-color:#f5f5f5}.trophy-info{text-align:center;vertical-align:top}.trophy-info div{margin-left:auto;margin-right:auto;width:130px;vertical-align:top;padding:15px 0 15px}.trophy-icon{margin-bottom:2px;width:40px;height:40px}.trophy-info.left{margin-right:10px}.trophy-name{color:black!important}.trophy-description{color:#555555;font-size:x-small}.dust{text-align:center;margin:45px auto;color:#d0d0d0}.removecup-button{display:inline}.cup-info-box{border:dashed #eeaa33 2px;padding:5px}.cup-info-box tt{background-color:#f5f5aa}.datepicker{z-index:1000;display:none;border-radius:6px;-webkit-box-shadow:0px 4px 6px 3px rgba(0,0,0,0.2),inset 0px 1px 0px 0px rgba(255,255,255,0.9);-moz-box-shadow:0px 4px 6px 3px rgba(0,0,0,0.2),inset 0px 1px 0px 0px rgba(255,255,255,0.9);box-shadow:0px 4px 6px 3px rgba(0,0,0,0.2),inset 0px 1px 0px 0px rgba(255,255,255,0.9);text-shadow:0px 1px 0px rgba(255,255,255,0.8)}.datepicker::before{content:' ';display:block;width:0;height:0;border:10px solid;position:absolute;top:-20px;left:17px;border-color:transparent transparent #369}.datepicker::after{content:' ';display:block;width:0;height:0;border:10px solid;position:absolute;top:-18px;left:17px;border-color:transparent transparent #E5F2FF}.datepicker.inuse{display:block}.ui-datepicker-inline{font-size:x-small;padding:5px}.ui-corner-all{border-radius:6px}.ui-datepicker-header{background:-webkit-gradient(linear,0% 0%,0% 100%,from(#d4e3f2),to(#adc9e6));background:-moz-linear-gradient(top,#d4e3f2,#adc9e6);background-color:#ADC9E6;border:1px solid #5E96CF;color:#2E6399;font-weight:bold;font-size:1.3em;text-shadow:0px 1px 0px rgba(255,255,255,0.7);-webkit-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8);-moz-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8);box-shadow:inset 0px 1px 0px rgba(255,255,255,0.8)}.ui-datepicker-inline .ui-datepicker-prev{float:left}.ui-datepicker-inline .ui-datepicker-next{float:right}.ui-datepicker-inline .ui-datepicker-prev span,.ui-datepicker-inline .ui-datepicker-next span{display:block;text-align:center;margin-right:1px;margin-bottom:1px;font-size:1.5em}.ui-datepicker-inline .ui-datepicker-prev:active,.ui-datepicker-inline .ui-datepicker-next:active{color:white}.ui-datepicker-inline .ui-datepicker-prev.ui-state-disabled,.ui-datepicker-inline .ui-datepicker-next.ui-state-disabled{display:none}.ui-datepicker-inline .ui-datepicker-prev,.ui-datepicker-inline .ui-datepicker-next{display:block;cursor:pointer;padding:0px 5px}.ui-datepicker-year{margin-left:none!important}.ui-datepicker-inline .ui-datepicker-title{text-align:center;padding:5px;margin:0em 2em}.ui-datepicker-inline table{clear:right;margin-top:5px;border:1px solid #5e96cf}.ui-datepicker-inline .ui-datepicker-calendar th,.ui-datepicker-inline .ui-datepicker-calendar td{padding:0px;border:1px solid #5E96CF;-webkit-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.7);-moz-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.7);box-shadow:inset 0px 1px 0px rgba(255,255,255,0.7)}.ui-datepicker-calendar th{font-size:1.1em}.ui-datepicker-inline .ui-datepicker-calendar th span,.ui-datepicker-inline .ui-datepicker-calendar td span,.ui-datepicker-inline .ui-datepicker-calendar td a{border:0px;margin:auto;padding:3px;display:block;width:30px;height:2em;text-align:center;vertical-align:middle;color:black;background-color:#C8DBEF;font-size:1.5em;font-weight:bold;-webkit-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.7);-moz-box-shadow:inset 0px 1px 0px rgba(255,255,255,0.7);box-shadow:inset 0px 1px 0px rgba(255,255,255,0.7)}.ui-datepicker-inline .ui-datepicker-calendar th span{text-align:center;border:none}.ui-datepicker-inline .ui-datepicker-calendar td.ui-datepicker-today a,.ui-datepicker-inline .ui-datepicker-calendar td.ui-datepicker-today span,.ui-datepicker-inline .ui-datepicker-calendar td a.ui-state-active{color:white;background:-webkit-gradient(linear,0% 0%,0% 100%,from(#76a6d6),to(#3573b1));background:-moz-linear-gradient(top,#76a6d6,#3573b1);background-color:#4F8AC9;-webkit-box-shadow:inset 0px 2px 3px rgba(0,0,0,0.6);-moz-box-shadow:inset 0px 2px 3px rgba(0,0,0,0.6);box-shadow:inset 0px 2px 3px rgba(0,0,0,0.6);text-shadow:0px -1px 0px rgba(0,0,0,0.8)}.ui-datepicker-inline .ui-datepicker-calendar td span{color:#888}.ui-datepicker-inline .ui-datepicker-calendar td a.ui-state-hover{background:#6BB3FF;color:white;text-shadow:0px -1px 0px rgba(0,0,0,0.6)}.ui-datepicker-inline .ui-datepicker-calendar td a.ui-state-active{background:-webkit-gradient(linear,0% 0%,0% 100%,from(#e29d9d),to(#ca4e4e));background:-moz-linear-gradient(top,#e29d9d,#ca4e4e);background-color:#E19D9D}.date-input{display:inline;position:relative}.date-input input{border:1px solid #888;padding:2px;text-align:center;margin:0 2px}.date-input .drop-choices{position:absolute;border:1px solid #369;background-color:#E5F2FF;margin:10px 3px}.payment-setup input[name=bid]{width:6em;text-align:right}.payment-setup form{margin:20px}.payment-setup p{margin-bottom:10px}.pay-form textarea[disabled]{font-size:smaller;padding:0}.pay-form *[disabled],.pay-form input[disabled]{border:none;color:black;font-weight:bold;background-color:white}.bid-table{margin:5px 10px}.bid-table td,.bid-table th{padding:2px 5px;text-align:right}.bid-table th{text-align:center;font-weight:bold}div #campaign-field{width:auto}#promo-form .linefield{width:auto}#promo-form .usertext-edit{width:auto}.form-group{display:block}.form-group>label,.form-group>.label,.form-group>.label-group{display:inline-block}.form-group>.label-group>.label{display:block}.input-group{display:inline-block;vertical-align:top}.checkbox-group,.radio-group{font-size:14px;line-height:20px}.checkbox-group .form-group,.radio-group .form-group{margin:5px 0}.checkbox-group input[type=radio],.radio-group input[type=radio],.checkbox-group input[type=checkbox],.radio-group input[type=checkbox]{font-size:20px;line-height:20px;margin-right:10px;margin-left:1px}.radio-group .label-group,.radio-group .label,.radio-group input[type=radio]{vertical-align:middle}.dashboard header{position:relative;margin-bottom:10px}.sponsored-page .checkbox-group,.sponsored-page .radio-group,.sponsored-page .form-group,.sponsored-page .select-group,.sponsored-page .collection-targeting,.sponsored-page .subreddit-targeting{margin-bottom:10px}.sponsored-page .checkbox-group>.label:first-child,.sponsored-page .radio-group>.label:first-child,.sponsored-page .form-group>.label:first-child,.sponsored-page .select-group>.label:first-child,.sponsored-page .collection-targeting>.label:first-child,.sponsored-page .subreddit-targeting>.label:first-child{width:110px;margin-right:10px;text-transform:uppercase;font-size:12px;color:#666666;letter-spacing:0.6px}.sponsored-page .radio-group .form-group{margin-bottom:5px}.sponsored-page .targeting-field .radio-group .label-group,.sponsored-page .targeting-field .radio-group input[type=radio]{vertical-align:middle}.sponsored-page .targeting-field .radio-group .label-group{font-size:15px}.sponsored-page .targeting-field .radio-group .label-group small{font-size:0.67em}.sponsored-page .targeting-field .linefield-content>.radio-group,.sponsored-page .targeting-field .linefield-content>.target-group{width:50%;display:inline-block;vertical-align:top}.sponsored-page .lookup-user-field .group,.sponsored-page .budget-field .group,.sponsored-page .timing-field .group{display:flex;margin-bottom:10px}.sponsored-page .lookup-user-field .form-group,.sponsored-page .budget-field .form-group,.sponsored-page .timing-field .form-group{flex-basis:0;flex-grow:1}.sponsored-page .lookup-user-field .form-group label,.sponsored-page .budget-field .form-group label,.sponsored-page .timing-field .form-group label,.sponsored-page .lookup-user-field .form-group .label,.sponsored-page .budget-field .form-group .label,.sponsored-page .timing-field .form-group .label{display:block}.sponsored-page .lookup-user-field .campaign-weekend-warning,.sponsored-page .budget-field .campaign-weekend-warning,.sponsored-page .timing-field .campaign-weekend-warning{font-size:.8em;color:#222222;background-color:#ffd635;padding:10px;margin-bottom:10px;border-radius:4px}.sponsored-page .display-text{font-size:16px;font-weight:bold;line-height:20px;margin:5px 0}.sponsored-page .budget-field .group{margin-bottom:10px}.sponsored-page .campaign-set{padding:10px;background:#fff;border-radius:2px;margin-bottom:5px}.sponsored-page .campaign-set .info-text{display:block;border-bottom:1px solid #e6e6e6}.sponsored-page .campaign-set .campaign-button{padding:5px 10px}.sponsored-page .campaign-set .button-group{white-space:nowrap}.sponsored-page .campaign-set .button-group button:first-child{border-top-right-radius:0;border-bottom-right-radius:0;border-right:0;padding-right:5px;margin-right:0}.sponsored-page .campaign-set .button-group button+button{border-top-left-radius:0;border-bottom-left-radius:0;border-left:0;padding-left:5px;margin-left:0}.sponsored-page .campaign-set+.campaign-set,.sponsored-page .campaign-set+.info-text{margin-top:20px}.sponsored-page .campaign-option-table{width:100%}.sponsored-page .campaign-option-table .impressions{width:30%}.sponsored-page .campaign-option-table .date{text-align:left;width:18%}.sponsored-page .campaign-option-table .bid{width:16%}.sponsored-page .campaign-option-table td{width:18%;line-height:27px;font-size:14px;font-weight:bold;vertical-align:bottom;text-align:right;padding:0 4px}.sponsored-page .lookup-user input[name=name]{width:10em}.sponsored-page .lookup-user input[name=email]{width:20em}.inventory-dashboard .geotargeting-group{display:none}.sponsored-page{width:800px;margin:auto;color:#0d0d0d}.sponsored-page textarea,.sponsored-page input[type=text]{width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box}.sponsored-page .hidden{display:none}.sponsored-page .help p{margin:0}.sponsored-page .help a.help{font-weight:bold;text-decoration:none;float:right;color:orangered}.sponsored-page h2{margin:20px 0 5px;font-size:200%;color:#666666;font-weight:normal}.sponsored-page .infobar{margin:5px 0;padding:0;background:transparent;border:0;color:#404040}.sponsored-page .infobar a{white-space:nowrap}.sponsored-page .post-type-field .radio-group .label-group,.sponsored-page .targeting-feild .radio-group .label-group{font-size:15px}.sponsored-page .post-type-field .radio-group .label-group small,.sponsored-page .targeting-feild .radio-group .label-group small{font-size:0.67em}.sponsored-page .post-type-field .radio-group{overflow:auto}.sponsored-page .post-type-field .form-group{float:left;width:33%}.sponsored-page>header{margin:10px}.sponsored-page .rules{float:left;font-size:13px;line-height:30px}.sponsored-page .primary-button{background:#ff9770;background:-moz-linear-gradient(top,#ff9770 0%,#ff7d4d 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ff9770),color-stop(100%,#ff7d4d));background:-webkit-linear-gradient(top,#ff9770 0%,#ff7d4d 100%);background:-o-linear-gradient(top,#ff9770 0%,#ff7d4d 100%);background:-ms-linear-gradient(top,#ff9770 0%,#ff7d4d 100%);background:linear-gradient(to bottom,#ff9770 0%,#ff7d4d 100%);border-color:#ff581a;color:white;text-shadow:0 1px 0 #ff581a}.sponsored-page .primary-button:hover{background:#ffa98a;background:-moz-linear-gradient(top,#ffa98a 0%,#ff7d4d 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ffa98a),color-stop(100%,#ff7d4d));background:-webkit-linear-gradient(top,#ffa98a 0%,#ff7d4d 100%);background:-o-linear-gradient(top,#ffa98a 0%,#ff7d4d 100%);background:-ms-linear-gradient(top,#ffa98a 0%,#ff7d4d 100%);background:linear-gradient(to bottom,#ffa98a 0%,#ff7d4d 100%)}.sponsored-page button{background:#bed6ef;background:-moz-linear-gradient(top,#bed6ef 0%,#a9c9ea 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#bed6ef),color-stop(100%,#a9c9ea));background:-webkit-linear-gradient(top,#bed6ef 0%,#a9c9ea 100%);background:-o-linear-gradient(top,#bed6ef 0%,#a9c9ea 100%);background:-ms-linear-gradient(top,#bed6ef 0%,#a9c9ea 100%);background:linear-gradient(to bottom,#bed6ef 0%,#a9c9ea 100%);border-color:#81b0df;margin:0;padding:5px 20px;font-size:12px;font-weight:bold;color:#3973ac;text-shadow:0 1px 0 #c6d9ec;vertical-align:text-top}.sponsored-page button:hover{background:#d2e3f4;background:-moz-linear-gradient(top,#d2e3f4 0%,#a9c9ea 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#d2e3f4),color-stop(100%,#a9c9ea));background:-webkit-linear-gradient(top,#d2e3f4 0%,#a9c9ea 100%);background:-o-linear-gradient(top,#d2e3f4 0%,#a9c9ea 100%);background:-ms-linear-gradient(top,#d2e3f4 0%,#a9c9ea 100%);background:linear-gradient(to bottom,#d2e3f4 0%,#a9c9ea 100%)}.sponsored-page .new-campaign{position:absolute;right:0;top:10px;padding:10px 15px;font-size:13px}.sponsored-page .campaign-buttons button,.sponsored-page .campaign-bid button{font-size:10px;font-weight:normal;border-top-width:1px;box-shadow:none;padding:2px 4px;margin:2px 2px 0}.sponsored-page .campaign-buttons button:active,.sponsored-page .campaign-bid button:active{box-shadow:inset 0 1px 0 1px rgba(0,0,0,0.09999999999999998)}.sponsored-page .campaign-buttons button:hover,.sponsored-page .campaign-bid button:hover,.sponsored-page .campaign-buttons button:active,.sponsored-page .campaign-bid button:active{margin-bottom:0}.sponsored-page .editor-group{position:relative;background:#e4f0fb;margin:0 0 10px;border-radius:2px;font-size:15px;line-height:20px}.sponsored-page .editor-group footer{margin:0 20px;padding:10px 0}.sponsored-page .promotelink-editor .collapsed-display .linefield{border-bottom:0;padding-bottom:0}.sponsored-page .promotelink-editor .thing{border-color:#b8d6f5;font-size:10px}.sponsored-page .promotelink-editor .thing .title{padding:0;font-weight:normal}.sponsored-page .promotelink-editor .thing .rank{display:none}.sponsored-page .promotelink-editor .thing .flat-list.buttons{text-align:left}.sponsored-page .promotelink-editor .thing a.thumbnail{line-height:0}.sponsored-page .dashboard{padding:20px;border-bottom:2px solid #ccc}.sponsored-page .campaign-editor .editor-group{background:transparent;background:#f8f8f8;border:none;box-shadow:none;font-size:13px}.sponsored-page .campaign-editor .editor-group>.linefield>.title:before{background:#dedede;margin-right:0}.sponsored-page .campaign-editor .editor-group>.linefield>.title{color:#666666}.sponsored-page .campaign-editor .editor-group .linefield{border-bottom-color:#e6e6e6}.sponsored-page .campaign-list-editor>.editor-group>.linefield{border-bottom:0;padding-bottom:10px}.sponsored-page .campaign-list-editor>.editor-group>.linefield .help{font-size:12px;margin-right:120px}.sponsored-page .campaign-list{padding-bottom:5px}.sponsored-page .editor .image-field{position:relative;overflow:auto}.sponsored-page .editor .image-field input[type=file]{margin-top:10px;margin-left:0}.sponsored-page .editor .image-field button.submit-img{position:absolute;bottom:10px;right:20px}.sponsored-page .editor .image-field img{max-width:600px}.sponsored-page .editor .image-field.has-image .linefield-content{margin-left:110px}.sponsored-page .editor .image-field.has-image .img-preview-container{position:absolute;left:0;top:45px;margin:0;padding:5px}.sponsored-page .editor .image-field.has-image .img-preview-container img{display:block;width:70px;height:auto}.sponsored-page .editor .image-field.has-image .img-preview-container br{display:none}.sponsored-page .editor textarea,.sponsored-page .editor input[type=text],.sponsored-page .editor .date-input input,.sponsored-page .editor .linefield{border-radius:2px;font-size:15px;line-height:20px}.sponsored-page .editor textarea,.sponsored-page .editor input[type=text],.sponsored-page .editor .date-input input{border:1px solid;border-color:#bfbfbf #cccccc #d9d9d9;background:#fcfcfc;padding:5px 10px}.sponsored-page .editor textarea:focus,.sponsored-page .editor input[type=text]:focus,.sponsored-page .editor .date-input input:focus{background:white;border-color:#538cc6;outline:none;box-shadow:0 0 3px white}.sponsored-page .editor textarea:disabled,.sponsored-page .editor input[type=text]:disabled,.sponsored-page .editor .date-input input:disabled{box-shadow:none;color:#999999;border-color:#cccccc;background:#fafafa}.sponsored-page .editor input[type=text],.sponsored-page .editor .date-input input{padding:5px;box-shadow:inset 0 1px 0 1px #f2f2f2;font-size:15px}.sponsored-page .editor textarea{resize:vertical;padding:10px;box-shadow:inset 0 2px 0 1px #f2f2f2}.sponsored-page .editor .date-input .datepicker{text-shadow:none;border-color:#8cb2d9}.sponsored-page .editor .date-input .datepicker .ui-corner-all,.sponsored-page .editor .date-input .datepicker{border-radius:2px}.sponsored-page .editor .date-input .datepicker .ui-datepicker-header,.sponsored-page .editor .date-input .datepicker .ui-datepicker-calendar,.sponsored-page .editor .date-input .datepicker td,.sponsored-page .editor .date-input .datepicker th,.sponsored-page .editor .date-input .datepicker th span{box-shadow:none;border-color:#8cb2d9}.sponsored-page .editor .date-input .datepicker table,.sponsored-page .editor .date-input .datepicker th{border:0}.sponsored-page .editor .date-input .datepicker th span{font-size:12px;font-weight:normal;background:transparent;height:auto}.sponsored-page .editor .date-input .datepicker td a,.sponsored-page .editor .date-input .datepicker td span{box-shadow:none;font-size:15px;width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;text-align:right}.sponsored-page .editor .date-input .datepicker .ui-datepicker-today span{background:#9fbfdf;box-shadow:none;text-shadow:none}.sponsored-page .editor .date-input .datepicker a{text-shadow:none}.sponsored-page .editor .date-input .datepicker a.ui-state-active{background:#ffffff;color:orangered;text-shadow:none}.sponsored-page .editor .date-input .datepicker a.ui-state-hover{text-shadow:none;border-color:#79a6d2}.sponsored-page .editor .linefield{width:auto;padding:20px 0;margin:0 20px;border-radius:0;border-bottom:1px solid #b8d6f5;background:transparent;font-size:15px}.sponsored-page .editor .linefield span{font-size:inherit}.sponsored-page .editor .linefield:last-child{border-bottom:none}.sponsored-page .editor .linefield>.linefield-content{padding:0}.sponsored-page .editor .linefield>.title{padding:0;display:block;margin:5px 0;color:#369;font-size:15px}.sponsored-page .editor .linefield>.title:before{position:absolute;width:20px;height:20px;right:100%;border-radius:10px;background:#cee3f8;margin-right:-10px}.sponsored-page .editor>.linefield{padding:0;background:transparent;border:0}.sponsored-page .editor>.linefield>.title{font-weight:normal;font-size:18px;line-height:20px;margin:10px;color:#004c99}.sponsored-page .editor .buttons{text-align:right}.sponsored-page .editor .buttons button{margin-left:5px}.sponsored-page .editor .infotext{border:0;background:transparent;font-style:italic;color:grey;padding:0;font-size:13px;line-height:20px;box-shadow:none}.sponsored-page .text-field textarea{font-size:13px}.sponsored-page .existing-campaigns .campaign-editor .editor-group{margin-bottom:10px;border-radius:0}.sponsored-page .existing-campaigns .campaign-editor footer{margin-bottom:10px}.sponsored-page .existing-campaigns .campaign{border:0}.sponsored-page .help{font-size:13px}.sponsored-page .campaign-dashboard header .error,.sponsored-page .campaign-dashboard header .help{margin-right:150px}.geotargeting-disabled{font-size:12px;color:grey}.fancy-settings h1{font-size:200%;color:#999;margin:10px 5px}.fancy-settings h2{font-size:200%;font-weight:normal;color:#999;margin:10px 5px}.fancy-settings h1 strong{font-weight:bold;color:#666}.bidding-history{padding-top:5px;margin-right:5px}.bidding-history .linefield{width:auto;overflow:hidden;padding-left:10px;border-left:1px #DDD dashed}.bidding-history .linefield .bid-table,.bidding-history .linefield .notes{font-size:x-small}.bidding-history .linefield .notes{margin-top:10px}.bidding-history .linefield .notes p{text-indent:-20px;padding-left:20px;margin-bottom:2px;font-family:courier}.pay-form tr.input-error th{color:red;font-weight:bold;font-style:italic}.pay-form th{padding:0px}.pay-form tr.input-error input,.pay-form tr.input-error textarea,.pay-form tr.input-error select{border:1px solid red}.pay-form input[name=expirationDate],.pay-form input[name=cardCode]{width:10ex}.pay-form .optional{font-size:smaller}.pay-form .disabled .optional{display:none}.pay-form p.info{color:red}.pay-link{font-size:smaller;margin-left:10px}dt{margin-left:10px;font-weight:bold}dd{margin-left:20px}.borderless td{border:none}.promote-report-form{margin:1.5em 2em}.promote-report-csv{font-size:small}.promote-report-table{border:0 none;font-size:small;margin:1.5em 2em}.promote-report-table thead th{font-weight:bold;text-align:center;padding:0 1em;border:1px solid white;background-color:#CEE3F8}.promote-report-table thead th.blank{background:none}.promote-report-table thead th[colspan]{text-align:center}.promote-report-table td{text-align:right;padding:0 2em}.promote-report-table td.text{text-align:left;padding:0 2em 0 0}.promote-report-table tr.total{background-color:#FFC;border-top:1px solid #000000;font-weight:bold}.inventory-table{font-size:smaller;text-align:right;margin-top:20px}.inventory-table th,.inventory-table td{padding:3px}.inventory-table th{border-bottom:1px solid #000000;text-align:right}.inventory-table th:first-child{text-align:left}.inventory-table td.title{width:120px;text-align:left}.inventory-table td:not(.title){border-left:1px dashed #DDD}.inventory-table tr:nth-child(even){background-color:#EFF7FF}.inventory-table tr.total{background-color:#FFC;border-top:1px solid #000000;font-weight:bold}.titlebox{font-size:larger}.titlebox h1{font-family:arial,verdana,helvetica,sans-serif;margin:0px;margin-bottom:5px;font-weight:bold;font-size:19px}.titlebox h1 a{color:black}.titlebox .karma{font-size:18px;font-weight:bold}.titlebox .fancy-toggle-button{display:inline-block;margin-right:5px}.titlebox .bottom{border-top:1px solid gray;padding-top:2px;font-size:80%;color:gray}.titlebox .age{float:right}#side-multi-list li{display:inline-block;width:93px;margin-right:3px;text-overflow:ellipsis;overflow:hidden}#side-multi-list+.expand-summary{padding:0 4px;margin:0;margin-top:3px;font-size:x-small}.confirm-button .confirmation{color:red;white-space:nowrap}.confirm-button .confirmation .prompt{margin-right:.5em}.gray-buttons button,.gray-buttons a{padding:0;margin:0;border:none;background:none;color:#888;font-weight:bold}.gray-buttons button:hover,.gray-buttons a:hover{text-decoration:underline}.multi-details h1,.filtered-details h1{margin-bottom:0}.multi-details h1 a,.filtered-details h1 a,.multi-details .throbber,.filtered-details .throbber{vertical-align:middle}.multi-details .throbber,.filtered-details .throbber{margin-left:5px}.multi-details h2,.filtered-details h2{margin-top:0;margin-bottom:3px}.multi-details .settings,.filtered-details .settings{margin-bottom:5px}.multi-details .settings input[type="radio"],.filtered-details .settings input[type="radio"]{margin:0;margin-right:3px;vertical-align:middle}.multi-details .settings button,.filtered-details .settings button{cursor:pointer}.multi-details .settings label,.filtered-details .settings label,.multi-details .settings>button,.filtered-details .settings>button{margin-right:12px}.multi-details .settings .visibility-group,.filtered-details .settings .visibility-group{margin-right:8px;margin-bottom:8px}.multi-details h3,.filtered-details h3{font-weight:normal;color:#777;margin-bottom:3px}.multi-details form.copy-multi,.filtered-details form.copy-multi,.multi-details form.rename-multi,.filtered-details form.rename-multi{display:none;margin-bottom:10px}.multi-details form.copy-multi .multi-name,.filtered-details form.copy-multi .multi-name,.multi-details form.rename-multi .multi-name,.filtered-details form.rename-multi .multi-name{border:1px solid #ccc;padding:3px}.multi-details form.copy-multi button,.filtered-details form.copy-multi button,.multi-details form.rename-multi button,.filtered-details form.rename-multi button{background:none;border:1px solid #777;border-radius:3px;box-shadow:0 1px 1px rgba(0,0,0,0.25);opacity:.75;padding:3px 4px}.multi-details form.copy-multi button:active,.filtered-details form.copy-multi button:active,.multi-details form.rename-multi button:active,.filtered-details form.rename-multi button:active{position:relative;top:1px;box-shadow:none}.multi-details form.copy-multi .throbber,.filtered-details form.copy-multi .throbber,.multi-details form.rename-multi .throbber,.filtered-details form.rename-multi .throbber{height:22px;display:none}.multi-details form.copy-multi.working .throbber,.filtered-details form.copy-multi.working .throbber,.multi-details form.rename-multi.working .throbber,.filtered-details form.rename-multi.working .throbber{display:inline-block}.multi-details form.copy-multi button,.filtered-details form.copy-multi button{background:#eeffdd}.multi-details form.rename-multi button,.filtered-details form.rename-multi button{background:#ffffdd}.multi-details form.rename-multi .warning,.filtered-details form.rename-multi .warning{margin-top:.5em;font-weight:bold;color:#c2461f}.multi-details .description,.filtered-details .description{margin:.75em 0}.multi-details .description .usertext-edit,.filtered-details .description .usertext-edit,.multi-details .description textarea,.filtered-details .description textarea{width:294px!important}.multi-details ul,.filtered-details ul,.multi-details form.add-sr,.filtered-details form.add-sr{margin-left:12px}.multi-details button.remove-sr,.filtered-details button.remove-sr,.multi-details button.add,.filtered-details button.add{box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;text-indent:-9999px;margin-left:3px;background:none no-repeat;border:3px solid transparent;padding:0;opacity:.3}.multi-details button.remove-sr:hover,.filtered-details button.remove-sr:hover,.multi-details button.add:hover,.filtered-details button.add:hover{opacity:1}.multi-details button.remove-sr:active,.filtered-details button.remove-sr:active,.multi-details button.add:active,.filtered-details button.add:active{position:relative;top:1px}.multi-details button.remove-sr.remove-sr,.filtered-details button.remove-sr.remove-sr,.multi-details button.add.remove-sr,.filtered-details button.add.remove-sr{width:9px;height:9px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-110px -642px;background-repeat:no-repeat}.multi-details button.remove-sr.add,.filtered-details button.remove-sr.add,.multi-details button.add.add,.filtered-details button.add.add{width:15px;height:15px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -818px;background-repeat:no-repeat}.multi-details.readonly button.remove-sr,.filtered-details.readonly button.remove-sr{display:none}.multi-details .share-in-sr,.filtered-details .share-in-sr{display:none}.multi-details.public .share-in-sr,.filtered-details.public .share-in-sr{display:inline}.multi-details form.add-sr .sr-name,.filtered-details form.add-sr .sr-name,.multi-details form.add-sr button.add,.filtered-details form.add-sr button.add{vertical-align:middle}.multi-details form.add-sr .sr-name,.filtered-details form.add-sr .sr-name{border:1px solid #ccc;padding:3px}.multi-details form.add-sr button.add,.filtered-details form.add-sr button.add{border:5px solid transparent}.multi-details li,.filtered-details li{font-size:1.15em;line-height:1.5em}.multi-details li a,.filtered-details li a,.multi-details li button,.filtered-details li button{vertical-align:middle}.multi-details .bottom,.filtered-details .bottom{margin-top:1em}.modsr-link{display:block;margin-top:5px;margin-left:15px;font-weight:bold}.filtered-details .unfilter{font-weight:bold;display:inline-block;margin-top:1em}.filtered-details .unfilter:hover{text-decoration:underline}.filtered-details .add-sr{margin-top:5px}.side .recommend-box{margin:15px 5px 30px 0px;opacity:0;-webkit-transition:all 0.1s ease-in-out 0s;-moz-transition:all 0.1s ease-in-out 0s;-o-transition:all 0.1s ease-in-out 0s;-ms-transition:all 0.1s ease-in-out 0s;transition:all 0.1s ease-in-out 0s}.side .recommend-box h1{display:inline-block;font-size:1.35em;font-weight:bold;white-space:nowrap}.side .recommend-box ul{margin:4px 0}.side .recommend-box .rec-item{background-color:#f7f7f7;border:solid thin silver;display:inline-block;font-size:1.0em;margin:2px;padding:0 0 1px 5px;position:relative;width:136px;white-space:nowrap}.side .recommend-box .rec-item a{display:inline-block;height:100%;overflow:hidden;line-height:1.8em;padding-left:2px;text-overflow:ellipsis;vertical-align:middle;width:111px}.side .recommend-box .rec-item button.add{background-color:#f7f7f7;background-image:none;border:none;cursor:pointer;height:100%;opacity:0.3}.side .recommend-box .rec-item button.add:after{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -818px;background-repeat:no-repeat;content:"";display:block;height:15px;width:15px}.side .recommend-box .rec-item button.add:hover{opacity:1.0}.side .recommend-box .more{color:#369;cursor:pointer;display:inline-block;font-weight:bold;vertical-align:top}.side .recommend-box .endoflist{background-color:#f7f7f7;padding:15px 25px}.side .recommend-box .endoflist h1{margin-bottom:10px}.side .recommend-box .endoflist .heading{color:#555;font-weight:bold}.side .recommend-box .endoflist ul{font-size:x-small;list-style-type:disc;margin:4px 0 0 20px}.side .recommend-box .endoflist .reset{cursor:pointer}.readonly .recommend-box li>button{display:none}.hover-bubble.multi-add-notice{padding:10px 15px;margin-top:-5px;margin-right:10px;background:#fff1d6;border-color:#ffb599;border-radius:4px}.hover-bubble.multi-add-notice:before{border-left-color:#ffb599}.hover-bubble.multi-add-notice:after{border-left-color:#fff1d6}.hover-bubble.multi-add-notice h3{font-size:2em}.hover-bubble.multi-add-notice p{font-size:1.5em;color:gray}.sidecontentbox{font-size:normal}.sidecontentbox .content{margin:0;padding:5px;border:1px solid gray;font-size:larger;list-style:none}.sidecontentbox .more{margin-top:5px;text-align:right;font-size:smaller}.sidecontentbox .more a{color:gray}.sidecontentbox .title h1{display:inline;text-transform:uppercase;margin:0;color:gray;font-size:130%}.sidecontentbox.collapsible .title{cursor:pointer}.sidecontentbox .collapse-button{display:inline-block;width:10px;height:10px;line-height:10px;text-align:center;font-size:10px;background:#eee;color:#333;border:1px solid #999;border-radius:2px;margin:1px 8px;vertical-align:bottom}.titlebox form.toggle,.leavemoderator{margin:0;padding:5px 0px;font-size:smaller;color:gray;background:#ffffff none no-repeat scroll center left}.usertable .moderator.toggle .main:before,.titlebox .leavemoderator:before,.titlebox form.leavecontributor-button:before,.icon-menu .reddit-edit:before,.icon-menu .reddit-traffic:before,.icon-menu .reddit-reported:before,.icon-menu .reddit-spam:before,.icon-menu .reddit-edited:before,.icon-menu .reddit-automod:before,.icon-menu .wikiaction-pages:before,.icon-menu .wikiaction-revisions:before,.icon-menu .reddit-ban:before,.icon-menu .reddit-flair:before,.icon-menu .reddit-moderationlog:before,.icon-menu .reddit-unmoderated:before,.icon-menu .reddit-moderators:before,.icon-menu .moderator-mail:before,.icon-menu .edit-stylesheet:before,.icon-menu .reddit-contributors:before,.icon-menu .reddit-modqueue:before,.giftgold a:before,.gilded-link a:before,.infobar.gold:before,.users-online:before,.notice-taken:before,.notice-available:before,.info-notice:before,.user-form .error:before{height:16px;width:16px;display:block;content:" ";float:left;margin-right:5px}.titlebox .leavemoderator:before,.moderator.toggle .main:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -796px;background-repeat:no-repeat}.moderator.accept-invite .main:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -642px;background-repeat:no-repeat}.titlebox form.leavecontributor-button:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -752px;background-repeat:no-repeat}.titlebox form.flairtoggle{padding:0}.titlebox .tagline{margin:5px 0 5px 20px}.icon-menu a{background:#ffffff none no-repeat scroll center left}.icon-menu li{margin:5px 0}.icon-menu .reddit-edit:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -752px;background-repeat:no-repeat}.icon-menu .edit-stylesheet:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -642px;background-repeat:no-repeat}.icon-menu .reddit-traffic:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -796px;background-repeat:no-repeat}.icon-menu .reddit-reported:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -774px;background-repeat:no-repeat}.icon-menu .reddit-spam:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -774px;background-repeat:no-repeat}.icon-menu .reddit-ban:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -752px;background-repeat:no-repeat}.icon-menu .reddit-flair:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -774px;background-repeat:no-repeat;margin-left:1px}.icon-menu .reddit-moderationlog:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -796px;background-repeat:no-repeat;margin-left:1px}.icon-menu .reddit-unmoderated:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -796px;background-repeat:no-repeat;margin-left:1px}.icon-menu .reddit-edited:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -774px;background-repeat:no-repeat;margin-left:1px}.icon-menu .reddit-automod:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -752px;background-repeat:no-repeat}.icon-menu .reddit-moderators:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -796px;background-repeat:no-repeat}.icon-menu .moderator-mail:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-61px -859px;background-repeat:no-repeat;width:15px;height:10px;margin-top:4px;margin-left:1px}.icon-menu .reddit-contributors:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -752px;background-repeat:no-repeat}.icon-menu .reddit-modqueue:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -774px;background-repeat:no-repeat}.users-online:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -730px;background-repeat:no-repeat}.notice-taken:before,.notice-available:before{margin-right:3px}.notice-taken:before,.user-form .error:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -774px;background-repeat:no-repeat}.notice-available:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -642px;background-repeat:no-repeat}.info-notice:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -642px;background-repeat:no-repeat}.linkinfo{padding:5px;border:1px solid #5f99cf;background-color:#EFF7FF;font-family:arial,helvetica,sans-serif;font-size:larger;border-radius:3px}.linkinfo .score .number{font-size:22px;font-weight:bold}.linkinfo .score .word{font-size:15px;font-weight:bold}.linkinfo .shortlink{font-size:80%;margin-top:3px}.linkinfo .shortlink input{border:1px solid gray;font-family:monospace;font-size:140%;padding:3px 2px;width:175px}.linkinfo .shortlink input:hover{cursor:text}.linkinfo table{margin-top:5px}.linkinfo td,.linkinfo th{padding:2px;font-size:smaller;border:1px solid gray}a.adminbox{border:solid 1px #eeeeee;color:#cdcdcd;font-family:monospace;text-align:center;padding-right:1px}a.adminbox:hover{text-decoration:none;color:orangered;border:solid 1px orangered}.email{font-family:monospace;font-size:larger}.lined-table,.lined-table th,.lined-table td{border:solid #cdcdcd 1px;border-collapse:collapse;padding:2px;margin-bottom:10px}.lined-table th{font-weight:bold}.wide{width:100%}.centered{text-align:center;vertical-align:middle}.sr-ad-table .inherited{background-color:#ddeeff}.sr-ad-table .overridden{background-color:#ffeedd}.sr-ad-table .unused{background-color:#eee}.sr-ad-table .inherited .whence{font-style:italic}.sr-ad-table .overridden .whence{font-weight:bold}.sr-ad-table .details{font-size:150%;padding:10px;vertical-align:top}.sr-ad-table .details .codename{font-size:150%;margin-bottom:20px}.sr-ad-table .weight{width:4em}.ad-assign-table .warning{font-weight:bold;color:red}a.pretty-button:hover{text-decoration:none!important}.pretty-button{display:inline-block;margin-left:5px;margin-bottom:5px;border:1px solid #666;padding:1px 6px;background:#ffffff none repeat-x scroll center left;color:#111;font-size:10px;font-weight:normal;border-radius:3px;outline-style:none}.pretty-button{color:black}.pretty-button.pressed{color:white}.pretty-button.negative{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -52px;background-repeat:repeat}.pretty-button.negative.pressed{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -26px;background-repeat:repeat}.pretty-button.neutral{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -104px;background-repeat:repeat}.pretty-button.neutral.pressed{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -78px;background-repeat:repeat}.pretty-button.positive{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -156px;background-repeat:repeat}.pretty-button.positive.pressed{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -130px;background-repeat:repeat}.oatmeal img{display:block;margin:5px auto}.gold-thanks.gold-accent{font-size:small;margin:35px auto 0;padding:20px;width:600px;position:relative;display:block;border-radius:3px}.gold-thanks p{margin:15px 0;text-align:center}.gold-thanks .lounge-msg p{font-size:medium}.gold-thanks .fancy-snoo img{margin:10px auto;position:relative;display:block}.gold-accent{margin-top:10px;padding:0 10px 5px;background-color:#fffdcc;border:solid 1px #e1b000;color:#9a7d2e;display:inline-block}tr.gold-accent{display:table-row;border-radius:3px}tr.gold-accent+tr>td{padding-top:10px}.gold-accent.titlebox{margin-top:0;padding-top:.5em}.allminus-link{margin-top:1em}body:not(.gold) .allminus-link{opacity:.75}.allminus-link a{font-size:1.15em}.gilded-link{margin-top:1em}.gilded-link a{color:#9a7d2e;font-weight:bold;font-size:1.15em}.gilded-link a:before{height:14px;width:14px;margin:0 6px 0 1px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -839px;background-repeat:no-repeat}#per-sr-karma{width:300px;margin:.6em auto 0 auto;table-layout:fixed}#per-sr-karma thead th,#per-sr-karma td{text-align:right}#per-sr-karma tbody th{text-align:left}#per-sr-karma #sr-karma-header{width:150px;text-align:left}#per-sr-karma thead th{font-weight:bold;padding-bottom:2px}#per-sr-karma tbody th{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis}#per-sr-karma tbody td{font-weight:bold;color:#666}#per-sr-karma th.helpful span{border-bottom:1px dotted #666;cursor:help;display:inline-block}.more-karmas{display:none}.karma-breakdown{margin-top:.6em;margin-bottom:5px}.karma-breakdown a{font-weight:bold}.rel-note button[type=submit]{visibility:hidden;font-size:x-small;padding-top:1px;padding-bottom:1px;margin:0px;margin-left:5px}.rel-note.edited button[type=submit]{visibility:visible}.rel-note.edited input[name=note]{width:65%}.rel-note input[name=note]{font-size:xx-small;max-width:200px;width:100%}form#banned textarea{display:block;margin-left:0}.gold-accent h1,.gold-accent th{color:#6a4d00;font-family:"Hoefler Text","Palatino Linotype","Book Antiqua",Palatino,georgia,garamond,FreeSerif,serif;font-variant:small-caps}.gold-accent .pretty-form input[type=text]{margin-top:1px;margin-bottom:2px;margin-left:0}.gold-accent .pretty-form input[type=text]#name{border-radius:3px}.gold-accent .pretty-form button{background-color:#fff088;color:#6a4d00;border:1px solid #9a7d2e;border-radius:3px}.gold-accent.snoovatar-link{color:#9A7D2E;display:block;padding:0;margin:3px 0;border-radius:5px;text-align:center;position:relative;line-height:30px}.gold-accent.snoovatar-link:before{background-image:url(../gold/snoo-head.png);background-repeat:no-repeat;content:'';display:inline-block;background-size:27px;width:27px;height:27px;vertical-align:top;background-position:center left;margin-top:1px;margin-left:-13px;margin-right:7px}.gold-expiration-info{display:block;margin:3px 0;text-align:center}.num-gildings{margin-top:5px}.gold-expiration-info .karma{color:#583800}.giftgold{margin-bottom:5px}.giftgold a{color:#9a7d2e;font-weight:bold}.giftgold a:before,.infobar.gold:before{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-21px -818px;background-repeat:no-repeat}.gold-accent.comment-visits-box{color:#583800;margin:0px 5px 15px;padding:7px 10px 7px 7px;max-width:550px}.gold-accent.roundfield{margin-top:0px}.gold-form .note{font-size:13px;line-height:16px;font-style:italic;color:#222;margin-top:25px}.gold-form p.goldtype-note{font-size:13px;line-height:16px;font-style:italic;color:#222;margin-top:25px;margin-top:0;margin-left:22px;padding-bottom:7px;border-bottom:1px solid #e1b000}.gold-form label:last-of-type{padding-right:0}.gold-form label:last-of-type p.goldtype-note{border-bottom:0;padding:0}.gold-form .spacer{margin-top:20px!important}.gold-subsection{display:none;position:absolute}.gold-wrap.inline-gold .fancy{width:620px;margin:0}.gold-wrap.inline-gold .fancy-content{margin:10px auto}.gold-wrap.inline-gold .sidelines{display:none}.gold-wrap.cloneable-link,.gold-wrap.cloneable-comment{display:none}.gold-form .credit-card-input{display:inline}.gold-form .stripe-submit{display:block;margin-top:10px}.gold-wrap form{display:inline}.gold-logo{float:left;margin:5px 0}.thing .gold-form{margin:10px 0 10px 4px;min-height:0}.gold-payment .roundfield-content{margin-left:80px}.gold-payment .close-button{position:absolute;top:0;right:0;width:13px;height:13px;margin:6px 4px 6px 8px;border:none;background:url(../close.png) no-repeat;text-indent:-9999px;opacity:.25}.gold-payment .close-button:hover{opacity:.55}.giftmessage{background-color:white;border-radius:3px;border:solid #888 1px;color:black;margin-bottom:15px;margin-left:20px;padding:0 10px;max-width:300px;width:90%}.gold-button{margin-left:5px;padding:10px 20px;color:#fff;font-size:1.1em;font-family:Palatino,georgia,garamond,FreeSerif,serif;text-align:center;background-color:#938870;border-radius:4px;border:1px solid transparent;-webkit-transition:background-color 0.2s ease 0s;-moz-transition:background-color 0.2s ease 0s;-o-transition:background-color 0.2s ease 0s;-ms-transition:background-color 0.2s ease 0s;transition:background-color 0.2s ease 0s;box-sizing:content-box;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-shadow:inset 0 -2px 0 rgba(0,0,0,0.27)}.gold-button:hover{background-color:#b8ab90}.gold-button:active{background-color:#b8ab90;border:1px solid #5e5137;box-shadow:inset 0px 0px 7px rgba(0,0,0,0.27)}.gold-button.disabled,.gold-button:disabled{color:#999;background-color:#ccc;border-color:#aaa;text-shadow:none}.creddits-gold .remaining{font-size:10px;text-align:center;width:125px;position:absolute;display:block;line-height:1.5}.creddits-gold .gold-button{padding-left:35px;position:relative}.creddits-gold .gold-button .snoo-head{background-image:url(../gold/snoo-head.png);background-repeat:no-repeat;position:absolute;top:7px;left:7px;right:0;bottom:0;background-size:23px;width:23px;opacity:0.5;-webkit-transition:opacity 0.2s ease 0s;-moz-transition:opacity 0.2s ease 0s;-o-transition:opacity 0.2s ease 0s;-ms-transition:opacity 0.2s ease 0s;transition:opacity 0.2s ease 0s}.creddits-gold .gold-button:hover .snoo-head{opacity:1}.gold-dropdown,.goldvertisement{font-family:"Bitstream Charter","Hoefler Text","Palatino Linotype","Book Antiqua",Palatino,georgia,garamond,FreeSerif,serif}.gold-dropdown{color:#482800;background-color:#fff088;font-size:16px}.gold-expiration-info,.server-seconds{padding:6px;border-radius:5px}.server-seconds{background-color:#EFF7FF;border:1px solid #5F99CF;text-align:center}.server-seconds p{padding:5px 0}.server-seconds em{font-weight:bold;color:#393939}.server-seconds-public.bottom{border-top-style:dashed;border-top-color:#ccc;margin-top:6px;padding-top:10px;text-align:left}.server-seconds-public *{vertical-align:middle}.server-seconds-public input[type=radio]{margin-top:0}.server-seconds-public label{margin:0 5px;position:relative;top:-2px}.server-seconds-public .title{float:left;padding-left:20px;margin-right:10px}.server-seconds-public .note{font-style:italic;margin-top:10px;text-align:center}.comment-visits-box .title{font-weight:bold;font-size:12px}.new-comment .usertext-body{background-color:#e5efff;border:solid 1px #cddaf3;margin:-1px 0;padding:0 4px}.role{width:800px}.styled-input{border:1px solid gray;padding:2px;-webkit-box-shadow:inset 0px 1px 1px rgba(0,0,0,0.3),0px 1px 0px rgba(255,255,255,0.6);-moz-box-shadow:inset 0px 1px 1px rgba(0,0,0,0.3),0px 1px 0px rgba(255,255,255,0.6);box-shadow:inset 0px 1px 1px rgba(0,0,0,0.3),0px 1px 0px rgba(255,255,255,0.6)}.infobar.client-info{position:relative;margin:10px 2%;width:94%;height:48px}.infobar.client-info .icon img{position:absolute;left:10px;width:48px;height:48px}.infobar.client-info div{line-height:48px;margin-left:56px}.infobar.client-info div p{white-space:nowrap}.oauth2-authorize{position:relative;background:url(../snoo-tray.png) no-repeat;width:542px;height:235px;margin:40px auto 0;padding-left:268px;padding-top:18px}.oauth2-authorize h1{margin-left:10px}.oauth2-authorize h1 a{font-weight:bold;letter-spacing:-0.04em}.oauth2-authorize .icon{position:absolute;left:160px;top:69px;width:72px;height:72px;line-height:72px;text-align:center;white-space:nowrap}.oauth2-authorize .icon img{vertical-align:middle}.oauth2-authorize .access,.infobar.client-info{background:#f7f7f7;border:1px solid #b3b3b3}.oauth2-authorize .access{position:relative;float:right;width:510px;padding:10px 15px;font-size:1.5em;line-height:1.5em}.oauth2-authorize .access:before{position:absolute;display:block;content:'';border-width:9px;border-style:solid solid outset;border-color:transparent #b3b3b3 transparent transparent;left:-19px;top:13px}.oauth2-authorize .access:after{position:absolute;display:block;content:'';border:9px solid;border-color:transparent #f7f7f7 transparent transparent;left:-18px;top:13px}.oauth2-authorize .access .notice{line-height:normal}.oauth2-authorize h2{font-size:1em;font-weight:normal;color:black}.oauth2-authorize ul{list-style-type:disc;padding-left:25px}.oauth2-authorize .notice{color:#333;font-size:.85em;margin:.5em 0}.oauth2-authorize .fancybutton{margin:0;margin-right:1em;cursor:pointer}.oauth2-authorize .fancybutton.allow{color:white;background:#ff4500;border-color:#541700;box-shadow:inset 0px 1px 0px rgba(255,255,255,0.25);text-shadow:0px 1px 0px rgba(0,0,0,0.7)}.oauth2-authorize .fancybutton.allow:hover{background:#ff571a}.oauth2-authorize .fancybutton.allow:active{background:#eb3f00;box-shadow:inset 0px -1px 0px rgba(255,255,255,0.25)}.oauth2-authorize .fancybutton.decline{color:black;background:#eee;border-color:#555;box-shadow:inset 0px 1px 0px rgba(255,255,255,0.5);text-shadow:0px 1px 0px rgba(255,255,255,0.7)}.oauth2-authorize .fancybutton.decline:hover{background:#f7f7f7}.oauth2-authorize .fancybutton.decline:active{background:#e4e4e4;box-shadow:inset 0px -1px 0px #ffffff}.modactionlisting table{margin:0 5px}.modactionlisting td.timestamp,.modactionlisting td.subreddit{white-space:nowrap}.modactionlisting td.button{padding-right:0;padding-left:1.5em}.modactionlisting td.description em{font-style:italic}.modactions td{font-size:small;text-align:left;padding:2px 10px}.modactions.banuser,.modactions.unbanuser,.modactions.removelink,.modactions.approvelink,.modactions.removecomment,.modactions.approvecomment,.modactions.addmoderator,.modactions.removemoderator,.modactions.invitemoderator,.modactions.uninvitemoderator,.modactions.acceptmoderatorinvite,.modactions.addcontributor,.modactions.removecontributor,.modactions.editsettings,.modactions.editflair,.modactions.distinguish,.modactions.marknsfw,.modactions.wikirevise,.modactions.wikipermlevel,.modactions.wikibanned,.modactions.wikiunbanned,.modactions.wikicontributor,.modactions.wikipagelisted,.modactions.removewikicontributor,.modactions.ignorereports,.modactions.unignorereports,.modactions.sticky,.modactions.unsticky{height:16px;width:16px;display:block;content:" ";float:left;margin-right:5px}.modactions.banuser{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -752px;background-repeat:no-repeat}.modactions.unbanuser{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -708px;background-repeat:no-repeat}.modactions.removelink{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -686px;background-repeat:no-repeat}.modactions.approvelink{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -642px;background-repeat:no-repeat}.modactions.removecomment{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -686px;background-repeat:no-repeat}.modactions.approvecomment{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -664px;background-repeat:no-repeat}.modactions.addmoderator,.modactions.invitemoderator,.modactions.acceptmoderatorinvite{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -642px;background-repeat:no-repeat}.modactions.removemoderator,.modactions.uninvitemoderator{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -708px;background-repeat:no-repeat}.modactions.addcontributor{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -664px;background-repeat:no-repeat}.modactions.removecontributor{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -686px;background-repeat:no-repeat}.modactions.wikipagelisted,.modactions.editsettings{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -752px;background-repeat:no-repeat}.modactions.editflair{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -774px;background-repeat:no-repeat}.modactions.distinguish{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -664px;background-repeat:no-repeat}.modactions.marknsfw{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -686px;background-repeat:no-repeat}.modactions.wikirevise{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -730px;background-repeat:no-repeat}.modactions.wikipermlevel{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -730px;background-repeat:no-repeat}.modactions.wikibanned{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -752px;background-repeat:no-repeat}.modactions.wikiunbanned{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -708px;background-repeat:no-repeat}.modactions.wikicontributor{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-44px -664px;background-repeat:no-repeat}.modactions.removewikicontributor{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -686px;background-repeat:no-repeat}.modactions.ignorereports{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -686px;background-repeat:no-repeat}.modactions.unignorereports{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -708px;background-repeat:no-repeat}.modactions.sticky{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-22px -708px;background-repeat:no-repeat}.modactions.unsticky{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -708px;background-repeat:no-repeat}.adminpasswordform{display:block;margin:.5em auto 0 auto}.adminpasswordform label{display:block;padding:.5em}.content.api-help{font-size:1.25em;margin:0 auto;max-width:950px}.api-help .contents{padding:0 20px;margin-left:24em;margin-top:20px}.api-help .contents .section{margin-bottom:2em}.api-help .sidebar{float:left;margin-left:10px}.api-help .sidebar .head{position:relative;background:url(../xray-snoo-head.png) top center no-repeat;height:188px;margin-bottom:-78px;z-index:2}.api-help .sidebar .feet{position:relative;background:url(../xray-snoo-feet.png) top center no-repeat;height:75px;margin-top:-42px;z-index:2}.api-help .toc{background:#181818 url(../xray-snoo-body.png) center repeat-y;border:5px solid #959595;border-radius:8px;padding:15px 2em 0 2em;width:18em}.api-help .contents .introduction{position:relative;border:2px solid #ccc;border-radius:12px;margin-bottom:-1em}.api-help .contents .introduction p{margin:1em 14px}.api-help .contents .introduction strong{color:#222;font-weight:bold}.api-help .introduction:before,.api-help .introduction:after{position:absolute;display:block;content:'';border:15px solid;border-style:solid solid outset}.api-help .introduction:before{border-color:transparent #ccc transparent transparent;left:-31px;top:58px}.api-help .introduction:after{border-color:transparent white transparent transparent;left:-28px;top:58px}.api-help .contents .overview h3{margin-top:1.5em}.api-help .contents .overview p{margin:.8em 0}.api-help .contents .overview code{background-color:#f0f0f0;padding:0 .5em;border-radius:3px}.api-help .toc ul{position:relative;margin-top:.5em;margin-bottom:1.5em;z-index:10}.api-help .toc>ul>li>strong{color:#aaa}.api-help .toc a.section{color:#888;font-weight:bold}.api-help .toc a{display:block;color:#8EB0D2}.api-help .toc a:hover,.api-help .endpoint a:hover{text-decoration:underline}.api-help .toc .mode-selector{display:inline-block;font-size:x-small;border-radius:5px;border:1px solid #888;margin-top:6px;vertical-align:middle}.api-help .toc .mode-selector .mode{display:inline-block;margin:2px;padding-top:2px;padding-bottom:3px;border-radius:3px;text-align:center;width:107px;color:#ddd}.api-help .toc .mode-selector .mode:hover{background-color:#ccc;color:black;text-decoration:none}.api-help .toc .mode-selector .mode-current{color:black;background-color:#eee}.api-help .toc .mode-selector .mode-current:hover{background-color:#ddd}.api-help em.placeholder{font-style:italic;font-weight:normal}.api-help .toc em.placeholder{color:#8EB0D2}.api-help .toc li.supports-oauth a{background:none}.api-help .toc li.supports-oauth a:after{content:'oauth';display:inline-block;position:absolute;right:0;font-size:.75em;background:#29440e;color:#ddc;padding:0 2px;margin-left:2px;border-radius:2px}.api-help .endpoint em.placeholder{color:#369}.api-help .endpoint,.api-help .section .description{margin-bottom:1.5em}.api-help .oauth-scope-list{display:inline;margin-left:1em}.api-help .api-badge{display:inline-block;margin-left:0.5em;font-size:.75em;font-weight:normal;vertical-align:bottom;color:#fbfbf9;padding:2px 6px;border-radius:2px}.api-badge.oauth-scope{background:#577439}.api-badge.rss-support{background:#f38f35}.api-help .overview h2,.api-help .methods h2{color:black;font-size:1.45em;text-align:middle;margin-top:1.5em;margin-bottom:1em;border-bottom:1px solid #aaa}.api-help .methods h2 .scope-id{margin-left:1em;font-size:small;font-weight:normal;font-style:italic}.api-help .endpoint .info{padding-left:1em;border-left:1px solid #ddd}.api-help .endpoint h3,.api-help .endpoint .uri-variants{color:#369;margin-bottom:.5em}.api-help .endpoint .uri-variants{opacity:.85;font-weight:bold;margin-top:-0.5em;margin-left:3em}.api-help .endpoint .method,.api-help .endpoint .extensions{font-weight:normal;color:gray}.api-help .endpoint .extensions{margin-left:.5em}.api-help .endpoint .links{float:right}.api-help .endpoint .links a{margin-left:.85em;opacity:.45}.api-help .endpoint:hover .links a{opacity:1}.api-help .parameters{background:#f0f0f0;border-collapse:separate;border-radius:3px;padding:5px 10px;border-spacing:0;width:100%}.api-help caption{font-weight:bold;margin:1em 0 .5em .5em}.api-help .parameters th,.api-help .parameters td{vertical-align:top;border-bottom:1px dotted #ccc;padding:5px 0;margin:0}.api-help .parameters tr:last-child th,.api-help .parameters tr:last-child td{border:none}.api-help .parameters th{font-family:'Courier New',monospace;line-height:1.6;width:30%;padding-right:10px}.api-help .parameters td pre{margin:.5em 0}.api-help .parameters code{white-space:pre-wrap}#classy-error{text-align:center}.errorpage-message{margin:1em auto;width:500px;font-size:small}.errorpage-message.sr-description{border-top:2px solid black;margin-top:2em;padding-top:2em}.errorpage-message.sr-description h2{color:black;font-weight:bold;font-size:125%;margin-bottom:.7em}.sr-description p{margin:.75em 0}#pref-otp .roundfield{margin:1em 0}#pref-otp-qr{display:none}#otp-secret-info{margin:2em;width:512px;font-size:small}#otp-secret-info div{margin:1em 0}#otp-secret-info .secret{font-weight:bold}.users-online{margin-bottom:.25em}.users-online .word,.users-online .number:after{cursor:help}.sr-interest-bar{position:relative;background:#cee3f8 url(../snoo-upside-down.png) 15px top no-repeat;padding:5px;overflow:hidden;border:1px solid #336699;margin-bottom:10px}.organic-listing .sr-interest-bar{border:none;margin:0}.sr-interest-bar .bubble{position:relative;margin-left:85px;margin-right:68px;max-width:700px;font-size:13px;background:white;padding:6px;border-radius:8px}.sr-interest-bar .bubble:after{position:absolute;display:block;content:'';border:10px solid;border-style:solid solid outset;border-color:transparent;border-right-color:white;left:-20px;top:15px}.sr-interest-bar .bubble p{margin:6px 3px;margin-top:0}.sr-interest-bar .subscribe{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px 0px;background-repeat:repeat;border:1px solid #444;border-radius:3px;padding:0 6px;color:white;font-weight:bold}.sr-interest-bar .query-box{position:relative;padding:2px 4px;border:2px solid #979797;border-radius:5px}.sr-interest-bar.focus .query-box{border-color:#5f99cf}.sr-interest-bar.error .query-box{border-color:#cf5e5e}.sr-interest-bar .error-caption,.sr-interest-bar.error .caption{display:none}.sr-interest-bar.error .error-caption{display:block}.sr-interest-bar .query{width:100%;font-size:20px;margin:0;padding:0;border:none;outline:none}.sr-interest-bar .throbber{position:absolute;right:3px;top:5px}.sr-interest-bar ul.results{margin:0;margin-top:6px;padding-top:2px;border-top:1px dotted #bbb;display:none}.sr-interest-bar li{display:inline-block;margin:6px 3px}.sr-interest-bar a{padding:1px 2px}.sr-interest-bar a:hover{text-decoration:underline}.sr-interest-bar .results .random{color:gray;font-weight:bold}.ajax-upload-form iframe{display:none}.developed-app,.authorized-app{border:solid 1px black;margin-left:20px;margin-bottom:0.5em;padding:7px;position:relative;width:880px;font-size:x-small}.developed-app.collapsed,.authorized-app{min-height:100px}.developed-app .collapsed{display:none}.developed-app .ajax-upload-form{display:none}.app-details{display:inline-block;width:200px;min-height:72px;margin-left:1em;vertical-align:top}.app-details h2{font-size:medium;margin:0px}.app-details h3{font-size:x-small;margin:0px}.app-icon{display:inline-block;width:72px;height:72px;line-height:72px;text-align:center;white-space:nowrap}.app-icon img{vertical-align:middle}.app-permissions li{position:relative}.app-permissions-details{margin-top:1em}.app-scope{display:none;position:absolute;top:1ex;left:3ex;border:1px solid black;background:#fffdcc;z-index:1}.app-description{display:inline-block;font-size:small;width:597px;height:80px;overflow-y:auto;vertical-align:top}.app-developers{position:absolute;left:289px;bottom:1ex;width:600px}.edit-app-button,.revoke-app-button{position:absolute;bottom:1ex;left:12px;width:200px}.edit-app.collapsed,.edit-app-icon,.developed-app .collapsed{display:none}.edit-app-icon-button{display:block;text-align:center;width:72px}.edit-app-form,.edit-app-form form{display:inline-block}.edit-app-form th,.edit-app-icon th{width:12ex}.edit-app-form input.text{margin:0px;width:50ex}.edit-app-form input[name="name"]{width:20ex!important}.edit-app-form input[type="file"]{width:auto!important}.edit-app-form input[type="submit"]{margin-left:10px;width:auto!important}.delete-app-button{position:absolute;bottom:7px;left:100px}#create-app{display:none}table.diff{font-size:small}.diff_header{background-color:#d3d3d3}.diff_next{background-color:#d3d3d3}.diff_add{background-color:#90ee90}.diff_chg{background-color:#ffff00}.diff_sub{background-color:#f08080}.gilded-icon{position:relative;display:inline-block;margin:0 0 -15px 8px;top:-8px;color:#99895F;font-size:.9em;vertical-align:middle}.gilded-icon:before{display:inline-block;content:'';background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:0px -839px;background-repeat:no-repeat;height:14px;width:13px;margin-right:2px;vertical-align:-3px}.user-gilded>.entry .gilded-icon:before{width:23px}body.post-under-6h-old .gilded-icon{opacity:.55}.goldvertisement{border:1px solid #c4b487;text-align:center;line-height:1.3em;box-shadow:0 0 10px #dad0b3 inset;color:#554a2a}.goldvertisement .inner{margin:1px;border:1px solid #dbd1b5;padding:6px 8px}.goldvertisement li{display:inline-block;margin-right:2em}.goldvertisement h2{margin:0;font-weight:normal;color:inherit}.goldvertisement .progress{padding:7.5px 0}.goldvertisement .progress .bar{border:1px solid #dad0b3;height:17px;overflow:auto;border-radius:10px}.goldvertisement .progress .bar span{display:block;height:100%;background-color:#f3e287;background-image:-webkit-linear-gradient(top,#fff8ba,#eccf90);background-image:linear-gradient(to bottom,#fff8ba 0%,#eccf90 100%);border-radius:8.5px}.goldvertisement .progress p{float:right;font-weight:bold;font-size:15px;color:#5a3f1a;line-height:19px;margin-left:6px;margin-top:0}.goldvertisement a{display:inline-block;margin:0;padding:2px 4px;border-radius:3px;background:#fbfaf8;border:1px solid #d5c9a9;border-bottom-width:2px;color:#554a2a}.goldvertisement a:hover{background:#fdf4c5}.goldvertisement a:active{margin-top:1px;border-bottom-width:1px}.goldvertisement.st-patrick{box-shadow:0 0 10px #5c7d03 inset;color:#000000}.goldvertisement.st-patrick .inner{border:1px solid #a1ba62}.goldvertisement.st-patrick h2{color:#5c7d03}.goldvertisement.st-patrick a{background:#a1ba62;border:1px solid #81af04;color:#2d3f01}.goldvertisement.st-patrick a:hover{background:#cbd9a9}.goldvertisement.st-patrick .progress{position:relative}.goldvertisement.st-patrick .progress .bar{border-color:#a1ba62;overflow:visible;margin-right:10px;padding-right:10px;position:relative}.goldvertisement.st-patrick .progress .bar:after{display:inline-block;position:absolute;top:0;right:0;margin-top:-3px;margin-right:-8px;content:'';background-image:url(../gold/gild-icon.png);width:22px;height:22px}.goldvertisement.st-patrick .progress .bar span{background:url(../gold/progress-bar-clovers.png);position:relative;border-top-right-radius:0px;border-bottom-right-radius:0px}.goldvertisement.st-patrick .progress .bar span:after{display:inline-block;position:absolute;top:0;right:0;margin-right:-22px;margin-top:-11px;content:'';background-image:url(../gold/snoo-leprechaun.png);width:29px;height:34px;z-index:200}.goldvertisement.st-patrick .progress p{position:absolute;width:100%;text-align:center;top:9px;color:#2d3f01;z-index:100;text-shadow:0 2px 1px rgba(255,255,255,0.5)}.gold-bubble{width:290px;border-radius:4px;font-size:125%;line-height:1.13;font-family:"Hoefler Text","Palatino Linotype","Book Antiqua",Palatino,georgia,garamond,FreeSerif,serif;border-color:#907c47;padding:4px}.gold-bubble.anchor-top-centered:before{border-bottom-color:#907c47}.gold-bubble p+p{margin-top:1em}.gold-bubble span.gold-branding{display:inline-block;vertical-align:bottom;text-indent:-9999px;background:transparent url(../gold/goldvertisement-logo.png) top left no-repeat;width:79px;height:18px;margin-right:1px}.gold-bubble p.buy-gold{background:transparent url(../gold/goldvertisement-gold.png) top left no-repeat;margin-left:13px;padding-left:67px;min-height:45px}.gold-bubble p.buy-gold a{color:#825b25}.gold-bubble p.give-gold{background:transparent url(../gold/goldvertisement-gild.png) top left no-repeat;margin-left:23px;padding-left:57px;min-height:39px}.gold-bubble p.aside{color:#777;font-style:italic}.gold-bubble p.aside a{color:inherit}.gold-bubble div.history{margin:5px 0;padding-top:2px;border-top:1px solid #e2ddcf}.gold-bubble div.history p{margin-bottom:0}.gold-bubble div.history .progress{padding:5px 0;margin:0 7px;opacity:0.8}.gold-bubble div.history .progress .bar{border:1px solid #dad0b3;height:12px;overflow:auto;border-radius:10px}.gold-bubble div.history .progress .bar span{display:block;height:100%;background-color:#f3e287;background-image:-webkit-linear-gradient(top,#fff8ba,#eccf90);background-image:linear-gradient(to bottom,#fff8ba 0%,#eccf90 100%);border-radius:6px}.gold-bubble div.history .progress p{float:right;font-weight:bold;font-size:10px;color:#5a3f1a;line-height:14px;margin-left:6px;margin-top:0}.gold-bubble div.history .progress p{margin-right:0;font-weight:normal}#stripe-payment th{padding:5px;vertical-align:top;text-align:right;white-space:nowrap;font-size:smaller}#stripe-payment{padding-top:15px}#stripe-payment .credit-card-amount,#stripe-payment .credit-card-interval{text-align:left}#stripe-payment th label{display:inline}#stripe-payment td input{font-size:small;width:200px}#stripe-payment input.card-cvc{width:9ex}#stripe-payment input.card-address_zip{width:13ex}.stripe-note a.icon{position:relative;float:left;text-indent:-9999px;margin-right:10px;width:119px;height:33px;background-image:url(../stripe.png)}.stripe-note div{float:left;width:250px;font-size:small}.gold-subscription{font-size:small;padding:2px}.gold-subscription div.buttons{padding:10px 0}.gold-subscription .cancel-button,.gold-subscription .edit-button{margin:5px;display:inline}.gold-subscription .status,.gold-subscription .error{font-size:small;margin:0}.gold-subscription .roundfield{background-color:#fffdd7;width:400px}.gold-subscription #stripe-cancel{display:inline}.permissions{display:inline-block;font-size:small;text-align:right;width:36ex}#moderator_invite .permissions{width:30ex}.permissions>form{display:none}.permission-summary{display:inline-block;font-size:small;border:1px solid white}.permission-summary.edited{border:dashed 1px black}.permission-bit.added{font-weight:bold}.permission-bit.removed{text-decoration:line-through}.permission-bit.none{font-style:italic}.permissions-edit{font-size:x-small}.permission-selector{border:1px solid black;background-color:white;position:absolute;width:24ex}.permission-selector.active{display:block}.permission-selector label{display:block;text-align:left;padding:0px 2px 1px 2px}.permission-selector label:first-child{border-bottom:1px solid black}.permission-selector label:hover{background-color:#bbb}.permission-selector label.disabled{background-color:#ddd}.permission-selector form{text-align:right}.permission-selector .status,.permission-selector .error{text-align:left;white-space:normal}.light-button{background:none;border:1px solid #777;border-radius:3px;box-shadow:0 1px 1px rgba(0,0,0,0.25);opacity:.75}.light-button:active{position:relative;top:1px;box-shadow:none}.light-text-input{background:white;border:1px solid #ccc;padding:2px 5px}body.with-listing-chooser{position:relative}body.with-listing-chooser #header .tabmenu{margin-left:8px}body.with-listing-chooser #header .tabmenu li:first-child.selected{margin-left:2px}body.with-listing-chooser #header .pagename{position:absolute;bottom:20px;margin-left:10px}body.with-listing-chooser>.content,body.with-listing-chooser .footer-parent{margin-left:148px}body.with-listing-chooser .listing-chooser{position:absolute;top:65px;left:0;bottom:0;width:130px;padding-right:14px;background:#f7f7f7;overflow:hidden}body.with-listing-chooser .listing-chooser.initialized{-webkit-transition:width 0.25s ease 0s;-moz-transition:width 0.25s ease 0s;-o-transition:width 0.25s ease 0s;-ms-transition:width 0.25s ease 0s;transition:width 0.25s ease 0s}body.with-listing-chooser .listing-chooser.initialized .grippy,body.with-listing-chooser .listing-chooser.initialized .grippy:before,body.with-listing-chooser .listing-chooser.initialized .grippy:after{-webkit-transition:all 0.1s ease 0.03s;-moz-transition:all 0.1s ease 0.03s;-o-transition:all 0.1s ease 0.03s;-ms-transition:all 0.1s ease 0.03s;transition:all 0.1s ease 0.03s}body.with-listing-chooser .listing-chooser .grippy{position:absolute;right:0;width:14px;height:100%;background:white;border-left:1px solid #ccc;box-shadow:0 0 6px rgba(0,0,0,0.2);z-index:25;cursor:pointer}body.with-listing-chooser .listing-chooser .grippy:before{content:'';display:block;position:absolute;width:8px;height:100%;background:url(../sidebar-grippy-hide.png) fixed no-repeat;background-position:131px center;margin-left:1px;opacity:.5}body.with-listing-chooser .listing-chooser .grippy:after{content:'';display:block;position:absolute;height:100%;right:5px;width:8px;border-right:1px dotted #e5e5e5;z-index:-1}body.with-listing-chooser .listing-chooser .grippy:hover:before{opacity:1}body.with-listing-chooser .listing-chooser .grippy:hover:after{background:#f4f4f4}body.with-listing-chooser .listing-chooser:hover .grippy:before{opacity:.8}body.with-listing-chooser.listing-chooser-collapsed #header .tabmenu{margin-left:0}body.with-listing-chooser.listing-chooser-collapsed #header .pagename{margin-left:2px}body.with-listing-chooser.listing-chooser-collapsed>.content,body.with-listing-chooser.listing-chooser-collapsed .footer-parent{margin-left:15px}body.with-listing-chooser.listing-chooser-collapsed .listing-chooser{width:0;padding-right:15px;z-index:-1}body.with-listing-chooser.listing-chooser-collapsed .listing-chooser .grippy{z-index:40;width:15px}body.with-listing-chooser.listing-chooser-collapsed .listing-chooser .grippy:before{background-image:url(../sidebar-grippy-show.png);background-position:2.5px center;margin-left:1.5px;width:9px}body.with-listing-chooser.listing-chooser-collapsed .listing-chooser .grippy:after{right:5px;width:9px;border-right:1px solid #ccc}.listing-chooser h3{color:#777;text-align:right;padding:4px}.listing-chooser .intro{background:#f8ecb6;border:1px solid #ffae1a;border-left:none;border-right:none;margin-bottom:10px;width:130px}.listing-chooser .intro p{font-size:1.15em;margin:4px;margin-left:8px}.listing-chooser .intro ul.multis{margin:6px 0}.listing-chooser ul.global,.listing-chooser ul.other{padding:8px 0}.listing-chooser ul.global li,.listing-chooser ul.other li{margin-left:4px}.listing-chooser ul.global li a,.listing-chooser ul.other li a{font-size:1.3em;padding:1em 5px;padding-left:12px}.listing-chooser ul.other{margin-top:10px}.listing-chooser ul.multis li{margin-left:12px;-webkit-transition:all 0.15s ease 0s;-moz-transition:all 0.15s ease 0s;-o-transition:all 0.15s ease 0s;-ms-transition:all 0.15s ease 0s;transition:all 0.15s ease 0s}.listing-chooser ul.multis li:hover{margin-left:9px}.listing-chooser ul.multis li a{font-size:1.2em;padding:.8em 5px;padding-left:10px}.listing-chooser li{text-align:left;margin-bottom:3px;background:#fff;border:1px solid #ccc;border-bottom-width:2px;border-right:none;border-top-left-radius:5px;border-bottom-left-radius:5px}.listing-chooser li a{display:block;position:relative;overflow:hidden;text-overflow:ellipsis;margin-right:5px}.listing-chooser li a .description{color:gray;font-size:.8em;font-weight:normal;white-space:nowrap}.listing-chooser li:last-child a{border-bottom:none}.listing-chooser li.selected{position:relative;background:#e9f2fc;border-color:#b3cce6;margin-right:-8px;padding-right:8px;box-shadow:-30px 0 30px -15px rgba(255,255,255,0.5) inset,0 2px 6px -1px rgba(0,0,0,0.2);z-index:35}.listing-chooser li.selected a{font-weight:bold}.listing-chooser li.selected:before{position:absolute;top:50%;right:0;margin-top:-5px;display:block;content:'';border:5px solid transparent;border-style:solid solid outset;border-left-color:#79a6d2}.listing-chooser li.gold-perks{background:#fdfbf2}.listing-chooser li.gold-perks a{color:#9a7d2e}.listing-chooser li.gold-perks.selected{border-color:#cec19c}.listing-chooser li.gold-perks.selected:before{border-left-color:#c9a74b}.listing-chooser .create{padding:5px}.listing-chooser .create input[type="text"]{background:white;border:1px solid #ccc;padding:2px 5px;width:95px;margin-bottom:3px;display:none}.listing-chooser .create .error{margin:4px 0;width:100px}.listing-chooser .create button{display:inline;text-align:center;padding:1px 4px;margin:0;background:none;border:1px solid #777;border-radius:3px;opacity:.5}.listing-chooser .create button:hover{opacity:.90}.listing-chooser .create button:active{background:#e9e9e9}.listing-chooser .create button,.listing-chooser .create .throbber{vertical-align:middle}.listing-chooser .create .throbber{float:right}.listing-chooser .create.expanded input[type="text"]{display:block}.listing-chooser .create.expanded button{background:none;border:1px solid #777;border-radius:3px;box-shadow:0 1px 1px rgba(0,0,0,0.25);opacity:.75}.listing-chooser .create.expanded button:active{position:relative;top:1px;box-shadow:none}.user-jumped-to{border-radius:5px;-moz-border-radius:5px;border:1px solid #DDF;display:inline-block;margin-top:10px;padding:10px 15px;background-color:#EEF}.submit_text{display:none;max-height:250px;overflow:auto}.submit_text ol,.submit_text ul{margin:0;margin-left:2em}.submit_text.working .content:before{content:"";width:16px;height:16px;display:block;background-image:url(../throbber.gif)}.submit_text h1{color:#336699;display:block;font-size:16px;font-weight:bold}.submit_text .content{margin:0}.submit_text .content p{word-wrap:break-word;clear:both}.submit_text.enabled{display:inline-block}.hover-bubble.save-selector{display:none}.hover-bubble.save-selector label{display:block;font-weight:bold;margin-left:5px;font-size:10px}.hover-bubble.save-selector .savedcategory{border:1px solid #ccc;padding:1px 3px;margin:0 2px}.save-category{margin-left:2px;background-color:#DDF;padding:2px 5px;border-radius:5px;-moz-border-radius:5px}.save-category.hidden{display:none}#adminnotes-form textarea{width:285px}#adminnotes-form .notes-button{margin:3px 0px;display:block}#past-notes{overflow-y:auto;max-height:150px}#past-notes li.adminnote{border-top:1px solid black;overflow-x:auto}#past-notes .adminnote-info{text-align:right;font-size:small;font-style:italic}.trending-subreddits{margin-top:-2px;margin-bottom:8px;line-height:1.75em;margin-left:17px}body.compressed-display .trending-subreddits{margin-left:15px}body.compressed-display .trending-subreddits .midcol-spacer{width:15px}.trending-subreddits .rank-spacer,.trending-subreddits .midcol-spacer{float:left;height:1px}.trending-subreddits .trending-subreddits-content{overflow:hidden}.trending-subreddits strong{color:#29541c}.trending-subreddits strong:before{height:14px;width:14px;display:inline-block;content:" ";margin-right:5px;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-71px -839px;background-repeat:no-repeat;vertical-align:middle}.trending-subreddits ul{display:inline}.trending-subreddits li{display:inline-block;margin-left:0.5em}.trending-subreddits li:first-child{margin-left:0}.trending-subreddits ul,.trending-subreddits .comments{margin-left:1em}.trending-subreddits .comments{color:#888;font-weight:bold;white-space:nowrap}.trending-subreddits .comments:hover{text-decoration:underline}.fancy{background-color:#fffcfc;border:2px solid #D4D3CF;margin:10px auto;max-width:974px;padding:0;position:relative;width:100%}.fancy .fancy-inner{background-image:url(../gold/gold-laurel-bg.png);background-position:top center;background-repeat:no-repeat;border:1px solid #e3e2df;margin:12px;padding:0;position:relative}.fancy:before,.fancy:after,.fancy .fancy-inner:before,.fancy .fancy-inner:after{background-image:url(../gold/endcap.png);background-repeat:no-repeat;background-size:27px 27px;content:'';display:block;height:27px;position:absolute;width:100%}.fancy:before{transform:scaleX(-1);-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-o-transform:scaleX(-1);-ms-transform:scaleX(-1);background-position:top left;margin-left:3px;margin-top:-3px}.fancy:after{transform:scaleY(-1);-webkit-transform:scaleY(-1);-moz-transform:scaleY(-1);-o-transform:scaleY(-1);-ms-transform:scaleY(-1);background-position:top left;margin-left:-3px;margin-top:-24px}.fancy .fancy-inner:before{background-position:top left;margin-left:-16px;margin-top:-16px}.fancy .fancy-inner:after{transform:scaleY(-1) scaleX(-1);-webkit-transform:scaleY(-1) scaleX(-1);-moz-transform:scaleY(-1) scaleX(-1);-o-transform:scaleY(-1) scaleX(-1);-ms-transform:scaleY(-1) scaleX(-1);background-position:top left;margin-left:16px;margin-top:-11px}.fancy .fancy-content{margin:30px auto;max-width:600px;padding:3px}.sidelines{overflow:hidden;text-align:center;font-size:1.75em;color:#444;font-weight:bold;line-height:1.6}.sidelines span{display:inline-block;position:relative}.sidelines span:before,.sidelines span:after{content:'';position:absolute;border:0 solid #ccc;height:1px;border-top-width:1px;top:50%;width:600px}.sidelines span:before{right:100%;margin-right:15px}.sidelines span:after{left:100%;margin-left:15px}.gold-page,.gilding{overflow-y:scroll}.gold-wrap{font-family:Palatino,georgia,garamond,FreeSerif,serif;color:#686868;font-size:1.5em;line-height:1.6em}.gold-wrap.inline-gold{margin:10px 0}.gold-wrap.inline-gold h1{display:none}.gold-wrap.inline-gold .fancy-inner{background-position:bottom center}.gold-wrap.inline-gold .gold-snoo{display:none}.gold-wrap.inline-gold .gold-form{margin:0 20px 5px;font-size:1em}.gold-wrap.inline-gold .gold-form .gold-button{font-size:1em}.gold-wrap.inline-gold .gold-form .container{padding:0;border:none;background-color:transparent}.gold-wrap.inline-gold .gold-form .transaction-summary{padding-bottom:0}.gold-wrap .gold-banner{background:transparent url(../gold/reddit-golds.png) center center no-repeat;background-size:contain;height:80px;margin:30px auto 20px;text-indent:-9999px;text-align:center;max-width:500px}.gold-wrap .gold-banner a{display:block;height:100%;width:100%}.gold-wrap .container{padding:10px 30px;border:1px solid #cccccb;background-color:#fffdfd}.gold-wrap .container a{color:#686868;text-decoration:underline}.gold-wrap .tab{display:none}.gold-wrap .tab.active{display:block}.gold-wrap .error{background:transparent center left no-repeat;background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-88px -774px;background-repeat:no-repeat;padding-left:20px;white-space:nowrap;line-height:1}.gold-wrap #form-options section{padding:10px 0}.gold-wrap .tab-chooser{margin-bottom:10px;width:100%;display:inline-block}.gold-wrap .tab-chooser h3{text-align:center;font-weight:normal;font-size:1em;font-style:italic;margin:0;line-height:3em}.gold-wrap a.tab-toggle{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;background-color:#938870;border-radius:0px;border-top:1px solid #5e5137;border-bottom:1px solid #5e5137;border-right:1px solid #5e5137;box-shadow:inset 0 -3px 0 rgba(0,0,0,0.27);color:#fffdfd;display:inline-block;float:left;font-family:Palatino,georgia,garamond,FreeSerif,serif;font-size:1.1em;height:66px;line-height:66px;text-align:center;text-decoration:none;vertical-align:middle;width:33%}.gold-wrap a.tab-toggle.active{background-color:#c3b598;box-shadow:inset 0px 0px 14px rgba(0,0,0,0.27)}.gold-wrap a.tab-toggle:not(.active):hover{background-color:#b8ab90;box-shadow:inset 0 -3px 0 rgba(0,0,0,0.27)}.gold-wrap a.tab-toggle:first-of-type{border-radius:3px 0 0 3px;border-left:1px solid #5e5137}.gold-wrap a.tab-toggle:last-of-type{border-right-width:1px;border-radius:0 3px 3px 0}.gold-wrap .buttons{margin-top:10px}.gold-wrap h2{color:#686868}.gold-wrap h3{font-size:1.1em;color:#686868;margin-bottom:10px}.gold-wrap h3.toggle,.gold-wrap dt.toggle{cursor:pointer;margin-bottom:0}.gold-wrap dt.toggle:before{content:"[+] "}.gold-wrap dt.toggle.toggled:before{content:"[–] "}.gold-wrap section#redeem-a-code{margin-top:-10px}.gold-wrap section#redeem-a-code .sidelines{font-size:1em;font-weight:normal;padding:0.7em;color:#686868}.gold-wrap .gold-payment .gift-message{background-color:#fff;margin:10px 30px;padding:0 10px;border:1px solid #cccccb}.gold-wrap .gold-payment .transaction-summary{padding-bottom:10px}.gold-wrap .gold-payment .transaction-summary p{padding:5px 0}.gold-wrap .gold-payment .divider-text{font-weight:bold;font-size:1.75em;color:#444}.gold-wrap .gold-payment .status{margin:5px 0 0 0}.gold-wrap span.gold-snoo{background:transparent url(../gold/gold-snoo.png) center center no-repeat;background-size:100px;position:absolute;right:160px;margin-top:-85px;width:100px;height:171px;text-indent:-9999px}.gold-wrap .login-note{text-align:center;font-size:13px;font-style:italic;line-height:1;margin-bottom:20px}.gold-wrap .login-note a{text-decoration:underline}.gold-wrap section.gold-question{margin-top:20px}.gold-wrap section.gold-question h3.toggle{font-weight:normal;font-size:0.9em}.gold-wrap section.gold-question h3.toggle:before{content:"[+] "}.gold-wrap section.gold-question h3.toggle.toggled:before{content:"[–] "}.gold-wrap section#give-as-gift{padding-top:10px}.gold-wrap input[type=checkbox],.gold-wrap input[type=radio]{margin:0 0.5em 0 0}.gold-wrap input[type=text].inline,.gold-wrap input[type=email].inline{font-size:0.9em;margin:2px 5px 5px 5px}.gold-wrap input[type=text],.gold-wrap input[type=email],.gold-wrap textarea{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;border:1px solid #cccccb;color:#686868;background-color:#fff;font-family:Palatino,georgia,garamond,FreeSerif,serif;font-style:italic;padding:5px;font-size:1em}.gold-wrap input[name="code"]{width:100%;padding:10px}.gold-wrap input:focus::-webkit-input-placeholder,.gold-wrap textarea:focus::-webkit-input-placeholder,.gold-wrap input:focus:-moz-placeholder,.gold-wrap textarea:focus:-moz-placeholder,.gold-wrap input:focus:-ms-input-placeholder,.gold-wrap textarea:focus:-ms-input-placeholder{opacity:0.3}.gold-wrap .hidden{display:none}.gold-wrap .gift-details{margin-left:1em;overflow:hidden;-webkit-transition:max-height 0.75s ease 0s;-moz-transition:max-height 0.75s ease 0s;-o-transition:max-height 0.75s ease 0s;-ms-transition:max-height 0.75s ease 0s;transition:max-height 0.75s ease 0s}.gold-wrap .gift-details.hidden{display:block;max-height:0}.gold-wrap .gift-details:not(.hidden){max-height:400px}.gold-wrap .details{font-size:0.9em;margin:10px 0 0 0;width:600px}.gold-wrap .gilding-info .details{width:538px}.gold-wrap .gilding-info .examples{margin-top:10px}.gold-wrap .gilding-info .examples img{display:block;margin:0 auto}.gold-wrap .gilding-info .examples p{text-align:center;font-size:0.7em}.gold-wrap .gold-dropdown{color:#686868;background-color:#fffdfd;font-size:16px}.gold-wrap .indent{margin-left:20px}.gold-wrap .loggedout-gold-form .loggedout-email{display:block;margin:10px 0}.gold-wrap .loggedout-gold-form .hint{font-size:12px;font-style:italic}@media screen and (max-width:1024px){.gold-wrap .buttons{text-align:center}.gold-wrap span.gold-snoo{display:block;position:static;width:100%;text-align:center;margin-top:25px}}.gold-page.creddits-purchase .gold-snoo,.gold-page.creddits-payment .gold-snoo{background-image:url(../gold/creddits-snoo.png)}.gold-page.gilding .gold-banner{background-image:url(../gold/reddit-gilding.png)}.gold-page.gilding dt{margin:0.9em 0 0.5em;font-weight:bold;padding-top:1em;border-top:1px solid #CCC;font-size:1.2em}.gold-page.gilding dt:first-of-type{padding-top:0;border-top-width:0}.gold-page.gilding dd{margin-left:0;line-height:1.8em}.gold-page.gilding .example{margin:1em 0}.gold-page.gilding .example figure{margin:0 auto;padding:0;width:339px;border:1px solid #cccccb}.gold-page.gilding .example figure.userpage-gild{height:227px;background:url('../gold/userpage-gild.png') no-repeat center center}.gold-page.gilding .example figure.comment-gild{height:160px;background:url('../gold/comment-gild.png') no-repeat top left}.gold-page.gilding .example figure.using-creddits{height:90px;background:url('../gold/using-creddits.png') no-repeat top left}.gold-page.gilding .gold-button{display:block;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;margin:0;font-size:1.3em}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.gold-page.gilding .example figure.userpage-gild{background:url('../gold/userpage-gild-x2.png') no-repeat center center;background-size:339px 227px}.gold-page.gilding .example figure.comment-gild{background:url('../gold/comment-gild-x2.png') no-repeat top left;background-size:339px 160px}.gold-page.gilding .example figure.using-creddits{background:url('../gold/using-creddits-x2.png') no-repeat top left;background-size:339px 90px}}.gold-only #header{border-bottom-color:#9a7d2e;background:#d7cc7e;background:-moz-linear-gradient(top,#d7cc7e 0%,#e2ce3e 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#d7cc7e),color-stop(100%,#e2ce3e));background:-webkit-linear-gradient(top,#d7cc7e 0%,#e2ce3e 100%);background:-o-linear-gradient(top,#d7cc7e 0%,#e2ce3e 100%);background:-ms-linear-gradient(top,#d7cc7e 0%,#e2ce3e 100%);background:linear-gradient(to bottom,#d7cc7e 0%,#e2ce3e 100%)}.gold-only #header #header-bottom-right{background-color:#faf1b3}.gold-only #header #header-bottom-right a{color:#9a7d2e}.gold-only #header #header-bottom-right .message-count{background-color:#e2ce3e}.gold-only #header #header-bottom-right #mail.havemail{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-19px -859px;background-repeat:no-repeat}.gold-only #header #header-bottom-right #modmail.havemail{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-66px -642px;background-repeat:no-repeat}.gold-only #header .tabmenu li a{background-color:#faf1b3;color:#9a7d2e}.gold-only #header .tabmenu li.selected a{background-color:#ffffff;border-color:#9a7d2e;border-bottom-color:#ffffff}.gold-only #header #sr-header-area{background-color:transparent;border:none;opacity:0.5}.gold-only #header #sr-header-area:hover{opacity:1}.gold-only .arrow.upmod{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-50px -839px;background-repeat:no-repeat}.gold-only .arrow.downmod{background-image:url(sprite-reddit.VLn6vQIEOc8.png);background-position:-29px -839px;background-repeat:no-repeat}.gold-only .link .score.dislikes{color:#a98d79}.gold-only .link .score.likes{color:#dec145}.fraud-reason{display:none}.fraud-reason:not(:empty){display:block;padding-bottom:5px;margin-bottom:5px;border-bottom:1px solid #d8bb3c}.fraud-reason:before{content:'reason(s): ';display:inline}.action-form{display:none;background-color:#f6e69f;border:thin solid #d8bb3c;max-width:300px;padding:5px;margin:5px 0;font-size:larger}.action-form input[type="radio"]{margin:2px 0.5em 0 0}.action-form input[type="text"]{margin-top:5px;width:95%}.action-form input:disabled{background:#dddddd}.action-form ol{margin-bottom:5px}.reported-stamp.has-reasons{cursor:pointer}ul.report-reasons{width:80%;background-color:#f6e69f;border:thin solid black;display:none}ul.report-reasons li.report-reason{padding:1px 10px;display:block;overflow:hidden;text-overflow:ellipsis}ul.report-reasons li.report-reason-title{padding:1px 10px;font-weight:bold}body.banned div#header{background-color:#cf6165}body.deleted div#header{background-color:#999}body.banned.deleted div#header{background-color:#999;background-image:repeating-linear-gradient(45deg,transparent,transparent 30px,#cf6165 30px,#cf6165 60px)}#compose-message select{font-size:100%}.embed-modal .modal-body,.embed-modal .modal-footer{padding:40px}.embed-modal .modal-body{padding-bottom:10px}.embed-modal .modal-body .c-checkbox{margin:10px 0}.embed-modal .modal-footer{padding-top:20px}.embed-modal .modal-footer .c-form-control{margin-top:10px}.embed-modal .modal-title{margin:0}.embed-modal #embed-preview{overflow-y:hidden}#related-srs{margin:3px;font-size:smaller}#add-related-sr{margin-left:3px;font-size:smaller}#add-related-sr #sr-autocomplete-area,#add-related-sr div.error{display:inline-block}#add-related-sr #sr-autocomplete{width:200px}#add-related-sr #sr-drop-down{width:206px}.more-actions .title{color:#888}.more-actions .title:hover{cursor:pointer}.full-context-info .md{padding:10px 5px 5px;border:1px solid #ea0027;border-radius:5px;background:#e5e3da}.full-context-info .parent{padding:0 9px}.full-context-info td{color:#4f4f4f}.full-context-info .arrow{display:inline-block;margin-right:100px}.full-context-info .arrow:after{display:inline-block;margin-left:20px;width:100px}.full-context-info .arrow.unvoted:after{content:"did not vote";margin-left:0}.full-context-info .arrow.vote-changed{background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAACcSURBVCiRfdExDgFBFIDhj2w2rkfjNrQSeoXYC7iHRhToNAoHeZohu+NRvGbyvszkH5jjjg2aiFAPGuxwK/vOiDKHGhZw6O1clRsigwkILGGMLoGTBHQYv5+QwWcGIkL/7Rn8AgNUYItHBR5oB3t/KqVxPugHuP+pmoKunGdVG1j9rJTH2So//D7YY1TFqeEJpjhi3c+awAUumL0ArW/DzGYDKjsAAAAASUVORK5CYII=') no-repeat;background-size:13px 13px}.full-context-info .arrow.vote-changed:after{content:"changed vote"}.full-context-info .arrow.upmod:after{content:"upvoted"}.full-context-info .arrow.downmod:after{content:"downvoted"}.mobile-web-redirect-bar{width:100%;display:block;position:relative;z-index:50;height:90px}.mobile-web-redirect{display:block;width:100%;line-height:90px;background-color:#4270a2;color:#FFF;font-size:45px;font-weight:bold;text-align:center;text-decoration:none;text-transform:uppercase}.mobile-web-redirect-optout{position:absolute;top:0;right:0px;line-height:90px;padding:0 20px 0px 30px;z-index:200;font-size:40px;color:#C6D4E3}body:not(.loggedin) .comment-save-button,body:not(.loggedin) .give-gold-button,body:not(.loggedin) .reply-button,body:not(.loggedin) .report-button{display:none} \ No newline at end of file diff --git a/codeview/src/main/assets/training-set/html/html.html b/codeview/src/main/assets/training-set/html/html.html new file mode 100755 index 0000000..a552c9e --- /dev/null +++ b/codeview/src/main/assets/training-set/html/html.html @@ -0,0 +1,937 @@ + + + + + + + Search · xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+
+ + + +
+
+

Search Results

+ + +
+ + +
+ +
+
+ +
+ + + +
+ + + +
+ + + +
+ + +
+
Repositories (84931)
+
(0.579 seconds)
+
+ +
+

+ TouchCode / TouchXML + (C) +

+
+ Official "clone" of TouchXML from TouchCode +
+
+ 382.8 KB | + 95 forks | + 369 stars | + last activity 6 months ago +
+
+ +
+

+ robbiehanson / KissXML + (Objective-C) +

+
+ A replacement for Cocoa's NSXML cluster of classes. Based on libxml. Works on iOS. +
+
+ 183.6 KB | + 62 forks | + 223 stars | + last activity 5 months ago +
+
+ +
+

+ ZaBlanc / RaptureXML + (Objective-C) +

+
+ A simple, sensible, block-based XML API for iOS and Mac development. +
+
+ 273.4 KB | + 33 forks | + 321 stars | + last activity 5 months ago +
+
+ +
+

+ Leonidas-from-XIV / node-xml2js + (CoffeeScript) +

+
+ Simple XML to JavaScript object converter. +
+
+ 168 KB | + 49 forks | + 312 stars | + last activity 1 day ago +
+
+ +
+

+ bcaccinolo / XML-to-NSDictionary + (Objective-C) +

+
+ an iPhone XML to NSDictionary converter +
+
+ 183.6 KB | + 62 forks | + 145 stars | + last activity almost 2 years ago +
+
+ + + + + +
+ + +
+
Users (47)
+
(0.008 seconds)
+
+ +
+
+ +

+ xml +

+
+ 0 followers + | + 0 repositories +
+
+ +
+
+ +

+ xmlwerks + - Hank Ratzesberger.org + +

+
+ 0 followers + | + 1 repository + | + located in California, USA +
+
+ +
+
+ +

+ xmly +

+
+ 0 followers + | + 8 repositories + | + Ruby +
+
+ +
+
+ +

+ xmlu + - Xiao-Ming Lu +

+
+ 0 followers + | + 2 repositories + | + Ruby +
+
+ +
+
+ +

+ xml5 +

+
+ 0 followers + | + 1 repository +
+
+ + + + + +
+
+ +
+
Source Code (14550850)
+
(1.464 seconds)
+
+
+

+ eed3si9n/scalaxb » cli / src_generated / wsdl20 / xmlprotocol.scala + (Scala) +

+ +
+
+
+/**
+usage:
+import scalaxb._
+import wsdl20._
+
+val obj = fromXML[Foo](node)
+val document = toXML
+
+
+ + +
+

+ michifunk/sample_app2 » gems / ruby / 1.8 / gems / nokogiri-1.4.4.1-x86-mingw32 / ext / nokogiri / xml_node.c + (C) +

+ +
+
#include <xml_node.h>
+
+static ID decorate, decorate_bang;
+
+#ifdef DEBUG
+static void debug_node_dealloc(xml
+
+
+ + +
+

+ eed3si9n/scalaxb » cli / src_generated / scalaxb / scalaxb.scala + (Scala) +

+ +
+
package scalaxb
+
+import scala.xml.{Node, NodeSeq, NamespaceBinding, Elem, Unprefixed
+
+
+ + +
+

+ sshwsfc/apf » core / lib / xmldb.js + (JavaScript) +

+ +
+
-1301 USA, or see the FSF site: http://www.fsf.org.
+ *
+ */
+
+//#ifdef __WITH_XMLDATABASE
+
+/**
+ * The xml
+
+
+ + +
+

+ sshwsfc/apf » databinding / lib / xmldb.js + (JavaScript) +

+ +
+
_XMLDATABASE
+    if (apf.xmldb)
+        apf.xmldb.unbind(apf.window);
+    //#endif
+});
+
+/**
+ * The xml database object
+
+
+ + + + + + +
+
+ +
+
+
+ +
+ + + + + + + + +
+

Markdown Cheat Sheet

+ +
+ +
+
+

Format Text

+

Headers

+
+# This is an <h1> tag
+## This is an <h2> tag
+###### This is an <h6> tag
+

Text styles

+
+*This text will be italic*
+_This will also be italic_
+**This text will be bold**
+__This will also be bold__
+
+*You **can** combine them*
+
+
+
+

Lists

+

Unordered

+
+* Item 1
+* Item 2
+  * Item 2a
+  * Item 2b
+

Ordered

+
+1. Item 1
+2. Item 2
+3. Item 3
+   * Item 3a
+   * Item 3b
+
+
+

Miscellaneous

+

Images

+
+![GitHub Logo](/images/logo.png)
+Format: ![Alt Text](url)
+
+

Links

+
+http://github.com - automatic!
+[GitHub](http://github.com)
+

Blockquotes

+
+As Kanye West said:
+
+> We're living the future so
+> the present is our past.
+
+
+
+
+ +

Code Examples in Markdown

+
+

Syntax highlighting with GFM

+
+```javascript
+function fancyAlert(arg) {
+  if(arg) {
+    $.facebox({div:'#foo'})
+  }
+}
+```
+
+
+

Or, indent your code 4 spaces

+
+Here is a Python code example
+without syntax highlighting:
+
+    def foo:
+      if not bar:
+        return true
+
+
+

Inline code for comments

+
+I think you should use an
+`<addr>` element here instead.
+
+
+ +
+ + + +
+ + Something went wrong with that request. Please try again. + +
+ +
+

Looking for the GitHub logo?

+ +
+ + + + + + + diff --git a/codeview/src/main/assets/training-set/html/index.html b/codeview/src/main/assets/training-set/html/index.html new file mode 100755 index 0000000..10c037d --- /dev/null +++ b/codeview/src/main/assets/training-set/html/index.html @@ -0,0 +1,402 @@ + + + + + + + + + Material icons guide - Google design + + +
+
+
+ Material icons guide +
+
+
+ +
+
+ + +

An overview of material icons—where to get them and how to integrate them with your projects.

+ + + +

What are material icons

+

Material design system icons are simple, modern, friendly, and sometimes +quirky. Each icon is created using our design guidelines to depict in simple +and minimal forms the universal concepts used commonly throughout a UI. +Ensuring readability and clarity at both large and small sizes, these icons +have been optimized for beautiful display on all common platforms and display +resolutions.

+

See the full set of material design icons at the material icons library.

+
alt text
+ +

Getting icons

+

The icons are available in several formats and are suitable for different types +of projects and platforms, for developers in their apps, and for designers in +their mockups or prototypes.

+

Licensing

+

We have made these icons available for you to incorporate them into your +products under the Creative Common Attribution 4.0 International License (CC-BY 4.0). Feel free to remix and re-share these icons and documentation in your +products. We'd love attribution in your app's about screen, but it's not required. The only thing we ask is that you not re-sell +the icons themselves.

+

Browsing and downloading individual icons

+

The complete set of material icons are available on the material icon library. The icons are available for download in SVG or PNGs, formats that are +suitable for web, Android, and iOS projects or for inclusion in any designer +tools.

+

Downloading everything

+

Grab the latest stable zip archive (~57MB) of all icons or the bleeding-edge version from master.

+

Git Repository

+

The material icons are available from the git repository which contains the complete set of icons including all the various formats we +are making available.

+
$ git clone http://github.com/google/material-design-icons/
+

Installing icons from bower

+

Install the icons using the Bower package manager.

+
$ bower install material-design-icons
+

Installing icons from npm

+

Install the icons using npm package manager.

+
$ npm install material-design-icons
+


+

Icon font for the web

+

The material icon font is the easiest way to incorporate material icons with +web projects. We have packaged all the material icons into a single font that +takes advantage of the typographic rendering capabilities of modern browsers so +that web developers can easily incorporate these icons with only a few lines of +code.

+

Using the font is not only the most convenient method, but it is efficient and +looks great:

+
    +
  • 750+ icons all from a single download.
  • +
  • Served from Google Web Font servers or can be self hosted.
  • +
  • Supported by all modern web browsers.
  • +
  • Colored, sized and positioned entirely with CSS.
  • +
  • Vector-based: Looks great at any scale, retina displays, low-dpi display +screens.
  • +
+

The icon font contains 750+ icons and weighs in at only 40KB (woff2 format). In +comparison, a ZIP file of these in SVGs will be more than 50% larger.

+

Setup Method 1. Using via Google Web Fonts

+

The easiest way to set up icon fonts for use in any web page is through Google Web Fonts. All you need to do is include a single line of HTML:

+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
+      rel="stylesheet">
+

Similar to other Google Web Fonts, the correct CSS will be served to activate +the 'Material Icons' font specific to the browser. An additional CSS class will +be declared called .material-icons. Any element that uses this class will have the correct CSS to render these +icons from the web font.

+

Setup Method 2. Self hosting

+

For those looking to self host the web font, some additional setup is necessary. +Host the icon font in a location, for example https://example.com/material-icons.woff and add the +following CSS rule:

+
@font-face {
+  font-family: 'Material Icons';
+  font-style: normal;
+  font-weight: 400;
+  src: url(https://example.com/MaterialIcons-Regular.eot); /* For IE6-8 */
+  src: local('Material Icons'),
+       local('MaterialIcons-Regular'),
+       url(https://example.com/MaterialIcons-Regular.woff2) format('woff2'),
+       url(https://example.com/MaterialIcons-Regular.woff) format('woff'),
+       url(https://example.com/MaterialIcons-Regular.ttf) format('truetype');
+}
+

In addition, the CSS rules for rendering the icon will need to be declared. +These rules are normally served as part of the Google Web Font stylesheet, but +will need to be included manually in your projects when self-hosting the font:

+
.material-icons {
+  font-family: 'Material Icons';
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;  /* Preferred icon size */
+  display: inline-block;
+  width: 1em;
+  height: 1em;
+  line-height: 1;
+  text-transform: none;
+  letter-spacing: normal;
+
+  /* Support for all WebKit browsers. */
+  -webkit-font-smoothing: antialiased;
+  /* Support for Safari and Chrome. */
+  text-rendering: optimizeLegibility;
+
+  /* Support for Firefox. */
+  -moz-osx-font-smoothing: grayscale;
+
+  /* Support for IE. */
+  font-feature-settings: 'liga';
+}
+

Using the icons in HTML

+

It’s easy to incorporate icons into your web page. Here’s a small example:

+
+ +
face
+ +
<i +class="material-icons">face</i>
+ +

+

This example uses a typographic feature called ligatures, which allows rendering of an icon glyph simply by using its textual name. The replacement is done automatically by the web browser and provides more readable code than the equivalent numeric character reference.

+

This feature is supported in most modern browsers on both desktop and mobile +devices.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BrowserVersion supporting ligatures
Google Chrome11
Mozilla Firefox3.5
Apple Safari5
Microsoft IE10
Opera15
Apple MobileSafariiOS 4.2
Android Browser3.0
+ +

For browsers that do not support ligatures, fall back to specifying the icons +using numeric character references unlike the example below:

+
+ +
+ +
<i +class="material-icons">&#xE87C;</i>
+ +

+

Find both the icon names and codepoints on the material icons library by selecting any icon and opening the icon font panel. A codepoints index is also available on our git repository which shows the complete set of names +and character codes.

+

Styling icons in material design

+

These icons were designed to follow the material design guidelines and they look best when using the recommended icon sizes and colors. The styles below make it easy to apply our recommended sizes, colors, and activity states.

+
// Rules for sizing the icon.
+.material-icons.md-18 { font-size: 18px; }
+.material-icons.md-24 { font-size: 24px; }
+.material-icons.md-36 { font-size: 36px; }
+.material-icons.md-48 { font-size: 48px; }
+
+// Rules for using icons as black on a light background.
+.material-icons.md-dark { color: rgba(0, 0, 0, 0.54); }
+.material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); }
+
+// Rules for using icons as white on a dark background.
+.material-icons.md-light { color: rgba(255, 255, 255, 1); }
+.material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); }
+

Sizing

+

Although the icons in the font can be scaled to any size, in accordance with material design icons guidelines, we recommend them to be shown in either 18, 24, 36 or 48px. The default being +24px.

+

CSS rules for the standard material design sizing guidelines:

+
.material-icons.md-18 { font-size: 18px; }
+.material-icons.md-24 { font-size: 24px; }
+.material-icons.md-36 { font-size: 36px; }
+.material-icons.md-48 { font-size: 48px; }
+

Material icons look best at 24px, but if an icon needs to be displayed in an +alternative size, using the above CSS rules can help:

+
+ +
face
18px
+ +
<i class="material-icons +md-18">face</i>
+ +

+
+ +
face
24px
+ +
<i class="material-icons +md-24">face</i>
+ +

+
+ +
face
36px
+ +
<i class="material-icons +md-36">face</i>
+ +

+
+ +
face
48px
+ +
<i class="material-icons +md-48">face</i>
+ +

+

Coloring

+

Using the icon font allows for easy styling of an icon in any color. +In accordance with material design icon guidelines, for active icons we recommend using either black at 54% opacity or white at +100% opacity when displaying these on light or dark backgrounds, respectively. +If an icon is disabled or inactive, using black at 26% or white at 30% for +light and dark backgrounds, respectively.

+

Here are some examples, using the material CSS styles described above:

+
.material-icons.md-dark { color: rgba(0, 0, 0, 0.54); }
+.material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); }
+
+.material-icons.md-light { color: rgba(255, 255, 255, 1); }
+.material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); }
+

Example for drawing an icon on a light background with a dark foreground color:

+
+ +
face
Normal
+ +
<i class="material-icons +md-dark">face</i>
+ +

+
+ +
face
Disabled
+ +
<i class="material-icons +md-dark md-inactive">face</i>
+ +

+

Example for drawing an icon on a dark background with a light foreground color:

+
+ +
face
Normal
+ +
<i class="material-icons +md-light">face</i>
+ +

+
+ +
face
Disabled
+ +
<i class="material-icons +md-light md-inactive">face</i>
+ +

+

To set a custom icon color, define a CSS rule specifying the desired color for +the font:

+
.material-icons.orange600 { color: #FB8C00; }
+

and then use the class when referring to the icon:

+
+ +
face
Normal
+ +
<i class="material-icons +orange600">face</i>
+ +

+


+

Icon images for the web

+

Material icons are also available as regular images, both in PNG and SVG +formats.

+

SVG

+

The material icons are provided as SVGs that are suitable for web projects. +Individual icons are downloadable from the material icons library. The SVGs are also available from the material design icons git repository under the path:

+
material-design-icons/*/svg/production/
+

For example, icons for maps are in maps/svg/production:

+
material-design-icons/maps/svg/production/
+

If multiple icons are in use on a web site, creating spritesheets out of the +images is recommended. For more information, refer to the documentation in the sprites directory of the git repository.

+

PNG

+

PNG is the most traditional way to display icons on the web. Our downloads from +the material icons library provide both single and double densities for each icon. They are referred to +as 1x_web and 2x_web respectively in the download. Icons are also available in the git repository +under:

+
material-design-icons/*/1x_web/
+material-design-icons/*/2x_web/
+

If multiple icons are in use on a web site, creating spritesheets out of the +images is recommended. For more information, refer to recommendations in the sprites directory in the git repository.

+


+

Icons for Android

+

PNGs suitable for Android are available from the material icons library. These come in all the supported screen densities so they should look good on +any device.

+

The icons are also available in the material design icons git repository in the same combination of colors and sizes named as follows:

+
*/drawable-{{density}}/ic_{{name}}_{{color}}_{{size}}dp.png
+

A density-independent VectorDrawable is provided which is supported from +Android Lollipop and later:

+
*/drawable-anydpi-v21/ic_{{name}}_black_24dp.xml
+

The Vector Drawable is currently only available as a black 24dp icon. This is +for compatibility with our most standard icon size. To render the icon in a +different color, use drawable tinting available on Android Lollipop.

+

When using the Vector Drawable, it may not be necessary to include the xxxhdpi +density PNG since it is unlikely a device supporting that screen density does +not support Vector Drawables.

+


+

Icons for iOS

+

Material icons also work well within iOS apps. In both the material icons library and git repository, these icons are packaged up in Xcode imagesets which will work easily with Xcode Asset Catalogs (xcassets). These imagesets can be added to any Xcode Asset Catalogs by +dragging them into Xcode on to the asset catalog or by copying the folder into +the xcasset folder.

+
alt text
+ +

The imageset contains the single, double and triple density images (1x, 2x, 3x) +so they work on all known iOS screen densities. Both black and white icons are +provided, but we recommend using UIImage's imageWithRenderingMode with UIImageRenderingModeAlwaysTemplate which will allow the image to be used as an alpha mask that can be tinted to +any possible color.

+

Objective-C example:

+
UIButton *button = [[UIButton alloc] init];
+UIImage *closeImage =
+    [[UIImage imageNamed:@"ic_close"]
+       imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+button.tintColor = [UIColor colorWithWhite:0 alpha:0.54f];
+[button setImage:closeImage forState:UIControlStateNormal];
+

Swift Example:

+
let button = UIButton()
+let closeImage = UIImage(named:"ic_close")?.imageWithRenderingMode(
+    UIImageRenderingMode.AlwaysTemplate)
+button.tintColor = UIColor(white:0, alpha:0.54)
+button.setImage(closeImage, forState:UIControlState.Normal)
+
+ +
+
+ + + + + diff --git a/codeview/src/main/assets/training-set/html/options.html b/codeview/src/main/assets/training-set/html/options.html new file mode 100755 index 0000000..92a646e --- /dev/null +++ b/codeview/src/main/assets/training-set/html/options.html @@ -0,0 +1,276 @@ + + + + + Chosen: A jQuery Plugin by Harvest to Tame Unwieldy Select Boxes + + + + + + +
+
+
+

Chosen (v1.4.2)

+
+

Chosen has a number of options and attributes that allow you to have full control of your select boxes.

+ +

Options

+

The following options are available to pass into Chosen on instantiation.

+ +

Example:

+
+  $(".my_select_box").chosen({
+    disable_search_threshold: 10,
+    no_results_text: "Oops, nothing found!",
+    width: "95%"
+  });
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionDefaultDescription
allow_single_deselectfalseWhen set to true on a single select, Chosen adds a UI element which selects the first element (if it is blank).
disable_searchfalseWhen set to true, Chosen will not display the search field (single selects only).
disable_search_threshold0Hide the search input on single selects if there are fewer than (n) options.
enable_split_word_searchtrueBy default, searching will match on any word within an option tag. Set this option to false if you want to only match on the entire text of an option tag.
inherit_select_classesfalseWhen set to true, Chosen will grab any classes on the original select field and add them to Chosen’s container div.
max_selected_optionsInfinityLimits how many options the user can select. When the limit is reached, the chosen:maxselected event is triggered.
no_results_text"No results match"The text to be displayed when no matching results are found. The current search is shown at the end of the text (e.g., + No results match "Bad Search").
placeholder_text_multiple"Select Some Options"The text to be displayed as a placeholder when no options are selected for a multiple select.
placeholder_text_single"Select an Option"The text to be displayed as a placeholder when no options are selected for a single select.
search_containsfalseBy default, Chosen’s search matches starting at the beginning of a word. Setting this option to true allows matches starting from anywhere within a word. This is especially useful for options that include a lot of special characters or phrases in ()s and []s.
single_backstroke_deletetrueBy default, pressing delete/backspace on multiple selects will remove a selected choice. When false, pressing delete/backspace will highlight the last choice, and a second press deselects it.
widthOriginal select width.The width of the Chosen select box. By default, Chosen attempts to match the width of the select box you are replacing. If your select is hidden when Chosen is instantiated, you must specify a width or the select will show up with a width of 0.
display_disabled_optionstrueBy default, Chosen includes disabled options in search results with a special styling. Setting this option to false will hide disabled results and exclude them from searches.
display_selected_optionstrue +

By default, Chosen includes selected options in search results with a special styling. Setting this option to false will hide selected results and exclude them from searches.

+

Note: this is for multiple selects only. In single selects, the selected result will always be displayed.

+
include_group_label_in_selectedfalse +

By default, Chosen only shows the text of a selected option. Setting this option to true will show the text and group (if any) of the selected option.

+
+ +

Attributes

+

Certain attributes placed on the select tag or its options can be used to configure Chosen.

+ +

Example:

+ +
+  <select class="my_select_box" data-placeholder="Select Your Options">
+    <option value="1">Option 1</option>
+    <option value="2" selected>Option 2</option>
+    <option value="3" disabled>Option 3</option>
+  </select>
+
+ + + + + + + + + + + + + + + + + +
AttributeDescription
data-placeholder +

The text to be displayed as a placeholder when no options are selected for a select. Defaults to "Select an Option" for single selects or "Select Some Options" for multiple selects.

+

Note:This attribute overrides anything set in the placeholder_text_multiple or placeholder_text_single options.

+
multipleThe attribute multiple on your select box dictates whether Chosen will render a multiple or single select.
selected, disabledChosen automatically highlights selected options and disables disabled options.
+ +

Classes

+

Classes placed on the select tag can be used to configure Chosen.

+ +

Example:

+ +
+  <select class="my_select_box chosen-rtl">
+    <option value="1">Option 1</option>
+    <option value="2">Option 2</option>
+    <option value="3">Option 3</option>
+  </select>
+
+ + + + + + + + + + +
ClassnameDescription
chosen-rtl +

Chosen supports right-to-left text in select boxes. Add the class chosen-rtl to your select tag to support right-to-left text options.

+

Note: The chosen-rtl class will pass through to the Chosen select even when the inherit_select_classes option is set to false.

+
+ +

Triggered Events

+

Chosen triggers a number of standard and custom events on the original select field.

+ +

Example:

+ +
+  $('.my_select_box').on('change', function(evt, params) {
+    do_something(evt, params);
+  });
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
EventDescription
change +

Chosen triggers the standard DOM event whenever a selection is made (it also sends a selected or deselected parameter that tells you which option was changed).

+

Note: in order to use change in the Prototype version, you have to include the Event.simulate class. The selected and deselected parameters are not available for Prototype.

+
chosen:readyTriggered after Chosen has been fully instantiated.
chosen:maxselectedTriggered if max_selected_options is set and that total is broken.
chosen:showing_dropdownTriggered when Chosen’s dropdown is opened.
chosen:hiding_dropdownTriggered when Chosen’s dropdown is closed.
chosen:no_resultsTriggered when a search returns no matching results.
+ +

+ Note: all custom Chosen events (those that being with chosen:) also include the chosen object as a parameter. +

+ +

Triggerable Events

+

You can trigger several events on the original select field to invoke a behavior in Chosen.

+ +

Example:

+ +
+  // tell Chosen that a select has changed
+  $('.my_select_box').trigger('chosen:updated');
+
+ + + + + + + + + + + + + + + + + + + + + +
EventDescription
chosen:updatedThis event should be triggered whenever Chosen’s underlying select element changes (such as a change in selected options).
chosen:activateThis is the equivalant of focusing a standard HTML select field. When activated, Chosen will capure keypress events as if you had clicked the field directly.
chosen:openThis event activates Chosen and also displays the search results.
chosen:closeThis event deactivates Chosen and hides the search results.
+ + + +
+
+ + + + diff --git a/codeview/src/main/assets/training-set/html/test.html b/codeview/src/main/assets/training-set/html/test.html new file mode 100755 index 0000000..fcd76b2 --- /dev/null +++ b/codeview/src/main/assets/training-set/html/test.html @@ -0,0 +1,444 @@ + + + + +Normalize CSS: UI tests + + + + +
+ . + +

Normalize.css: UI tests

+ +

html

+

should have sans-serif font family (opinionated)

+
+ abcdefghijklmnopqrstuvwxyz +
+ +

body

+

should have no margin (opinionated)

+
+ (there should be no red background visible on this page) +
+ +

+ article, aside, details, + figure, figcaption, footer, + header, hgroup, main, + menu, nav, section, + summary +

+

should render as block

+
+
article
+ +
+ summary + details +
+
+ figure +
figcaption
+
+
footer
+
header
+
hgroup
+
main
+
  • menu
  • + +
    section
    +
    + +

    audio, canvas, progress, video

    +

    should render as inline-block and baseline-aligned

    +
    + + canvas + progress + +
    + +

    audio:not([controls]), template, [hidden]

    +

    should not display

    +
    + + + +
    + +

    a

    +

    should have a transparent background when active

    + +

    should not have a focus outline when both focused and hovered (opinionated)

    + + +

    abbr[title]

    +

    should have a dotted bottom border

    +
    + abbr +
    + +

    b, strong

    +

    should have bold font-weight

    +
    + b + strong +
    + +

    dfn

    +

    should have italic font-style

    +
    + dfn +
    + +

    h1

    +

    should not change size within an article

    +
    +

    Heading (control)

    +
    +

    Heading (in article)

    +
    +
    +

    should not change size within a section

    +
    +

    Heading (control)

    +
    +

    Heading (in section)

    +
    +
    + +

    mark

    +

    should have a yellow background

    +
    + mark +
    + +

    small

    +

    should render equally small in all browsers

    +
    + control. small. +
    + +

    sub and sup

    +

    should not affect a line's visual line-height

    +
    +

    control.

    +

    control. sub.

    +

    control. sup.

    +
    + +

    img

    +

    should not have a border when wrapped in an anchor

    + + +

    svg

    +

    should not overflow

    +
    + + + +
    + +

    figure

    +

    should have margins

    +
    +
    + +
    +
    + +

    hr

    +

    should have a content-box box model

    +
    +
    +
    + +

    pre

    +

    should trigger a scrollbar when too wide for its container

    +
    +
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et me.
    +
    + +

    code, kbd, pre, samp

    +

    should render em-unit preformatted text at the same absolute size as normal text

    +
    + span: abcdefghijklmnopqrstuvwxyz.
    + code: abcdefghijklmnopqrstuvwxyz.
    + kbd: abcdefghijklmnopqrstuvwxyz.
    + samp: abcdefghijklmnopqrstuvwxyz. +
    pre: abcdefghijklmnopqrstuvwxyz.
    +
    + +

    button, input, optgroup, select, textarea

    +

    should inherit color from ancestor

    +
    +
    +
    +
    + +
    +

    should inherit font from ancestor

    +
    +
    +
    +
    + +
    +

    should not have margins

    +
    + + + + + +
    + +

    button

    +

    should have visible overflow

    +
    + + +
    + +

    button, select

    +

    should not inherit text-transform

    +
    + + +
    + +

    button and button-style input

    +

    should have pointer cursor style

    +
    +

    +

    +

    +

    +

    +
    +

    should be styleable

    +
    + +

    +

    +

    +

    +

    +
    + +

    disabled button and input

    +

    should have default cursor style

    +
    +

    +

    +

    +

    +

    +
    + +

    button, input

    +

    should not have extra inner padding in Firefox

    +
    + +

    +

    +

    +

    +

    +
    + +

    input

    +

    should not inherit line-height

    +
    + +
    + +

    input[type="checkbox"], input[type="radio"]

    +

    should have a border-box box model

    +
    + + + +
    +

    should not have padding

    +
    + + +
    + +

    input[type="number"]

    +

    should display a default cursor for the decrement button's click target in Chrome

    +
    + +
    + +

    input[type="search"]

    +

    should be styleable

    +
    + +
    +

    should have a content-box box model

    +
    +
    + +
    +
    +

    should not have a cancel button in Safari or Chrome

    +
    + +
    + +

    fieldset

    +

    should have consistent border, padding, and margin

    +
    +
    +
    +
    +
    + +

    legend

    +

    should inherit color

    +
    +
    + legend +
    +
    +

    should not have padding

    +
    +
    + legend +
    +
    + +

    textarea

    +

    should not have a scrollbar unless overflowing

    +
    + +
    + +

    table

    +

    should not have spaces between cells

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Jimi Hendrix - albums
    AlbumYearPrice
    AlbumYearPrice
    Are You Experienced1967$10.00
    Axis: Bold as Love1967$12.00
    Electric Ladyland1968$10.00
    Band of Gypsys1970$12.00
    +
    + +
    diff --git a/codeview/src/main/assets/training-set/javascript/javascript.js b/codeview/src/main/assets/training-set/javascript/javascript.js new file mode 100755 index 0000000..5cd1117 --- /dev/null +++ b/codeview/src/main/assets/training-set/javascript/javascript.js @@ -0,0 +1,830 @@ + +/** + * Module dependencies. + */ + +var Emitter = require('emitter'); + +/** + * Root reference for iframes. + */ + +var root = 'undefined' == typeof window + ? this + : window; + +/** + * Noop. + */ + +function noop(){}; + +/** + * Determine XHR. + */ + +function getXHR() { + if (root.XMLHttpRequest + && ('file:' != root.location.protocol || !root.ActiveXObject)) { + return new XMLHttpRequest; + } else { + try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} + try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} + } + return false; +} + +/** + * Removes leading and trailing whitespace, added to support IE. + * + * @param {String} s + * @return {String} + * @api private + */ + +var trim = ''.trim + ? function(s) { return s.trim(); } + : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; + +/** + * Check if `obj` is an object. + * + * @param {Object} obj + * @return {Boolean} + * @api private + */ + +function isObject(obj) { + return obj === Object(obj); +} + +/** + * Serialize the given `obj`. + * + * @param {Object} obj + * @return {String} + * @api private + */ + +function serialize(obj) { + if (!isObject(obj)) return obj; + var pairs = []; + for (var key in obj) { + pairs.push(encodeURIComponent(key) + + '=' + encodeURIComponent(obj[key])); + } + return pairs.join('&'); +} + +/** + * Expose serialization method. + */ + + request.serializeObject = serialize; + + /** + * Parse the given x-www-form-urlencoded `str`. + * + * @param {String} str + * @return {Object} + * @api private + */ + +function parseString(str) { + var obj = {}; + var pairs = str.split('&'); + var parts; + var pair; + + for (var i = 0, len = pairs.length; i < len; ++i) { + pair = pairs[i]; + parts = pair.split('='); + obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); + } + + return obj; +} + +/** + * Expose parser. + */ + +request.parseString = parseString; + +/** + * Default MIME type map. + * + * superagent.types.xml = 'application/xml'; + * + */ + +request.types = { + html: 'text/html', + json: 'application/json', + urlencoded: 'application/x-www-form-urlencoded', + 'form': 'application/x-www-form-urlencoded', + 'form-data': 'application/x-www-form-urlencoded' +}; + +/** + * Default serialization map. + * + * superagent.serialize['application/xml'] = function(obj){ + * return 'generated xml here'; + * }; + * + */ + + request.serialize = { + 'application/x-www-form-urlencoded': serialize, + 'application/json': JSON.stringify + }; + + /** + * Default parsers. + * + * superagent.parse['application/xml'] = function(str){ + * return { object parsed from str }; + * }; + * + */ + +request.parse = { + 'application/x-www-form-urlencoded': parseString, + 'application/json': JSON.parse +}; + +/** + * Parse the given header `str` into + * an object containing the mapped fields. + * + * @param {String} str + * @return {Object} + * @api private + */ + +function parseHeader(str) { + var lines = str.split(/\r?\n/); + var fields = {}; + var index; + var line; + var field; + var val; + + lines.pop(); // trailing CRLF + + for (var i = 0, len = lines.length; i < len; ++i) { + line = lines[i]; + index = line.indexOf(':'); + field = line.slice(0, index).toLowerCase(); + val = trim(line.slice(index + 1)); + fields[field] = val; + } + + return fields; +} + +/** + * Return the mime type for the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +function type(str){ + return str.split(/ *; */).shift(); +}; + +/** + * Return header field parameters. + * + * @param {String} str + * @return {Object} + * @api private + */ + +function params(str){ + return str.split(/ *; */).reduce(function(obj, str){ + var parts = str.split(/ *= */) + , key = parts.shift() + , val = parts.shift(); + + if (key && val) obj[key] = val; + return obj; + }, {}); +}; + +/** + * Initialize a new `Response` with the given `xhr`. + * + * - set flags (.ok, .error, etc) + * - parse header + * + * Examples: + * + * Aliasing `superagent` as `request` is nice: + * + * request = superagent; + * + * We can use the promise-like API, or pass callbacks: + * + * request.get('/').end(function(res){}); + * request.get('/', function(res){}); + * + * Sending data can be chained: + * + * request + * .post('/user') + * .send({ name: 'tj' }) + * .end(function(res){}); + * + * Or passed to `.send()`: + * + * request + * .post('/user') + * .send({ name: 'tj' }, function(res){}); + * + * Or passed to `.post()`: + * + * request + * .post('/user', { name: 'tj' }) + * .end(function(res){}); + * + * Or further reduced to a single call for simple cases: + * + * request + * .post('/user', { name: 'tj' }, function(res){}); + * + * @param {XMLHTTPRequest} xhr + * @param {Object} options + * @api private + */ + +function Response(xhr, options) { + options = options || {}; + this.xhr = xhr; + this.text = xhr.responseText; + this.setStatusProperties(xhr.status); + this.header = parseHeader(xhr.getAllResponseHeaders()); + this.setHeaderProperties(this.header); + this.body = this.parseBody(this.text); +} + +/** + * Set header related properties: + * + * - `.type` the content type without params + * + * A response of "Content-Type: text/plain; charset=utf-8" + * will provide you with a `.type` of "text/plain". + * + * @param {Object} header + * @api private + */ + +Response.prototype.setHeaderProperties = function(header){ + // content-type + var ct = this.header['content-type'] || ''; + this.type = type(ct); + + // params + var obj = params(ct); + for (var key in obj) this[key] = obj[key]; +}; + +/** + * Parse the given body `str`. + * + * Used for auto-parsing of bodies. Parsers + * are defined on the `superagent.parse` object. + * + * @param {String} str + * @return {Mixed} + * @api private + */ + +Response.prototype.parseBody = function(str){ + var parse = request.parse[this.type]; + return parse + ? parse(str) + : null; +}; + +/** + * Set flags such as `.ok` based on `status`. + * + * For example a 2xx response will give you a `.ok` of __true__ + * whereas 5xx will be __false__ and `.error` will be __true__. The + * `.clientError` and `.serverError` are also available to be more + * specific, and `.statusType` is the class of error ranging from 1..5 + * sometimes useful for mapping respond colors etc. + * + * "sugar" properties are also defined for common cases. Currently providing: + * + * - .noContent + * - .badRequest + * - .unauthorized + * - .notAcceptable + * - .notFound + * + * @param {Number} status + * @api private + */ + +Response.prototype.setStatusProperties = function(status){ + var type = status / 100 | 0; + + // status / class + this.status = status; + this.statusType = type; + + // basics + this.info = 1 == type; + this.ok = 2 == type; + this.clientError = 4 == type; + this.serverError = 5 == type; + this.error = 4 == type || 5 == type; + + // sugar + this.accepted = 202 == status; + this.noContent = 204 == status || 1223 == status; + this.badRequest = 400 == status; + this.unauthorized = 401 == status; + this.notAcceptable = 406 == status; + this.notFound = 404 == status; + this.forbidden = 403 == status; +}; + +/** + * Return an `Error` representative of this response. + * + * @return {Error} + * @api public + */ + +Response.prototype.toError = function(){ + var msg = 'got ' + this.status + ' response'; + var err = new Error(msg); + err.status = this.status; + return err; +}; + +/** + * Expose `Response`. + */ + +request.Response = Response; + +/** + * Initialize a new `Request` with the given `method` and `url`. + * + * @param {String} method + * @param {String} url + * @api public + */ + +function Request(method, url) { + var self = this; + Emitter.call(this); + this._query = this._query || []; + this.method = method; + this.url = url; + this.header = {}; + this.set('X-Requested-With', 'XMLHttpRequest'); + this.on('end', function(){ + self.callback(null, new Response(self.xhr)); + }); +} + +/** + * Inherit from `Emitter.prototype`. + */ + +Request.prototype = new Emitter; +Request.prototype.constructor = Request; + +/** + * Set timeout to `ms`. + * + * @param {Number} ms + * @return {Request} for chaining + * @api public + */ + +Request.prototype.timeout = function(ms){ + this._timeout = ms; + return this; +}; + +/** + * Clear previous timeout. + * + * @return {Request} for chaining + * @api public + */ + +Request.prototype.clearTimeout = function(){ + this._timeout = 0; + clearTimeout(this._timer); + return this; +}; + +/** + * Abort the request, and clear potential timeout. + * + * @return {Request} + * @api public + */ + +Request.prototype.abort = function(){ + if (this.aborted) return; + this.xhr.abort(); + this.emit('abort'); + this.aborted = true; + this.clearTimeout(); + return this; +}; + +/** + * Set header `field` to `val`, or multiple fields with one object. + * + * Examples: + * + * req.get('/') + * .set('Accept', 'application/json') + * .set('X-API-Key', 'foobar') + * .end(callback); + * + * req.get('/') + * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) + * .end(callback); + * + * @param {String|Object} field + * @param {String} val + * @return {Request} for chaining + * @api public + */ + +Request.prototype.set = function(field, val){ + if (isObject(field)) { + for (var key in field) { + this.set(key, field[key]); + } + return this; + } + this.header[field.toLowerCase()] = val; + return this; +}; + +/** + * Set Content-Type to `type`, mapping values from `request.types`. + * + * Examples: + * + * superagent.types.xml = 'application/xml'; + * + * request.post('/') + * .type('xml') + * .send(xmlstring) + * .end(callback); + * + * request.post('/') + * .type('application/xml') + * .send(xmlstring) + * .end(callback); + * + * @param {String} type + * @return {Request} for chaining + * @api public + */ + +Request.prototype.type = function(type){ + this.set('Content-Type', request.types[type] || type); + return this; +}; + +/** +* Add query-string `val`. +* +* Examples: +* +* request.get('/shoes') +* .query('size=10') +* .query({ color: 'blue' }) +* +* @param {Object|String} val +* @return {Request} for chaining +* @api public +*/ + +Request.prototype.query = function(val){ + if ('string' != typeof val) val = serialize(val); + this._query.push(val); + return this; +}; + +/** + * Send `data`, defaulting the `.type()` to "json" when + * an object is given. + * + * Examples: + * + * // querystring + * request.get('/search') + * .end(callback) + * + * // multiple data "writes" + * request.get('/search') + * .send({ search: 'query' }) + * .send({ range: '1..5' }) + * .send({ order: 'desc' }) + * .end(callback) + * + * // manual json + * request.post('/user') + * .type('json') + * .send('{"name":"tj"}) + * .end(callback) + * + * // auto json + * request.post('/user') + * .send({ name: 'tj' }) + * .end(callback) + * + * // manual x-www-form-urlencoded + * request.post('/user') + * .type('form') + * .send('name=tj') + * .end(callback) + * + * // auto x-www-form-urlencoded + * request.post('/user') + * .type('form') + * .send({ name: 'tj' }) + * .end(callback) + * + * // defaults to x-www-form-urlencoded + * request.post('/user') + * .send('name=tobi') + * .send('species=ferret') + * .end(callback) + * + * @param {String|Object} data + * @return {Request} for chaining + * @api public + */ + +Request.prototype.send = function(data){ + var obj = isObject(data); + var type = this.header['content-type']; + + // merge + if (obj && isObject(this._data)) { + for (var key in data) { + this._data[key] = data[key]; + } + } else if ('string' == typeof data) { + if (!type) this.type('form'); + type = this.header['content-type']; + if ('application/x-www-form-urlencoded' == type) { + this._data = this._data + ? this._data + '&' + data + : data; + } else { + this._data = (this._data || '') + data; + } + } else { + this._data = data; + } + + if (!obj) return this; + if (!type) this.type('json'); + return this; +}; + +/** + * Invoke the callback with `err` and `res` + * and handle arity check. + * + * @param {Error} err + * @param {Response} res + * @api private + */ + +Request.prototype.callback = function(err, res){ + var fn = this._callback; + if (2 == fn.length) return fn(err, res); + if (err) return this.emit('error', err); + fn(res); +}; + +/** + * Initiate request, invoking callback `fn(res)` + * with an instanceof `Response`. + * + * @param {Function} fn + * @return {Request} for chaining + * @api public + */ + +Request.prototype.end = function(fn){ + var self = this; + var xhr = this.xhr = getXHR(); + var query = this._query.join('&'); + var timeout = this._timeout; + var data = this._data; + + // store callback + this._callback = fn || noop; + + // state change + xhr.onreadystatechange = function(){ + if (4 == xhr.readyState && 0 != xhr.status) self.emit('end'); + }; + + // timeout + if (timeout && !this._timer) { + this._timer = setTimeout(function(){ + var err = new Error('timeout of ' + timeout + 'ms exceeded'); + err.timeout = timeout; + self.callback(err); + self.abort(); + }, timeout); + } + + // querystring + if (query) { + query = request.serializeObject(query); + this.url += ~this.url.indexOf('?') + ? '&' + query + : '?' + query; + } + + // initiate request + xhr.open(this.method, this.url, true); + + // body + if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data) { + // serialize stuff + var serialize = request.serialize[this.header['content-type']]; + if (serialize) data = serialize(data); + } + + // set header fields + for (var field in this.header) { + xhr.setRequestHeader(field, this.header[field]); + } + + // send stuff + xhr.send(data); + return this; +}; + +/** + * Expose `Request`. + */ + +request.Request = Request; + +/** + * Issue a request: + * + * Examples: + * + * request('GET', '/users').end(callback) + * request('/users').end(callback) + * request('/users', callback) + * + * @param {String} method + * @param {String|Function} url or callback + * @return {Request} + * @api public + */ + +function request(method, url) { + // callback + if ('function' == typeof url) { + return new Request('GET', method).end(url); + } + + // url first + if (1 == arguments.length) { + return new Request('GET', method); + } + + return new Request(method, url); +} + +/** + * GET `url` with optional callback `fn(res)`. + * + * @param {String} url + * @param {Mixed|Function} data or fn + * @param {Function} fn + * @return {Request} + * @api public + */ + +request.get = function(url, data, fn){ + var req = request('GET', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.query(data); + if (fn) req.end(fn); + return req; +}; + +/** + * GET `url` with optional callback `fn(res)`. + * + * @param {String} url + * @param {Mixed|Function} data or fn + * @param {Function} fn + * @return {Request} + * @api public + */ + +request.head = function(url, data, fn){ + var req = request('HEAD', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; + +/** + * DELETE `url` with optional callback `fn(res)`. + * + * @param {String} url + * @param {Function} fn + * @return {Request} + * @api public + */ + +request.del = function(url, fn){ + var req = request('DELETE', url); + if (fn) req.end(fn); + return req; +}; + +/** + * PATCH `url` with optional `data` and callback `fn(res)`. + * + * @param {String} url + * @param {Mixed} data + * @param {Function} fn + * @return {Request} + * @api public + */ + +request.patch = function(url, data, fn){ + var req = request('PATCH', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; + +/** + * POST `url` with optional `data` and callback `fn(res)`. + * + * @param {String} url + * @param {Mixed} data + * @param {Function} fn + * @return {Request} + * @api public + */ + +request.post = function(url, data, fn){ + var req = request('POST', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; + +/** + * PUT `url` with optional `data` and callback `fn(res)`. + * + * @param {String} url + * @param {Mixed|Function} data or fn + * @param {Function} fn + * @return {Request} + * @api public + */ + +request.put = function(url, data, fn){ + var req = request('PUT', url); + if ('function' == typeof data) fn = data, data = null; + if (data) req.send(data); + if (fn) req.end(fn); + return req; +}; + +/** + * Expose `request`. + */ + +module.exports = request; diff --git a/codeview/src/main/assets/training-set/javascript/new 2.txt b/codeview/src/main/assets/training-set/javascript/new 2.txt new file mode 100755 index 0000000..dbd0373 --- /dev/null +++ b/codeview/src/main/assets/training-set/javascript/new 2.txt @@ -0,0 +1,1157 @@ +/* + + Agility.js + Licensed under the MIT license + Copyright (c) Artur B. Adib, 2011 + http://agilityjs.com + +*/ + +// Sandboxed, so kids don't get hurt. Inspired by jQuery's code: +// Creates local ref to window for performance reasons (as JS looks up local vars first) +// Redefines undefined as it could have been tampered with +(function(window, undefined){ + + if (!window.jQuery) { + throw "agility.js: jQuery not found"; + } + + // Local references + var document = window.document, + location = window.location, + + // In case $ is being used by another lib + $ = jQuery, + + // Main agility object builder + agility, + + // Internal utility functions + util = {}, + + // Default object prototype + defaultPrototype = {}, + + // Global object counter + idCounter = 0, + + // Constant + ROOT_SELECTOR = '&'; + + ////////////////////////////////////////////////////////////////////////// + // + // Modernizing old JS + // + + // Modified from Douglas Crockford's Object.create() + // The condition below ensures we override other manual implementations (most are not adequate) + if (!Object.create || Object.create.toString().search(/native code/i)<0) { + Object.create = function(obj){ + var Aux = function(){}; + $.extend(Aux.prototype, obj); // simply setting Aux.prototype = obj somehow messes with constructor, so getPrototypeOf wouldn't work in IE + return new Aux(); + }; + } + + // Modified from John Resig's Object.getPrototypeOf() + // The condition below ensures we override other manual implementations (most are not adequate) + if (!Object.getPrototypeOf || Object.getPrototypeOf.toString().search(/native code/i)<0) { + if ( typeof "test".__proto__ === "object" ) { + Object.getPrototypeOf = function(object){ + return object.__proto__; + }; + } else { + Object.getPrototypeOf = function(object){ + // May break if the constructor has been tampered with + return object.constructor.prototype; + }; + } + } + + + ////////////////////////////////////////////////////////////////////////// + // + // util.* + // + + // Checks if provided obj is an agility object + util.isAgility = function(obj){ + return obj._agility === true; + }; + + // Scans object for functions (depth=2) and proxies their 'this' to dest. + // * To ensure it works with previously proxied objects, we save the original function as + // a '._preProxy' method and when available always use that as the proxy source. + // * To skip a given method, create a sub-method called '_noProxy'. + util.proxyAll = function(obj, dest){ + if (!obj || !dest) { + throw "agility.js: util.proxyAll needs two arguments"; + } + for (var attr1 in obj) { + var proxied = obj[attr1]; + // Proxy root methods + if (typeof obj[attr1] === 'function') { + proxied = obj[attr1]._noProxy ? obj[attr1] : $.proxy(obj[attr1]._preProxy || obj[attr1], dest); + proxied._preProxy = obj[attr1]._noProxy ? undefined : (obj[attr1]._preProxy || obj[attr1]); // save original + obj[attr1] = proxied; + } + // Proxy sub-methods (model.*, view.*, etc) + else if (typeof obj[attr1] === 'object') { + for (var attr2 in obj[attr1]) { + var proxied2 = obj[attr1][attr2]; + if (typeof obj[attr1][attr2] === 'function') { + proxied2 = obj[attr1][attr2]._noProxy ? obj[attr1][attr2] : $.proxy(obj[attr1][attr2]._preProxy || obj[attr1][attr2], dest); + proxied2._preProxy = obj[attr1][attr2]._noProxy ? undefined : (obj[attr1][attr2]._preProxy || obj[attr1][attr2]); // save original + proxied[attr2] = proxied2; + } + } // for attr2 + obj[attr1] = proxied; + } // if not func + } // for attr1 + }; // proxyAll + + // Reverses the order of events attached to an object + util.reverseEvents = function(obj, eventType){ + var events = $(obj).data('events'); + if (events !== undefined && events[eventType] !== undefined){ + // can't reverse what's not there + var reverseEvents = []; + for (var e in events[eventType]){ + if (!events[eventType].hasOwnProperty(e)) continue; + reverseEvents.unshift(events[eventType][e]); + } + events[eventType] = reverseEvents; + } + }; //reverseEvents + + // Determines # of attributes of given object (prototype inclusive) + util.size = function(obj){ + var size = 0, key; + for (key in obj) { + size++; + } + return size; + }; + + // Find controllers to be extended (with syntax '~'), redefine those to encompass previously defined controllers + // Example: + // var a = $$({}, '', {'click &': function(){ alert('A'); }}); + // var b = $$(a, {}, '', {'~click &': function(){ alert('B'); }}); + // Clicking on button B will alert both 'A' and 'B'. + util.extendController = function(object) { + for (var controllerName in object.controller) { + (function(){ // new scope as we need one new function handler per controller + var matches, extend, eventName, + previousHandler, currentHandler, newHandler; + + if (typeof object.controller[controllerName] === 'function') { + matches = controllerName.match(/^(\~)*(.+)/); // 'click button', '~click button', '_create', etc + extend = matches[1]; + eventName = matches[2]; + + if (!extend) return; // nothing to do + + // Redefine controller: + // '~click button' ---> 'click button' = previousHandler + currentHandler + previousHandler = object.controller[eventName] ? (object.controller[eventName]._preProxy || object.controller[eventName]) : undefined; + currentHandler = object.controller[controllerName]; + newHandler = function() { + if (previousHandler) previousHandler.apply(this, arguments); + if (currentHandler) currentHandler.apply(this, arguments); + }; + + object.controller[eventName] = newHandler; + delete object.controller[controllerName]; // delete '~click button' + } // if function + })(); + } // for controllerName + }; + + ////////////////////////////////////////////////////////////////////////// + // + // Default object prototype + // + + defaultPrototype = { + + _agility: true, + + ////////////////////////////////////////////////////////////////////////// + // + // _container + // + // API and related auxiliary functions for storing child Agility objects. + // Not all methods are exposed. See 'shortcuts' below for exposed methods. + // + + _container: { + + // Adds child object to container, appends/prepends/etc view, listens for child removal + _insertObject: function(obj, selector, method){ + var self = this; + if (!util.isAgility(obj)) { + throw "agility.js: append argument is not an agility object"; + } + this._container.children[obj._id] = obj; // children is *not* an array; this is for simpler lookups by global object id + this.trigger(method, [obj, selector]); + obj._parent = this; + // ensures object is removed from container when destroyed: + obj.bind('destroy', function(event, id){ + self._container.remove(id); + }); + return this; + }, + + append: function(obj, selector) { + return this._container._insertObject.call(this, obj, selector, 'append'); + }, + + prepend: function(obj, selector) { + return this._container._insertObject.call(this, obj, selector, 'prepend'); + }, + + after: function(obj, selector) { + return this._container._insertObject.call(this, obj, selector, 'after'); + }, + + before: function(obj, selector) { + return this._container._insertObject.call(this, obj, selector, 'before'); + }, + + // Removes child object from container + remove: function(id){ + delete this._container.children[id]; + this.trigger('remove', id); + return this; + }, + + // Iterates over all child objects in container + each: function(fn){ + $.each(this._container.children, fn); + return this; // for chainable calls + }, + + // Removes all objects in container + empty: function(){ + this.each(function(){ + this.destroy(); + }); + return this; + }, + + // Number of children + size: function() { + return util.size(this._container.children); + } + + }, + + ////////////////////////////////////////////////////////////////////////// + // + // _events + // + // API and auxiliary functions for handling events. Not all methods are exposed. + // See 'shortcuts' below for exposed methods. + // + + _events: { + + // Parses event string unlike: + // 'event' : custom event + // 'event selector' : DOM event using 'selector' + // Returns { type:'event' [, selector:'selector'] } + parseEventStr: function(eventStr){ + var eventObj = { type:eventStr }, + spacePos = eventStr.search(/\s/); + // DOM event 'event selector', e.g. 'click button' + if (spacePos > -1) { + eventObj.type = eventStr.substr(0, spacePos); + eventObj.selector = eventStr.substr(spacePos+1); + } + return eventObj; + }, + + // Binds eventStr to fn. eventStr is parsed as per parseEventStr() + bind: function(eventStr, fn){ + var eventObj = this._events.parseEventStr(eventStr); + // DOM event 'event selector', e.g. 'click button' + if (eventObj.selector) { + // Manually override root selector, as jQuery selectors can't select self object + if (eventObj.selector === ROOT_SELECTOR) { + this.view.$().bind(eventObj.type, fn); + } + else { + this.view.$().delegate(eventObj.selector, eventObj.type, fn); + } + } + // Custom event + else { + $(this._events.data).bind(eventObj.type, fn); + } + return this; // for chainable calls + }, // bind + + // Triggers eventStr. Syntax for eventStr is same as that for bind() + trigger: function(eventStr, params){ + var eventObj = this._events.parseEventStr(eventStr); + // DOM event 'event selector', e.g. 'click button' + if (eventObj.selector) { + // Manually override root selector, as jQuery selectors can't select self object + if (eventObj.selector === ROOT_SELECTOR) { + this.view.$().trigger(eventObj.type, params); + } + else { + this.view.$().find(eventObj.selector).trigger(eventObj.type, params); + } + } + // Custom event + else { + $(this._events.data).trigger('_'+eventObj.type, params); + // fire 'pre' hooks in reverse attachment order ( last first ) + util.reverseEvents(this._events.data, 'pre:' + eventObj.type); + $(this._events.data).trigger('pre:' + eventObj.type, params); + // put the order of events back + util.reverseEvents(this._events.data, 'pre:' + eventObj.type); + $(this._events.data).trigger(eventObj.type, params); + if(this.parent()) + this.parent().trigger((eventObj.type.match(/^child:/) ? '' : 'child:') + eventObj.type, params); + $(this._events.data).trigger('post:' + eventObj.type, params); + } + return this; // for chainable calls + } // trigger + + }, // _events + + ////////////////////////////////////////////////////////////////////////// + // + // Model + // + // Main model API. All methods are exposed, but methods starting with '_' + // are meant to be used internally only. + // + + model: { + + // Setter + set: function(arg, params) { + var self = this; + var modified = []; // list of modified model attributes + if (typeof arg === 'object') { + var _clone = false; + if (params && params.reset) { + _clone = this.model._data; // hold on to data for change events + this.model._data = $.extend({}, arg); // erases previous model attributes without pointing to object + } + else { + $.extend(this.model._data, arg); // default is extend + } + for (var key in arg) { + delete _clone[ key ]; // no need to fire change twice + modified.push(key); + } + for (key in _clone) { + modified.push(key); + } + } + else { + throw "agility.js: unknown argument type in model.set()"; + } + + // Events + if (params && params.silent===true) return this; // do not fire events + this.trigger('change'); + $.each(modified, function(index, val){ + self.trigger('change:'+val); + }); + return this; // for chainable calls + }, + + // Getter + get: function(arg){ + // Full model getter + if (arg === undefined) { + return this.model._data; + } + // Attribute getter + if (typeof arg === 'string') { + return this.model._data[arg]; + } + throw 'agility.js: unknown argument for getter'; + }, + + // Resetter (to initial model upon object initialization) + reset: function(){ + this.model.set(this.model._initData, {reset:true}); + return this; // for chainable calls + }, + + // Number of model properties + size: function(){ + return util.size(this.model._data); + }, + + // Convenience function - loops over each model property + each: function(fn){ + $.each(this.model._data, fn); + return this; // for chainable calls + } + + }, // model prototype + + ////////////////////////////////////////////////////////////////////////// + // + // View + // + // Main view API. All methods are exposed, but methods starting with '_' + // are meant to be used internally only. + // + + view: { + + // Defaults + format: '
    ', + style: '', + + // Shortcut to view.$root or view.$root.find(), depending on selector presence + $: function(selector){ + return (!selector || selector === ROOT_SELECTOR) ? this.view.$root : this.view.$root.find(selector); + }, + + // Render $root + // Only function to access $root directly other than $() + render: function(){ + // Without format there is no view + if (this.view.format.length === 0) { + throw "agility.js: empty format in view.render()"; + } + if (this.view.$root.size() === 0) { + this.view.$root = $(this.view.format); + } + else { + this.view.$root.html( $(this.view.format).html() ); // can't overwrite $root as this would reset its presence in the DOM and all events already bound, and + } + // Ensure we have a valid (non-empty) $root + if (this.view.$root.size() === 0) { + throw 'agility.js: could not generate html from format'; + } + return this; + }, // render + + // Parse data-bind string of the type '[attribute][=] variable[, [attribute][=] variable ]...' + // If the variable is not an attribute, it must occur by itself + // all pairs in the list are assumed to be attributes + // Returns { key:'model key', attr: [ {attr : 'attribute', attrVar : 'variable' }... ] } + _parseBindStr: function(str){ + var obj = {key:null, attr:[]}, + pairs = str.split(','), + regex = /([a-zA-Z0-9_\-]+)(?:[\s=]+([a-zA-Z0-9_\-]+))?/, + keyAssigned = false, + matched; + + if (pairs.length > 0) { + for (var i = 0; i < pairs.length; i++) { + matched = pairs[i].match(regex); + // [ "attribute variable", "attribute", "variable" ] + // or [ "attribute=variable", "attribute", "variable" ] + // or + // [ "variable", "variable", undefined ] + // in some IE it will be [ "variable", "variable", "" ] + // or + // null + if (matched) { + if (typeof(matched[2]) === "undefined" || matched[2] === "") { + if (keyAssigned) { + throw new Error("You may specify only one key (" + + keyAssigned + " has already been specified in data-bind=" + + str + ")"); + } else { + keyAssigned = matched[1]; + obj.key = matched[1]; + } + } else { + obj.attr.push({attr: matched[1], attrVar: matched[2]}); + } + } // if (matched) + } // for (pairs.length) + } // if (pairs.length > 0) + + return obj; + }, + + // Apply two-way (DOM <--> Model) bindings to elements with 'data-bind' attributes + bindings: function(){ + var self = this; + var $rootNode = this.view.$().filter('[data-bind]'); + var $childNodes = this.view.$('[data-bind]'); + var createAttributePairClosure = function(bindData, node, i) { + var attrPair = bindData.attr[i]; // capture the attribute pair in closure + return function() { + node.attr(attrPair.attr, self.model.get(attrPair.attrVar)); + }; + }; + $rootNode.add($childNodes).each(function(){ + var $node = $(this); + var bindData = self.view._parseBindStr( $node.data('bind') ); + + var bindAttributesOneWay = function() { + // 1-way attribute binding + if (bindData.attr) { + for (var i = 0; i < bindData.attr.length; i++) { + self.bind('_change:'+bindData.attr[i].attrVar, + createAttributePairClosure(bindData, $node, i)); + } // for (bindData.attr) + } // if (bindData.attr) + }; // bindAttributesOneWay() + + // : 2-way binding + if ($node.is('input:checkbox')) { + // Model --> DOM + self.bind('_change:'+bindData.key, function(){ + $node.prop("checked", self.model.get(bindData.key)); // this won't fire a DOM 'change' event, saving us from an infinite event loop (Model <--> DOM) + }); + // DOM --> Model + $node.change(function(){ + var obj = {}; + obj[bindData.key] = $(this).prop("checked"); + self.model.set(obj); // not silent as user might be listening to change events + }); + // 1-way attribute binding + bindAttributesOneWay(); + } + + // : 2-way binding + else if ($node.is('input:radio')) { + // Model --> DOM + self.bind('_change:'+bindData.key, function(){ + var nodeName = $node.attr('name'); + var modelValue = self.model.get(bindData.key); + $node.siblings('input[name="'+nodeName+'"]').filter('[value="'+modelValue+'"]').prop("checked", true); // this won't fire a DOM 'change' event, saving us from an infinite event loop (Model <--> DOM) + }); + // DOM --> Model + $node.change(function(){ + if (!$node.prop("checked")) return; // only handles check=true events + var obj = {}; + obj[bindData.key] = $node.val(); + self.model.set(obj); // not silent as user might be listening to change events + }); + // 1-way attribute binding + bindAttributesOneWay(); + } + + // (model is updated after every keypress event) + else if ($node.is('input[type="search"]')) { + // Model --> DOM + self.bind('_change:'+bindData.key, function(){ + $node.val(self.model.get(bindData.key)); // this won't fire a DOM 'change' event, saving us from an infinite event loop (Model <--> DOM) + }); + // Model <-- DOM + $node.keypress(function(){ + // Without timeout $node.val() misses the last entered character + setTimeout(function(){ + var obj = {}; + obj[bindData.key] = $node.val(); + self.model.set(obj); // not silent as user might be listening to change events + }, 50); + }); + // 1-way attribute binding + bindAttributesOneWay(); + } + + // , , and