git-svn-id: http://webrtc.googlecode.com/svn/trunk@156 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/src/modules/video_coding/main/source/Android.mk b/src/modules/video_coding/main/source/Android.mk
new file mode 100644
index 0000000..9478957
--- /dev/null
+++ b/src/modules/video_coding/main/source/Android.mk
@@ -0,0 +1,79 @@
+# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS.  All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := libwebrtc_video_coding
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+LOCAL_SRC_FILES := codec_database.cc \
+    codec_timer.cc \
+    content_metrics_processing.cc \
+    encoded_frame.cc \
+    exp_filter.cc \
+    frame_buffer.cc \
+    frame_dropper.cc \
+    frame_list.cc \
+    generic_decoder.cc \
+    generic_encoder.cc \
+    inter_frame_delay.cc \
+    jitter_buffer.cc \
+    jitter_estimator.cc \
+    media_opt_util.cc \
+    media_optimization.cc \
+    packet.cc \
+    qm_select.cc \
+    receiver.cc \
+    rtt_filter.cc \
+    session_info.cc \
+    timestamp_extrapolator.cc \
+    timestamp_map.cc \
+    timing.cc \
+    video_coding_impl.cc
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS :=  
+MY_CFLAGS_C :=
+MY_DEFS := '-DNO_TCMALLOC' \
+    '-DNO_HEAPCHECKER' \
+    '-DWEBRTC_TARGET_PC' \
+    '-DWEBRTC_LINUX' \
+    '-DWEBRTC_THREAD_RR' \
+    '-DWEBRTC_ANDROID' \
+    '-DANDROID' 
+LOCAL_CFLAGS := $(MY_CFLAGS_C) $(MY_CFLAGS) $(MY_DEFS)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../.. \
+    $(LOCAL_PATH)/../interface \
+    $(LOCAL_PATH)/../../../interface \
+    $(LOCAL_PATH)/../../codecs/interface \
+    $(LOCAL_PATH)/../../codecs/i420/main/interface \
+    $(LOCAL_PATH)/../../codecs/vp8/main/interface \
+    $(LOCAL_PATH)/../../../../common_video/vplib/main/interface \
+    $(LOCAL_PATH)/../../../../system_wrappers/interface 
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS := 
+
+LOCAL_LDFLAGS :=
+
+LOCAL_STATIC_LIBRARIES :=
+
+LOCAL_SHARED_LIBRARIES := libcutils \
+    libdl \
+    libstlport
+LOCAL_ADDITIONAL_DEPENDENCIES :=
+
+include external/stlport/libstlport.mk
+include $(BUILD_STATIC_LIBRARY)
diff --git a/src/modules/video_coding/main/source/codec_database.cc b/src/modules/video_coding/main/source/codec_database.cc
new file mode 100644
index 0000000..612b88b
--- /dev/null
+++ b/src/modules/video_coding/main/source/codec_database.cc
@@ -0,0 +1,799 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "codec_database.h"
+#include "../../../../engine_configurations.h"
+#include "internal_defines.h"
+#include "trace.h"
+
+#if defined(_WIN32)
+    // VS 2005: Don't warn for default initialized arrays. See help for more info.
+    // Don't warn for strncpy being unsecure.
+    // switch statement contains 'default' but no 'case' labels
+#pragma warning(disable:4351; disable:4996; disable:4065)
+#endif
+
+// Supported codecs
+#ifdef  VIDEOCODEC_VP8
+    #include "vp8.h"
+#endif
+#ifdef  VIDEOCODEC_I420
+    #include "i420.h"
+#endif
+
+namespace webrtc
+{
+
+VCMDecoderMapItem::VCMDecoderMapItem(VideoCodec* settings,
+                                     WebRtc_UWord32 numberOfCores,
+                                     bool requireKeyFrame)
+:
+_settings(settings),
+_numberOfCores(numberOfCores),
+_requireKeyFrame(requireKeyFrame)
+{
+}
+
+VCMExtDecoderMapItem::VCMExtDecoderMapItem(VideoDecoder* externalDecoderInstance,
+                                           WebRtc_UWord8 payloadType,
+                                           bool internalRenderTiming)
+:
+_payloadType(payloadType),
+_externalDecoderInstance(externalDecoderInstance),
+_internalRenderTiming(internalRenderTiming)
+{
+}
+
+VCMCodecDataBase::VCMCodecDataBase(WebRtc_Word32 id):
+_id(id),
+_numberOfCores(0),
+_maxPayloadSize(kDefaultPayloadSize),
+_periodicKeyFrames(false),
+_currentEncIsExternal(false),
+_sendCodec(),
+_receiveCodec(),
+_externalPayloadType(0),
+_externalEncoder(NULL),
+_internalSource(false),
+_ptrEncoder(NULL),
+_ptrDecoder(NULL),
+_currentDecIsExternal(false),
+_decMap(),
+_decExternalMap()
+{
+    //
+}
+
+VCMCodecDataBase::~VCMCodecDataBase()
+{
+    Reset();
+}
+
+WebRtc_Word32
+VCMCodecDataBase::Version(WebRtc_Word8* version,
+                                WebRtc_UWord32& remainingBufferInBytes,
+                                WebRtc_UWord32& position) const
+{
+    VCMGenericEncoder* encoder = NULL;
+    VideoCodec settings;
+    WebRtc_Word32 ret;
+    for (int i = 0; i < VCMCodecDataBase::NumberOfCodecs(); i++)
+    {
+        ret = VCMCodecDataBase::Codec(i, &settings);
+        if (ret < 0)
+        {
+            return ret;
+        }
+        encoder = CreateEncoder(settings.codecType);
+        if (encoder == NULL)
+        {
+            return VCM_MEMORY;
+        }
+        ret = encoder->_encoder.Version(&version[position], remainingBufferInBytes);
+        if (ret < 0)
+        {
+            return ret;
+        }
+        remainingBufferInBytes -= ret;
+        position += ret;
+        delete &encoder->_encoder;
+        delete encoder;
+    }
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::Reset()
+{
+    WebRtc_Word32 ret = ResetReceiver();
+    if (ret < 0)
+    {
+        return ret;
+    }
+    ret = ResetSender();
+    if (ret < 0)
+    {
+        return ret;
+    }
+   return VCM_OK;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::ResetSender()
+{
+    DeleteEncoder();
+    _periodicKeyFrames = false;
+    return VCM_OK;
+}
+
+VCMGenericEncoder*
+VCMCodecDataBase::CreateEncoder(VideoCodecType type) const
+{
+    switch(type)
+    {
+#ifdef  VIDEOCODEC_VP8
+        case kVideoCodecVP8:
+            return new VCMGenericEncoder(*(new VP8Encoder));
+        break;
+#endif
+#ifdef VIDEOCODEC_I420
+        case kVideoCodecI420:
+            return new VCMGenericEncoder(*(new I420Encoder));
+            break;
+#endif
+        default:
+        return NULL;
+        break;
+    }
+}
+
+void
+VCMCodecDataBase::DeleteEncoder()
+{
+    if (_ptrEncoder)
+    {
+        _ptrEncoder->Release();
+        if (!_currentEncIsExternal)
+        {
+            delete &_ptrEncoder->_encoder;
+        }
+        delete _ptrEncoder;
+        _ptrEncoder = NULL;
+    }
+}
+
+WebRtc_UWord8
+VCMCodecDataBase::NumberOfCodecs()
+{
+    return VCM_NUM_VIDEO_CODECS_AVAILABLE;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::Codec(WebRtc_UWord8 listId, VideoCodec *settings)
+{
+    if (settings == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+
+    if (listId >= VCM_NUM_VIDEO_CODECS_AVAILABLE)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    memset(settings, 0, sizeof(VideoCodec));
+    switch (listId)
+    {
+#ifdef VIDEOCODEC_VP8
+    case VCM_VP8_IDX:
+        {
+            strncpy(settings->plName, "VP8", 3);
+            settings->codecType = kVideoCodecVP8;
+            // 96 to 127 dynamic payload types for video codecs
+            settings->plType = VCM_VP8_PAYLOAD_TYPE;
+            settings->startBitrate = 100;
+            settings->minBitrate = VCM_MIN_BITRATE;
+            settings->maxBitrate = 0;
+            settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
+            settings->width = VCM_DEFAULT_CODEC_WIDTH;
+            settings->height = VCM_DEFAULT_CODEC_HEIGHT;
+            break;
+        }
+#endif
+#ifdef VIDEOCODEC_I420
+    case VCM_I420_IDX:
+        {
+            strncpy(settings->plName, "I420", 4);
+            settings->codecType = kVideoCodecI420;
+            // 96 to 127 dynamic payload types for video codecs
+            settings->plType = VCM_I420_PAYLOAD_TYPE;
+            // Bitrate needed for this size and framerate
+            settings->startBitrate = 3*VCM_DEFAULT_CODEC_WIDTH*
+                                       VCM_DEFAULT_CODEC_HEIGHT*8*
+                                       VCM_DEFAULT_FRAME_RATE/1000/2;
+            settings->maxBitrate = settings->startBitrate;
+            settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
+            settings->width = VCM_DEFAULT_CODEC_WIDTH;
+            settings->height = VCM_DEFAULT_CODEC_HEIGHT;
+            settings->minBitrate = VCM_MIN_BITRATE;
+            break;
+        }
+#endif
+    default:
+        {
+            return VCM_PARAMETER_ERROR;
+        }
+    }
+
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::Codec(VideoCodecType codecType, VideoCodec* settings)
+{
+    for (int i = 0; i < VCMCodecDataBase::NumberOfCodecs(); i++)
+    {
+        const WebRtc_Word32 ret = VCMCodecDataBase::Codec(i, settings);
+        if (ret != VCM_OK)
+        {
+            return ret;
+        }
+        if (codecType == settings->codecType)
+        {
+            return VCM_OK;
+        }
+    }
+    return VCM_PARAMETER_ERROR;
+}
+
+// assuming only one registered encoder - since only one used, no need for more
+WebRtc_Word32
+VCMCodecDataBase::RegisterSendCodec(const VideoCodec* sendCodec,
+                                    WebRtc_UWord32 numberOfCores,
+                                    WebRtc_UWord32 maxPayloadSize)
+ {
+    if (sendCodec == NULL)
+    {
+        return VCM_UNINITIALIZED;
+    }
+    if (maxPayloadSize == 0)
+    {
+        maxPayloadSize = kDefaultPayloadSize;
+    }
+    if (numberOfCores > 32)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    if (strcmp(sendCodec->plName, "H263") == 0 &&
+        (sendCodec->plType != 34))
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    if (sendCodec->plType <= 0)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    // Make sure the start bit rate is sane...
+    if (sendCodec->startBitrate > 1000000)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    if (sendCodec->codecType == kVideoCodecUnknown)
+    {
+        return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+    }
+    _numberOfCores = numberOfCores;
+    _maxPayloadSize = maxPayloadSize;
+
+    memcpy(&_sendCodec, sendCodec, sizeof(VideoCodec));
+
+    if (_sendCodec.maxBitrate == 0)
+    {
+        // max is one bit per pixel
+        _sendCodec.maxBitrate = ((WebRtc_Word32)_sendCodec.height *
+                                 (WebRtc_Word32)_sendCodec.width *
+                                 (WebRtc_Word32)_sendCodec.maxFramerate) / 1000;
+        if (_sendCodec.startBitrate > _sendCodec.maxBitrate)
+        {
+            // but if the customer tries to set a higher start bit rate we will increase
+            // the max accordingly
+            _sendCodec.maxBitrate = _sendCodec.startBitrate;
+        }
+    }
+
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::SendCodec(VideoCodec* currentSendCodec) const
+{
+    WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, VCMId(_id), "SendCodec");
+
+    if(_ptrEncoder == NULL)
+    {
+        return VCM_UNINITIALIZED;
+    }
+    memcpy(currentSendCodec, &_sendCodec, sizeof(VideoCodec));
+    return VCM_OK;
+}
+
+VideoCodecType
+VCMCodecDataBase::SendCodec() const
+{
+    WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, VCMId(_id),
+            "SendCodec type");
+    if (_ptrEncoder == NULL)
+    {
+        return kVideoCodecUnknown;
+    }
+    return _sendCodec.codecType;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::DeRegisterExternalEncoder(WebRtc_UWord8 payloadType, bool& wasSendCodec)
+{
+    wasSendCodec = false;
+    if (_externalPayloadType != payloadType)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    if (_sendCodec.plType == payloadType)
+    {
+        //De-register as send codec if needed
+        DeleteEncoder();
+        memset(&_sendCodec, 0, sizeof(VideoCodec));
+        _currentEncIsExternal = false;
+        wasSendCodec = true;
+    }
+    _externalPayloadType = 0;
+    _externalEncoder = NULL;
+    _internalSource = false;
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::RegisterExternalEncoder(VideoEncoder* externalEncoder,
+                                          WebRtc_UWord8 payloadType,
+                                          bool internalSource)
+{
+    // since only one encoder can be used at a given time,
+    // only one external encoder can be registered/used
+    _externalEncoder = externalEncoder;
+    _externalPayloadType = payloadType;
+    _internalSource = internalSource;
+
+    return VCM_OK;
+}
+
+VCMGenericEncoder*
+VCMCodecDataBase::SetEncoder(const VideoCodec* settings,
+                             VCMEncodedFrameCallback* VCMencodedFrameCallback)
+
+{
+    // if encoder exists, will destroy it and create new one
+    DeleteEncoder();
+
+    if (settings->plType == _externalPayloadType)
+    {
+        // External encoder
+        _ptrEncoder = new VCMGenericEncoder(*_externalEncoder, _internalSource);
+        _currentEncIsExternal = true;
+    }
+    else
+    {
+        _ptrEncoder = CreateEncoder(settings->codecType);
+        _currentEncIsExternal = false;
+    }
+
+    VCMencodedFrameCallback->SetPayloadType(settings->plType);
+
+    if (_ptrEncoder == NULL)
+    {
+        return NULL;
+    }
+
+    if (_ptrEncoder->InitEncode(settings, _numberOfCores, _maxPayloadSize) < 0)
+    {
+        DeleteEncoder();
+        return NULL;
+    }
+    else if (_ptrEncoder->RegisterEncodeCallback(VCMencodedFrameCallback) < 0)
+    {
+        DeleteEncoder();
+        return NULL;
+    }
+    // Intentionally don't check return value since the encoder registration
+    // shouldn't fail because the codec doesn't support changing the
+    // periodic key frame setting.
+    _ptrEncoder->SetPeriodicKeyFrames(_periodicKeyFrames);
+    return _ptrEncoder;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::SetPeriodicKeyFrames(bool enable)
+{
+    _periodicKeyFrames = enable;
+    if (_ptrEncoder != NULL)
+    {
+        return _ptrEncoder->SetPeriodicKeyFrames(_periodicKeyFrames);
+    }
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::RegisterReceiveCodec(const VideoCodec* receiveCodec,
+                                       WebRtc_UWord32 numberOfCores,
+                                       bool requireKeyFrame)
+{
+    WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCoding, VCMId(_id),
+                 "Codec: %s, Payload type %d, Height %d, Width %d, Bitrate %d, Framerate %d.",
+                 receiveCodec->plName, receiveCodec->plType,
+                 receiveCodec->height, receiveCodec->width,
+                 receiveCodec->startBitrate, receiveCodec->maxFramerate);
+
+    // check if payload value already exists, if so  - erase old and insert new
+    DeRegisterReceiveCodec(receiveCodec->plType);
+    if (receiveCodec->codecType == kVideoCodecUnknown)
+    {
+        return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+    }
+    VideoCodec* newReceiveCodec = new VideoCodec(*receiveCodec);
+    _decMap.Insert(receiveCodec->plType,
+        new VCMDecoderMapItem(newReceiveCodec, numberOfCores, requireKeyFrame));
+
+    return VCM_OK;
+}
+
+WebRtc_Word32 VCMCodecDataBase::DeRegisterReceiveCodec(WebRtc_UWord8 payloadType)
+{
+    MapItem* item = _decMap.Find(payloadType);
+    if (item == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    VCMDecoderMapItem* decItem = static_cast<VCMDecoderMapItem*>(item->GetItem());
+    delete decItem->_settings;
+    delete decItem;
+    _decMap.Erase(item);
+    if (_receiveCodec.plType == payloadType)
+    {
+        // This codec is currently in use.
+        memset(&_receiveCodec, 0, sizeof(VideoCodec));
+        _currentDecIsExternal = false;
+    }
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::ResetReceiver()
+{
+    ReleaseDecoder(_ptrDecoder);
+    _ptrDecoder = NULL;
+    memset(&_receiveCodec, 0, sizeof(VideoCodec));
+    MapItem* item = _decMap.First();
+    while (item != NULL)
+    {
+        VCMDecoderMapItem* decItem = static_cast<VCMDecoderMapItem*>(item->GetItem());
+        if (decItem != NULL)
+        {
+            if (decItem->_settings != NULL)
+            {
+                delete decItem->_settings;
+            }
+            delete decItem;
+        }
+        _decMap.Erase(item);
+        item = _decMap.First();
+    }
+    item = _decExternalMap.First();
+    while (item != NULL)
+    {
+        VCMExtDecoderMapItem* decItem = static_cast<VCMExtDecoderMapItem*>(item->GetItem());
+        if (decItem != NULL)
+        {
+            delete decItem;
+        }
+        _decExternalMap.Erase(item);
+        item = _decExternalMap.First();
+    }
+    _currentDecIsExternal = false;
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMCodecDataBase::DeRegisterExternalDecoder(WebRtc_UWord8 payloadType)
+{
+    MapItem* item = _decExternalMap.Find(payloadType);
+    if (item == NULL)
+    {
+        // Not found
+        return VCM_PARAMETER_ERROR;
+    }
+    if (_receiveCodec.plType == payloadType)
+    {
+        // Release it if it was registered and in use
+        ReleaseDecoder(_ptrDecoder);
+        _ptrDecoder = NULL;
+    }
+    DeRegisterReceiveCodec(payloadType);
+    VCMExtDecoderMapItem* decItem = static_cast<VCMExtDecoderMapItem*>(item->GetItem());
+    delete decItem;
+    _decExternalMap.Erase(item);
+    return VCM_OK;
+}
+
+// Add the external encoder object to the list of external decoders.
+// Won't be registered as a receive codec until RegisterReceiveCodec is called.
+WebRtc_Word32
+VCMCodecDataBase::RegisterExternalDecoder(VideoDecoder* externalDecoder,
+                                          WebRtc_UWord8 payloadType,
+                                          bool internalRenderTiming)
+{
+    // check if payload value already exists, if so  - erase old and insert new
+    VCMExtDecoderMapItem* extDecoder = new VCMExtDecoderMapItem(externalDecoder,
+                                                                payloadType,
+                                                                internalRenderTiming);
+    if (extDecoder == NULL)
+    {
+        return VCM_MEMORY;
+    }
+    DeRegisterExternalDecoder(payloadType);
+    _decExternalMap.Insert(payloadType, extDecoder);
+
+    return VCM_OK;
+}
+
+bool
+VCMCodecDataBase::DecoderRegistered() const
+{
+    return (_decMap.Size() > 0);
+}
+
+WebRtc_Word32
+VCMCodecDataBase::ReceiveCodec(VideoCodec* currentReceiveCodec) const
+{
+    if (_ptrDecoder == NULL)
+    {
+        return VCM_NO_FRAME_DECODED;
+    }
+    memcpy(currentReceiveCodec, &_receiveCodec, sizeof(VideoCodec));
+    return VCM_OK;
+}
+
+VideoCodecType
+VCMCodecDataBase::ReceiveCodec() const
+{
+    if (_ptrDecoder == NULL)
+    {
+        return kVideoCodecUnknown;
+    }
+    return _receiveCodec.codecType;
+}
+
+VCMGenericDecoder*
+VCMCodecDataBase::SetDecoder(WebRtc_UWord8 payloadType, VCMDecodedFrameCallback& callback)
+{
+    if (payloadType == _receiveCodec.plType || payloadType == 0)
+    {
+        return _ptrDecoder;
+    }
+    // check for exisitng decoder, if exists - delete
+    if (_ptrDecoder)
+    {
+        ReleaseDecoder(_ptrDecoder);
+        _ptrDecoder = NULL;
+        memset(&_receiveCodec, 0, sizeof(VideoCodec));
+    }
+    _ptrDecoder = CreateAndInitDecoder(payloadType, _receiveCodec, _currentDecIsExternal);
+    if (_ptrDecoder == NULL)
+    {
+        return NULL;
+    }
+    if (_ptrDecoder->RegisterDecodeCompleteCallback(&callback) < 0)
+    {
+        ReleaseDecoder(_ptrDecoder);
+        _ptrDecoder = NULL;
+        memset(&_receiveCodec, 0, sizeof(VideoCodec));
+        return NULL;
+    }
+    return _ptrDecoder;
+}
+
+VCMGenericDecoder*
+VCMCodecDataBase::CreateAndInitDecoder(WebRtc_UWord8 payloadType,
+                                       VideoCodec& newCodec,
+                                       bool &external) const
+{
+    VCMDecoderMapItem* decoderItem = FindDecoderItem(payloadType);
+    if (decoderItem == NULL)
+    {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id),
+                     "Unknown payload type: %u", payloadType);
+        return NULL;
+    }
+    VCMGenericDecoder* ptrDecoder = NULL;
+    VCMExtDecoderMapItem* externalDecItem = FindExternalDecoderItem(payloadType);
+    if (externalDecItem != NULL)
+    {
+        // External codec
+        ptrDecoder = new VCMGenericDecoder(*externalDecItem->_externalDecoderInstance, _id,
+                                           true);
+        external = true;
+    }
+    else
+    {
+        // create decoder
+        ptrDecoder = CreateDecoder(decoderItem->_settings->codecType);
+        external = false;
+    }
+    if (ptrDecoder == NULL)
+    {
+        return NULL;
+    }
+
+    if (ptrDecoder->InitDecode(decoderItem->_settings,
+                               decoderItem->_numberOfCores,
+                               decoderItem->_requireKeyFrame) < 0)
+    {
+        ReleaseDecoder(ptrDecoder);
+        return NULL;
+    }
+
+    SetCodecConfigParameters(*ptrDecoder, *decoderItem->_settings);
+
+    memcpy(&newCodec, decoderItem->_settings, sizeof(VideoCodec));
+    return ptrDecoder;
+}
+
+VCMGenericDecoder*
+VCMCodecDataBase::CreateDecoderCopy() const
+{
+    if (_ptrDecoder == NULL)
+    {
+        return NULL;
+    }
+    VideoDecoder* decoderCopy = _ptrDecoder->_decoder.Copy();
+    if (decoderCopy == NULL)
+    {
+        return NULL;
+    }
+    return new VCMGenericDecoder(*decoderCopy, _id, _ptrDecoder->External());
+}
+
+void
+VCMCodecDataBase::CopyDecoder(const VCMGenericDecoder& decoder)
+{
+    VideoDecoder* decoderCopy = decoder._decoder.Copy();
+    if (decoderCopy != NULL)
+    {
+        ReleaseDecoder(_ptrDecoder);
+        _ptrDecoder = new VCMGenericDecoder(*decoderCopy, _id, decoder.External());
+    }
+}
+
+bool
+VCMCodecDataBase::RenderTiming() const
+{
+    bool renderTiming = true;
+    if (_currentDecIsExternal)
+    {
+        VCMExtDecoderMapItem* extItem = FindExternalDecoderItem(_receiveCodec.plType);
+        renderTiming = extItem->_internalRenderTiming;
+    }
+    return renderTiming;
+}
+
+void
+VCMCodecDataBase::ReleaseDecoder(VCMGenericDecoder* decoder) const
+{
+    if (decoder != NULL)
+    {
+        decoder->Release();
+        if (!decoder->External() && &decoder->_decoder != NULL)
+        {
+            delete &decoder->_decoder;
+        }
+        delete decoder;
+    }
+}
+
+WebRtc_Word32
+VCMCodecDataBase::SetCodecConfigParameters(WebRtc_UWord8 payloadType,
+                                           const WebRtc_UWord8* buffer,
+                                           WebRtc_Word32 length)
+{
+    VCMDecoderMapItem* decItem = FindDecoderItem(payloadType);
+    if (decItem == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    switch (decItem->_settings->codecType)
+    {
+    case kVideoCodecMPEG4:
+    {
+        memcpy(decItem->_settings->codecSpecific.MPEG4.configParameters, buffer, length);
+        decItem->_settings->codecSpecific.MPEG4.configParametersSize =
+                static_cast<WebRtc_UWord8>(length);
+        break;
+    }
+    default:
+        // This codec doesn't have codec config parameters
+        return VCM_GENERAL_ERROR;
+    }
+    if (_ptrDecoder != NULL && _receiveCodec.plType == decItem->_settings->plType)
+    {
+        return _ptrDecoder->SetCodecConfigParameters(buffer, length);
+    }
+    return VCM_OK;
+}
+
+VCMDecoderMapItem*
+VCMCodecDataBase::FindDecoderItem(WebRtc_UWord8 payloadType) const
+{
+    MapItem* item = _decMap.Find(payloadType);
+    if (item != NULL)
+    {
+        return static_cast<VCMDecoderMapItem*>(item->GetItem());
+    }
+    return NULL;
+}
+
+VCMExtDecoderMapItem*
+VCMCodecDataBase::FindExternalDecoderItem(WebRtc_UWord8 payloadType) const
+{
+    MapItem* item = _decExternalMap.Find(payloadType);
+    if (item != NULL)
+    {
+        return static_cast<VCMExtDecoderMapItem*>(item->GetItem());
+    }
+    return NULL;
+}
+
+VCMGenericDecoder*
+VCMCodecDataBase::CreateDecoder(VideoCodecType type) const
+{
+    switch(type)
+    {
+#ifdef VIDEOCODEC_VP8
+    case kVideoCodecVP8:
+        return new VCMGenericDecoder(*(new VP8Decoder), _id);
+#endif
+#ifdef VIDEOCODEC_I420
+    case kVideoCodecI420:
+         return new VCMGenericDecoder(*(new I420Decoder), _id);
+#endif
+    default:
+        return NULL;
+    }
+}
+
+void
+VCMCodecDataBase::SetCodecConfigParameters(VCMGenericDecoder& decoder,
+                                           const VideoCodec& settings)
+{
+    switch (settings.codecType)
+    {
+    case kVideoCodecMPEG4:
+    {
+        if (settings.codecSpecific.MPEG4.configParametersSize > 0)
+        {
+            decoder.SetCodecConfigParameters(
+                                    settings.codecSpecific.MPEG4.configParameters,
+                                    settings.codecSpecific.MPEG4.configParametersSize);
+        }
+        break;
+    }
+    default:
+        // No codec config parameters for this codec
+        return;
+    }
+    return;
+}
+
+}
diff --git a/src/modules/video_coding/main/source/codec_database.h b/src/modules/video_coding/main/source/codec_database.h
new file mode 100644
index 0000000..37943e8
--- /dev/null
+++ b/src/modules/video_coding/main/source/codec_database.h
@@ -0,0 +1,221 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_CODEC_DATABASE_H_
+#define WEBRTC_MODULES_VIDEO_CODING_CODEC_DATABASE_H_
+
+#include "video_coding.h"
+#include "video_codec_interface.h"
+#include "generic_decoder.h"
+#include "generic_encoder.h"
+#include "typedefs.h"
+#include "map_wrapper.h"
+
+namespace webrtc
+{
+
+enum VCMCodecDBProperties
+{
+    kDefaultPayloadSize = 1440
+};
+
+class VCMDecoderMapItem {
+public:
+    VCMDecoderMapItem(VideoCodec* settings,
+                      WebRtc_UWord32 numberOfCores,
+                      bool requireKeyFrame);
+
+    VideoCodec*     _settings;
+    WebRtc_UWord32  _numberOfCores;
+    bool            _requireKeyFrame;
+};
+
+class VCMExtDecoderMapItem {
+public:
+    VCMExtDecoderMapItem(VideoDecoder* externalDecoderInstance,
+                         WebRtc_UWord8 payloadType,
+                         bool internalRenderTiming);
+
+    WebRtc_UWord8   _payloadType;
+    VideoDecoder*   _externalDecoderInstance;
+    bool            _internalRenderTiming;
+};
+
+/*******************************/
+/* VCMCodecDataBase class      */
+/*******************************/
+class VCMCodecDataBase
+{
+public:
+    VCMCodecDataBase(WebRtc_Word32 id);
+    ~VCMCodecDataBase();
+    /**
+    * Fills "version" with the version of all codecs supported.
+    */
+    WebRtc_Word32 Version(WebRtc_Word8* version,
+                        WebRtc_UWord32& remainingBufferInBytes,
+                        WebRtc_UWord32& position) const;
+    /**
+    * Release codecdatabase - release all memory for both send and receive side
+    */
+    WebRtc_Word32 Reset();
+    /**
+    * Sender Side
+    */
+    /**
+    * Returns the number of supported codecs (or -1 in case of error).
+    */
+    static WebRtc_UWord8 NumberOfCodecs();
+    /**
+    * Get supported codecs with ID
+    * Input Values:
+    *       listnr    : Requested codec id number
+    *       codec_inst: Pointer to the struct in which the returned codec information is copied
+    * Return Values: 0 if successful, otherwise
+    */
+    static WebRtc_Word32 Codec(WebRtc_UWord8 listId, VideoCodec* settings);
+    static WebRtc_Word32 Codec(VideoCodecType codecType, VideoCodec* settings);
+    /**
+    * Reset Sender side
+    */
+    WebRtc_Word32 ResetSender();
+    /**
+    * Setting the sender side codec and initiaiting the desired codec given the VideoCodec
+    * struct.
+    * Return Value:	0 if the codec and the settings are supported, otherwise
+    */
+    WebRtc_Word32 RegisterSendCodec(const VideoCodec* sendCodec,
+                                  WebRtc_UWord32 numberOfCores,
+                                  WebRtc_UWord32 maxPayloadSize);
+    /**
+    * Get current send side codec. Relevant for internal codecs only.
+    */
+    WebRtc_Word32 SendCodec(VideoCodec* currentSendCodec) const;
+    /**
+    * Get current send side codec type. Relevant for internal codecs only.
+    */
+    VideoCodecType SendCodec() const;
+    /**
+    * Register external encoder - current assumption - if one is registered then it will also
+    * be used, and therefore it is also initialized
+    * Return value: A pointer to the encoder on success, or null, in case of an error.
+    */
+    WebRtc_Word32 DeRegisterExternalEncoder(WebRtc_UWord8 payloadType, bool& wasSendCodec);
+    WebRtc_Word32 RegisterExternalEncoder(VideoEncoder* externalEncoder,
+                                        WebRtc_UWord8 payloadType,
+                                        bool internalSource);
+    /**
+    * Returns a encoder given a payloadname - to be used with internal encoders only.
+    * Special cases:
+    *	 Encoder exists -  If payload matches, returns existing one, otherwise,
+    *	 deletes existing one and creates new one.
+    *	 No match found / Error - returns NULL.
+    */
+    VCMGenericEncoder* SetEncoder(const VideoCodec* settings,
+                                  VCMEncodedFrameCallback* VCMencodedFrameCallback);
+
+    WebRtc_Word32 SetPeriodicKeyFrames(bool enable);
+
+    bool InternalSource() const;
+
+    /*
+    * Receiver Side
+    */
+    WebRtc_Word32 ResetReceiver();
+    /**
+    * Register external decoder/render object
+    */
+    WebRtc_Word32 DeRegisterExternalDecoder(WebRtc_UWord8 payloadType);
+    WebRtc_Word32 RegisterExternalDecoder(VideoDecoder* externalDecoder,
+                                        WebRtc_UWord8 payloadType,
+                                        bool internalRenderTiming);
+
+    bool DecoderRegistered() const;
+    /**
+    * Register recieve codec
+    */
+    WebRtc_Word32 RegisterReceiveCodec(const VideoCodec* receiveCodec,
+                                     WebRtc_UWord32 numberOfCores,
+                                     bool requireKeyFrame);
+    WebRtc_Word32 DeRegisterReceiveCodec(WebRtc_UWord8 payloadType);
+    /**
+    * Get current receive side codec. Relevant for internal codecs only.
+    */
+    WebRtc_Word32 ReceiveCodec(VideoCodec* currentReceiveCodec) const;
+    /**
+    * Get current receive side codec type. Relevant for internal codecs only.
+    */
+    VideoCodecType ReceiveCodec() const;
+    /**
+    * Returns a decoder given which matches a payload type.
+    * Special cases:
+    *	 Decoder exists -  If payload matches, returns existing one, otherwise, deletes
+    *	 existing one, and creates new one.
+    *	 No match found / Error - returns NULL.
+    */
+    VCMGenericDecoder* SetDecoder(WebRtc_UWord8 payloadType, VCMDecodedFrameCallback& callback);
+
+    VCMGenericDecoder* CreateAndInitDecoder(WebRtc_UWord8 payloadType,
+                                            VideoCodec& newCodec,
+                                            bool &external) const;
+
+    VCMGenericDecoder* CreateDecoderCopy() const;
+
+    void ReleaseDecoder(VCMGenericDecoder* decoder) const;
+
+    void CopyDecoder(const VCMGenericDecoder& decoder);
+
+    bool RenderTiming() const;
+
+    WebRtc_Word32 SetCodecConfigParameters(WebRtc_UWord8 payloadType,
+                                         const WebRtc_UWord8* buffer,
+                                         WebRtc_Word32 length);
+
+protected:
+    /**
+    * Create an internal Encoder given a codec type
+    */
+    VCMGenericEncoder* CreateEncoder(VideoCodecType type) const;
+
+    void DeleteEncoder();
+    /*
+    * Create an internal Decoder given a codec type
+    */
+    VCMGenericDecoder* CreateDecoder(VideoCodecType type) const;
+
+    static void SetCodecConfigParameters(VCMGenericDecoder& decoder,
+                                         const VideoCodec& settings);
+
+    VCMDecoderMapItem* FindDecoderItem(WebRtc_UWord8 payloadType) const;
+
+    VCMExtDecoderMapItem* FindExternalDecoderItem(WebRtc_UWord8 payloadType) const;
+
+private:
+    WebRtc_Word32         _id;
+    WebRtc_UWord32        _numberOfCores;
+    WebRtc_UWord32        _maxPayloadSize;
+    bool                  _periodicKeyFrames;
+    bool                  _currentEncIsExternal;
+    VideoCodec            _sendCodec;
+    VideoCodec            _receiveCodec;
+    WebRtc_UWord8         _externalPayloadType;
+    VideoEncoder*         _externalEncoder;
+    bool                  _internalSource;
+    VCMGenericEncoder*    _ptrEncoder;
+    VCMGenericDecoder*    _ptrDecoder;
+    bool                  _currentDecIsExternal;
+    MapWrapper               _decMap;
+    MapWrapper               _decExternalMap;
+
+}; // end of VCMCodecDataBase class definition
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_CODEC_DATABASE_H_
diff --git a/src/modules/video_coding/main/source/codec_timer.cc b/src/modules/video_coding/main/source/codec_timer.cc
new file mode 100644
index 0000000..1d112fa
--- /dev/null
+++ b/src/modules/video_coding/main/source/codec_timer.cc
@@ -0,0 +1,133 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "codec_timer.h"
+
+#include <assert.h>
+
+namespace webrtc
+{
+
+VCMCodecTimer::VCMCodecTimer()
+:
+_filteredMax(0),
+_firstDecodeTime(true),
+_shortMax(0),
+_history()
+{
+    Reset();
+}
+
+WebRtc_Word32 VCMCodecTimer::StopTimer(WebRtc_Word64 startTimeMs, WebRtc_Word64 nowMs)
+{
+    const WebRtc_Word32 timeDiff = static_cast<WebRtc_Word32>(nowMs - startTimeMs);
+    MaxFilter(timeDiff, nowMs);
+    return timeDiff;
+}
+
+void VCMCodecTimer::Reset()
+{
+    _filteredMax = 0;
+    _firstDecodeTime = true;
+    _shortMax = 0;
+    for (int i=0; i < MAX_HISTORY_SIZE; i++)
+    {
+        _history[i].shortMax = 0;
+        _history[i].timeMs = -1;
+    }
+}
+
+// Update the max-value filter
+void VCMCodecTimer::MaxFilter(WebRtc_Word32 decodeTime, WebRtc_Word64 nowMs)
+{
+    if (!_firstDecodeTime)
+    {
+        UpdateMaxHistory(decodeTime, nowMs);
+        ProcessHistory(nowMs);
+    }
+    else
+    {
+        _firstDecodeTime = false;
+    }
+}
+
+void
+VCMCodecTimer::UpdateMaxHistory(WebRtc_Word32 decodeTime, WebRtc_Word64 now)
+{
+    if (_history[0].timeMs >= 0 &&
+        now - _history[0].timeMs < SHORT_FILTER_MS)
+    {
+        if (decodeTime > _shortMax)
+        {
+            _shortMax = decodeTime;
+        }
+    }
+    else
+    {
+        // Only add a new value to the history once a second
+        if(_history[0].timeMs == -1)
+        {
+            // First, no shift
+            _shortMax = decodeTime;
+        }
+        else
+        {
+            // Shift
+            for(int i = (MAX_HISTORY_SIZE - 2); i >= 0 ; i--)
+            {
+                _history[i+1].shortMax = _history[i].shortMax;
+                _history[i+1].timeMs = _history[i].timeMs;
+            }
+        }
+        if (_shortMax == 0)
+        {
+            _shortMax = decodeTime;
+        }
+
+        _history[0].shortMax = _shortMax;
+        _history[0].timeMs = now;
+        _shortMax = 0;
+    }
+}
+
+void
+VCMCodecTimer::ProcessHistory(WebRtc_Word64 nowMs)
+{
+    _filteredMax = _shortMax;
+    if (_history[0].timeMs == -1)
+    {
+        return;
+    }
+    for (int i=0; i < MAX_HISTORY_SIZE; i++)
+    {
+        if (_history[i].timeMs == -1)
+        {
+            break;
+        }
+        if (nowMs - _history[i].timeMs > MAX_HISTORY_SIZE * SHORT_FILTER_MS)
+        {
+            // This sample (and all samples after this) is too old
+            break;
+        }
+        if (_history[i].shortMax > _filteredMax)
+        {
+            // This sample is the largest one this far into the history
+            _filteredMax = _history[i].shortMax;
+        }
+    }
+}
+
+// Get the maximum observed time within a time window
+WebRtc_Word32 VCMCodecTimer::RequiredDecodeTimeMs(FrameType /*frameType*/) const
+{
+    return _filteredMax;
+}
+
+}
diff --git a/src/modules/video_coding/main/source/codec_timer.h b/src/modules/video_coding/main/source/codec_timer.h
new file mode 100644
index 0000000..e03c5bf
--- /dev/null
+++ b/src/modules/video_coding/main/source/codec_timer.h
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_CODEC_TIMER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_CODEC_TIMER_H_
+
+#include "typedefs.h"
+#include "module_common_types.h"
+
+namespace webrtc
+{
+
+// MAX_HISTORY_SIZE * SHORT_FILTER_MS defines the window size in milliseconds
+#define MAX_HISTORY_SIZE 20
+#define SHORT_FILTER_MS 1000
+
+class VCMShortMaxSample
+{
+public:
+    VCMShortMaxSample() : shortMax(0), timeMs(-1) {};
+
+    WebRtc_Word32     shortMax;
+    WebRtc_Word64     timeMs;
+};
+
+class VCMCodecTimer
+{
+public:
+    VCMCodecTimer();
+
+    // Updates and returns the max filtered decode time.
+    WebRtc_Word32 StopTimer(WebRtc_Word64 startTimeMs, WebRtc_Word64 nowMs);
+
+    // Empty the list of timers.
+    void Reset();
+
+    // Get the required decode time in ms.
+    WebRtc_Word32 RequiredDecodeTimeMs(FrameType frameType) const;
+
+private:
+    void UpdateMaxHistory(WebRtc_Word32 decodeTime, WebRtc_Word64 now);
+    void MaxFilter(WebRtc_Word32 newTime, WebRtc_Word64 nowMs);
+    void ProcessHistory(WebRtc_Word64 nowMs);
+
+    WebRtc_Word32                     _filteredMax;
+    bool                              _firstDecodeTime;
+    WebRtc_Word32                     _shortMax;
+    VCMShortMaxSample                 _history[MAX_HISTORY_SIZE];
+
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_CODEC_TIMER_H_
diff --git a/src/modules/video_coding/main/source/content_metrics_processing.cc b/src/modules/video_coding/main/source/content_metrics_processing.cc
new file mode 100644
index 0000000..5206da0
--- /dev/null
+++ b/src/modules/video_coding/main/source/content_metrics_processing.cc
@@ -0,0 +1,213 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "content_metrics_processing.h"
+#include "tick_time.h"
+#include "module_common_types.h"
+#include "video_coding_defines.h"
+
+#include <math.h>
+
+namespace webrtc {
+
+//////////////////////////////////
+/// VCMContentMetricsProcessing //
+//////////////////////////////////
+
+VCMContentMetricsProcessing::VCMContentMetricsProcessing():
+_frameRate(0),
+_recAvgFactor(1 / 150.0f), // matched to  30fps
+_frameCntRecursiveAvg(0),
+_frameCntUniformAvg(0),
+_avgMotionLevel(0.0f),
+_avgSpatialLevel(0.0f)
+{
+    _recursiveAvg = new VideoContentMetrics();
+    _uniformAvg = new VideoContentMetrics();
+}
+
+VCMContentMetricsProcessing::~VCMContentMetricsProcessing()
+{
+    delete _recursiveAvg;
+    delete _uniformAvg;
+}
+
+WebRtc_Word32
+VCMContentMetricsProcessing::Reset()
+{
+    _recursiveAvg->Reset();
+    _uniformAvg->Reset();
+    _frameRate = 0;
+    _frameCntRecursiveAvg = 0;
+    _frameCntUniformAvg = 0;
+    _avgMotionLevel  = 0.0f;
+    _avgSpatialLevel = 0.0f;
+    return VCM_OK;
+}
+
+void
+VCMContentMetricsProcessing::UpdateFrameRate(WebRtc_UWord32 frameRate)
+{
+    _frameRate = frameRate;
+    // Update factor for recursive averaging.
+    _recAvgFactor = (float) 1000.0f / ((float)(_frameRate *  kQmMinIntervalMs));
+
+}
+
+VideoContentMetrics*
+VCMContentMetricsProcessing::LongTermAvgData()
+{
+    if (_frameCntRecursiveAvg == 0)
+    {
+        return NULL;
+    }
+    return _recursiveAvg;
+}
+
+VideoContentMetrics*
+VCMContentMetricsProcessing::ShortTermAvgData()
+{
+    if (_frameCntUniformAvg == 0)
+    {
+        return NULL;
+    }
+
+    // Two metrics are used: motion and spatial level.
+    _uniformAvg->motionMagnitudeNZ = _avgMotionLevel /
+        (float)(_frameCntUniformAvg);
+    _uniformAvg->spatialPredErr = _avgSpatialLevel /
+        (float)(_frameCntUniformAvg);
+
+    return _uniformAvg;
+}
+
+void
+VCMContentMetricsProcessing::ResetShortTermAvgData()
+{
+     // Reset
+    _avgMotionLevel = 0.0f;
+    _avgSpatialLevel = 0.0f;
+    _frameCntUniformAvg = 0;
+}
+
+WebRtc_Word32
+VCMContentMetricsProcessing::UpdateContentData(const VideoContentMetrics *contentMetrics)
+{
+    if (contentMetrics == NULL)
+    {
+        return VCM_OK;
+    }
+    return ProcessContent(contentMetrics);
+
+}
+
+WebRtc_UWord32
+VCMContentMetricsProcessing::ProcessContent(const VideoContentMetrics *contentMetrics)
+{
+    // Update the recursive averaged metrics
+    // average is over longer window of time: over QmMinIntervalMs ms.
+    UpdateRecursiveAvg(contentMetrics);
+
+    // Update the uniform averaged metrics:
+    // average is over shorter window of time: based on ~RTCP reports.
+    UpdateUniformAvg(contentMetrics);
+
+    return VCM_OK;
+}
+
+void
+VCMContentMetricsProcessing::UpdateUniformAvg(const VideoContentMetrics *contentMetrics)
+{
+
+    // Update frame counter
+    _frameCntUniformAvg += 1;
+
+    // Update averaged metrics: motion and spatial level are used.
+    _avgMotionLevel += contentMetrics->motionMagnitudeNZ;
+    _avgSpatialLevel +=  contentMetrics->spatialPredErr;
+
+    return;
+
+}
+void
+VCMContentMetricsProcessing::UpdateRecursiveAvg(const VideoContentMetrics *contentMetrics)
+{
+
+    // Threshold for size of zero motion cluster:
+    // Use for updating 3 motion vector derived metrics:
+    // motion magnitude, cluster distortion, and horizontalness.
+    float nonZeroMvThr = 0.1f;
+
+    float tmpRecAvgFactor  = _recAvgFactor;
+
+    // Take value as is for first frame (no motion search in frame zero).
+    if (_frameCntRecursiveAvg < 1)
+    {
+        tmpRecAvgFactor = 1;
+    }
+
+    _recursiveAvg->motionPredErr = (1 - tmpRecAvgFactor) *
+        _recursiveAvg->motionPredErr +
+        tmpRecAvgFactor * contentMetrics->motionPredErr;
+
+    _recursiveAvg->sizeZeroMotion = (1 - tmpRecAvgFactor) *
+        _recursiveAvg->sizeZeroMotion +
+        tmpRecAvgFactor * contentMetrics->sizeZeroMotion;
+
+    _recursiveAvg->spatialPredErr = (1 - tmpRecAvgFactor) *
+        _recursiveAvg->spatialPredErr +
+        tmpRecAvgFactor * contentMetrics->spatialPredErr;
+
+    _recursiveAvg->spatialPredErrH = (1 - tmpRecAvgFactor) *
+        _recursiveAvg->spatialPredErrH +
+        tmpRecAvgFactor * contentMetrics->spatialPredErrH;
+
+    _recursiveAvg->spatialPredErrV = (1 - tmpRecAvgFactor) *
+        _recursiveAvg->spatialPredErrV +
+        tmpRecAvgFactor * contentMetrics->spatialPredErrV;
+
+    // motionMag metric is derived from NFD (normalized frame difference).
+    if (kNfdMetric == 1)
+    {
+        _recursiveAvg->motionMagnitudeNZ = (1 - tmpRecAvgFactor) *
+            _recursiveAvg->motionMagnitudeNZ +
+            tmpRecAvgFactor * contentMetrics->motionMagnitudeNZ;
+    }
+
+    if (contentMetrics->sizeZeroMotion > nonZeroMvThr)
+    {
+        _recursiveAvg->motionClusterDistortion = (1 - tmpRecAvgFactor) *
+            _recursiveAvg->motionClusterDistortion +
+            tmpRecAvgFactor *contentMetrics->motionClusterDistortion;
+
+        _recursiveAvg->motionHorizontalness = (1 - _recAvgFactor) *
+            _recursiveAvg->motionHorizontalness +
+            tmpRecAvgFactor * contentMetrics->motionHorizontalness;
+
+        // motionMag metric is derived from motion vectors.
+        if (kNfdMetric == 0)
+        {
+            _recursiveAvg->motionMagnitudeNZ = (1 - tmpRecAvgFactor) *
+                _recursiveAvg->motionMagnitudeNZ +
+                tmpRecAvgFactor * contentMetrics->motionMagnitudeNZ;
+        }
+    }
+
+    // Update native values:
+    // TODO (marpan): we don't need to update this every frame.
+    _recursiveAvg->nativeHeight = contentMetrics->nativeHeight;
+    _recursiveAvg->nativeWidth = contentMetrics->nativeWidth;
+    _recursiveAvg->nativeFrameRate = contentMetrics->nativeFrameRate;
+
+    _frameCntRecursiveAvg++;
+
+    return;
+}
+} //end of namespace
diff --git a/src/modules/video_coding/main/source/content_metrics_processing.h b/src/modules/video_coding/main/source/content_metrics_processing.h
new file mode 100644
index 0000000..155c4ad
--- /dev/null
+++ b/src/modules/video_coding/main/source/content_metrics_processing.h
@@ -0,0 +1,78 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_CONTENT_METRICS_PROCESSING_H_
+#define WEBRTC_MODULES_VIDEO_CODING_CONTENT_METRICS_PROCESSING_H_
+
+#include "typedefs.h"
+
+namespace webrtc
+{
+
+struct VideoContentMetrics;
+
+// QM interval time (in ms)
+enum { kQmMinIntervalMs = 10000 };
+
+// Flag for NFD metric vs motion metric
+enum { kNfdMetric = 1 };
+
+/**********************************/
+/* Content Metrics Processing     */
+/**********************************/
+class VCMContentMetricsProcessing
+{
+public:
+    VCMContentMetricsProcessing();
+    ~VCMContentMetricsProcessing();
+
+    // Update class with latest metrics
+    WebRtc_Word32 UpdateContentData(const VideoContentMetrics *contentMetrics);
+
+    // Reset the short-term averaged content data
+     void ResetShortTermAvgData();
+
+    // Initialize to
+    WebRtc_Word32 Reset();
+
+    // Inform class of current frame rate
+    void UpdateFrameRate(WebRtc_UWord32 frameRate);
+
+    // Returns the long-term averaged content data:
+    // recursive average over longer time scale
+    VideoContentMetrics* LongTermAvgData();
+
+    // Returns the short-term averaged content data:
+    // uniform average over shorter time scale
+     VideoContentMetrics* ShortTermAvgData();
+private:
+
+    // Compute working avg
+    WebRtc_UWord32 ProcessContent(const VideoContentMetrics *contentMetrics);
+
+    // Update the recursive averaged metrics: longer time average (~5/10 secs).
+    void UpdateRecursiveAvg(const VideoContentMetrics *contentMetrics);
+
+    // Update the uniform averaged metrics: shorter time average (~RTCP reports).
+    void UpdateUniformAvg(const VideoContentMetrics *contentMetrics);
+
+    VideoContentMetrics*    _recursiveAvg;
+    VideoContentMetrics*    _uniformAvg;
+    WebRtc_UWord32          _frameRate;
+    float                   _recAvgFactor;
+    WebRtc_UWord32          _frameCntRecursiveAvg;
+    WebRtc_UWord32          _frameCntUniformAvg;
+    float                   _avgMotionLevel;
+    float                   _avgSpatialLevel;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_CONTENT_METRICS_PROCESSING_H_
diff --git a/src/modules/video_coding/main/source/encoded_frame.cc b/src/modules/video_coding/main/source/encoded_frame.cc
new file mode 100644
index 0000000..4515ca0
--- /dev/null
+++ b/src/modules/video_coding/main/source/encoded_frame.cc
@@ -0,0 +1,201 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "encoded_frame.h"
+#include "generic_encoder.h"
+#include "jitter_buffer_common.h"
+#include "video_coding_defines.h"
+
+namespace webrtc {
+
+VCMEncodedFrame::VCMEncodedFrame()
+:
+webrtc::EncodedImage(),
+_renderTimeMs(-1),
+_payloadType(0),
+_missingFrame(false),
+_codecSpecificInfo(NULL),
+_codecSpecificInfoLength(0),
+_codec(kVideoCodecUnknown)
+{
+}
+
+VCMEncodedFrame::VCMEncodedFrame(const webrtc::EncodedImage& rhs)
+:
+webrtc::EncodedImage(rhs),
+_renderTimeMs(-1),
+_payloadType(0),
+_missingFrame(false),
+_codecSpecificInfo(NULL),
+_codecSpecificInfoLength(0),
+_codec(kVideoCodecUnknown)
+{
+    _buffer = NULL;
+    _size = NULL;
+    _length = NULL;
+    if (rhs._buffer != NULL)
+    {
+        VerifyAndAllocate(rhs._length);
+        memcpy(_buffer, rhs._buffer, rhs._length);
+    }
+}
+
+VCMEncodedFrame::VCMEncodedFrame(const VCMEncodedFrame& rhs)
+:
+webrtc::EncodedImage(rhs),
+_renderTimeMs(rhs._renderTimeMs),
+_payloadType(rhs._payloadType),
+_missingFrame(rhs._missingFrame),
+_codecSpecificInfo(NULL),
+_codecSpecificInfoLength(0),
+_codec(rhs._codec)
+{
+    _buffer = NULL;
+    _size = NULL;
+    _length = NULL;
+    if (rhs._buffer != NULL)
+    {
+        VerifyAndAllocate(rhs._size);
+        memcpy(_buffer, rhs._buffer, rhs._length);
+    }
+}
+
+VCMEncodedFrame::~VCMEncodedFrame()
+{
+    Free();
+}
+
+void VCMEncodedFrame::Free()
+{
+    Reset();
+    if (_buffer != NULL)
+    {
+        delete [] _buffer;
+        _buffer = NULL;
+    }
+}
+
+void VCMEncodedFrame::Reset()
+{
+    _renderTimeMs = -1;
+    _timeStamp = 0;
+    _payloadType = 0;
+    _codecSpecificInfo = NULL;
+    _codecSpecificInfoLength = 0;
+    _frameType = kDeltaFrame;
+    _encodedWidth = 0;
+    _encodedHeight = 0;
+    _completeFrame = false;
+    _missingFrame = false;
+    _length = 0;
+    _codec = kVideoCodecUnknown;
+}
+
+WebRtc_Word32
+VCMEncodedFrame::Store(VCMFrameStorageCallback& storeCallback) const
+{
+    EncodedVideoData frameToStore;
+    frameToStore.codec = _codec;
+    if (_buffer != NULL)
+    {
+        frameToStore.VerifyAndAllocate(_length);
+        memcpy(frameToStore.payloadData, _buffer, _length);
+        frameToStore.payloadSize = _length;
+    }
+    frameToStore.completeFrame = _completeFrame;
+    frameToStore.encodedWidth = _encodedWidth;
+    frameToStore.encodedHeight = _encodedHeight;
+    frameToStore.frameType = ConvertFrameType(_frameType);
+    frameToStore.missingFrame = _missingFrame;
+    frameToStore.payloadType = _payloadType;
+    frameToStore.renderTimeMs = _renderTimeMs;
+    frameToStore.timeStamp = _timeStamp;
+    storeCallback.StoreReceivedFrame(frameToStore);
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMEncodedFrame::VerifyAndAllocate(const WebRtc_UWord32 minimumSize)
+{
+    if(minimumSize > _size)
+    {
+        // create buffer of sufficient size
+        WebRtc_UWord8* newBuffer = new WebRtc_UWord8[minimumSize];
+        if (newBuffer == NULL)
+        {
+            return -1;
+        }
+        if(_buffer)
+        {
+            // copy old data
+            memcpy(newBuffer, _buffer, _size);
+            delete [] _buffer;
+        }
+        _buffer = newBuffer;
+        _size = minimumSize;
+    }
+    return 0;
+}
+
+webrtc::FrameType VCMEncodedFrame::ConvertFrameType(VideoFrameType frameType)
+{
+    switch(frameType)
+    {
+    case kKeyFrame:
+        {
+            return  kVideoFrameKey;
+        }
+    case kDeltaFrame:
+        {
+            return kVideoFrameDelta;
+        }
+    case kGoldenFrame:
+        {
+            return kVideoFrameGolden;
+        }
+    case kAltRefFrame:
+        {
+            return kVideoFrameAltRef;
+        }
+    default:
+        {
+            return kVideoFrameDelta;
+        }
+    }
+}
+
+VideoFrameType VCMEncodedFrame::ConvertFrameType(webrtc::FrameType frameType)
+{
+    switch (frameType)
+    {
+    case kVideoFrameKey:
+        {
+            return kKeyFrame;
+        }
+    case kVideoFrameDelta:
+        {
+            return kDeltaFrame;
+        }
+    case kVideoFrameGolden:
+        {
+            return kGoldenFrame;
+        }
+    case kVideoFrameAltRef:
+        {
+            return kAltRefFrame;
+        }
+    default:
+        {
+            return kDeltaFrame;
+        }
+    }
+}
+
+}
diff --git a/src/modules/video_coding/main/source/encoded_frame.h b/src/modules/video_coding/main/source/encoded_frame.h
new file mode 100644
index 0000000..89cbd5e
--- /dev/null
+++ b/src/modules/video_coding/main/source/encoded_frame.h
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_ENCODED_FRAME_H_
+#define WEBRTC_MODULES_VIDEO_CODING_ENCODED_FRAME_H_
+
+#include "module_common_types.h"
+#include "common_types.h"
+#include "video_coding_defines.h"
+#include "video_image.h"
+
+namespace webrtc
+{
+
+class VCMEncodedFrame : protected EncodedImage
+{
+public:
+    VCMEncodedFrame();
+    VCMEncodedFrame(const webrtc::EncodedImage& rhs);
+    VCMEncodedFrame(const VCMEncodedFrame& rhs);
+
+    ~VCMEncodedFrame();
+    /**
+    *   Delete VideoFrame and resets members to zero
+    */
+    void Free();
+    /**
+    *   Set render time in milliseconds
+    */
+    void SetRenderTime(const WebRtc_Word64 renderTimeMs) {_renderTimeMs = renderTimeMs;}
+
+    /**
+    *   Set the encoded frame size
+    */
+    void SetEncodedSize(WebRtc_UWord32 width, WebRtc_UWord32 height)
+                       { _encodedWidth  = width; _encodedHeight = height; }
+    /**
+    *   Get the encoded image
+    */
+    const webrtc::EncodedImage& EncodedImage() const
+                       { return static_cast<const webrtc::EncodedImage&>(*this); }
+    /**
+    *   Get pointer to frame buffer
+    */
+    const WebRtc_UWord8* Buffer() const {return _buffer;}
+    /**
+    *   Get frame length
+    */
+    WebRtc_UWord32 Length() const {return _length;}
+    /**
+    *   Get frame timestamp (90kHz)
+    */
+    WebRtc_UWord32 TimeStamp() const {return _timeStamp;}
+    /**
+    *   Get render time in milliseconds
+    */
+    WebRtc_Word64 RenderTimeMs() const {return _renderTimeMs;}
+    /**
+    *   Get frame type
+    */
+    webrtc::FrameType FrameType() const {return ConvertFrameType(_frameType);}
+    /**
+    *   True if this frame is complete, false otherwise
+    */
+    bool Complete() const { return _completeFrame; }
+    /**
+    *   True if there's a frame missing before this frame
+    */
+    bool MissingFrame() const { return _missingFrame; }
+    /**
+    *   Payload type of the encoded payload
+    */
+    WebRtc_UWord8 PayloadType() const { return _payloadType; }
+    /**
+    *   Get codec specific info
+    */
+    const void* CodecSpecificInfo() const {return _codecSpecificInfo;}
+
+    WebRtc_Word32 Store(VCMFrameStorageCallback& storeCallback) const;
+
+    static webrtc::FrameType ConvertFrameType(VideoFrameType frameType);
+    static VideoFrameType ConvertFrameType(webrtc::FrameType frameType);
+
+protected:
+    /**
+    * Verifies that current allocated buffer size is larger than or equal to the input size.
+    * If the current buffer size is smaller, a new allocation is made and the old buffer data
+    * is copied to the new buffer.
+    * Buffer size is updated to minimumSize.
+    */
+    WebRtc_Word32 VerifyAndAllocate(const WebRtc_UWord32 minimumSize);
+
+    void Reset();
+
+    WebRtc_Word64                 _renderTimeMs;
+    WebRtc_UWord8                 _payloadType;
+    bool                          _missingFrame;
+    void*                         _codecSpecificInfo;
+    WebRtc_UWord32                _codecSpecificInfoLength;
+    webrtc::VideoCodecType        _codec;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_ENCODED_FRAME_H_
diff --git a/src/modules/video_coding/main/source/er_tables_xor.h b/src/modules/video_coding/main/source/er_tables_xor.h
new file mode 100644
index 0000000..7dc5191
--- /dev/null
+++ b/src/modules/video_coding/main/source/er_tables_xor.h
@@ -0,0 +1,38728 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_SOURCE_ER_TABLES_XOR_H_
+#define WEBRTC_MODULES_VIDEO_CODING_SOURCE_ER_TABLES_XOR_H_
+
+namespace webrtc
+{
+
+// Table for average FEC recovery from packet loss, for XOR code.
+// From RPL model of random loss.
+// Input is the received packet loss (up to 50%), and FEC code parameters (up to 24x24):
+// i.e., averageFECRecoveryRS[k] where k= code_i*129 + loss_j;
+// code_i=1x1,2x1,2x2,..24x24, loss_j=0,1,..128.
+const unsigned char VCMAvgFECRecoveryXOR[38700] = {
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+37,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+52,
+53,
+53,
+54,
+54,
+54,
+55,
+55,
+55,
+56,
+56,
+56,
+57,
+57,
+57,
+58,
+58,
+58,
+59,
+59,
+59,
+59,
+60,
+60,
+60,
+60,
+60,
+61,
+61,
+61,
+61,
+61,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+32,
+31,
+31,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+39,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+45,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+56,
+57,
+57,
+58,
+58,
+58,
+59,
+59,
+59,
+60,
+60,
+60,
+60,
+61,
+61,
+61,
+61,
+62,
+62,
+62,
+62,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+64,
+63,
+63,
+63,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+21,
+22,
+22,
+22,
+23,
+23,
+23,
+23,
+24,
+24,
+24,
+24,
+25,
+25,
+25,
+25,
+25,
+25,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+24,
+24,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+15,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+41,
+42,
+42,
+43,
+43,
+43,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+46,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+46,
+46,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+0,
+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,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+49,
+50,
+51,
+51,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+59,
+59,
+60,
+60,
+61,
+61,
+61,
+62,
+62,
+62,
+63,
+63,
+63,
+63,
+64,
+64,
+64,
+64,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+64,
+64,
+64,
+64,
+63,
+63,
+63,
+63,
+62,
+62,
+62,
+61,
+61,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+18,
+18,
+19,
+19,
+19,
+19,
+19,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+25,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+51,
+51,
+52,
+52,
+52,
+52,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+47,
+46,
+46,
+45,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+55,
+56,
+57,
+57,
+58,
+58,
+59,
+59,
+60,
+60,
+61,
+61,
+62,
+62,
+62,
+63,
+63,
+64,
+64,
+64,
+65,
+65,
+65,
+65,
+66,
+66,
+66,
+66,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+68,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+66,
+66,
+66,
+66,
+65,
+65,
+65,
+65,
+64,
+64,
+64,
+63,
+63,
+63,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+26,
+27,
+27,
+28,
+28,
+28,
+28,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+31,
+31,
+31,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+39,
+40,
+40,
+41,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+44,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+46,
+46,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+40,
+40,
+40,
+39,
+39,
+39,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+34,
+0,
+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,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+43,
+43,
+44,
+44,
+45,
+46,
+46,
+47,
+47,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+51,
+52,
+52,
+53,
+53,
+53,
+54,
+54,
+54,
+55,
+55,
+55,
+55,
+56,
+56,
+56,
+56,
+56,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+56,
+56,
+56,
+56,
+56,
+55,
+55,
+55,
+55,
+55,
+54,
+54,
+54,
+53,
+53,
+53,
+52,
+52,
+52,
+51,
+51,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+59,
+60,
+60,
+61,
+61,
+61,
+62,
+62,
+63,
+63,
+64,
+64,
+64,
+65,
+65,
+65,
+66,
+66,
+66,
+66,
+67,
+67,
+67,
+67,
+67,
+67,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+67,
+67,
+67,
+67,
+67,
+67,
+66,
+66,
+66,
+66,
+65,
+65,
+65,
+64,
+64,
+64,
+63,
+63,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+5,
+6,
+7,
+7,
+8,
+8,
+9,
+9,
+10,
+10,
+11,
+11,
+11,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+22,
+23,
+23,
+24,
+24,
+24,
+25,
+25,
+25,
+25,
+26,
+26,
+26,
+26,
+26,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+25,
+25,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+25,
+0,
+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,
+25,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+48,
+48,
+48,
+49,
+49,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+49,
+49,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+46,
+46,
+45,
+45,
+45,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+33,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+56,
+57,
+57,
+57,
+58,
+58,
+58,
+58,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+58,
+58,
+58,
+58,
+57,
+57,
+57,
+56,
+56,
+56,
+55,
+55,
+55,
+54,
+54,
+53,
+53,
+52,
+52,
+51,
+51,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+46,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+50,
+50,
+51,
+52,
+53,
+53,
+54,
+55,
+55,
+56,
+57,
+57,
+58,
+58,
+59,
+60,
+60,
+61,
+61,
+62,
+62,
+63,
+63,
+63,
+64,
+64,
+64,
+65,
+65,
+65,
+66,
+66,
+66,
+66,
+66,
+66,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+66,
+66,
+66,
+66,
+66,
+66,
+65,
+65,
+65,
+64,
+64,
+64,
+63,
+63,
+63,
+62,
+62,
+61,
+61,
+60,
+60,
+59,
+59,
+58,
+57,
+57,
+56,
+55,
+55,
+54,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+9,
+9,
+10,
+10,
+10,
+11,
+11,
+11,
+11,
+11,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+19,
+20,
+20,
+20,
+21,
+21,
+21,
+22,
+22,
+22,
+22,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+32,
+32,
+32,
+32,
+33,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+28,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+39,
+39,
+40,
+40,
+41,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+43,
+44,
+44,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+40,
+40,
+40,
+39,
+39,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+0,
+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,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+51,
+52,
+52,
+52,
+52,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+59,
+59,
+59,
+60,
+60,
+60,
+61,
+61,
+61,
+61,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+63,
+63,
+63,
+63,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+61,
+61,
+61,
+61,
+60,
+60,
+60,
+59,
+59,
+58,
+58,
+58,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+54,
+53,
+52,
+52,
+51,
+51,
+50,
+49,
+49,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+55,
+55,
+56,
+57,
+57,
+58,
+59,
+59,
+60,
+61,
+61,
+62,
+62,
+63,
+63,
+64,
+64,
+65,
+65,
+65,
+66,
+66,
+66,
+67,
+67,
+67,
+68,
+68,
+68,
+68,
+68,
+68,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+68,
+68,
+68,
+68,
+68,
+68,
+67,
+67,
+67,
+67,
+66,
+66,
+65,
+65,
+65,
+64,
+64,
+63,
+63,
+62,
+62,
+61,
+61,
+60,
+59,
+59,
+58,
+57,
+57,
+56,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+9,
+9,
+9,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+18,
+18,
+19,
+19,
+19,
+19,
+20,
+20,
+20,
+20,
+20,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+27,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+30,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+0,
+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,
+26,
+26,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+42,
+43,
+43,
+43,
+44,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+46,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+27,
+26,
+25,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+36,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+44,
+45,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+53,
+53,
+53,
+54,
+54,
+54,
+55,
+55,
+55,
+55,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+55,
+55,
+55,
+55,
+54,
+54,
+54,
+54,
+53,
+53,
+53,
+52,
+52,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+41,
+41,
+40,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+51,
+52,
+53,
+53,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+59,
+59,
+60,
+60,
+60,
+61,
+61,
+61,
+62,
+62,
+62,
+62,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+62,
+62,
+62,
+62,
+61,
+61,
+61,
+60,
+60,
+60,
+59,
+59,
+58,
+58,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+54,
+53,
+52,
+52,
+51,
+50,
+50,
+49,
+48,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+55,
+56,
+56,
+57,
+58,
+59,
+59,
+60,
+61,
+61,
+62,
+63,
+63,
+64,
+65,
+65,
+66,
+66,
+67,
+67,
+68,
+68,
+68,
+69,
+69,
+69,
+70,
+70,
+70,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+70,
+70,
+70,
+69,
+69,
+69,
+68,
+68,
+67,
+67,
+66,
+66,
+65,
+65,
+64,
+64,
+63,
+62,
+62,
+61,
+60,
+59,
+59,
+58,
+57,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+6,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+18,
+18,
+18,
+18,
+18,
+18,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+24,
+25,
+25,
+25,
+26,
+26,
+26,
+26,
+27,
+27,
+27,
+27,
+27,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+25,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+16,
+15,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+40,
+41,
+41,
+42,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+40,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+0,
+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,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+46,
+47,
+47,
+48,
+48,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+51,
+51,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+34,
+33,
+33,
+32,
+31,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+49,
+50,
+50,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+56,
+57,
+57,
+57,
+58,
+58,
+58,
+58,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+58,
+58,
+58,
+58,
+57,
+57,
+57,
+56,
+56,
+56,
+55,
+55,
+54,
+54,
+53,
+53,
+52,
+52,
+51,
+51,
+50,
+49,
+49,
+48,
+48,
+47,
+46,
+46,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+56,
+56,
+57,
+58,
+58,
+59,
+59,
+60,
+60,
+61,
+61,
+62,
+62,
+63,
+63,
+63,
+64,
+64,
+64,
+64,
+65,
+65,
+65,
+65,
+65,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+65,
+65,
+65,
+65,
+65,
+65,
+64,
+64,
+64,
+63,
+63,
+63,
+62,
+62,
+61,
+61,
+60,
+60,
+59,
+59,
+58,
+58,
+57,
+56,
+56,
+55,
+54,
+54,
+53,
+52,
+52,
+51,
+50,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+51,
+52,
+53,
+54,
+55,
+55,
+56,
+57,
+58,
+58,
+59,
+60,
+61,
+61,
+62,
+62,
+63,
+64,
+64,
+65,
+65,
+66,
+66,
+67,
+67,
+68,
+68,
+68,
+69,
+69,
+69,
+70,
+70,
+70,
+70,
+70,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+71,
+70,
+70,
+70,
+70,
+70,
+69,
+69,
+69,
+68,
+68,
+67,
+67,
+66,
+66,
+65,
+65,
+64,
+64,
+63,
+63,
+62,
+61,
+61,
+60,
+59,
+58,
+58,
+57,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+5,
+6,
+6,
+7,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+22,
+23,
+23,
+23,
+24,
+24,
+24,
+24,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+24,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+39,
+39,
+39,
+39,
+40,
+40,
+40,
+40,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+40,
+40,
+40,
+40,
+40,
+40,
+39,
+39,
+39,
+38,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+0,
+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,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+0,
+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,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+45,
+45,
+46,
+47,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+52,
+52,
+52,
+53,
+53,
+53,
+53,
+53,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+54,
+53,
+53,
+53,
+53,
+52,
+52,
+52,
+51,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+50,
+51,
+52,
+52,
+53,
+53,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+57,
+58,
+58,
+59,
+59,
+59,
+60,
+60,
+60,
+60,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+61,
+60,
+60,
+60,
+60,
+59,
+59,
+59,
+58,
+58,
+57,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+53,
+53,
+52,
+52,
+51,
+51,
+50,
+49,
+49,
+48,
+47,
+47,
+46,
+45,
+44,
+44,
+0,
+1,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+56,
+56,
+57,
+58,
+58,
+59,
+59,
+60,
+60,
+60,
+61,
+61,
+62,
+62,
+62,
+63,
+63,
+63,
+63,
+63,
+63,
+64,
+64,
+64,
+64,
+64,
+64,
+63,
+63,
+63,
+63,
+63,
+62,
+62,
+62,
+62,
+61,
+61,
+60,
+60,
+59,
+59,
+58,
+58,
+57,
+57,
+56,
+55,
+55,
+54,
+53,
+53,
+52,
+51,
+50,
+50,
+49,
+48,
+47,
+46,
+45,
+44,
+44,
+43,
+42,
+41,
+40,
+39,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+54,
+55,
+56,
+57,
+58,
+59,
+59,
+60,
+61,
+62,
+62,
+63,
+64,
+64,
+65,
+65,
+66,
+67,
+67,
+68,
+68,
+69,
+69,
+70,
+70,
+71,
+71,
+71,
+72,
+72,
+72,
+72,
+73,
+73,
+73,
+73,
+73,
+73,
+73,
+73,
+73,
+73,
+73,
+73,
+73,
+73,
+72,
+72,
+72,
+72,
+71,
+71,
+70,
+70,
+70,
+69,
+69,
+68,
+68,
+67,
+66,
+66,
+65,
+64,
+64,
+63,
+62,
+61,
+61,
+60,
+59,
+58,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+5,
+6,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+7,
+8,
+9,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+20,
+21,
+21,
+21,
+22,
+22,
+22,
+22,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+30,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+34,
+34,
+34,
+35,
+35,
+36,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+0,
+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,
+25,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+44,
+44,
+44,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+42,
+42,
+41,
+41,
+40,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+0,
+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,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+47,
+48,
+48,
+48,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+54,
+55,
+55,
+55,
+56,
+56,
+56,
+56,
+56,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+56,
+56,
+56,
+56,
+56,
+56,
+55,
+55,
+55,
+54,
+54,
+54,
+53,
+53,
+53,
+52,
+52,
+51,
+51,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+45,
+45,
+44,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+59,
+59,
+59,
+60,
+60,
+60,
+61,
+61,
+61,
+61,
+61,
+61,
+62,
+62,
+62,
+62,
+62,
+61,
+61,
+61,
+61,
+61,
+61,
+60,
+60,
+60,
+60,
+59,
+59,
+58,
+58,
+57,
+57,
+57,
+56,
+55,
+55,
+54,
+54,
+53,
+52,
+52,
+51,
+50,
+50,
+49,
+48,
+47,
+47,
+46,
+45,
+44,
+44,
+43,
+42,
+41,
+40,
+39,
+39,
+38,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+50,
+51,
+52,
+53,
+54,
+54,
+55,
+56,
+57,
+57,
+58,
+59,
+59,
+60,
+61,
+61,
+62,
+62,
+63,
+63,
+64,
+64,
+65,
+65,
+65,
+66,
+66,
+66,
+67,
+67,
+67,
+67,
+67,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+67,
+67,
+67,
+67,
+67,
+67,
+66,
+66,
+66,
+65,
+65,
+64,
+64,
+64,
+63,
+63,
+62,
+61,
+61,
+60,
+60,
+59,
+58,
+57,
+57,
+56,
+55,
+54,
+54,
+53,
+52,
+51,
+50,
+49,
+49,
+48,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+55,
+56,
+57,
+58,
+59,
+59,
+60,
+61,
+62,
+62,
+63,
+64,
+64,
+65,
+66,
+66,
+67,
+67,
+68,
+68,
+69,
+69,
+70,
+70,
+70,
+71,
+71,
+71,
+72,
+72,
+72,
+72,
+72,
+72,
+73,
+73,
+73,
+73,
+73,
+72,
+72,
+72,
+72,
+72,
+72,
+71,
+71,
+71,
+70,
+70,
+70,
+69,
+69,
+68,
+68,
+67,
+66,
+66,
+65,
+65,
+64,
+63,
+62,
+62,
+61,
+60,
+59,
+58,
+58,
+57,
+56,
+0,
+0,
+1,
+2,
+3,
+3,
+4,
+5,
+5,
+5,
+6,
+6,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+17,
+18,
+18,
+18,
+19,
+19,
+20,
+20,
+20,
+20,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+26,
+27,
+27,
+27,
+28,
+28,
+28,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+38,
+38,
+38,
+39,
+39,
+40,
+40,
+40,
+40,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+41,
+40,
+40,
+40,
+40,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+0,
+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,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+42,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+23,
+22,
+0,
+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,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+44,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+51,
+52,
+52,
+52,
+52,
+52,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+34,
+33,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+56,
+56,
+57,
+57,
+57,
+57,
+57,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+57,
+57,
+57,
+57,
+57,
+56,
+56,
+56,
+55,
+55,
+55,
+54,
+54,
+53,
+53,
+52,
+52,
+51,
+51,
+50,
+50,
+49,
+48,
+48,
+47,
+46,
+46,
+45,
+44,
+43,
+43,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+51,
+51,
+52,
+53,
+53,
+54,
+55,
+55,
+56,
+57,
+57,
+58,
+58,
+59,
+59,
+60,
+60,
+60,
+61,
+61,
+62,
+62,
+62,
+62,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+62,
+62,
+62,
+61,
+61,
+61,
+60,
+60,
+60,
+59,
+59,
+58,
+58,
+57,
+56,
+56,
+55,
+54,
+54,
+53,
+52,
+52,
+51,
+50,
+49,
+49,
+48,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+55,
+56,
+56,
+57,
+58,
+58,
+59,
+60,
+60,
+61,
+62,
+62,
+63,
+63,
+64,
+64,
+65,
+65,
+66,
+66,
+67,
+67,
+67,
+68,
+68,
+68,
+68,
+68,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+68,
+68,
+68,
+68,
+67,
+67,
+67,
+66,
+66,
+65,
+65,
+64,
+64,
+63,
+63,
+62,
+61,
+61,
+60,
+59,
+59,
+58,
+57,
+56,
+56,
+55,
+54,
+53,
+52,
+51,
+50,
+50,
+49,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+54,
+55,
+56,
+57,
+58,
+58,
+59,
+60,
+61,
+62,
+62,
+63,
+64,
+64,
+65,
+66,
+66,
+67,
+67,
+68,
+68,
+69,
+69,
+70,
+70,
+71,
+71,
+72,
+72,
+72,
+73,
+73,
+73,
+73,
+73,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+73,
+73,
+73,
+73,
+73,
+72,
+72,
+72,
+71,
+71,
+70,
+70,
+69,
+69,
+68,
+67,
+67,
+66,
+66,
+65,
+64,
+63,
+63,
+62,
+61,
+60,
+59,
+0,
+0,
+1,
+2,
+3,
+3,
+4,
+4,
+5,
+5,
+5,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+5,
+6,
+7,
+7,
+8,
+9,
+9,
+9,
+10,
+10,
+11,
+11,
+11,
+12,
+12,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+18,
+19,
+19,
+19,
+19,
+19,
+19,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+23,
+23,
+24,
+24,
+25,
+25,
+25,
+25,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+27,
+27,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+23,
+23,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+28,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+0,
+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,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+41,
+41,
+41,
+40,
+40,
+39,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+48,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+49,
+48,
+48,
+47,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+45,
+46,
+47,
+47,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+52,
+53,
+53,
+53,
+54,
+54,
+54,
+54,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+54,
+54,
+54,
+54,
+53,
+53,
+53,
+52,
+52,
+52,
+51,
+51,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+46,
+46,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+28,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+51,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+58,
+59,
+59,
+59,
+59,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+59,
+59,
+59,
+59,
+58,
+58,
+58,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+54,
+53,
+53,
+52,
+51,
+51,
+50,
+49,
+49,
+48,
+47,
+47,
+46,
+45,
+44,
+43,
+43,
+42,
+41,
+40,
+39,
+39,
+38,
+37,
+36,
+35,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+56,
+57,
+57,
+58,
+58,
+59,
+60,
+60,
+61,
+61,
+62,
+62,
+62,
+63,
+63,
+63,
+64,
+64,
+64,
+64,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+64,
+64,
+64,
+64,
+63,
+63,
+63,
+62,
+62,
+61,
+61,
+60,
+60,
+59,
+59,
+58,
+57,
+57,
+56,
+55,
+55,
+54,
+53,
+52,
+52,
+51,
+50,
+49,
+48,
+47,
+47,
+46,
+45,
+44,
+43,
+42,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+54,
+55,
+56,
+57,
+58,
+58,
+59,
+60,
+61,
+61,
+62,
+63,
+63,
+64,
+64,
+65,
+65,
+66,
+66,
+67,
+67,
+68,
+68,
+69,
+69,
+69,
+69,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+69,
+69,
+69,
+68,
+68,
+68,
+67,
+67,
+66,
+66,
+65,
+65,
+64,
+63,
+63,
+62,
+61,
+60,
+60,
+59,
+58,
+57,
+56,
+55,
+55,
+54,
+53,
+52,
+51,
+50,
+49,
+0,
+1,
+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,
+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,
+51,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+58,
+59,
+60,
+61,
+62,
+62,
+63,
+64,
+64,
+65,
+66,
+66,
+67,
+68,
+68,
+69,
+69,
+70,
+70,
+71,
+71,
+72,
+72,
+72,
+73,
+73,
+73,
+73,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+73,
+73,
+73,
+73,
+72,
+72,
+72,
+71,
+71,
+70,
+70,
+69,
+69,
+68,
+67,
+67,
+66,
+65,
+64,
+64,
+63,
+62,
+61,
+60,
+59,
+58,
+57,
+56,
+55,
+54,
+0,
+0,
+1,
+2,
+3,
+3,
+4,
+4,
+5,
+5,
+5,
+5,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+9,
+10,
+10,
+10,
+11,
+11,
+11,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+21,
+22,
+22,
+22,
+23,
+23,
+23,
+23,
+23,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+26,
+27,
+27,
+28,
+28,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+28,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+0,
+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,
+24,
+25,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+36,
+36,
+37,
+37,
+38,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+0,
+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,
+26,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+45,
+45,
+45,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+49,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+51,
+51,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+53,
+53,
+53,
+54,
+54,
+55,
+55,
+55,
+55,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+55,
+55,
+55,
+55,
+54,
+54,
+54,
+53,
+53,
+53,
+52,
+52,
+51,
+51,
+50,
+50,
+49,
+48,
+48,
+47,
+47,
+46,
+45,
+45,
+44,
+43,
+43,
+42,
+41,
+41,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+35,
+34,
+33,
+32,
+32,
+31,
+30,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+50,
+51,
+51,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+55,
+56,
+56,
+56,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+56,
+56,
+56,
+55,
+55,
+55,
+54,
+54,
+53,
+53,
+52,
+52,
+51,
+50,
+50,
+49,
+48,
+48,
+47,
+46,
+45,
+44,
+44,
+43,
+42,
+41,
+40,
+39,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+32,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+48,
+49,
+50,
+51,
+51,
+52,
+53,
+54,
+54,
+55,
+56,
+57,
+57,
+58,
+59,
+59,
+60,
+60,
+61,
+61,
+62,
+62,
+63,
+63,
+64,
+64,
+64,
+65,
+65,
+65,
+65,
+65,
+65,
+66,
+66,
+66,
+66,
+66,
+65,
+65,
+65,
+65,
+65,
+65,
+64,
+64,
+64,
+63,
+63,
+62,
+62,
+61,
+61,
+60,
+59,
+59,
+58,
+57,
+57,
+56,
+55,
+54,
+54,
+53,
+52,
+51,
+50,
+49,
+48,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+53,
+54,
+55,
+56,
+57,
+58,
+58,
+59,
+60,
+60,
+61,
+62,
+63,
+63,
+64,
+64,
+65,
+66,
+66,
+67,
+67,
+67,
+68,
+68,
+69,
+69,
+69,
+70,
+70,
+70,
+70,
+70,
+70,
+71,
+71,
+71,
+71,
+70,
+70,
+70,
+70,
+70,
+70,
+69,
+69,
+69,
+68,
+68,
+67,
+67,
+66,
+66,
+65,
+65,
+64,
+63,
+63,
+62,
+61,
+60,
+60,
+59,
+58,
+57,
+56,
+55,
+54,
+53,
+52,
+51,
+50,
+49,
+48,
+0,
+1,
+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,
+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,
+51,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+58,
+59,
+60,
+61,
+62,
+62,
+63,
+64,
+65,
+65,
+66,
+67,
+67,
+68,
+68,
+69,
+70,
+70,
+71,
+71,
+72,
+72,
+72,
+73,
+73,
+73,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+73,
+73,
+73,
+72,
+72,
+72,
+71,
+71,
+70,
+69,
+69,
+68,
+67,
+67,
+66,
+65,
+64,
+63,
+63,
+62,
+61,
+60,
+59,
+58,
+57,
+56,
+55,
+54,
+0,
+0,
+1,
+2,
+3,
+3,
+4,
+4,
+4,
+5,
+5,
+5,
+5,
+5,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+5,
+6,
+7,
+7,
+8,
+8,
+9,
+9,
+10,
+10,
+10,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+21,
+22,
+22,
+22,
+22,
+22,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+27,
+28,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+32,
+33,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+0,
+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,
+24,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+43,
+44,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+0,
+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,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+48,
+49,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+52,
+52,
+52,
+52,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+45,
+45,
+44,
+43,
+43,
+42,
+41,
+41,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+35,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+50,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+57,
+58,
+58,
+58,
+58,
+58,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+58,
+58,
+58,
+58,
+57,
+57,
+57,
+56,
+56,
+56,
+55,
+55,
+54,
+54,
+53,
+52,
+52,
+51,
+51,
+50,
+49,
+48,
+48,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+41,
+41,
+40,
+39,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+30,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+50,
+51,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+58,
+59,
+59,
+59,
+59,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+59,
+59,
+59,
+59,
+58,
+58,
+58,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+54,
+53,
+52,
+52,
+51,
+50,
+49,
+49,
+48,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+0,
+1,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+55,
+55,
+56,
+57,
+57,
+58,
+59,
+59,
+60,
+61,
+61,
+62,
+62,
+63,
+63,
+63,
+64,
+64,
+64,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+65,
+64,
+64,
+64,
+63,
+63,
+63,
+62,
+62,
+61,
+60,
+60,
+59,
+58,
+58,
+57,
+56,
+55,
+55,
+54,
+53,
+52,
+51,
+50,
+49,
+48,
+47,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+0,
+1,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+55,
+56,
+57,
+58,
+59,
+59,
+60,
+61,
+62,
+62,
+63,
+64,
+64,
+65,
+65,
+66,
+66,
+67,
+67,
+68,
+68,
+69,
+69,
+69,
+69,
+70,
+70,
+70,
+70,
+70,
+71,
+71,
+71,
+71,
+71,
+70,
+70,
+70,
+70,
+70,
+69,
+69,
+69,
+68,
+68,
+68,
+67,
+67,
+66,
+65,
+65,
+64,
+63,
+63,
+62,
+61,
+61,
+60,
+59,
+58,
+57,
+56,
+55,
+54,
+53,
+52,
+52,
+51,
+50,
+49,
+48,
+0,
+1,
+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,
+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,
+52,
+53,
+54,
+54,
+55,
+56,
+57,
+58,
+59,
+60,
+60,
+61,
+62,
+63,
+64,
+64,
+65,
+66,
+66,
+67,
+68,
+68,
+69,
+69,
+70,
+70,
+71,
+71,
+72,
+72,
+73,
+73,
+73,
+73,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+73,
+73,
+73,
+72,
+72,
+71,
+71,
+70,
+70,
+69,
+69,
+68,
+67,
+67,
+66,
+65,
+64,
+63,
+62,
+61,
+61,
+60,
+59,
+58,
+57,
+56,
+54,
+53,
+52,
+51,
+0,
+0,
+1,
+2,
+3,
+3,
+4,
+4,
+4,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+5,
+6,
+7,
+7,
+8,
+8,
+9,
+9,
+9,
+10,
+10,
+10,
+10,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+25,
+26,
+26,
+26,
+26,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+33,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+34,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+37,
+37,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+38,
+38,
+38,
+39,
+39,
+40,
+40,
+40,
+40,
+41,
+41,
+41,
+41,
+41,
+41,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+41,
+41,
+40,
+40,
+40,
+40,
+39,
+39,
+39,
+38,
+38,
+37,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+0,
+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,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+39,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+45,
+45,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+47,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+45,
+45,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+30,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+51,
+52,
+52,
+52,
+52,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+48,
+47,
+47,
+46,
+46,
+45,
+44,
+43,
+43,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+36,
+35,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+49,
+50,
+51,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+56,
+56,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+56,
+56,
+56,
+56,
+55,
+55,
+54,
+54,
+53,
+53,
+52,
+52,
+51,
+50,
+50,
+49,
+48,
+48,
+47,
+46,
+45,
+44,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+21,
+0,
+1,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+50,
+51,
+51,
+52,
+53,
+54,
+54,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+59,
+59,
+60,
+60,
+60,
+61,
+61,
+61,
+61,
+61,
+62,
+62,
+62,
+62,
+62,
+62,
+61,
+61,
+61,
+61,
+61,
+60,
+60,
+60,
+59,
+59,
+58,
+58,
+57,
+56,
+56,
+55,
+54,
+54,
+53,
+52,
+51,
+51,
+50,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+27,
+0,
+1,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+55,
+56,
+57,
+58,
+58,
+59,
+60,
+60,
+61,
+62,
+62,
+63,
+63,
+64,
+64,
+65,
+65,
+65,
+66,
+66,
+66,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+67,
+66,
+66,
+66,
+65,
+65,
+65,
+64,
+64,
+63,
+62,
+62,
+61,
+61,
+60,
+59,
+58,
+58,
+57,
+56,
+55,
+54,
+53,
+52,
+51,
+50,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+0,
+1,
+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,
+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,
+52,
+52,
+53,
+54,
+55,
+56,
+57,
+57,
+58,
+59,
+60,
+61,
+61,
+62,
+63,
+63,
+64,
+65,
+65,
+66,
+66,
+67,
+67,
+68,
+68,
+68,
+69,
+69,
+69,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+69,
+69,
+69,
+68,
+68,
+68,
+67,
+67,
+66,
+66,
+65,
+64,
+64,
+63,
+62,
+61,
+60,
+60,
+59,
+58,
+57,
+56,
+55,
+54,
+53,
+52,
+51,
+50,
+49,
+48,
+47,
+45,
+44,
+43,
+42,
+0,
+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,
+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,
+52,
+53,
+54,
+55,
+56,
+56,
+57,
+58,
+59,
+60,
+61,
+62,
+62,
+63,
+64,
+65,
+65,
+66,
+67,
+67,
+68,
+69,
+69,
+70,
+70,
+71,
+71,
+72,
+72,
+73,
+73,
+73,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+74,
+73,
+73,
+73,
+72,
+72,
+71,
+71,
+70,
+69,
+69,
+68,
+67,
+66,
+66,
+65,
+64,
+63,
+62,
+61,
+60,
+59,
+58,
+57,
+56,
+54,
+53,
+52,
+51,
+50,
+49,
+0,
+0,
+1,
+2,
+3,
+3,
+4,
+4,
+4,
+4,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+9,
+9,
+9,
+9,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+18,
+18,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+22,
+23,
+23,
+23,
+24,
+24,
+24,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+27,
+27,
+27,
+28,
+28,
+29,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+0,
+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,
+24,
+25,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+0,
+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,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+0,
+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,
+26,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+43,
+43,
+44,
+44,
+44,
+43,
+43,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+46,
+46,
+47,
+47,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+52,
+52,
+52,
+52,
+52,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+46,
+46,
+45,
+44,
+44,
+43,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+47,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+51,
+51,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+51,
+51,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+41,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+15,
+15,
+14,
+13,
+0,
+0,
+2,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+51,
+52,
+53,
+53,
+54,
+55,
+55,
+56,
+56,
+56,
+57,
+57,
+57,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+57,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+53,
+53,
+52,
+51,
+51,
+50,
+49,
+48,
+47,
+46,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+17,
+0,
+0,
+2,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+55,
+56,
+57,
+57,
+57,
+58,
+58,
+59,
+59,
+59,
+59,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+59,
+59,
+59,
+59,
+58,
+58,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+53,
+53,
+52,
+51,
+50,
+49,
+48,
+47,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+0,
+1,
+2,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+58,
+59,
+59,
+59,
+59,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+59,
+59,
+59,
+59,
+58,
+58,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+53,
+52,
+52,
+51,
+50,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+0,
+0,
+1,
+2,
+3,
+3,
+3,
+4,
+4,
+4,
+4,
+4,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+9,
+9,
+9,
+9,
+9,
+9,
+10,
+10,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+7,
+8,
+9,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+21,
+22,
+22,
+22,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+26,
+27,
+27,
+28,
+28,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+32,
+32,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+0,
+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,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+40,
+41,
+41,
+41,
+41,
+41,
+41,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+41,
+41,
+40,
+40,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+31,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+40,
+41,
+41,
+41,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+40,
+40,
+39,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+0,
+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,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+36,
+36,
+37,
+38,
+38,
+39,
+39,
+40,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+0,
+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,
+26,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+0,
+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,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+36,
+37,
+38,
+39,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+46,
+45,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+30,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+52,
+52,
+52,
+52,
+52,
+53,
+53,
+53,
+53,
+53,
+53,
+53,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+48,
+47,
+47,
+46,
+46,
+45,
+44,
+43,
+43,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+0,
+0,
+1,
+2,
+2,
+3,
+3,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+8,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+7,
+8,
+9,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+21,
+21,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+26,
+26,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+33,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+0,
+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,
+25,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+0,
+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,
+25,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+2,
+2,
+0,
+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,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+41,
+41,
+41,
+42,
+42,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+41,
+40,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+39,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+43,
+44,
+44,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+47,
+48,
+48,
+48,
+49,
+49,
+49,
+49,
+49,
+49,
+49,
+49,
+49,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+43,
+43,
+42,
+41,
+41,
+40,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+48,
+48,
+48,
+49,
+49,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+49,
+49,
+48,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+50,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+54,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+54,
+54,
+54,
+54,
+53,
+53,
+52,
+52,
+51,
+50,
+50,
+49,
+48,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+13,
+0,
+1,
+2,
+3,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+44,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+51,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+56,
+56,
+56,
+56,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+57,
+56,
+56,
+56,
+55,
+55,
+54,
+54,
+53,
+53,
+52,
+51,
+50,
+50,
+49,
+48,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+17,
+17,
+18,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+33,
+34,
+35,
+36,
+37,
+38,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+50,
+50,
+51,
+52,
+52,
+52,
+53,
+53,
+53,
+54,
+54,
+54,
+54,
+54,
+54,
+53,
+53,
+53,
+53,
+52,
+52,
+51,
+51,
+50,
+50,
+49,
+48,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+14,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+35,
+36,
+37,
+38,
+39,
+40,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+52,
+53,
+53,
+54,
+54,
+54,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+55,
+54,
+54,
+53,
+53,
+53,
+52,
+51,
+51,
+50,
+49,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+15,
+14,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+16,
+16,
+17,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+29,
+30,
+31,
+32,
+33,
+35,
+36,
+37,
+38,
+40,
+41,
+42,
+43,
+44,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+56,
+56,
+57,
+57,
+57,
+57,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+57,
+57,
+57,
+56,
+56,
+56,
+55,
+55,
+54,
+53,
+53,
+52,
+51,
+50,
+49,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+17,
+0,
+0,
+1,
+2,
+2,
+3,
+3,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+7,
+8,
+9,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+18,
+18,
+19,
+19,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+25,
+26,
+26,
+26,
+26,
+26,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+31,
+31,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+25,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+27,
+27,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+32,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+41,
+41,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+40,
+40,
+39,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+18,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+14,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+46,
+46,
+45,
+45,
+45,
+44,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+33,
+32,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+37,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+41,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+36,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+42,
+43,
+44,
+44,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+32,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+11,
+12,
+12,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+0,
+0,
+1,
+2,
+2,
+3,
+3,
+3,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+6,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+10,
+10,
+10,
+11,
+11,
+11,
+12,
+12,
+12,
+12,
+12,
+12,
+13,
+13,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+18,
+18,
+18,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+19,
+18,
+18,
+18,
+18,
+17,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+24,
+24,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+0,
+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,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+40,
+41,
+41,
+41,
+41,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+40,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+0,
+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,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+0,
+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,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+40,
+41,
+41,
+41,
+41,
+41,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+41,
+41,
+40,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+30,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+0,
+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,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+36,
+37,
+37,
+38,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+5,
+5,
+5,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+33,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+48,
+47,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+10,
+10,
+9,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+47,
+48,
+48,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+46,
+45,
+44,
+44,
+43,
+42,
+41,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+10,
+10,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+16,
+16,
+17,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+30,
+31,
+32,
+33,
+34,
+35,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+48,
+49,
+50,
+50,
+51,
+51,
+51,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+50,
+50,
+49,
+49,
+48,
+47,
+47,
+46,
+45,
+44,
+43,
+42,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+15,
+16,
+17,
+17,
+17,
+18,
+18,
+18,
+19,
+19,
+19,
+20,
+20,
+20,
+21,
+21,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+51,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+52,
+51,
+51,
+51,
+50,
+50,
+49,
+48,
+48,
+47,
+46,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+29,
+30,
+31,
+32,
+34,
+35,
+36,
+37,
+39,
+40,
+41,
+42,
+43,
+45,
+46,
+47,
+48,
+49,
+49,
+50,
+51,
+52,
+53,
+53,
+54,
+54,
+55,
+55,
+55,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+55,
+55,
+55,
+54,
+54,
+54,
+53,
+52,
+52,
+51,
+50,
+50,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+13,
+13,
+12,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+9,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+20,
+21,
+23,
+24,
+26,
+27,
+29,
+30,
+32,
+33,
+35,
+36,
+38,
+39,
+40,
+42,
+43,
+44,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+52,
+53,
+54,
+54,
+55,
+55,
+55,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+55,
+55,
+54,
+54,
+54,
+53,
+52,
+52,
+51,
+50,
+49,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+16,
+15,
+14,
+13,
+13,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+13,
+14,
+15,
+17,
+18,
+19,
+21,
+22,
+24,
+25,
+27,
+28,
+30,
+31,
+33,
+35,
+36,
+38,
+39,
+41,
+42,
+43,
+45,
+46,
+47,
+48,
+49,
+51,
+52,
+52,
+53,
+54,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+58,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+58,
+58,
+58,
+58,
+57,
+57,
+56,
+55,
+55,
+54,
+53,
+53,
+52,
+51,
+50,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+0,
+0,
+1,
+2,
+2,
+3,
+3,
+3,
+3,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+5,
+6,
+6,
+7,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+9,
+10,
+10,
+11,
+11,
+11,
+11,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+22,
+23,
+23,
+23,
+23,
+23,
+23,
+24,
+24,
+24,
+24,
+24,
+23,
+23,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+26,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+25,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+26,
+26,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+27,
+26,
+26,
+26,
+26,
+25,
+25,
+24,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+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,
+25,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+36,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+0,
+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,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+37,
+37,
+36,
+36,
+36,
+35,
+34,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+33,
+32,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+36,
+36,
+36,
+37,
+37,
+37,
+36,
+36,
+36,
+36,
+36,
+36,
+35,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+32,
+33,
+33,
+34,
+35,
+35,
+36,
+37,
+37,
+38,
+38,
+39,
+39,
+39,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+40,
+39,
+39,
+39,
+38,
+38,
+37,
+37,
+36,
+36,
+35,
+35,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+12,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+28,
+29,
+30,
+31,
+32,
+33,
+35,
+36,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+43,
+43,
+44,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+45,
+45,
+45,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+9,
+9,
+9,
+10,
+10,
+11,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+17,
+18,
+20,
+21,
+22,
+23,
+24,
+25,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+43,
+43,
+43,
+43,
+44,
+43,
+43,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+33,
+32,
+32,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+8,
+8,
+8,
+9,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+21,
+22,
+23,
+24,
+26,
+27,
+28,
+30,
+31,
+32,
+33,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+46,
+45,
+45,
+44,
+44,
+44,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+10,
+10,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+8,
+8,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+23,
+24,
+25,
+26,
+27,
+28,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+38,
+37,
+36,
+35,
+35,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+8,
+8,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+18,
+19,
+20,
+22,
+23,
+25,
+26,
+28,
+29,
+30,
+32,
+33,
+35,
+36,
+37,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+49,
+50,
+50,
+50,
+51,
+51,
+51,
+51,
+51,
+52,
+51,
+51,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+0,
+0,
+1,
+2,
+2,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+5,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+9,
+10,
+10,
+10,
+11,
+11,
+11,
+11,
+11,
+12,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+16,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+15,
+16,
+16,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+16,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+20,
+20,
+21,
+21,
+21,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+23,
+23,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+14,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+27,
+28,
+28,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+28,
+28,
+28,
+28,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+23,
+23,
+24,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+28,
+29,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+15,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+34,
+33,
+32,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+27,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+34,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+28,
+29,
+29,
+30,
+31,
+31,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+30,
+31,
+32,
+32,
+33,
+33,
+34,
+34,
+34,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+35,
+34,
+34,
+34,
+33,
+33,
+33,
+32,
+31,
+31,
+30,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+25,
+24,
+23,
+22,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+40,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+14,
+15,
+15,
+16,
+16,
+17,
+18,
+19,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+42,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+20,
+21,
+22,
+24,
+25,
+26,
+27,
+28,
+30,
+31,
+32,
+34,
+35,
+36,
+37,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+45,
+46,
+47,
+48,
+48,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+47,
+47,
+46,
+45,
+45,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+9,
+9,
+8,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+9,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+21,
+22,
+24,
+25,
+26,
+28,
+29,
+31,
+32,
+34,
+35,
+36,
+38,
+39,
+40,
+41,
+42,
+44,
+44,
+45,
+46,
+47,
+48,
+48,
+49,
+49,
+50,
+50,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+47,
+47,
+46,
+45,
+44,
+44,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+14,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+18,
+19,
+21,
+22,
+23,
+25,
+26,
+28,
+29,
+31,
+32,
+34,
+35,
+37,
+38,
+39,
+40,
+42,
+43,
+44,
+45,
+46,
+46,
+47,
+48,
+48,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+47,
+46,
+46,
+45,
+44,
+43,
+43,
+42,
+41,
+40,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+15,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+9,
+9,
+8,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+9,
+10,
+10,
+10,
+10,
+10,
+11,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+26,
+27,
+28,
+29,
+31,
+32,
+33,
+34,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+47,
+48,
+49,
+49,
+49,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+50,
+49,
+49,
+49,
+48,
+48,
+47,
+46,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+40,
+39,
+38,
+37,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+13,
+12,
+12,
+11,
+10,
+10,
+9,
+9,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+8,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+13,
+14,
+16,
+17,
+18,
+20,
+21,
+23,
+24,
+26,
+27,
+29,
+31,
+32,
+34,
+35,
+37,
+39,
+40,
+42,
+43,
+44,
+46,
+47,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+59,
+58,
+58,
+57,
+57,
+56,
+56,
+55,
+55,
+54,
+53,
+52,
+51,
+50,
+49,
+48,
+47,
+46,
+45,
+44,
+43,
+42,
+41,
+40,
+38,
+37,
+36,
+35,
+34,
+32,
+31,
+30,
+29,
+28,
+27,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+16,
+15,
+15,
+14,
+13,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+7,
+7,
+8,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+16,
+17,
+18,
+20,
+21,
+23,
+25,
+26,
+28,
+30,
+31,
+33,
+35,
+36,
+38,
+39,
+41,
+42,
+44,
+45,
+46,
+48,
+49,
+50,
+51,
+52,
+53,
+54,
+55,
+55,
+56,
+56,
+57,
+57,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+57,
+57,
+57,
+56,
+56,
+55,
+54,
+54,
+53,
+52,
+51,
+51,
+50,
+49,
+48,
+47,
+46,
+45,
+43,
+42,
+41,
+40,
+39,
+38,
+36,
+35,
+34,
+33,
+32,
+31,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+17,
+16,
+15,
+14,
+13,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+9,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+19,
+20,
+21,
+23,
+24,
+26,
+27,
+29,
+30,
+32,
+34,
+35,
+37,
+38,
+40,
+41,
+43,
+44,
+46,
+47,
+48,
+50,
+51,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+59,
+60,
+61,
+61,
+61,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+62,
+61,
+61,
+60,
+60,
+59,
+58,
+58,
+57,
+56,
+55,
+54,
+53,
+52,
+51,
+50,
+49,
+48,
+47,
+46,
+44,
+43,
+42,
+41,
+39,
+38,
+37,
+36,
+34,
+33,
+32,
+31,
+29,
+28,
+27,
+26,
+25,
+24,
+22,
+21,
+20,
+19,
+18,
+0,
+0,
+1,
+2,
+2,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+4,
+5,
+5,
+6,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+9,
+9,
+10,
+10,
+10,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+11,
+10,
+10,
+10,
+10,
+10,
+9,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+13,
+13,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+15,
+14,
+14,
+14,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+12,
+12,
+13,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+16,
+17,
+17,
+17,
+17,
+17,
+16,
+16,
+16,
+16,
+16,
+15,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+19,
+20,
+20,
+20,
+20,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+22,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+22,
+22,
+22,
+21,
+21,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+1,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+13,
+14,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+18,
+18,
+18,
+18,
+19,
+19,
+19,
+19,
+20,
+20,
+20,
+20,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+21,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+22,
+21,
+21,
+21,
+21,
+21,
+21,
+20,
+20,
+20,
+20,
+19,
+19,
+19,
+18,
+18,
+18,
+17,
+17,
+17,
+16,
+16,
+15,
+15,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+20,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+3,
+2,
+2,
+2,
+2,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+16,
+17,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+23,
+24,
+25,
+26,
+26,
+27,
+27,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+32,
+32,
+32,
+33,
+33,
+33,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+34,
+33,
+33,
+33,
+33,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+5,
+4,
+4,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+11,
+12,
+13,
+14,
+14,
+15,
+15,
+16,
+16,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+33,
+32,
+32,
+32,
+32,
+31,
+31,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+14,
+15,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+24,
+25,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+31,
+32,
+32,
+33,
+33,
+34,
+34,
+35,
+35,
+35,
+36,
+36,
+36,
+37,
+37,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+32,
+31,
+30,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+16,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+20,
+21,
+21,
+22,
+23,
+23,
+24,
+25,
+25,
+26,
+26,
+27,
+27,
+28,
+28,
+29,
+29,
+29,
+30,
+30,
+30,
+30,
+30,
+31,
+31,
+31,
+30,
+30,
+30,
+30,
+30,
+29,
+29,
+29,
+28,
+28,
+27,
+27,
+27,
+26,
+25,
+25,
+24,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+15,
+16,
+16,
+16,
+17,
+17,
+17,
+18,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+22,
+23,
+24,
+24,
+25,
+26,
+26,
+27,
+28,
+28,
+29,
+29,
+30,
+30,
+30,
+31,
+31,
+31,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+32,
+31,
+31,
+31,
+30,
+30,
+30,
+29,
+29,
+28,
+28,
+27,
+27,
+26,
+25,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+3,
+3,
+3,
+3,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+9,
+10,
+11,
+11,
+12,
+12,
+12,
+13,
+13,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+14,
+15,
+15,
+15,
+16,
+16,
+17,
+17,
+18,
+19,
+19,
+20,
+21,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+7,
+8,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+13,
+13,
+14,
+14,
+14,
+14,
+15,
+15,
+16,
+16,
+16,
+17,
+18,
+18,
+19,
+20,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+38,
+38,
+39,
+39,
+40,
+40,
+41,
+41,
+41,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+41,
+41,
+41,
+41,
+40,
+40,
+39,
+39,
+38,
+38,
+37,
+36,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+7,
+6,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+9,
+9,
+9,
+9,
+9,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+14,
+15,
+15,
+16,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+26,
+27,
+27,
+28,
+29,
+30,
+31,
+32,
+32,
+33,
+34,
+34,
+35,
+35,
+36,
+36,
+37,
+37,
+37,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+38,
+37,
+37,
+37,
+36,
+36,
+36,
+35,
+35,
+34,
+34,
+33,
+33,
+32,
+31,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+13,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+8,
+8,
+9,
+9,
+9,
+9,
+9,
+9,
+10,
+10,
+11,
+11,
+12,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+20,
+22,
+23,
+24,
+25,
+27,
+28,
+29,
+30,
+31,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+42,
+42,
+43,
+43,
+44,
+44,
+44,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+45,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+29,
+28,
+27,
+26,
+25,
+24,
+23,
+23,
+22,
+21,
+20,
+19,
+19,
+18,
+17,
+16,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+6,
+7,
+7,
+8,
+8,
+9,
+10,
+10,
+11,
+12,
+13,
+14,
+16,
+17,
+18,
+19,
+20,
+22,
+23,
+24,
+25,
+26,
+28,
+29,
+30,
+31,
+32,
+33,
+34,
+34,
+35,
+36,
+37,
+37,
+38,
+38,
+38,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+39,
+38,
+38,
+38,
+37,
+37,
+36,
+35,
+35,
+34,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+24,
+24,
+23,
+22,
+21,
+20,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+8,
+7,
+7,
+6,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+8,
+8,
+8,
+8,
+8,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+8,
+8,
+8,
+9,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+19,
+21,
+22,
+23,
+25,
+26,
+27,
+29,
+30,
+31,
+32,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+41,
+42,
+43,
+43,
+43,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+39,
+38,
+37,
+37,
+36,
+35,
+34,
+33,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+10,
+9,
+9,
+8,
+8,
+7,
+7,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+6,
+6,
+6,
+7,
+7,
+8,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+19,
+20,
+21,
+22,
+24,
+25,
+26,
+27,
+29,
+30,
+31,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+39,
+40,
+41,
+41,
+42,
+42,
+42,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+43,
+42,
+42,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+31,
+30,
+29,
+28,
+27,
+26,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+15,
+15,
+14,
+13,
+13,
+12,
+12,
+11,
+10,
+10,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+5,
+5,
+5,
+6,
+7,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+16,
+17,
+18,
+20,
+21,
+22,
+24,
+25,
+26,
+28,
+29,
+30,
+32,
+33,
+34,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+41,
+42,
+43,
+43,
+44,
+44,
+44,
+44,
+44,
+45,
+45,
+44,
+44,
+44,
+44,
+44,
+43,
+43,
+42,
+42,
+41,
+41,
+40,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+14,
+14,
+13,
+12,
+12,
+11,
+11,
+10,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+5,
+5,
+6,
+6,
+7,
+8,
+8,
+9,
+10,
+11,
+12,
+13,
+15,
+16,
+17,
+18,
+20,
+21,
+23,
+24,
+25,
+27,
+28,
+29,
+31,
+32,
+33,
+34,
+35,
+37,
+38,
+39,
+40,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+45,
+45,
+46,
+46,
+46,
+47,
+47,
+47,
+47,
+47,
+47,
+47,
+46,
+46,
+46,
+46,
+45,
+45,
+44,
+44,
+44,
+43,
+42,
+42,
+41,
+41,
+40,
+39,
+38,
+38,
+37,
+36,
+35,
+34,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+28,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+21,
+20,
+19,
+18,
+17,
+17,
+16,
+15,
+0,
+0,
+1,
+2,
+3,
+4,
+5,
+6,
+6,
+6,
+7,
+7,
+7,
+7,
+7,
+7,
+6,
+6,
+6,
+5,
+5,
+5,
+5,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+4,
+5,
+5,
+6,
+6,
+7,
+7,
+8,
+9,
+10,
+11,
+12,
+13,
+14,
+15,
+16,
+17,
+18,
+20,
+21,
+22,
+23,
+25,
+26,
+27,
+29,
+30,
+31,
+32,
+33,
+35,
+36,
+37,
+38,
+39,
+40,
+41,
+42,
+43,
+43,
+44,
+45,
+45,
+46,
+46,
+47,
+47,
+47,
+47,
+48,
+48,
+48,
+48,
+48,
+47,
+47,
+47,
+47,
+46,
+46,
+45,
+45,
+44,
+44,
+43,
+42,
+42,
+41,
+40,
+39,
+39,
+38,
+37,
+36,
+35,
+34,
+33,
+32,
+31,
+30,
+29,
+28,
+27,
+27,
+26,
+25,
+24,
+23,
+22,
+21,
+20,
+19,
+18,
+18,
+17,
+16,
+
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_SOURCE_ER_TABLES_XOR_H_
diff --git a/src/modules/video_coding/main/source/event.h b/src/modules/video_coding/main/source/event.h
new file mode 100644
index 0000000..39fd494
--- /dev/null
+++ b/src/modules/video_coding/main/source/event.h
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_EVENT_H_
+#define WEBRTC_MODULES_VIDEO_CODING_EVENT_H_
+
+#include "event_wrapper.h"
+
+namespace webrtc
+{
+
+//#define EVENT_DEBUG
+
+class VCMEvent : public EventWrapper
+{
+public:
+    VCMEvent() : _event(*EventWrapper::Create()) {};
+
+    virtual ~VCMEvent() { delete &_event; };
+
+    /**
+    *   Release waiting threads
+    */
+    bool Set() { return _event.Set(); };
+
+    bool Reset() { return _event.Reset(); };
+
+    /**
+    *   Wait for this event
+    */
+    EventTypeWrapper Wait(unsigned long maxTime)
+    {
+#ifdef EVENT_DEBUG
+        return kEventTimeout;
+#else
+        return _event.Wait(maxTime);
+#endif
+    };
+
+    /**
+    *   Start a timer
+    */
+    bool StartTimer(bool periodic, unsigned long time)
+                   { return _event.StartTimer(periodic, time); };
+    /**
+    *   Stop the timer
+    */
+    bool StopTimer() { return _event.StopTimer(); };
+
+private:
+    EventWrapper&      _event;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_EVENT_H_
diff --git a/src/modules/video_coding/main/source/exp_filter.cc b/src/modules/video_coding/main/source/exp_filter.cc
new file mode 100644
index 0000000..1d6f9a7
--- /dev/null
+++ b/src/modules/video_coding/main/source/exp_filter.cc
@@ -0,0 +1,60 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "exp_filter.h"
+
+#include <math.h>
+
+namespace webrtc {
+
+void
+VCMExpFilter::Reset(float alpha)
+{
+    _alpha = alpha;
+    _filtered = -1.0;
+}
+
+float
+VCMExpFilter::Apply(float exp, float sample)
+{
+    if (_filtered == -1.0)
+    {
+        // Initialize filtered bit rates
+        _filtered = sample;
+    }
+    else if (exp == 1.0)
+    {
+        _filtered = _alpha * _filtered + (1 - _alpha) * sample;
+    }
+    else
+    {
+        float alpha = pow(_alpha, exp);
+        _filtered = alpha * _filtered + (1 - alpha) * sample;
+    }
+    if (_max != -1 && _filtered > _max)
+    {
+        _filtered = _max;
+    }
+    return _filtered;
+}
+
+void
+VCMExpFilter::UpdateBase(float alpha)
+{
+    _alpha = alpha;
+}
+
+float
+VCMExpFilter::Value() const
+{
+    return _filtered;
+}
+
+}
diff --git a/src/modules/video_coding/main/source/exp_filter.h b/src/modules/video_coding/main/source/exp_filter.h
new file mode 100644
index 0000000..46d206a
--- /dev/null
+++ b/src/modules/video_coding/main/source/exp_filter.h
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_EXP_FILTER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_EXP_FILTER_H_
+
+namespace webrtc
+{
+
+/**********************/
+/* ExpFilter class    */
+/**********************/
+
+class VCMExpFilter
+{
+public:
+    VCMExpFilter(float alpha, float max = -1.0) : _alpha(alpha), _filtered(-1.0), _max(max) {}
+
+    // Resets the filter to its initial state, and resets alpha to the given value
+    //
+    // Input:
+    //          - alpha     : the new value of the filter factor base.
+    void Reset(float alpha);
+
+    // Applies the filter with the given exponent on the provided sample
+    //
+    // Input:
+    //          - exp       : Exponent T in y(k) = alpha^T * y(k-1) + (1 - alpha^T) * x(k)
+    //          - sample    : x(k) in the above filter equation
+    float Apply(float exp, float sample);
+
+    // Return current filtered value: y(k)
+    //
+    // Return value         : The current filter output
+    float Value() const;
+
+    // Change the filter factor base
+    //
+    // Input:
+    //          - alpha     : The new filter factor base.
+    void UpdateBase(float alpha);
+
+private:
+    float          _alpha;     // Filter factor base
+    float          _filtered;  // Current filter output
+    const float    _max;
+}; // end of ExpFilter class
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_EXP_FILTER_H_
diff --git a/src/modules/video_coding/main/source/fec_tables_xor.h b/src/modules/video_coding/main/source/fec_tables_xor.h
new file mode 100644
index 0000000..3c9eaeb
--- /dev/null
+++ b/src/modules/video_coding/main/source/fec_tables_xor.h
@@ -0,0 +1,6478 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_SOURCE_FEC_TABLES_XOR_H_
+#define WEBRTC_MODULES_VIDEO_CODING_SOURCE_FEC_TABLES_XOR_H_
+
+namespace webrtc
+{
+
+// Table for Protection factor (code rate) of delta frames, for the XOR FEC.
+// Input is the packet loss and average bits/frame (bitRate/frame_rate):
+// i.e., codeRateXORTable[k] where k = rate_i*129 + loss_j; loss_j=0,1,..128,
+// and rate_i varies over some range
+const unsigned char VCMCodeRateXORTable[6450] = {
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+0,
+0,
+0,
+0,
+0,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+0,
+0,
+0,
+0,
+31,
+31,
+31,
+31,
+31,
+31,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+0,
+0,
+25,
+25,
+25,
+25,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+0,
+0,
+0,
+0,
+25,
+25,
+25,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+0,
+0,
+0,
+0,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+0,
+0,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+42,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+0,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+0,
+0,
+0,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+36,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+0,
+0,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+31,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+0,
+0,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+28,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+56,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+0,
+0,
+25,
+25,
+25,
+25,
+25,
+25,
+25,
+51,
+51,
+51,
+51,
+51,
+51,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+0,
+25,
+25,
+25,
+25,
+25,
+25,
+51,
+51,
+51,
+51,
+51,
+51,
+51,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+46,
+46,
+46,
+46,
+46,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+0,
+23,
+23,
+23,
+23,
+23,
+23,
+23,
+46,
+46,
+46,
+46,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+0,
+23,
+23,
+23,
+23,
+23,
+23,
+46,
+46,
+46,
+46,
+46,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+69,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+0,
+21,
+21,
+21,
+21,
+21,
+42,
+42,
+42,
+42,
+42,
+42,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+21,
+21,
+21,
+21,
+21,
+42,
+42,
+42,
+42,
+42,
+42,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+106,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+19,
+19,
+19,
+19,
+19,
+39,
+39,
+39,
+39,
+58,
+58,
+58,
+58,
+58,
+58,
+58,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+0,
+19,
+19,
+19,
+19,
+39,
+39,
+39,
+39,
+39,
+58,
+58,
+58,
+58,
+58,
+58,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+78,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+98,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+117,
+0,
+18,
+18,
+18,
+18,
+36,
+36,
+36,
+54,
+54,
+54,
+54,
+54,
+54,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+18,
+18,
+18,
+18,
+36,
+36,
+36,
+54,
+54,
+54,
+54,
+54,
+54,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+18,
+18,
+18,
+18,
+36,
+36,
+36,
+54,
+54,
+54,
+54,
+54,
+54,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+91,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+17,
+17,
+17,
+17,
+34,
+34,
+51,
+51,
+51,
+51,
+51,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+0,
+17,
+17,
+17,
+17,
+34,
+34,
+51,
+51,
+51,
+51,
+51,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+68,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+119,
+0,
+15,
+15,
+15,
+31,
+31,
+31,
+47,
+47,
+47,
+47,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+15,
+15,
+15,
+31,
+31,
+31,
+47,
+47,
+47,
+47,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+63,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+79,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+95,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+111,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+15,
+15,
+15,
+30,
+30,
+30,
+45,
+45,
+45,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+0,
+15,
+15,
+15,
+30,
+30,
+30,
+45,
+45,
+45,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+0,
+15,
+15,
+15,
+30,
+30,
+45,
+45,
+45,
+45,
+60,
+60,
+60,
+60,
+60,
+60,
+60,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+75,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+90,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+105,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+0,
+14,
+14,
+28,
+28,
+28,
+42,
+42,
+56,
+56,
+56,
+56,
+56,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+14,
+14,
+28,
+28,
+28,
+42,
+42,
+56,
+56,
+56,
+56,
+56,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+70,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+113,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+13,
+13,
+26,
+26,
+40,
+40,
+40,
+40,
+53,
+53,
+67,
+67,
+67,
+67,
+67,
+67,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+0,
+13,
+13,
+26,
+26,
+40,
+40,
+40,
+40,
+53,
+53,
+67,
+67,
+67,
+67,
+67,
+67,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+80,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+93,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+107,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+120,
+0,
+12,
+12,
+25,
+25,
+38,
+38,
+38,
+38,
+63,
+63,
+63,
+63,
+63,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+12,
+12,
+25,
+25,
+38,
+38,
+38,
+38,
+63,
+63,
+63,
+63,
+63,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+76,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+89,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+102,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+114,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+12,
+12,
+24,
+24,
+36,
+36,
+48,
+48,
+48,
+48,
+60,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+0,
+12,
+12,
+24,
+24,
+36,
+36,
+48,
+48,
+48,
+48,
+60,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+0,
+12,
+12,
+24,
+24,
+36,
+48,
+48,
+48,
+48,
+48,
+60,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+72,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+85,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+97,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+109,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+0,
+11,
+11,
+23,
+34,
+34,
+34,
+46,
+46,
+57,
+57,
+57,
+57,
+57,
+57,
+69,
+69,
+69,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+11,
+11,
+23,
+34,
+34,
+34,
+46,
+46,
+57,
+57,
+57,
+57,
+57,
+57,
+69,
+69,
+69,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+81,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+92,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+104,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+115,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+127,
+0,
+11,
+11,
+22,
+33,
+33,
+44,
+44,
+44,
+55,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+66,
+88,
+88,
+88,
+88,
+88,
+88,
+88,
+88,
+88,
+88,
+88,
+88,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+99,
+110,
+110,
+110,
+110,
+110,
+110,
+110,
+110,
+110,
+110,
+110,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+121,
+
+
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_SOURCE_FEC_TABLES_XOR_H_
diff --git a/src/modules/video_coding/main/source/frame_buffer.cc b/src/modules/video_coding/main/source/frame_buffer.cc
new file mode 100644
index 0000000..df7b37b
--- /dev/null
+++ b/src/modules/video_coding/main/source/frame_buffer.cc
@@ -0,0 +1,402 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "../../../../engine_configurations.h"
+#include "frame_buffer.h"
+#include "packet.h"
+
+#include <cassert>
+#include <string.h>
+
+#if defined(_WIN32)
+    // VS 2005: Don't warn for default initialized arrays. See help for more info.
+    #pragma warning(disable:4351)
+#endif
+
+namespace webrtc {
+
+// Constructor
+VCMFrameBuffer::VCMFrameBuffer() :
+    _state(kStateFree),
+    _frameCounted(false),
+    _nackCount(0),
+    _latestPacketTimeMs(-1)
+{
+}
+
+// Destructor
+VCMFrameBuffer::~VCMFrameBuffer()
+{
+    Reset();
+}
+
+VCMFrameBuffer::VCMFrameBuffer(VCMFrameBuffer& rhs)
+:
+VCMEncodedFrame(rhs),
+_state(rhs._state),
+_frameCounted(rhs._frameCounted),
+_sessionInfo(),
+_nackCount(rhs._nackCount),
+_latestPacketTimeMs(rhs._latestPacketTimeMs)
+{
+    _sessionInfo = rhs._sessionInfo;
+}
+
+webrtc::FrameType
+VCMFrameBuffer::FrameType() const
+{
+    return _sessionInfo.FrameType();
+}
+
+void
+VCMFrameBuffer::SetPreviousFrameLoss()
+{
+    _sessionInfo.SetPreviousFrameLoss();
+}
+
+WebRtc_Word32
+VCMFrameBuffer::GetLowSeqNum()
+{
+    return _sessionInfo.GetLowSeqNum();
+}
+
+// Get highest sequence number for complete sessions
+WebRtc_Word32
+VCMFrameBuffer::GetHighSeqNumComplete()
+{
+    if (_sessionInfo.IsSessionComplete())
+    {
+        return _sessionInfo.GetHighSeqNum();
+    }
+    return -1;
+}
+
+WebRtc_Word32
+VCMFrameBuffer::GetHighSeqNum()
+{
+    return _sessionInfo.GetHighSeqNum();
+}
+
+bool
+VCMFrameBuffer::IsSessionComplete()
+{
+    return _sessionInfo.IsSessionComplete();
+}
+
+// Insert packet
+VCMFrameBufferEnum
+VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs)
+{
+    if (_state == kStateDecoding)
+    {
+        // Do not insert packet
+        return kIncomplete;
+    }
+
+    // Sanity to check if the frame has been freed. (Too old for example)
+    if(_state == kStateFree)
+    {
+        return kStateError;
+    }
+
+    // is this packet part of this frame
+    if (TimeStamp() && (TimeStamp() != packet.timestamp))
+    {
+        return kTimeStampError;
+    }
+
+    // sanity checks
+    if (_size + packet.sizeBytes +
+        (packet.insertStartCode ?  kH264StartCodeLengthBytes : 0 )
+        > kMaxJBFrameSizeBytes)
+    {
+        return kSizeError;
+    }
+    if (NULL == packet.dataPtr && packet.sizeBytes > 0)
+    {
+        return kSizeError;
+    }
+    if ((packet.frameType != kFrameEmpty) &&
+        (!_sessionInfo.HaveStartSeqNumber()))
+    {
+        _sessionInfo.SetStartSeqNumber(packet.seqNum);
+    }
+    if (packet.dataPtr != NULL)
+    {
+        _payloadType = packet.payloadType;
+    }
+
+    if (kStateEmpty == _state)
+    {
+        // First packet (empty and/or media) inserted into this frame.
+        // store some info and set some initial values.
+        _timeStamp = packet.timestamp;
+        _codec = packet.codec;
+        if (packet.frameType != kFrameEmpty)
+        {
+            // first media packet
+            SetState(kStateIncomplete);
+        }
+    }
+
+    WebRtc_UWord32 requiredSizeBytes = Length() + packet.sizeBytes +
+                   (packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
+    if (requiredSizeBytes >= _size)
+    {
+        const WebRtc_UWord32 increments = requiredSizeBytes /
+                                          kBufferIncStepSizeBytes +
+                                        (requiredSizeBytes %
+                                         kBufferIncStepSizeBytes > 0);
+        const WebRtc_UWord32 newSize = _size +
+                                       increments * kBufferIncStepSizeBytes;
+        if (newSize > kMaxJBFrameSizeBytes)
+        {
+            return kSizeError;
+        }
+        if (VerifyAndAllocate(newSize) == -1)
+        {
+            return kSizeError;
+        }
+    }
+    WebRtc_Word64 retVal = _sessionInfo.InsertPacket(packet, _buffer);
+    if (retVal == -1)
+    {
+        return kSizeError;
+    }
+    else if (retVal == -2)
+    {
+        return kDuplicatePacket;
+    }
+    // update length
+    _length = Length() + static_cast<WebRtc_UWord32>(retVal);
+
+    _latestPacketTimeMs = timeInMs;
+
+    if(_sessionInfo.IsSessionComplete())
+    {
+        return kCompleteSession;
+    }
+    else
+    {
+        // this layer is not complete
+        if (_state == kStateComplete)
+        {
+            // we already have a complete layer
+            // wait for all independent layers belonging to the same frame
+            _state = kStateIncomplete;
+        }
+    }
+    return kIncomplete;
+}
+
+WebRtc_Word64 VCMFrameBuffer::LatestPacketTimeMs()
+{
+    return _latestPacketTimeMs;
+}
+
+// Zero out all entries in list up to and including the (first) entry equal to _lowSeqNum
+WebRtc_Word32 VCMFrameBuffer::ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 num)
+{
+    if(_sessionInfo.ZeroOutSeqNum(list, num) != 0)
+    {
+       return -1;
+    }
+    return 0;
+}
+
+// Zero out all entries in list up to and including the (first) entry equal to
+// _lowSeqNum. Hybrid mode: 1. Don't NACK FEC packets 2. Make a smart decision
+// on whether to NACK or not
+
+WebRtc_Word32 VCMFrameBuffer::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
+                                                  WebRtc_Word32 num,
+                                                  float rttScore)
+{
+    return _sessionInfo.ZeroOutSeqNumHybrid(list, num, rttScore);
+}
+
+void VCMFrameBuffer::IncrementNackCount()
+{
+    _nackCount++;
+}
+
+WebRtc_Word16 VCMFrameBuffer::GetNackCount() const
+{
+    return _nackCount;
+}
+
+bool VCMFrameBuffer::HaveLastPacket()
+{
+    return _sessionInfo.HaveLastPacket();
+}
+
+bool
+VCMFrameBuffer::ForceSetHaveLastPacket()
+{
+    _sessionInfo.ForceSetHaveLastPacket();
+    return _sessionInfo.IsSessionComplete();
+}
+
+void VCMFrameBuffer::Reset()
+{
+    _length = 0;
+    _timeStamp = 0;
+    _sessionInfo.Reset();
+    _frameCounted = false;
+    _payloadType = 0;
+    _nackCount = 0;
+    _latestPacketTimeMs = -1;
+    _state = kStateFree;
+    VCMEncodedFrame::Reset();
+}
+
+// Makes sure the session contains a decodable stream.
+void
+VCMFrameBuffer::MakeSessionDecodable()
+{
+    WebRtc_Word32 retVal = _sessionInfo.MakeSessionDecodable(_buffer);
+    // update length
+    _length -= retVal;
+}
+
+// Set state of frame
+void
+VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state)
+{
+    if(_state == state)
+    {
+        return;
+    }
+    switch (state)
+    {
+    case kStateFree:
+        // Reset everything
+        // We can go to this state from all other states.
+        // The one setting the state to free must ensure
+        // that the frame is removed from the timestamp
+        // ordered frame list in the jb.
+        Reset();
+        break;
+
+    case kStateIncomplete:
+        // we can go to this state from state kStateEmpty
+        assert(_state == kStateEmpty ||
+            _state == kStateDecoding);
+
+        // Do nothing, we received a packet
+        break;
+
+    case kStateComplete:
+        assert(_state == kStateEmpty ||
+               _state == kStateIncomplete ||
+               _state == kStateDecodable);
+
+        break;
+
+    case kStateEmpty:
+        assert(_state == kStateFree);
+        // Do nothing
+        break;
+
+    case kStateDecoding:
+        // we can go to this state from state kStateComplete kStateIncomplete
+        assert(_state == kStateComplete || _state == kStateIncomplete ||
+               _state == kStateDecodable);
+        // Transfer frame information to EncodedFrame and create any codec specific information
+        RestructureFrameInformation();
+        break;
+
+    case kStateDecodable:
+        if (_state == kStateComplete)
+        {
+            // if complete, obviously decodable, keep as is.
+            return;
+        }
+        assert(_state == kStateEmpty ||
+               _state == kStateIncomplete);
+        break;
+
+    default:
+        // Should never happen
+        assert(!"FrameBuffer::SetState Incorrect frame buffer state as input");
+        return;
+    }
+    _state = state;
+}
+
+void
+VCMFrameBuffer::RestructureFrameInformation()
+{
+    PrepareForDecode();
+    _frameType = ConvertFrameType(_sessionInfo.FrameType());
+    _completeFrame = _sessionInfo.IsSessionComplete();
+    _missingFrame = _sessionInfo.PreviousFrameLoss();
+}
+
+WebRtc_Word32
+VCMFrameBuffer::ExtractFromStorage(const EncodedVideoData& frameFromStorage)
+{
+    _frameType = ConvertFrameType(frameFromStorage.frameType);
+    _timeStamp = frameFromStorage.timeStamp;
+    _payloadType = frameFromStorage.payloadType;
+    _encodedWidth = frameFromStorage.encodedWidth;
+    _encodedHeight = frameFromStorage.encodedHeight;
+    _missingFrame = frameFromStorage.missingFrame;
+    _completeFrame = frameFromStorage.completeFrame;
+    _renderTimeMs = frameFromStorage.renderTimeMs;
+    _codec = frameFromStorage.codec;
+    if (VerifyAndAllocate(frameFromStorage.payloadSize) < 0)
+    {
+        return VCM_MEMORY;
+    }
+    memcpy(_buffer, frameFromStorage.payloadData, frameFromStorage.payloadSize);
+    _length = frameFromStorage.payloadSize;
+    return VCM_OK;
+}
+
+// Set counted status (as counted by JB or not)
+void VCMFrameBuffer::SetCountedFrame(bool frameCounted)
+{
+    _frameCounted = frameCounted;
+}
+
+bool VCMFrameBuffer::GetCountedFrame()
+{
+    return _frameCounted;
+}
+
+// Get current state of frame
+VCMFrameBufferStateEnum
+VCMFrameBuffer::GetState() const
+{
+    return _state;
+}
+
+// Get current state of frame
+VCMFrameBufferStateEnum
+VCMFrameBuffer::GetState(WebRtc_UWord32& timeStamp) const
+{
+    timeStamp = TimeStamp();
+    return GetState();
+}
+
+bool
+VCMFrameBuffer::IsRetransmitted()
+{
+    return _sessionInfo.IsRetransmitted();
+}
+
+void
+VCMFrameBuffer::PrepareForDecode()
+{
+    _length = _sessionInfo.PrepareForDecode(_buffer, _codec);
+}
+
+}
diff --git a/src/modules/video_coding/main/source/frame_buffer.h b/src/modules/video_coding/main/source/frame_buffer.h
new file mode 100644
index 0000000..65c56a3
--- /dev/null
+++ b/src/modules/video_coding/main/source/frame_buffer.h
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_FRAME_BUFFER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_FRAME_BUFFER_H_
+
+#include "typedefs.h"
+#include "module_common_types.h"
+
+#include "encoded_frame.h"
+#include "frame_list.h"
+#include "jitter_buffer_common.h"
+#include "session_info.h"
+
+namespace webrtc
+{
+
+class VCMFrameBuffer : public VCMEncodedFrame
+{
+public:
+    VCMFrameBuffer();
+    virtual ~VCMFrameBuffer();
+
+    VCMFrameBuffer(VCMFrameBuffer& rhs);
+
+    virtual void Reset();
+
+    VCMFrameBufferEnum InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs);
+
+    // State
+    // Get current state of frame
+    VCMFrameBufferStateEnum GetState() const;
+    // Get current state and timestamp of frame
+    VCMFrameBufferStateEnum GetState(WebRtc_UWord32& timeStamp) const;
+    void SetState(VCMFrameBufferStateEnum state); // Set state of frame
+
+    bool IsRetransmitted();
+    bool IsSessionComplete();
+    bool HaveLastPacket();
+    bool ForceSetHaveLastPacket();
+    // Makes sure the session contain a decodable stream.
+    void MakeSessionDecodable();
+
+    // Sequence numbers
+    // Get lowest packet sequence number in frame
+    WebRtc_Word32 GetLowSeqNum();
+    // Get highest packet sequence number in frame
+    WebRtc_Word32 GetHighSeqNum();
+
+    // Get highest sequence number of complete session
+    WebRtc_Word32 GetHighSeqNumComplete();
+
+    // Set counted status (as counted by JB or not)
+    void SetCountedFrame(bool frameCounted);
+    bool GetCountedFrame();
+
+    // NACK
+    // Zero out all entries in list up to and including the entry equal to _lowSeqNum
+    WebRtc_Word32 ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 num);
+    // Hybrid extension: only NACK important packets, discard FEC packets
+    WebRtc_Word32 ZeroOutSeqNumHybrid(WebRtc_Word32* list,
+                                      WebRtc_Word32 num,
+                                      float rttScore);
+    void IncrementNackCount();
+    WebRtc_Word16 GetNackCount() const;
+
+    WebRtc_Word64 LatestPacketTimeMs();
+
+    webrtc::FrameType FrameType() const;
+    void SetPreviousFrameLoss();
+
+    WebRtc_Word32 ExtractFromStorage(const EncodedVideoData& frameFromStorage);
+
+protected:
+    void RestructureFrameInformation();
+    void PrepareForDecode();
+
+private:
+    VCMFrameBufferStateEnum    _state;         // Current state of the frame
+    bool                       _frameCounted;  // If this frame has been counted by JB
+    VCMSessionInfo             _sessionInfo;
+    WebRtc_UWord16             _nackCount;
+    WebRtc_Word64              _latestPacketTimeMs;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_FRAME_BUFFER_H_
diff --git a/src/modules/video_coding/main/source/frame_dropper.cc b/src/modules/video_coding/main/source/frame_dropper.cc
new file mode 100644
index 0000000..065e452
--- /dev/null
+++ b/src/modules/video_coding/main/source/frame_dropper.cc
@@ -0,0 +1,331 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "frame_dropper.h"
+#include "internal_defines.h"
+#include "trace.h"
+
+namespace webrtc
+{
+
+VCMFrameDropper::VCMFrameDropper(WebRtc_Word32 vcmId)
+:
+_vcmId(vcmId),
+_keyFrameSizeAvgKbits(0.9f),
+_keyFrameRatio(0.99f),
+_dropRatio(0.9f, 0.96f)
+{
+    Reset();
+}
+
+void
+VCMFrameDropper::Reset()
+{
+    _keyFrameRatio.Reset(0.99f);
+    _keyFrameRatio.Apply(1.0f, 1.0f/300.0f); // 1 key frame every 10th second in 30 fps
+    _keyFrameSizeAvgKbits.Reset(0.9f);
+    _keyFrameCount = 0;
+    _accumulator = 0.0f;
+    _accumulatorMax = 150.0f; // assume 300 kb/s and 0.5 s window
+    _targetBitRate = 300.0f;
+    _userFrameRate = 30;
+    _keyFrameSpreadFrames = 0.5f * _userFrameRate;
+    _dropNext = false;
+    _dropRatio.Reset(0.9f);
+    _dropRatio.Apply(0.0f, 0.0f); // Initialize to 0
+    _dropCount = 0;
+    _windowSize = 0.5f;
+    _wasBelowMax = true;
+    _enabled = true;
+    _fastMode = false; // start with normal (non-aggressive) mode
+}
+
+void
+VCMFrameDropper::Enable(bool enable)
+{
+    _enabled = enable;
+}
+
+void
+VCMFrameDropper::Fill(WebRtc_UWord32 frameSizeBytes, bool deltaFrame)
+{
+    if (!_enabled)
+    {
+        return;
+    }
+    float frameSizeKbits = 8.0f * static_cast<float>(frameSizeBytes) / 1000.0f;
+    if (!deltaFrame && !_fastMode) // fast mode does not treat key-frames any different
+    {
+        _keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
+        _keyFrameRatio.Apply(1.0, 1.0);
+        if (frameSizeKbits > _keyFrameSizeAvgKbits.Value())
+        {
+            // Remove the average key frame size since we
+            // compensate for key frames when adding delta
+            // frames.
+            frameSizeKbits -= _keyFrameSizeAvgKbits.Value();
+        }
+        else
+        {
+            // Shouldn't be negative, so zero is the lower bound.
+            frameSizeKbits = 0;
+        }
+        if (_keyFrameRatio.Value() > 1e-5 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
+        {
+            // We are sending key frames more often than our upper bound for
+            // how much we allow the key frame compensation to be spread
+            // out in time. Therefor we must use the key frame ratio rather
+            // than keyFrameSpreadFrames.
+            _keyFrameCount = static_cast<WebRtc_Word32>(1 / _keyFrameRatio.Value() + 0.5);
+        }
+        else
+        {
+            // Compensate for the key frame the following frames
+            _keyFrameCount = static_cast<WebRtc_Word32>(_keyFrameSpreadFrames + 0.5);
+        }
+    }
+    else
+    {
+        // Decrease the keyFrameRatio
+        _keyFrameRatio.Apply(1.0, 0.0);
+    }
+    // Change the level of the accumulator (bucket)
+    _accumulator += frameSizeKbits;
+}
+
+void
+VCMFrameDropper::Leak(WebRtc_UWord32 inputFrameRate)
+{
+    if (!_enabled)
+    {
+        return;
+    }
+    if (inputFrameRate < 1)
+    {
+        return;
+    }
+    if (_targetBitRate < 0.0f)
+    {
+        return;
+    }
+    _keyFrameSpreadFrames = 0.5f * inputFrameRate;
+    // T is the expected bits per frame (target). If all frames were the same size,
+    // we would get T bits per frame. Notice that T is also weighted to be able to
+    // force a lower frame rate if wanted.
+    float T = _targetBitRate / inputFrameRate;
+    if (_keyFrameCount > 0)
+    {
+        // Perform the key frame compensation
+        if (_keyFrameRatio.Value() > 0 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
+        {
+            T -= _keyFrameSizeAvgKbits.Value() * _keyFrameRatio.Value();
+        }
+        else
+        {
+            T -= _keyFrameSizeAvgKbits.Value() / _keyFrameSpreadFrames;
+        }
+        _keyFrameCount--;
+    }
+    _accumulator -= T;
+    UpdateRatio();
+
+}
+
+void
+VCMFrameDropper::UpdateNack(WebRtc_UWord32 nackBytes)
+{
+    if (!_enabled)
+    {
+        return;
+    }
+    _accumulator += static_cast<float>(nackBytes) * 8.0f / 1000.0f;
+}
+
+void
+VCMFrameDropper::FillBucket(float inKbits, float outKbits)
+{
+    _accumulator += (inKbits - outKbits);
+}
+
+void
+VCMFrameDropper::UpdateRatio()
+{
+    if (_accumulator > 1.3f * _accumulatorMax)
+    {
+        // Too far above accumulator max, react faster
+        _dropRatio.UpdateBase(0.8f);
+    }
+    else
+    {
+        // Go back to normal reaction
+        _dropRatio.UpdateBase(0.9f);
+    }
+    if (_accumulator > _accumulatorMax)
+    {
+        // We are above accumulator max, and should ideally
+        // drop a frame. Increase the dropRatio and drop
+        // the frame later.
+        if (_wasBelowMax)
+        {
+            _dropNext = true;
+        }
+        if (_fastMode)
+        {
+            // always drop in aggressive mode
+            _dropNext = true;
+        }
+
+        _dropRatio.Apply(1.0f, 1.0f);
+        _dropRatio.UpdateBase(0.9f);
+    }
+    else
+    {
+        _dropRatio.Apply(1.0f, 0.0f);
+    }
+    if (_accumulator < 0.0f)
+    {
+        _accumulator = 0.0f;
+    }
+    _wasBelowMax = _accumulator < _accumulatorMax;
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId),  "FrameDropper: dropRatio = %f accumulator = %f, accumulatorMax = %f", _dropRatio.Value(), _accumulator, _accumulatorMax);
+}
+
+// This function signals when to drop frames to the caller. It makes use of the dropRatio
+// to smooth out the drops over time.
+bool
+VCMFrameDropper::DropFrame()
+{
+    if (!_enabled)
+    {
+        return false;
+    }
+    if (_dropNext)
+    {
+        _dropNext = false;
+        _dropCount = 0;
+    }
+
+    if (_dropRatio.Value() >= 0.5f) // Drops per keep
+    {
+        // limit is the number of frames we should drop between each kept frame
+        // to keep our drop ratio. limit is positive in this case.
+        float denom = 1.0f - _dropRatio.Value();
+        if (denom < 1e-5)
+        {
+            denom = (float)1e-5;
+        }
+        WebRtc_Word32 limit = static_cast<WebRtc_Word32>(1.0f / denom - 1.0f + 0.5f);
+        if (_dropCount < 0)
+        {
+            // Reset the _dropCount since it was negative and should be positive.
+            if (_dropRatio.Value() > 0.4f)
+            {
+                _dropCount = -_dropCount;
+            }
+            else
+            {
+                _dropCount = 0;
+            }
+        }
+        if (_dropCount < limit)
+        {
+            // As long we are below the limit we should drop frames.
+            _dropCount++;
+            return true;
+        }
+        else
+        {
+            // Only when we reset _dropCount a frame should be kept.
+            _dropCount = 0;
+            return false;
+        }
+    }
+    else if (_dropRatio.Value() > 0.0f && _dropRatio.Value() < 0.5f) // Keeps per drop
+    {
+        // limit is the number of frames we should keep between each drop
+        // in order to keep the drop ratio. limit is negative in this case,
+        // and the _dropCount is also negative.
+        float denom = _dropRatio.Value();
+        if (denom < 1e-5)
+        {
+            denom = (float)1e-5;
+        }
+        WebRtc_Word32 limit = -static_cast<WebRtc_Word32>(1.0f / denom - 1.0f + 0.5f);
+        if (_dropCount > 0)
+        {
+            // Reset the _dropCount since we have a positive
+            // _dropCount, and it should be negative.
+            if (_dropRatio.Value() < 0.6f)
+            {
+                _dropCount = -_dropCount;
+            }
+            else
+            {
+                _dropCount = 0;
+            }
+        }
+        if (_dropCount > limit)
+        {
+            if (_dropCount == 0)
+            {
+                // Drop frames when we reset _dropCount.
+                _dropCount--;
+                return true;
+            }
+            else
+            {
+                // Keep frames as long as we haven't reached limit.
+                _dropCount--;
+                return false;
+            }
+        }
+        else
+        {
+            _dropCount = 0;
+            return false;
+        }
+    }
+    _dropCount = 0;
+    return false;
+
+    // A simpler version, unfiltered and quicker
+    //bool dropNext = _dropNext;
+    //_dropNext = false;
+    //return dropNext;
+}
+
+void
+VCMFrameDropper::SetRates(float bitRate, float userFrameRate)
+{
+    // Bit rate of -1 means infinite bandwidth.
+    _accumulatorMax = bitRate * _windowSize; // bitRate * windowSize (in seconds)
+    if (_targetBitRate > 0.0f && bitRate < _targetBitRate && _accumulator > _accumulatorMax)
+    {
+        // Rescale the accumulator level if the accumulator max decreases
+        _accumulator = bitRate / _targetBitRate * _accumulator;
+    }
+    _targetBitRate = bitRate;
+    if (userFrameRate > 0.0f)
+    {
+        _userFrameRate = userFrameRate;
+    }
+}
+
+float
+VCMFrameDropper::ActualFrameRate(WebRtc_UWord32 inputFrameRate) const
+{
+    if (!_enabled)
+    {
+        return static_cast<float>(inputFrameRate);
+    }
+    return inputFrameRate * (1.0f - _dropRatio.Value());
+}
+
+}
diff --git a/src/modules/video_coding/main/source/frame_dropper.h b/src/modules/video_coding/main/source/frame_dropper.h
new file mode 100644
index 0000000..5e7e8a1
--- /dev/null
+++ b/src/modules/video_coding/main/source/frame_dropper.h
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_FRAME_DROPPER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_FRAME_DROPPER_H_
+
+#include "exp_filter.h"
+#include "typedefs.h"
+
+namespace webrtc
+{
+
+/******************************/
+/* VCMFrameDropper class     */
+/****************************/
+// The Frame Dropper implements a variant of the leaky bucket algorithm
+// for keeping track of when to drop frames to avoid bit rate
+// over use when the encoder can't keep its bit rate.
+class VCMFrameDropper
+{
+public:
+    VCMFrameDropper(WebRtc_Word32 vcmId = 0);
+    // Resets the FrameDropper to its initial state.
+    // This means that the frameRateWeight is set to its
+    // default value as well.
+    void Reset();
+
+    void Enable(bool enable);
+    // Answers the question if it's time to drop a frame
+    // if we want to reach a given frame rate. Must be
+    // called for every frame.
+    //
+    // Return value     : True if we should drop the current frame
+    bool DropFrame();
+    // Updates the FrameDropper with the size of the latest encoded
+    // frame. The FrameDropper calculates a new drop ratio (can be
+    // seen as the probability to drop a frame) and updates its
+    // internal statistics.
+    //
+    // Input:
+    //          - frameSizeBytes    : The size of the latest frame
+    //                                returned from the encoder.
+    //          - deltaFrame        : True if the encoder returned
+    //                                a key frame.
+    void Fill(WebRtc_UWord32 frameSizeBytes, bool deltaFrame);
+
+    void Leak(WebRtc_UWord32 inputFrameRate);
+
+    void UpdateNack(WebRtc_UWord32 nackBytes);
+
+    // Sets the target bit rate and the frame rate produced by
+    // the camera.
+    //
+    // Input:
+    //          - bitRate       : The target bit rate
+    void SetRates(float bitRate, float userFrameRate);
+
+    // Return value     : The current average frame rate produced
+    //                    if the DropFrame() function is used as
+    //                    instruction of when to drop frames.
+    float ActualFrameRate(WebRtc_UWord32 inputFrameRate) const;
+
+private:
+    void FillBucket(float inKbits, float outKbits);
+    void UpdateRatio();
+
+    WebRtc_Word32     _vcmId;
+    VCMExpFilter       _keyFrameSizeAvgKbits;
+    VCMExpFilter       _keyFrameRatio;
+    float           _keyFrameSpreadFrames;
+    WebRtc_Word32     _keyFrameCount;
+    float           _accumulator;
+    float           _accumulatorMax;
+    float           _targetBitRate;
+    bool            _dropNext;
+    VCMExpFilter       _dropRatio;
+    WebRtc_Word32     _dropCount;
+    float           _windowSize;
+    float           _userFrameRate;
+    bool            _wasBelowMax;
+    bool            _enabled;
+    bool            _fastMode;
+}; // end of VCMFrameDropper class
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_FRAME_DROPPER_H_
diff --git a/src/modules/video_coding/main/source/frame_list.cc b/src/modules/video_coding/main/source/frame_list.cc
new file mode 100644
index 0000000..e79dc91
--- /dev/null
+++ b/src/modules/video_coding/main/source/frame_list.cc
@@ -0,0 +1,113 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "frame_list.h"
+#include "frame_buffer.h"
+#include "jitter_buffer.h"
+#include <cstdlib>
+
+namespace webrtc {
+
+VCMFrameListTimestampOrderAsc::~VCMFrameListTimestampOrderAsc()
+{
+    Flush();
+}
+
+void
+VCMFrameListTimestampOrderAsc::Flush()
+{
+    while(Erase(First()) != -1) { }
+}
+
+// Inserts frame in timestamp order, with the oldest timestamp first. Takes wrap arounds into account
+WebRtc_Word32
+VCMFrameListTimestampOrderAsc::Insert(VCMFrameBuffer* frame)
+{
+    VCMFrameListItem* item = static_cast<VCMFrameListItem*>(First());
+    VCMFrameListItem* newItem = new VCMFrameListItem(frame);
+    bool inserted = false;
+    if (newItem == NULL)
+    {
+        return -1;
+    }
+    while (item != NULL)
+    {
+        const WebRtc_UWord32 itemTimestamp = item->GetItem()->TimeStamp();
+        if (VCMJitterBuffer::LatestTimestamp(itemTimestamp, frame->TimeStamp()) == itemTimestamp)
+        {
+            if (InsertBefore(item, newItem) < 0)
+            {
+                delete newItem;
+                return -1;
+            }
+            inserted = true;
+            break;
+        }
+        item = Next(item);
+    }
+    if (!inserted && ListWrapper::Insert(ListWrapper::Last(), newItem) < 0)
+    {
+        delete newItem;
+        return -1;
+    }
+    return 0;
+}
+
+VCMFrameBuffer*
+VCMFrameListTimestampOrderAsc::FirstFrame() const
+{
+    VCMFrameListItem* item = First();
+    if (item != NULL)
+    {
+        return item->GetItem();
+    }
+    return NULL;
+}
+
+VCMFrameListItem*
+VCMFrameListTimestampOrderAsc::FindFrameListItem(FindFrameCriteria criteria,
+                                         const void* compareWith,
+                                         VCMFrameListItem* startItem) const
+{
+    if (startItem == NULL)
+    {
+        startItem = First();
+    }
+    if (criteria == NULL)
+    {
+        return NULL;
+    }
+    while (startItem != NULL)
+    {
+        if (criteria(startItem->GetItem(), compareWith))
+        {
+            return startItem;
+        }
+        startItem = Next(startItem);
+    }
+    // No frame found
+    return NULL;
+}
+
+VCMFrameBuffer*
+VCMFrameListTimestampOrderAsc::FindFrame(FindFrameCriteria criteria,
+                                         const void* compareWith,
+                                         VCMFrameListItem* startItem) const
+{
+    const VCMFrameListItem* frameListItem = FindFrameListItem(criteria, compareWith, startItem);
+    if (frameListItem == NULL)
+    {
+        return NULL;
+    }
+    return frameListItem->GetItem();
+}
+
+}
+
diff --git a/src/modules/video_coding/main/source/frame_list.h b/src/modules/video_coding/main/source/frame_list.h
new file mode 100644
index 0000000..cc5d053
--- /dev/null
+++ b/src/modules/video_coding/main/source/frame_list.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_FRAME_LIST_H_
+#define WEBRTC_MODULES_VIDEO_CODING_FRAME_LIST_H_
+
+#include "list_wrapper.h"
+#include "typedefs.h"
+#include <stdlib.h>
+
+namespace webrtc
+{
+
+class VCMFrameBuffer;
+
+typedef bool (*FindFrameCriteria)(VCMFrameBuffer*, const void*);
+
+class VCMFrameListItem : public ListItem
+{
+    friend class VCMFrameListTimestampOrderAsc;
+public:
+    VCMFrameListItem(const VCMFrameBuffer* ptr) : ListItem(ptr) {}
+    ~VCMFrameListItem() {};
+
+    VCMFrameBuffer* GetItem() const
+            { return static_cast<VCMFrameBuffer*>(ListItem::GetItem()); }
+};
+
+class VCMFrameListTimestampOrderAsc : public ListWrapper
+{
+public:
+    VCMFrameListTimestampOrderAsc() : ListWrapper() {};
+    ~VCMFrameListTimestampOrderAsc();
+
+    void Flush();
+
+    // Inserts frame in timestamp order, with the oldest timestamp first.
+    // Takes wrap arounds into account.
+    WebRtc_Word32 Insert(VCMFrameBuffer* frame);
+    VCMFrameBuffer* FirstFrame() const;
+    VCMFrameListItem* Next(VCMFrameListItem* item) const
+            { return static_cast<VCMFrameListItem*>(ListWrapper::Next(item)); }
+    VCMFrameListItem* Previous(VCMFrameListItem* item) const
+            { return static_cast<VCMFrameListItem*>(ListWrapper::Previous(item)); }
+    VCMFrameListItem* First() const
+            { return static_cast<VCMFrameListItem*>(ListWrapper::First()); }
+    VCMFrameListItem* Last() const
+            { return static_cast<VCMFrameListItem*>(ListWrapper::Last()); }
+    VCMFrameListItem* FindFrameListItem(FindFrameCriteria criteria,
+                              const void* compareWith = NULL,
+                              VCMFrameListItem* startItem = NULL) const;
+    VCMFrameBuffer* FindFrame(FindFrameCriteria criteria,
+                                             const void* compareWith = NULL,
+                                             VCMFrameListItem* startItem = NULL) const;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_FRAME_LIST_H_
diff --git a/src/modules/video_coding/main/source/generic_decoder.cc b/src/modules/video_coding/main/source/generic_decoder.cc
new file mode 100644
index 0000000..1fddb52
--- /dev/null
+++ b/src/modules/video_coding/main/source/generic_decoder.cc
@@ -0,0 +1,203 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "video_coding.h"
+#include "trace.h"
+#include "generic_decoder.h"
+#include "internal_defines.h"
+#include "tick_time.h"
+
+namespace webrtc {
+
+VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming& timing)
+:
+_critSect(*CriticalSectionWrapper::CreateCriticalSection()),
+_receiveCallback(NULL),
+_timing(timing),
+_timestampMap(kDecoderFrameMemoryLength)
+{
+}
+
+VCMDecodedFrameCallback::~VCMDecodedFrameCallback()
+{
+    delete &_critSect;
+}
+
+void VCMDecodedFrameCallback::SetUserReceiveCallback(VCMReceiveCallback* receiveCallback)
+{
+    CriticalSectionScoped cs(_critSect);
+    _receiveCallback = receiveCallback;
+}
+
+WebRtc_Word32 VCMDecodedFrameCallback::Decoded(RawImage& decodedImage)
+{
+    CriticalSectionScoped cs(_critSect);
+    VCMFrameInformation* frameInfo = static_cast<VCMFrameInformation*>(_timestampMap.Pop(decodedImage._timeStamp));
+    if (frameInfo == NULL)
+    {
+        return WEBRTC_VIDEO_CODEC_ERROR;
+    }
+
+    WebRtc_Word32 ret = _timing.StopDecodeTimer(decodedImage._timeStamp, frameInfo->decodeStartTimeMs, VCMTickTime::MillisecondTimestamp());
+
+    if (_receiveCallback != NULL)
+    {
+        _frame.Swap(decodedImage._buffer, decodedImage._length, decodedImage._size);
+        _frame.SetWidth(decodedImage._width);
+        _frame.SetHeight(decodedImage._height);
+        _frame.SetTimeStamp(decodedImage._timeStamp);
+        _frame.SetRenderTime(frameInfo->renderTimeMs);
+        // Convert raw image to video frame
+        WebRtc_Word32 callbackReturn = _receiveCallback->FrameToRender(_frame);
+        if (callbackReturn < 0)
+        {
+            return callbackReturn;
+        }
+    }
+    if (ret < 0)
+    {
+        return ret;
+    }
+    return WEBRTC_VIDEO_CODEC_OK;
+}
+
+WebRtc_Word32
+VCMDecodedFrameCallback::ReceivedDecodedReferenceFrame(const WebRtc_UWord64 pictureId)
+{
+    CriticalSectionScoped cs(_critSect);
+    if (_receiveCallback != NULL)
+    {
+        return _receiveCallback->ReceivedDecodedReferenceFrame(pictureId);
+    }
+    return -1;
+}
+
+WebRtc_Word32
+VCMDecodedFrameCallback::ReceivedDecodedFrame(const WebRtc_UWord64 pictureId)
+{
+    _lastReceivedPictureID = pictureId;
+    return 0;
+}
+
+WebRtc_UWord64 VCMDecodedFrameCallback::LastReceivedPictureID() const
+{
+    return _lastReceivedPictureID;
+}
+
+WebRtc_Word32 VCMDecodedFrameCallback::Map(WebRtc_UWord32 timestamp, VCMFrameInformation* frameInfo)
+{
+    CriticalSectionScoped cs(_critSect);
+    return _timestampMap.Add(timestamp, frameInfo);
+}
+
+WebRtc_Word32 VCMDecodedFrameCallback::Pop(WebRtc_UWord32 timestamp)
+{
+    CriticalSectionScoped cs(_critSect);
+    if (_timestampMap.Pop(timestamp) == NULL)
+    {
+        return VCM_GENERAL_ERROR;
+    }
+    return VCM_OK;
+}
+
+VCMGenericDecoder::VCMGenericDecoder(VideoDecoder& decoder, WebRtc_Word32 id, bool isExternal)
+:
+_id(id),
+_callback(NULL),
+_frameInfos(),
+_nextFrameInfoIdx(0),
+_decoder(decoder),
+_codecType(kVideoCodecUnknown),
+_isExternal(isExternal),
+_requireKeyFrame(false),
+_keyFrameDecoded(false)
+{
+}
+
+VCMGenericDecoder::~VCMGenericDecoder()
+{
+}
+
+WebRtc_Word32 VCMGenericDecoder::InitDecode(const VideoCodec* settings, WebRtc_Word32 numberOfCores, bool requireKeyFrame)
+{
+    _requireKeyFrame = requireKeyFrame;
+    _keyFrameDecoded = false;
+    _codecType = settings->codecType;
+
+    return _decoder.InitDecode(settings, numberOfCores);
+}
+
+WebRtc_Word32 VCMGenericDecoder::Decode(const VCMEncodedFrame& frame)
+{
+    if (_requireKeyFrame &&
+        !_keyFrameDecoded &&
+        frame.FrameType() != kVideoFrameKey &&
+        frame.FrameType() != kVideoFrameGolden)
+    {
+        // Require key frame is enabled, meaning that one key frame must be decoded
+        // before we can decode delta frames.
+        return VCM_CODEC_ERROR;
+    }
+    _frameInfos[_nextFrameInfoIdx].decodeStartTimeMs = VCMTickTime::MillisecondTimestamp();
+    _frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs();
+    _callback->Map(frame.TimeStamp(), &_frameInfos[_nextFrameInfoIdx]);
+
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_id),
+               "Decoding timestamp %u",
+               frame.TimeStamp());
+
+    _nextFrameInfoIdx = (_nextFrameInfoIdx + 1) % kDecoderFrameMemoryLength;
+
+    WebRtc_Word32 ret = _decoder.Decode(frame.EncodedImage(),
+                                        frame.MissingFrame(),
+                                        frame.CodecSpecificInfo(),
+                                        frame.RenderTimeMs());
+
+    if (ret < WEBRTC_VIDEO_CODEC_OK)
+    {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id), "Decoder error: %d\n", ret);
+        _callback->Pop(frame.TimeStamp());
+        return ret;
+    }
+    // Update the key frame decoded variable so that we know whether or not we've decoded a key frame since reset.
+    _keyFrameDecoded = (frame.FrameType() == kVideoFrameKey || frame.FrameType() == kVideoFrameGolden);
+    return ret;
+}
+
+WebRtc_Word32
+VCMGenericDecoder::Release()
+{
+    _keyFrameDecoded = false;
+    return _decoder.Release();
+}
+
+WebRtc_Word32 VCMGenericDecoder::Reset()
+{
+    _keyFrameDecoded = false;
+    return _decoder.Reset();
+}
+
+WebRtc_Word32 VCMGenericDecoder::SetCodecConfigParameters(const WebRtc_UWord8* buffer, WebRtc_Word32 size)
+{
+    return _decoder.SetCodecConfigParameters(buffer, size);
+}
+
+WebRtc_Word32 VCMGenericDecoder::RegisterDecodeCompleteCallback(VCMDecodedFrameCallback* callback)
+{
+    _callback = callback;
+    return _decoder.RegisterDecodeCompleteCallback(callback);
+}
+
+bool VCMGenericDecoder::External() const
+{
+    return _isExternal;
+}
+
+}
diff --git a/src/modules/video_coding/main/source/generic_decoder.h b/src/modules/video_coding/main/source/generic_decoder.h
new file mode 100644
index 0000000..9569055
--- /dev/null
+++ b/src/modules/video_coding/main/source/generic_decoder.h
@@ -0,0 +1,120 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_GENERIC_DECODER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_GENERIC_DECODER_H_
+
+#include "timing.h"
+#include "timestamp_map.h"
+#include "video_codec_interface.h"
+#include "encoded_frame.h"
+#include "module_common_types.h"
+
+namespace webrtc
+{
+
+class VCMReceiveCallback;
+
+enum { kDecoderFrameMemoryLength = 10 };
+
+struct VCMFrameInformation
+{
+    WebRtc_Word64     renderTimeMs;
+    WebRtc_Word64     decodeStartTimeMs;
+    void*             userData;
+};
+
+class VCMDecodedFrameCallback : public DecodedImageCallback
+{
+public:
+    VCMDecodedFrameCallback(VCMTiming& timing);
+    virtual ~VCMDecodedFrameCallback();
+    void SetUserReceiveCallback(VCMReceiveCallback* receiveCallback);
+
+    virtual WebRtc_Word32 Decoded(RawImage& decodedImage);
+    virtual WebRtc_Word32 ReceivedDecodedReferenceFrame(const WebRtc_UWord64 pictureId);
+    virtual WebRtc_Word32 ReceivedDecodedFrame(const WebRtc_UWord64 pictureId);
+
+    WebRtc_UWord64 LastReceivedPictureID() const;
+
+    WebRtc_Word32 Map(WebRtc_UWord32 timestamp, VCMFrameInformation* frameInfo);
+    WebRtc_Word32 Pop(WebRtc_UWord32 timestamp);
+
+private:
+    CriticalSectionWrapper&        _critSect;
+    VideoFrame                  _frame;
+    VCMReceiveCallback*         _receiveCallback;
+    VCMTiming&                  _timing;
+    VCMTimestampMap             _timestampMap;
+    WebRtc_UWord64				_lastReceivedPictureID;
+};
+
+
+class VCMGenericDecoder
+{
+    friend class VCMCodecDataBase;
+public:
+    VCMGenericDecoder(VideoDecoder& decoder, WebRtc_Word32 id = 0, bool isExternal = false);
+    ~VCMGenericDecoder();
+
+    /**
+    *	Initialize the decoder with the information from the VideoCodec
+    */
+    WebRtc_Word32 InitDecode(const VideoCodec* settings,
+                             WebRtc_Word32 numberOfCores,
+                             bool requireKeyFrame);
+
+    /**
+    *	Decode to a raw I420 frame,
+    *
+    *	inputVideoBuffer	reference to encoded video frame
+    */
+    WebRtc_Word32 Decode(const VCMEncodedFrame& inputFrame);
+
+    /**
+    *	Free the decoder memory
+    */
+    WebRtc_Word32 Release();
+
+    /**
+    *	Reset the decoder state, prepare for a new call
+    */
+    WebRtc_Word32 Reset();
+
+    /**
+    *	Codec configuration data sent out-of-band, i.e. in SIP call setup
+    *
+    *	buffer pointer to the configuration data
+    *	size the size of the configuration data in bytes
+    */
+    WebRtc_Word32 SetCodecConfigParameters(const WebRtc_UWord8* /*buffer*/,
+                                           WebRtc_Word32 /*size*/);
+
+    WebRtc_Word32 RegisterDecodeCompleteCallback(VCMDecodedFrameCallback* callback);
+
+    bool External() const;
+
+protected:
+
+    WebRtc_Word32               _id;
+    VCMDecodedFrameCallback*    _callback;
+    VCMFrameInformation         _frameInfos[kDecoderFrameMemoryLength];
+    WebRtc_UWord32              _nextFrameInfoIdx;
+    VideoDecoder&               _decoder;
+    VideoCodecType              _codecType;
+    bool                        _isExternal;
+    bool                        _requireKeyFrame;
+    bool                        _keyFrameDecoded;
+
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_GENERIC_DECODER_H_
diff --git a/src/modules/video_coding/main/source/generic_encoder.cc b/src/modules/video_coding/main/source/generic_encoder.cc
new file mode 100644
index 0000000..eeb3f32
--- /dev/null
+++ b/src/modules/video_coding/main/source/generic_encoder.cc
@@ -0,0 +1,260 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "encoded_frame.h"
+#include "generic_encoder.h"
+#include "media_optimization.h"
+#include "../../../../engine_configurations.h"
+
+namespace webrtc {
+
+//#define DEBUG_ENCODER_BIT_STREAM
+
+VCMGenericEncoder::VCMGenericEncoder(VideoEncoder& encoder, bool internalSource /*= false*/)
+:
+_encoder(encoder),
+_codecType(kVideoCodecUnknown),
+_VCMencodedFrameCallback(NULL),
+_bitRate(0),
+_frameRate(0),
+_internalSource(false)
+{
+}
+
+
+VCMGenericEncoder::~VCMGenericEncoder()
+{
+}
+
+WebRtc_Word32
+VCMGenericEncoder::Reset()
+{
+    _bitRate = 0;
+    _frameRate = 0;
+    _VCMencodedFrameCallback = NULL;
+    return _encoder.Reset();
+}
+
+WebRtc_Word32 VCMGenericEncoder::Release()
+{
+    _bitRate = 0;
+    _frameRate = 0;
+    _VCMencodedFrameCallback = NULL;
+    return _encoder.Release();
+}
+
+WebRtc_Word32
+VCMGenericEncoder::InitEncode(const VideoCodec* settings, WebRtc_Word32 numberOfCores, WebRtc_UWord32 maxPayloadSize)
+{
+    _bitRate = settings->startBitrate;
+    _frameRate = settings->maxFramerate;
+    _codecType = settings->codecType;
+    if (_VCMencodedFrameCallback != NULL)
+    {
+        _VCMencodedFrameCallback->SetCodecType(_codecType);
+    }
+    return _encoder.InitEncode(settings, numberOfCores, maxPayloadSize);
+}
+
+WebRtc_Word32
+VCMGenericEncoder::Encode(const VideoFrame& inputFrame,
+                          const CodecSpecificInfo* codecSpecificInfo,
+                          FrameType frameType)
+{
+    RawImage rawImage(inputFrame.Buffer(), inputFrame.Length(), inputFrame.Size());
+    rawImage._width     = inputFrame.Width();
+    rawImage._height    = inputFrame.Height();
+    rawImage._timeStamp = inputFrame.TimeStamp();
+
+    WebRtc_Word32 ret = _encoder.Encode(rawImage, codecSpecificInfo, VCMEncodedFrame::ConvertFrameType(frameType));
+
+    return ret;
+}
+
+WebRtc_Word32
+VCMGenericEncoder::SetPacketLoss(WebRtc_Word32 packetLoss)
+{
+    return _encoder.SetPacketLoss(packetLoss);
+}
+
+WebRtc_Word32
+VCMGenericEncoder::SetRates(WebRtc_UWord32 newBitRate, WebRtc_UWord32 frameRate)
+{
+    WebRtc_Word32 ret = _encoder.SetRates(newBitRate, frameRate);
+    if (ret < 0)
+    {
+        return ret;
+    }
+    _bitRate = newBitRate;
+    _frameRate = frameRate;
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMGenericEncoder::CodecConfigParameters(WebRtc_UWord8* buffer, WebRtc_Word32 size)
+{
+    WebRtc_Word32 ret = _encoder.CodecConfigParameters(buffer, size);
+    if (ret < 0)
+    {
+        return ret;
+    }
+    return ret;
+}
+
+WebRtc_UWord32 VCMGenericEncoder::BitRate() const
+{
+    return _bitRate;
+}
+
+WebRtc_UWord32 VCMGenericEncoder::FrameRate() const
+{
+    return _frameRate;
+}
+
+WebRtc_Word32
+VCMGenericEncoder::SetPeriodicKeyFrames(bool enable)
+{
+    return _encoder.SetPeriodicKeyFrames(enable);
+}
+
+WebRtc_Word32
+VCMGenericEncoder::RequestFrame(FrameType frameType)
+{
+    RawImage image;
+    return _encoder.Encode(image, NULL, VCMEncodedFrame::ConvertFrameType(frameType));
+}
+
+WebRtc_Word32
+VCMGenericEncoder::RegisterEncodeCallback(VCMEncodedFrameCallback* VCMencodedFrameCallback)
+{
+   _VCMencodedFrameCallback = VCMencodedFrameCallback;
+
+   _VCMencodedFrameCallback->SetCodecType(_codecType);
+   _VCMencodedFrameCallback->SetInternalSource(_internalSource);
+   return _encoder.RegisterEncodeCompleteCallback(_VCMencodedFrameCallback);
+}
+
+bool
+VCMGenericEncoder::InternalSource() const
+{
+    return _internalSource;
+}
+
+ /***************************
+  * Callback Implementation
+  ***************************/
+VCMEncodedFrameCallback::VCMEncodedFrameCallback():
+_sendCallback(),
+_encodedBytes(0),
+_payloadType(0),
+_bitStreamAfterEncoder(NULL)
+{
+#ifdef DEBUG_ENCODER_BIT_STREAM
+    _bitStreamAfterEncoder = fopen("encoderBitStream.bit", "wb");
+#endif
+}
+
+VCMEncodedFrameCallback::~VCMEncodedFrameCallback()
+{
+#ifdef DEBUG_ENCODER_BIT_STREAM
+    fclose(_bitStreamAfterEncoder);
+#endif
+}
+
+WebRtc_Word32
+VCMEncodedFrameCallback::SetTransportCallback(VCMPacketizationCallback* transport)
+{
+    _sendCallback = transport;
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMEncodedFrameCallback::Encoded(
+    EncodedImage &encodedImage,
+    const CodecSpecificInfo* codecSpecificInfo,
+    const RTPFragmentationHeader* fragmentationHeader)
+{
+    FrameType frameType = VCMEncodedFrame::ConvertFrameType(encodedImage._frameType);
+
+    WebRtc_UWord32 encodedBytes = 0;
+    if (_sendCallback != NULL)
+    {
+            encodedBytes = encodedImage._length;
+
+        if (_bitStreamAfterEncoder != NULL)
+        {
+            fwrite(encodedImage._buffer, 1, encodedImage._length, _bitStreamAfterEncoder);
+        }
+
+        RTPVideoTypeHeader rtpTypeHeader;
+        RTPVideoTypeHeader* rtpTypeHeaderPtr = &rtpTypeHeader;
+        if (codecSpecificInfo)
+        {
+            CopyCodecSpecific(*codecSpecificInfo, &rtpTypeHeaderPtr);
+        }
+        else
+        {
+            rtpTypeHeaderPtr = NULL;
+        }
+
+        WebRtc_Word32 callbackReturn = _sendCallback->SendData(
+            frameType,
+            _payloadType,
+            encodedImage._timeStamp,
+            encodedImage._buffer,
+            encodedBytes,
+            *fragmentationHeader,
+            rtpTypeHeaderPtr);
+       if (callbackReturn < 0)
+       {
+           return callbackReturn;
+       }
+    }
+    else
+    {
+        return VCM_UNINITIALIZED;
+    }
+    _encodedBytes = encodedBytes;
+    _mediaOpt->UpdateWithEncodedData(_encodedBytes, frameType);
+    if (_internalSource)
+    {
+        return _mediaOpt->DropFrame(); // Signal to encoder to drop next frame
+    }
+
+    return VCM_OK;
+}
+
+WebRtc_UWord32
+VCMEncodedFrameCallback::EncodedBytes()
+{
+    return _encodedBytes;
+}
+
+void
+VCMEncodedFrameCallback::SetMediaOpt(VCMMediaOptimization *mediaOpt)
+{
+    _mediaOpt = mediaOpt;
+}
+
+void VCMEncodedFrameCallback::CopyCodecSpecific(const CodecSpecificInfo& info,
+                                                RTPVideoTypeHeader** rtp) {
+    switch (info.codecType)
+    {
+        //TODO(hlundin): Implement case for kVideoCodecVP8.
+        default: {
+            // No codec specific info. Change RTP header pointer to NULL.
+            *rtp = NULL;
+            return;
+        }
+
+    }
+}
+
+} // namespace webrtc
diff --git a/src/modules/video_coding/main/source/generic_encoder.h b/src/modules/video_coding/main/source/generic_encoder.h
new file mode 100644
index 0000000..26d19df
--- /dev/null
+++ b/src/modules/video_coding/main/source/generic_encoder.h
@@ -0,0 +1,147 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_GENERIC_ENCODER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_GENERIC_ENCODER_H_
+
+#include "video_codec_interface.h"
+
+#include <stdio.h>
+
+namespace webrtc
+{
+
+class VCMMediaOptimization;
+
+/*************************************/
+/* VCMEncodeFrameCallback class     */
+/***********************************/
+class VCMEncodedFrameCallback : public EncodedImageCallback
+{
+public:
+    VCMEncodedFrameCallback();
+    virtual ~VCMEncodedFrameCallback();
+
+    /*
+    * Callback implementation - codec encode complete
+    */
+    WebRtc_Word32 Encoded(
+        EncodedImage& encodedImage,
+        const CodecSpecificInfo* codecSpecificInfo = NULL,
+        const RTPFragmentationHeader* fragmentationHeader = NULL);
+    /*
+    * Get number of encoded bytes
+    */
+    WebRtc_UWord32 EncodedBytes();
+    /*
+    * Callback implementation - generic encoder encode complete
+    */
+    WebRtc_Word32 SetTransportCallback(VCMPacketizationCallback* transport);
+    /**
+    * Set media Optimization
+    */
+    void SetMediaOpt (VCMMediaOptimization* mediaOpt);
+
+    void SetPayloadType(WebRtc_UWord8 payloadType) { _payloadType = payloadType; };
+    void SetCodecType(VideoCodecType codecType) {_codecType = codecType;};
+    void SetInternalSource(bool internalSource) { _internalSource = internalSource; };
+
+private:
+    /*
+     * Map information from info into rtp. If no relevant information is found
+     * in info, rtp is set to NULL.
+     */
+    static void CopyCodecSpecific(const CodecSpecificInfo& info,
+                                  RTPVideoTypeHeader** rtp);
+
+    VCMPacketizationCallback* _sendCallback;
+    VCMMediaOptimization*     _mediaOpt;
+    WebRtc_UWord32            _encodedBytes;
+    WebRtc_UWord8             _payloadType;
+    VideoCodecType            _codecType;
+    bool                      _internalSource;
+    FILE*                     _bitStreamAfterEncoder;
+};// end of VCMEncodeFrameCallback class
+
+
+/******************************/
+/* VCMGenericEncoder class    */
+/******************************/
+class VCMGenericEncoder
+{
+    friend class VCMCodecDataBase;
+public:
+    VCMGenericEncoder(VideoEncoder& encoder, bool internalSource = false);
+    ~VCMGenericEncoder();
+    /**
+    *	Reset the encoder state, prepare for a new call
+    */
+    WebRtc_Word32 Reset();
+    /**
+    *	Free encoder memory
+    */
+    WebRtc_Word32 Release();
+    /**
+    *	Initialize the encoder with the information from the VideoCodec
+    */
+    WebRtc_Word32 InitEncode(const VideoCodec* settings,
+                             WebRtc_Word32 numberOfCores,
+                             WebRtc_UWord32 maxPayloadSize);
+    /**
+    *	Encode raw image
+    *	inputFrame        : Frame containing raw image
+    *	codecSpecificInfo : Specific codec data
+    *	cameraFrameRate	  :	request or information from the remote side
+    *	frameType         : The requested frame type to encode
+    */
+    WebRtc_Word32 Encode(const VideoFrame& inputFrame,
+                         const CodecSpecificInfo* codecSpecificInfo,
+                         FrameType frameType);
+    /**
+    *	Set new target bit rate and frame rate
+    * Return Value: new bit rate if OK, otherwise <0s
+    */
+    WebRtc_Word32 SetRates(WebRtc_UWord32 newBitRate, WebRtc_UWord32 frameRate);
+    /**
+    * Set a new packet loss rate
+    */
+    WebRtc_Word32 SetPacketLoss(WebRtc_Word32 packetLoss);
+    WebRtc_Word32 CodecConfigParameters(WebRtc_UWord8* buffer, WebRtc_Word32 size);
+    /**
+    * Register a transport callback which will be called to deliver the encoded buffers
+    */
+    WebRtc_Word32 RegisterEncodeCallback(VCMEncodedFrameCallback* VCMencodedFrameCallback);
+    /**
+    * Get encoder bit rate
+    */
+    WebRtc_UWord32 BitRate() const;
+     /**
+    * Get encoder frame rate
+    */
+    WebRtc_UWord32 FrameRate() const;
+
+    WebRtc_Word32 SetPeriodicKeyFrames(bool enable);
+
+    WebRtc_Word32 RequestFrame(FrameType frameType);
+
+    bool InternalSource() const;
+
+private:
+    VideoEncoder&               _encoder;
+    VideoCodecType              _codecType;
+    VCMEncodedFrameCallback*    _VCMencodedFrameCallback;
+    WebRtc_UWord32              _bitRate;
+    WebRtc_UWord32              _frameRate;
+    bool                        _internalSource;
+}; // end of VCMGenericEncoder class
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_GENERIC_ENCODER_H_
diff --git a/src/modules/video_coding/main/source/inter_frame_delay.cc b/src/modules/video_coding/main/source/inter_frame_delay.cc
new file mode 100644
index 0000000..f3bc013
--- /dev/null
+++ b/src/modules/video_coding/main/source/inter_frame_delay.cc
@@ -0,0 +1,120 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "inter_frame_delay.h"
+#include "tick_time.h"
+
+namespace webrtc {
+
+VCMInterFrameDelay::VCMInterFrameDelay()
+{
+    Reset();
+}
+
+// Resets the delay estimate
+void
+VCMInterFrameDelay::Reset()
+{
+    _zeroWallClock = VCMTickTime::MillisecondTimestamp();
+    _wrapArounds = 0;
+    _prevWallClock = 0;
+    _prevTimestamp = 0;
+    _dTS = 0;
+}
+
+// Calculates the delay of a frame with the given timestamp.
+// This method is called when the frame is complete.
+bool
+VCMInterFrameDelay::CalculateDelay(WebRtc_UWord32 timestamp,
+                                WebRtc_Word64 *delay,
+                                WebRtc_Word64 currentWallClock /* = -1 */)
+{
+    if (currentWallClock <= -1)
+    {
+        currentWallClock = VCMTickTime::MillisecondTimestamp();
+    }
+
+    if (_prevWallClock == 0)
+    {
+        // First set of data, initialization, wait for next frame
+        _prevWallClock = currentWallClock;
+        _prevTimestamp = timestamp;
+        *delay = 0;
+        return true;
+    }
+
+    WebRtc_Word32 prevWrapArounds = _wrapArounds;
+    CheckForWrapArounds(timestamp);
+
+    // This will be -1 for backward wrap arounds and +1 for forward wrap arounds
+    WebRtc_Word32 wrapAroundsSincePrev = _wrapArounds - prevWrapArounds;
+
+    // Account for reordering in jitter variance estimate in the future?
+    // Note that this also captures incomplete frames which are grabbed
+    // for decoding after a later frame has been complete, i.e. real
+    // packet losses.
+    if ((wrapAroundsSincePrev == 0 && timestamp < _prevTimestamp) || wrapAroundsSincePrev < 0)
+    {
+        *delay = 0;
+        return false;
+    }
+
+    // Compute the compensated timestamp difference and convert it to ms and
+    // round it to closest integer.
+    _dTS = static_cast<WebRtc_Word64>((timestamp + wrapAroundsSincePrev *
+                (static_cast<WebRtc_Word64>(1)<<32) - _prevTimestamp) / 90.0 + 0.5);
+
+    // frameDelay is the difference of dT and dTS -- i.e. the difference of
+    // the wall clock time difference and the timestamp difference between
+    // two following frames.
+    *delay = static_cast<WebRtc_Word64>(currentWallClock - _prevWallClock - _dTS);
+
+    _prevTimestamp = timestamp;
+    _prevWallClock = currentWallClock;
+
+    return true;
+}
+
+// Returns the current difference between incoming timestamps
+WebRtc_UWord32 VCMInterFrameDelay::CurrentTimeStampDiffMs() const
+{
+    if (_dTS < 0)
+    {
+        return 0;
+    }
+    return static_cast<WebRtc_UWord32>(_dTS);
+}
+
+// Investigates if the timestamp clock has overflowed since the last timestamp and
+// keeps track of the number of wrap arounds since reset.
+void
+VCMInterFrameDelay::CheckForWrapArounds(WebRtc_UWord32 timestamp)
+{
+    if (timestamp < _prevTimestamp)
+    {
+        // This difference will probably be less than -2^31 if we have had a wrap around
+        // (e.g. timestamp = 1, _previousTimestamp = 2^32 - 1). Since it is cast to a Word32,
+        // it should be positive.
+        if (static_cast<WebRtc_Word32>(timestamp - _prevTimestamp) > 0)
+        {
+            // Forward wrap around
+            _wrapArounds++;
+        }
+    }
+    // This difference will probably be less than -2^31 if we have had a backward wrap around.
+    // Since it is cast to a Word32, it should be positive.
+    else if (static_cast<WebRtc_Word32>(_prevTimestamp - timestamp) > 0)
+    {
+        // Backward wrap around
+        _wrapArounds--;
+    }
+}
+
+}
diff --git a/src/modules/video_coding/main/source/inter_frame_delay.h b/src/modules/video_coding/main/source/inter_frame_delay.h
new file mode 100644
index 0000000..7a976a4
--- /dev/null
+++ b/src/modules/video_coding/main/source/inter_frame_delay.h
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_INTER_FRAME_DELAY_H_
+#define WEBRTC_MODULES_VIDEO_CODING_INTER_FRAME_DELAY_H_
+
+#include "typedefs.h"
+
+namespace webrtc
+{
+
+class VCMInterFrameDelay
+{
+public:
+    VCMInterFrameDelay();
+
+    // Resets the estimate. Zeros are given as parameters.
+    void Reset();
+
+    // Calculates the delay of a frame with the given timestamp.
+    // This method is called when the frame is complete.
+    //
+    // Input:
+    //          - timestamp         : RTP timestamp of a received frame
+    //          - *delay            : Pointer to memory where the result should be stored
+    //          - currentWallClock  : The current time in milliseconds.
+    //                                Should be -1 for normal operation, only used for testing.
+    // Return value                 : true if OK, false when reordered timestamps
+    bool CalculateDelay(WebRtc_UWord32 timestamp,
+                        WebRtc_Word64 *delay,
+                        WebRtc_Word64 currentWallClock = -1);
+
+    // Returns the current difference between incoming timestamps
+    //
+    // Return value                 : Wrap-around compensated difference between incoming
+    //                                timestamps.
+    WebRtc_UWord32 CurrentTimeStampDiffMs() const;
+
+private:
+    // Controls if the RTP timestamp counter has had a wrap around
+    // between the current and the previously received frame.
+    //
+    // Input:
+    //          - timestmap         : RTP timestamp of the current frame.
+    void CheckForWrapArounds(WebRtc_UWord32 timestamp);
+
+    WebRtc_Word64         _zeroWallClock; // Local timestamp of the first video packet received
+    WebRtc_Word32         _wrapArounds;   // Number of wrapArounds detected
+    // The previous timestamp passed to the delay estimate
+    WebRtc_UWord32        _prevTimestamp;
+    // The previous wall clock timestamp used by the delay estimate
+    WebRtc_Word64         _prevWallClock;
+    // Wrap-around compensated difference between incoming timestamps
+    WebRtc_Word64         _dTS;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_INTER_FRAME_DELAY_H_
diff --git a/src/modules/video_coding/main/source/internal_defines.h b/src/modules/video_coding/main/source/internal_defines.h
new file mode 100644
index 0000000..781e668
--- /dev/null
+++ b/src/modules/video_coding/main/source/internal_defines.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_SOURCE_INTERNAL_DEFINES_H_
+#define WEBRTC_MODULES_VIDEO_CODING_SOURCE_INTERNAL_DEFINES_H_
+
+#include "typedefs.h"
+
+namespace webrtc
+{
+
+#define MASK_32_BITS(x) (0xFFFFFFFF & (x))
+
+inline WebRtc_UWord32 MaskWord64ToUWord32(WebRtc_Word64 w64)
+{
+    return static_cast<WebRtc_UWord32>(MASK_32_BITS(w64));
+}
+
+#define VCM_MAX(a, b) ((a) > (b)) ? (a) : (b)
+#define VCM_MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+#define VCM_DEFAULT_CODEC_WIDTH 352
+#define VCM_DEFAULT_CODEC_HEIGHT 288
+#define VCM_DEFAULT_FRAME_RATE 30
+#define VCM_MIN_BITRATE 30
+
+// Helper macros for creating the static codec list
+#define VCM_NO_CODEC_IDX -1
+#ifdef VIDEOCODEC_VP8
+  #define VCM_VP8_IDX VCM_NO_CODEC_IDX + 1
+#else
+  #define VCM_VP8_IDX VCM_NO_CODEC_IDX
+#endif
+#ifdef VIDEOCODEC_I420
+  #define VCM_I420_IDX VCM_VP8_IDX + 1
+#else
+  #define VCM_I420_IDX VCM_VP8_IDX
+#endif
+#define VCM_NUM_VIDEO_CODECS_AVAILABLE VCM_I420_IDX + 1
+
+#define VCM_NO_RECEIVER_ID 0
+
+inline WebRtc_Word32 VCMId(const WebRtc_Word32 vcmId, const WebRtc_Word32 receiverId = 0)
+{
+    return static_cast<WebRtc_Word32>((vcmId << 16) + receiverId);
+}
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_SOURCE_INTERNAL_DEFINES_H_
diff --git a/src/modules/video_coding/main/source/jitter_buffer.cc b/src/modules/video_coding/main/source/jitter_buffer.cc
new file mode 100644
index 0000000..d4d7ab9
--- /dev/null
+++ b/src/modules/video_coding/main/source/jitter_buffer.cc
@@ -0,0 +1,2015 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "critical_section_wrapper.h"
+
+#include "frame_buffer.h"
+#include "inter_frame_delay.h"
+#include "internal_defines.h"
+#include "jitter_buffer.h"
+#include "jitter_buffer_common.h"
+#include "jitter_estimator.h"
+#include "media_optimization.h" // hybrid NACK/FEC thresholds.
+#include "packet.h"
+
+#include "event.h"
+#include "trace.h"
+#include "tick_time.h"
+#include "list_wrapper.h"
+
+#include <cassert>
+#include <string.h>
+#include <cmath>
+
+#if defined(_WIN32)
+    // VS 2005: Don't warn for default initialized arrays. See help for more info.
+    #pragma warning(disable:4351)
+#endif
+
+namespace webrtc {
+
+// Criteria used when searching for frames in the frame buffer list
+bool
+VCMJitterBuffer::FrameEqualTimestamp(VCMFrameBuffer* frame, const void* timestamp)
+{
+    if (timestamp == NULL)
+    {
+        return false;
+    }
+    return (*static_cast<const WebRtc_UWord32*>(timestamp)) == frame->TimeStamp();
+}
+
+bool
+VCMJitterBuffer::CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame,
+                                                   const void* /*notUsed*/)
+{
+    const VCMFrameBufferStateEnum state = frame->GetState();
+    // We can decode key frame or decodable/complete frames.
+    return (frame->FrameType() == kVideoFrameKey) &&
+           ((state == kStateComplete)
+           || (state == kStateDecodable));
+}
+
+// Constructor
+VCMJitterBuffer::VCMJitterBuffer(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId,
+                                 bool master) :
+    _vcmId(vcmId),
+    _receiverId(receiverId),
+    _running(false),
+    _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
+    _master(master),
+    _frameEvent(),
+    _packetEvent(),
+    _maxNumberOfFrames(kStartNumberOfFrames),
+    _frameBuffers(),
+    _frameBuffersTSOrder(),
+    _lastDecodedSeqNum(),
+    _lastDecodedTimeStamp(-1),
+    _receiveStatistics(),
+    _incomingFrameRate(0),
+    _incomingFrameCount(0),
+    _timeLastIncomingFrameCount(0),
+    _incomingBitCount(0),
+    _dropCount(0),
+    _numConsecutiveOldFrames(0),
+    _numConsecutiveOldPackets(0),
+    _jitterEstimate(vcmId, receiverId),
+    _rttMs(0),
+    _nackMode(kNoNack),
+    _NACKSeqNum(),
+    _NACKSeqNumLength(0),
+    _missingMarkerBits(false),
+    _firstPacket(true)
+{
+    memset(_frameBuffers, 0, sizeof(_frameBuffers));
+    memset(_receiveStatistics, 0, sizeof(_receiveStatistics));
+    _lastDecodedSeqNum = -1;
+    memset(_NACKSeqNumInternal, -1, sizeof(_NACKSeqNumInternal));
+
+    for (int i = 0; i< kStartNumberOfFrames; i++)
+    {
+        _frameBuffers[i] = new VCMFrameBuffer();
+    }
+}
+
+// Destructor
+VCMJitterBuffer::~VCMJitterBuffer()
+{
+    Stop();
+    for (int i = 0; i< kMaxNumberOfFrames; i++)
+    {
+        if (_frameBuffers[i])
+        {
+            delete _frameBuffers[i];
+        }
+    }
+    delete &_critSect;
+}
+
+VCMJitterBuffer&
+VCMJitterBuffer::operator=(const VCMJitterBuffer& rhs)
+{
+    if (this != &rhs)
+    {
+        _critSect.Enter();
+        rhs._critSect.Enter();
+        _vcmId = rhs._vcmId;
+        _receiverId = rhs._receiverId;
+        _running = rhs._running;
+        _master = !rhs._master;
+        _maxNumberOfFrames = rhs._maxNumberOfFrames;
+        _lastDecodedTimeStamp = rhs._lastDecodedTimeStamp;
+        _incomingFrameRate = rhs._incomingFrameRate;
+        _incomingFrameCount = rhs._incomingFrameCount;
+        _timeLastIncomingFrameCount = rhs._timeLastIncomingFrameCount;
+        _incomingBitCount = rhs._incomingBitCount;
+        _dropCount = rhs._dropCount;
+        _numConsecutiveOldFrames = rhs._numConsecutiveOldFrames;
+        _numConsecutiveOldPackets = rhs._numConsecutiveOldPackets;
+        _jitterEstimate = rhs._jitterEstimate;
+        _delayEstimate = rhs._delayEstimate;
+        _waitingForCompletion = rhs._waitingForCompletion;
+        _nackMode = rhs._nackMode;
+        _rttMs = rhs._rttMs;
+        _NACKSeqNumLength = rhs._NACKSeqNumLength;
+        _missingMarkerBits = rhs._missingMarkerBits;
+        _firstPacket = rhs._firstPacket;
+        _lastDecodedSeqNum =  rhs._lastDecodedSeqNum;
+        memcpy(_receiveStatistics, rhs._receiveStatistics, sizeof(_receiveStatistics));
+        memcpy(_NACKSeqNumInternal, rhs._NACKSeqNumInternal, sizeof(_NACKSeqNumInternal));
+        memcpy(_NACKSeqNum, rhs._NACKSeqNum, sizeof(_NACKSeqNum));
+        for (int i = 0; i < kMaxNumberOfFrames; i++)
+        {
+            if (_frameBuffers[i] != NULL)
+            {
+                delete _frameBuffers[i];
+                _frameBuffers[i] = NULL;
+            }
+        }
+        while(_frameBuffersTSOrder.Erase(_frameBuffersTSOrder.First()) != -1) { }
+        for (int i = 0; i < _maxNumberOfFrames; i++)
+        {
+            _frameBuffers[i] = new VCMFrameBuffer(*(rhs._frameBuffers[i]));
+            if (_frameBuffers[i]->Length() > 0)
+            {
+                _frameBuffersTSOrder.Insert(_frameBuffers[i]);
+            }
+        }
+        rhs._critSect.Leave();
+        _critSect.Leave();
+    }
+    return *this;
+}
+
+WebRtc_UWord32
+VCMJitterBuffer::LatestTimestamp(const WebRtc_UWord32 existingTimestamp,
+                                 const WebRtc_UWord32 newTimestamp)
+{
+    bool wrap = (newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) ||
+                (newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff);
+    if (existingTimestamp > newTimestamp && !wrap)
+    {
+        return existingTimestamp;
+    }
+    else if (existingTimestamp <= newTimestamp && !wrap)
+    {
+        return newTimestamp;
+    }
+    else if (existingTimestamp < newTimestamp && wrap)
+    {
+        return existingTimestamp;
+    }
+    else
+    {
+        return newTimestamp;
+    }
+}
+
+// Start jitter buffer
+void
+VCMJitterBuffer::Start()
+{
+    CriticalSectionScoped cs(_critSect);
+    _running = true;
+    _incomingFrameCount = 0;
+    _incomingFrameRate = 0;
+    _incomingBitCount = 0;
+    _timeLastIncomingFrameCount = VCMTickTime::MillisecondTimestamp();
+    memset(_receiveStatistics, 0, sizeof(_receiveStatistics));
+
+    _numConsecutiveOldFrames = 0;
+    _numConsecutiveOldPackets = 0;
+
+    _frameEvent.Reset(); // start in a non-signaled state
+    _packetEvent.Reset(); // start in a non-signaled state
+    _waitingForCompletion.frameSize = 0;
+    _waitingForCompletion.timestamp = 0;
+    _waitingForCompletion.latestPacketTime = -1;
+    _missingMarkerBits = false;
+    _firstPacket = true;
+    _NACKSeqNumLength = 0;
+    _rttMs = 0;
+
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId,
+                 _receiverId), "JB(0x%x): Jitter buffer: start", this);
+}
+
+
+// Stop jitter buffer
+void
+VCMJitterBuffer::Stop()
+{
+    _critSect.Enter();
+    _running = false;
+    _lastDecodedTimeStamp = -1;
+    _lastDecodedSeqNum = -1;
+    _frameBuffersTSOrder.Flush();
+    for (int i = 0; i < kMaxNumberOfFrames; i++)
+    {
+        if (_frameBuffers[i] != NULL)
+        {
+            static_cast<VCMFrameBuffer*>(_frameBuffers[i])->SetState(kStateFree);
+        }
+    }
+
+    _critSect.Leave();
+    _frameEvent.Set(); // Make sure we exit from trying to get a frame to decoder
+    _packetEvent.Set(); // Make sure we exit from trying to get a sequence number
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId,
+                 _receiverId), "JB(0x%x): Jitter buffer: stop", this);
+}
+
+bool
+VCMJitterBuffer::Running() const
+{
+    CriticalSectionScoped cs(_critSect);
+    return _running;
+}
+
+// Flush jitter buffer
+void
+VCMJitterBuffer::Flush()
+{
+    CriticalSectionScoped cs(_critSect);
+    FlushInternal();
+}
+
+// Must be called under the critical section _critSect
+void
+VCMJitterBuffer::FlushInternal()
+{
+    // Erase all frames from the sorted list and set their state to free.
+    _frameBuffersTSOrder.Flush();
+    for (int i = 0; i < _maxNumberOfFrames; i++)
+    {
+        ReleaseFrameInternal(_frameBuffers[i]);
+    }
+    _lastDecodedSeqNum = -1;
+    _lastDecodedTimeStamp = -1;
+
+    _frameEvent.Reset();
+    _packetEvent.Reset();
+
+    _numConsecutiveOldFrames = 0;
+    _numConsecutiveOldPackets = 0;
+
+    // Also reset the jitter and delay estimates
+    _jitterEstimate.Reset();
+    _delayEstimate.Reset();
+
+    _waitingForCompletion.frameSize = 0;
+    _waitingForCompletion.timestamp = 0;
+    _waitingForCompletion.latestPacketTime = -1;
+
+    _missingMarkerBits = false;
+    _firstPacket = true;
+
+    _NACKSeqNumLength = 0;
+
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId,
+                 _receiverId), "JB(0x%x): Jitter buffer: flush", this);
+}
+
+// Set the frame state to free and remove it from the sorted
+// frame list. Must be called from inside the critical section _critSect.
+void
+VCMJitterBuffer::ReleaseFrameInternal(VCMFrameBuffer* frame)
+{
+    if (frame != NULL)
+    {
+        frame->SetState(kStateFree);
+    }
+}
+
+// Update frame state (set as complete if conditions are met)
+// Doing it here increases the degree of freedom for e.g. future
+// reconstructability of separate layers. Must be called under the
+// critical section _critSect.
+void
+VCMJitterBuffer::UpdateFrameState(VCMFrameBuffer* frame)
+{
+    if (frame == NULL)
+    {
+        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
+                     VCMId(_vcmId, _receiverId), "JB(0x%x) FB(0x%x): "
+                         "UpdateFrameState NULL frame pointer", this, frame);
+        return;
+    }
+
+    int length = frame->Length();
+    if (_master)
+    {
+        // Only trace the primary jitter buffer to make it possible to parse and plot the trace file.
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                   "JB(0x%x) FB(0x%x): Complete frame added to jitter buffer, size:%d type %d",
+                   this, frame,length,frame->FrameType());
+    }
+
+    if (length != 0 && !frame->GetCountedFrame())
+    {
+        // ignore Ack frames
+        _incomingFrameCount++;
+        frame->SetCountedFrame(true);
+    }
+
+    // Check if we should drop frame
+    // an old complete frame can arrive too late
+    if(_lastDecodedTimeStamp > 0 &&
+            LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
+                            frame->TimeStamp()) == _lastDecodedTimeStamp)
+    {
+        // Frame is older than the latest decoded frame, drop it.
+        // This will trigger a release in CleanUpSizeZeroFrames later.
+        frame->Reset();
+        frame->SetState(kStateEmpty);
+
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+            "JB(0x%x) FB(0x%x): Dropping old frame in Jitter buffer", this, frame);
+        _dropCount++;
+        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+            "Jitter buffer drop count: %d, consecutive drops: %u", _dropCount, _numConsecutiveOldFrames);
+        // Flush() if this happens consistently.
+        _numConsecutiveOldFrames++;
+        if (_numConsecutiveOldFrames > kMaxConsecutiveOldFrames)
+        {
+            FlushInternal();
+        }
+        return;
+    }
+    _numConsecutiveOldFrames = 0;
+    frame->SetState(kStateComplete);
+
+
+    // Update receive statistics. We count all layers, thus when you use layers
+    // adding all key and delta frames might differ from frame count
+    if (frame->IsSessionComplete())
+    {
+        switch (frame->FrameType())
+        {
+        case kVideoFrameKey:
+            {
+                _receiveStatistics[0]++;
+                break;
+            }
+        case kVideoFrameDelta:
+            {
+                _receiveStatistics[1]++;
+                break;
+            }
+        case kVideoFrameGolden:
+            {
+                _receiveStatistics[2]++;
+                break;
+            }
+        case kVideoFrameAltRef:
+            {
+                _receiveStatistics[3]++;
+                break;
+            }
+        default:
+            assert(false);
+
+        }
+    }
+    const VCMFrameListItem* oldFrameListItem = FindOldestCompleteContinuousFrame();
+    VCMFrameBuffer* oldFrame = NULL;
+    if (oldFrameListItem != NULL)
+    {
+        oldFrame = oldFrameListItem->GetItem();
+    }
+
+    // Only signal if this is the oldest frame.
+    // Not necessary the case due to packet reordering or NACK.
+    if (!WaitForNack() || (oldFrame != NULL && oldFrame == frame))
+    {
+        _frameEvent.Set();
+    }
+}
+
+
+// Get received key and delta frames
+WebRtc_Word32
+VCMJitterBuffer::GetFrameStatistics(WebRtc_UWord32& receivedDeltaFrames,
+                                    WebRtc_UWord32& receivedKeyFrames) const
+{
+    {
+        CriticalSectionScoped cs(_critSect);
+        receivedDeltaFrames = _receiveStatistics[1] + _receiveStatistics[3];
+        receivedKeyFrames = _receiveStatistics[0] + _receiveStatistics[2];
+    }
+    return 0;
+}
+
+// Gets frame to use for this timestamp. If no match, get empty frame.
+WebRtc_Word32
+VCMJitterBuffer::GetFrame(const VCMPacket& packet, VCMEncodedFrame*& frame)
+{
+    if (!_running) // don't accept incoming packets until we are started
+    {
+        return VCM_UNINITIALIZED;
+    }
+
+    _critSect.Enter();
+    if (LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp), packet.timestamp)
+        == _lastDecodedTimeStamp
+        && packet.sizeBytes > 0) // Make sure that old filler packets are inserted.
+    {
+        // Trying to get an old frame.
+        _numConsecutiveOldPackets++;
+        if (_numConsecutiveOldPackets > kMaxConsecutiveOldPackets)
+        {
+            FlushInternal();
+        }
+        _critSect.Leave();
+        return VCM_OLD_PACKET_ERROR;
+    }
+    _numConsecutiveOldPackets = 0;
+
+    frame = _frameBuffersTSOrder.FindFrame(FrameEqualTimestamp, &packet.timestamp);
+    _critSect.Leave();
+
+    if (frame != NULL)
+    {
+        return VCM_OK;
+    }
+
+    // No match, return empty frame
+    frame = GetEmptyFrame();
+    if (frame != NULL)
+    {
+        return VCM_OK;
+    }
+    // No free frame! Try to reclaim some...
+    _critSect.Enter();
+    RecycleFramesUntilKeyFrame();
+    _critSect.Leave();
+
+    frame = GetEmptyFrame();
+    if (frame != NULL)
+    {
+        return VCM_OK;
+    }
+    return VCM_JITTER_BUFFER_ERROR;
+}
+
+// Deprecated! Kept for testing purposes.
+VCMEncodedFrame*
+VCMJitterBuffer::GetFrame(const VCMPacket& packet)
+{
+    VCMEncodedFrame* frame = NULL;
+    if (GetFrame(packet, frame) < 0)
+    {
+        return NULL;
+    }
+    return frame;
+}
+
+// Get empty frame, creates new (i.e. increases JB size) if necessary
+VCMFrameBuffer*
+VCMJitterBuffer::GetEmptyFrame()
+{
+    if (!_running) // don't accept incoming packets until we are started
+    {
+        return NULL;
+    }
+
+    _critSect.Enter();
+
+    for (int i = 0; i <_maxNumberOfFrames; ++i)
+    {
+        if (kStateFree == _frameBuffers[i]->GetState())
+        {
+            // found a free buffer
+            _frameBuffers[i]->SetState(kStateEmpty);
+            _critSect.Leave();
+            return _frameBuffers[i];
+        }
+    }
+
+    // Check if we can increase JB size
+    if (_maxNumberOfFrames < kMaxNumberOfFrames)
+    {
+        VCMFrameBuffer* ptrNewBuffer = new VCMFrameBuffer();
+        ptrNewBuffer->SetState(kStateEmpty);
+        _frameBuffers[_maxNumberOfFrames] = ptrNewBuffer;
+        _maxNumberOfFrames++;
+
+        _critSect.Leave();
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
+        VCMId(_vcmId, _receiverId), "JB(0x%x) FB(0x%x): Jitter buffer "
+        "increased to:%d frames", this, ptrNewBuffer, _maxNumberOfFrames);
+        return ptrNewBuffer;
+    }
+    _critSect.Leave();
+
+    // We have reached max size, cannot increase JB size
+    return NULL;
+}
+
+// Must be called under the critical section _critSect.
+VCMFrameListItem*
+VCMJitterBuffer::FindOldestSequenceNum() const
+{
+    WebRtc_UWord16 currentLow = 0xffff;
+    VCMFrameBufferStateEnum state = kStateFree;
+    WebRtc_UWord16 sequenceNumber = 0;
+    bool first = true;
+    VCMFrameListItem* frameListItem = _frameBuffersTSOrder.First();
+    VCMFrameListItem* oldestFrameListItem = NULL;
+
+    while (frameListItem != NULL)
+    {
+        // if we have more than one frame done since last time,
+        // pick oldest
+        VCMFrameBuffer* ptrFrame = NULL;
+        ptrFrame = frameListItem->GetItem();
+        state = ptrFrame->GetState();
+        sequenceNumber = static_cast<WebRtc_UWord16>(ptrFrame->GetLowSeqNum());
+
+        // Find the oldest, hence lowest, using sequence numbers
+        if (first)
+        {
+            currentLow = sequenceNumber;
+            oldestFrameListItem = frameListItem;
+            first = false;
+        }
+        else if ((currentLow < 0x0fff) && (sequenceNumber > 0xf000))
+        {
+            // We have a wrap and this one is older
+            currentLow = sequenceNumber;
+            oldestFrameListItem = frameListItem;
+        }
+        else if ((sequenceNumber < 0x0fff) && (currentLow > 0xf000))
+        {
+            // This one is after a wrap, leave as is
+        }
+        else if (currentLow > sequenceNumber)
+        {
+            // Normal case, this one is lower.
+            currentLow = sequenceNumber;
+            oldestFrameListItem = frameListItem;
+        }
+        frameListItem = _frameBuffersTSOrder.Next(frameListItem);
+    }
+    return oldestFrameListItem;
+}
+
+// Find oldest complete frame used for getting next frame to decode
+// Must be called under critical section
+// Based on sequence number
+// Return NULL for lost packets
+VCMFrameListItem*
+VCMJitterBuffer::FindOldestCompleteContinuousFrame()
+{
+    // if we have more than one frame done since last time, pick oldest
+    VCMFrameBuffer* oldestFrame = NULL;
+    int currentLow = -1;
+
+    VCMFrameListItem* oldestFrameItem = _frameBuffersTSOrder.First();
+    if (oldestFrameItem != NULL)
+    {
+        oldestFrame = oldestFrameItem->GetItem();
+    }
+    // is the frame complete?
+    if (oldestFrame != NULL)
+    {
+        if (kStateComplete != oldestFrame->GetState())
+        {
+            // Try to see if the frame is complete even though the state is not
+            // complete. Can happen if markerbit is not set.
+            if (!CheckForCompleteFrame(oldestFrameItem))
+            {
+                oldestFrame = NULL;
+            }
+        }
+        else
+        {
+            // we have a complete frame
+            currentLow = oldestFrame->GetLowSeqNum();
+        }
+    }
+    if (oldestFrame == NULL)
+    {
+        // no complete frame no point to continue
+        return NULL;
+    }
+
+    // we have a complete frame
+    // check if it's continuous, otherwise we are missing a full frame
+    // Use seqNum not timestamp since a full frame might be lost
+    if (_lastDecodedSeqNum != -1)
+    {
+        // it's not enough that we have complete frame we need the seq numbers
+        // to be continuous too for layers it's not enough that we have complete
+        // frame we need the layers to be continuous too
+        currentLow = oldestFrame->GetLowSeqNum();
+
+        WebRtc_UWord16 lastDecodedSeqNum = (WebRtc_UWord16)_lastDecodedSeqNum;
+
+        // we could have received the first packet of the last frame before a
+        // long period if drop, that case is handled by GetNackList
+        if (((WebRtc_UWord16)(lastDecodedSeqNum + 1)) != currentLow)
+        {
+            // wait since we want a complete continuous frame
+            return NULL;
+        }
+    }
+    return oldestFrameItem;
+}
+
+// Check if the oldest frame is complete even though it isn't complete.
+// This can happen when makerbit is not set
+// Must be called under the critical section _critSect.
+// Return false for lost packets
+bool
+VCMJitterBuffer::CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem)
+{
+    const VCMFrameListItem* nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameItem);
+    VCMFrameBuffer* oldestFrame = NULL;
+    if (oldestFrameItem != NULL)
+    {
+        oldestFrame = oldestFrameItem->GetItem();
+    }
+    if (nextFrameItem != NULL)
+    {
+        // We have received at least one packet from a later frame.
+        if(!oldestFrame->HaveLastPacket()) // If we don't have the markerbit
+        {
+            VCMFrameBuffer* nextFrame = nextFrameItem->GetItem();
+            // Verify that we have received the first packet of the next frame.
+            // This is the only way we can be sure we're not missing the last packet.
+            if (nextFrame != NULL && nextFrame->GetLowSeqNum() ==
+                static_cast<WebRtc_UWord16>(oldestFrame->GetHighSeqNum() + 1))
+            {
+                _missingMarkerBits = true;
+                bool completeSession = oldestFrame->ForceSetHaveLastPacket();
+                if (completeSession)
+                {
+                    UpdateFrameState(oldestFrame);
+                }
+                const VCMFrameBufferStateEnum state = oldestFrame->GetState();
+                if (state == kStateComplete)
+                {
+                    if(oldestFrame->Length() > 0)
+                    {
+                        UpdateJitterAndDelayEstimates(*oldestFrame, false);
+                    }
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+// Call from inside the critical section _critSect
+void
+VCMJitterBuffer::RecycleFrame(VCMFrameBuffer* frame)
+{
+    if (frame == NULL)
+    {
+        return;
+    }
+
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+               "JB(0x%x) FB(0x%x): RecycleFrame, size:%d",
+               this, frame, frame->Length());
+
+    ReleaseFrameInternal(frame);
+}
+
+
+// Calculate frame and bit rates
+WebRtc_Word32
+VCMJitterBuffer::GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate)
+{
+    CriticalSectionScoped cs(_critSect);
+    const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
+    WebRtc_Word64 diff = now - _timeLastIncomingFrameCount;
+    if (diff < 1000 && _incomingFrameRate > 0 && _incomingBitRate > 0)
+    {
+        // Make sure we report something even though less than
+        // 1 second has passed since last update.
+        frameRate = _incomingFrameRate;
+        bitRate = _incomingBitRate;
+    }
+    else if (_incomingFrameCount != 0)
+    {
+        // We have received frame(s) since last call to this function
+
+        // Prepare calculations
+        if (diff <= 0)
+        {
+            diff = 1;
+        }
+        // we add 0.5f for rounding
+        float rate = 0.5f + ((_incomingFrameCount * 1000.0f) / diff);
+        if (rate < 1.0f) // don't go below 1, can crash
+        {
+            rate = 1.0f;
+        }
+
+        // Calculate frame rate
+        // Let r be rate.
+        // r(0) = 1000*framecount/delta_time. (I.e. frames per second since last calculation.)
+        // frameRate = r(0)/2 + r(-1)/2      (I.e. fr/s average this and the previous calculation.)
+        frameRate = (_incomingFrameRate + (WebRtc_Word32)rate) >> 1;
+        _incomingFrameRate = (WebRtc_UWord8)rate;
+
+        // Calculate bit rate
+        if (_incomingBitCount == 0)
+        {
+            bitRate = 0;
+        }
+        else
+        {
+            bitRate = 10 * ((100 * _incomingBitCount) / static_cast<WebRtc_UWord32>(diff));
+        }
+        _incomingBitRate = bitRate;
+
+        // Reset count
+        _incomingFrameCount = 0;
+        _incomingBitCount = 0;
+        _timeLastIncomingFrameCount = now;
+
+    }
+    else
+    {
+        // No frames since last call
+        _timeLastIncomingFrameCount = VCMTickTime::MillisecondTimestamp();
+        frameRate = 0;
+        bitRate = 0;
+        _incomingBitRate = 0;
+    }
+
+    return 0;
+}
+
+// Returns immediately or a X ms event hang waiting for a decodable frame, X decided by caller
+VCMEncodedFrame*
+VCMJitterBuffer::GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS)
+{
+    if (!_running)
+    {
+        return NULL;
+    }
+
+    _critSect.Enter();
+
+    CleanUpOldFrames();
+    CleanUpSizeZeroFrames();
+
+    VCMFrameListItem* oldestFrameListItem = FindOldestCompleteContinuousFrame();
+    VCMFrameBuffer* oldestFrame = NULL;
+    if (oldestFrameListItem != NULL)
+    {
+        oldestFrame = oldestFrameListItem->GetItem();
+    }
+
+    if (oldestFrame == NULL)
+    {
+        if (maxWaitTimeMS == 0)
+        {
+            _critSect.Leave();
+            return NULL;
+        }
+        const WebRtc_Word64 endWaitTimeMs = VCMTickTime::MillisecondTimestamp()
+                                            + maxWaitTimeMS;
+        WebRtc_Word64 waitTimeMs = maxWaitTimeMS;
+        while (waitTimeMs > 0)
+        {
+            _critSect.Leave();
+            const EventTypeWrapper ret = _frameEvent.Wait(static_cast<WebRtc_UWord32>(waitTimeMs));
+            _critSect.Enter();
+            if (ret == kEventSignaled)
+            {
+                // are we closing down the Jitter buffer
+                if (!_running)
+                {
+                    _critSect.Leave();
+                    return NULL;
+                }
+
+                // Finding oldest frame ready for decoder, but check sequence number and size
+                CleanUpOldFrames();
+                CleanUpSizeZeroFrames();
+                oldestFrameListItem = FindOldestCompleteContinuousFrame();
+                if (oldestFrameListItem != NULL)
+                {
+                    oldestFrame = oldestFrameListItem->GetItem();
+                }
+                if (oldestFrame == NULL)
+                {
+                    waitTimeMs = endWaitTimeMs - VCMTickTime::MillisecondTimestamp();
+                }
+                else
+                {
+                    break;
+                }
+            }
+            else
+            {
+                _critSect.Leave();
+                return NULL;
+            }
+        }
+        // Inside critSect
+    }
+    else
+    {
+        // we already have a frame reset the event
+        _frameEvent.Reset();
+    }
+
+    if (oldestFrame == NULL)
+    {
+        // Even after signaling we're still missing a complete _continuous_ frame
+        _critSect.Leave();
+        return NULL;
+    }
+
+    // we have a frame
+    // store seqnum
+    _lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
+    // store current timestamp
+    _lastDecodedTimeStamp = oldestFrame->TimeStamp();
+
+    // Update jitter estimate
+    const bool retransmitted = (oldestFrame->GetNackCount() > 0);
+    if (retransmitted)
+    {
+        _jitterEstimate.FrameNacked();
+    }
+    else if (oldestFrame->Length() > 0)
+    {
+        // Ignore retransmitted and empty frames.
+        UpdateJitterAndDelayEstimates(*oldestFrame, false);
+    }
+
+    // This needs to be done before we clean up old frames,
+    // otherwise we'll remove ourselves...
+    oldestFrame->SetState(kStateDecoding);
+    _frameBuffersTSOrder.Erase(oldestFrameListItem);
+    oldestFrameListItem = NULL;
+
+    CleanUpOldFrames();
+    CleanUpSizeZeroFrames();
+
+    _critSect.Leave();
+
+    return oldestFrame;
+}
+
+WebRtc_UWord32
+VCMJitterBuffer::GetEstimatedJitterMS()
+{
+    CriticalSectionScoped cs(_critSect);
+    return GetEstimatedJitterMsInternal();
+}
+
+WebRtc_UWord32
+VCMJitterBuffer::GetEstimatedJitterMsInternal()
+{
+    WebRtc_UWord32 estimate = VCMJitterEstimator::OPERATING_SYSTEM_JITTER;
+
+    // compute RTT multiplier for estimation
+    double rttMult = 1.0f;
+    if (_nackMode == kNackHybrid && _rttMs > kLowRttNackMs)
+    {
+        // from here we count on FEC
+        rttMult = 0.0f;
+    }
+    estimate += static_cast<WebRtc_UWord32>
+                (_jitterEstimate.GetJitterEstimate(rttMult) + 0.5);
+    if (_missingMarkerBits)
+    {
+        // Since the incoming packets are all missing marker bits we have to
+        // wait until the first packet of the next frame arrives, before we can
+        // safely say that the frame is complete. Therefore we have to compensate
+        // the jitter buffer level with one frame period.
+        // TODO(holmer): The timestamp diff should probably be filtered
+        // (max filter) since the diff can alternate between e.g. 3000 and 6000
+        // if we have a frame rate between 15 and 30 frames per seconds.
+        estimate += _delayEstimate.CurrentTimeStampDiffMs();
+    }
+    return estimate;
+}
+
+void
+VCMJitterBuffer::UpdateRtt(WebRtc_UWord32 rttMs)
+{
+    CriticalSectionScoped cs(_critSect);
+    _rttMs = rttMs;
+    _jitterEstimate.UpdateRtt(rttMs);
+}
+
+// wait for the first packet in the next frame to arrive
+WebRtc_Word64
+VCMJitterBuffer::GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
+                                  FrameType& incomingFrameType,
+                                  WebRtc_Word64& renderTimeMs)
+{
+    if (!_running)
+    {
+        return -1;
+    }
+
+    _critSect.Enter();
+
+    // Finding oldest frame ready for decoder, but check sequence number and size
+    CleanUpOldFrames();
+    CleanUpSizeZeroFrames();
+
+    VCMFrameBuffer* oldestFrame = _frameBuffersTSOrder.FirstFrame();
+
+    if (oldestFrame == NULL)
+    {
+        _critSect.Leave();
+        if(_packetEvent.Wait(maxWaitTimeMS) == kEventSignaled)
+        {
+            // are we closing down the Jitter buffer
+            if (!_running)
+            {
+                return -1;
+            }
+            _critSect.Enter();
+
+            CleanUpOldFrames();
+            CleanUpSizeZeroFrames();
+            oldestFrame = _frameBuffersTSOrder.FirstFrame();
+        }else
+        {
+            _critSect.Enter();
+        }
+    }
+    _packetEvent.Reset();
+
+    if (oldestFrame == NULL)
+    {
+        _critSect.Leave();
+        return -1;
+    }
+    // we have a frame
+
+    // return frame type
+    incomingFrameType = oldestFrame->FrameType(); // All layers are assumed to have the same type
+
+    renderTimeMs = oldestFrame->RenderTimeMs();
+
+    const WebRtc_UWord32 timestamp = oldestFrame->TimeStamp();
+
+    _critSect.Leave();
+
+    // return current time
+    return timestamp;
+}
+
+// Answers the question:
+// Will the packet sequence be complete if the next frame is grabbed for decoding right now?
+// That is, have we lost a frame between the last decoded frame and the next, or is the next
+// frame missing one or more packets?
+bool
+VCMJitterBuffer::CompleteSequenceWithNextFrame()
+{
+    CriticalSectionScoped cs(_critSect);
+    // Finding oldest frame ready for decoder, but check sequence number and size
+    CleanUpOldFrames();
+    CleanUpSizeZeroFrames();
+
+    VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
+    if (oldestFrameListItem == NULL)
+    {
+        // No frame found
+        return true;
+    }
+
+    VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem();
+    const VCMFrameListItem* nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameListItem);
+    if (nextFrameItem == NULL && !oldestFrame->HaveLastPacket())
+    {
+        // Frame not ready to be decoded.
+        return true;
+    }
+
+    // See if we have lost a frame before this one.
+    if (_lastDecodedSeqNum == -1)
+    {
+        // The sequence is not complete since we haven't yet.
+        if (oldestFrame->FrameType() != kVideoFrameKey)
+        {
+            return false;
+        }
+    }
+    else if (oldestFrame->GetLowSeqNum() == -1)
+    {
+        return false;
+    }
+    else if (oldestFrame->GetLowSeqNum() != (_lastDecodedSeqNum + 1) % 0x00010000)
+    {
+        return false;
+    }
+    return true;
+}
+
+// Returns immediately
+VCMEncodedFrame*
+VCMJitterBuffer::GetFrameForDecoding()
+{
+    CriticalSectionScoped cs(_critSect);
+    if (!_running)
+    {
+        return NULL;
+    }
+
+    if (WaitForNack())
+    {
+        return GetFrameForDecodingNACK();
+    }
+
+    CleanUpOldFrames();
+    CleanUpSizeZeroFrames();
+
+    VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
+    if (oldestFrameListItem == NULL)
+    {
+        return NULL;
+    }
+    VCMFrameBuffer* oldestFrame = oldestFrameListItem->GetItem();
+
+    const VCMFrameListItem* nextFrameItem = _frameBuffersTSOrder.Next(oldestFrameListItem);
+    if (nextFrameItem == NULL && !oldestFrame->HaveLastPacket())
+    {
+        return NULL;
+    }
+
+    // Incomplete frame pulled out from jitter buffer,
+    // update the jitter estimate with what we currently know.
+    // This frame shouldn't have been retransmitted, but if we recently
+    // turned off NACK this might still happen.
+    const bool retransmitted = (oldestFrame->GetNackCount() > 0);
+    if (retransmitted)
+    {
+        _jitterEstimate.FrameNacked();
+    }
+    else if (oldestFrame->Length() > 0)
+    {
+        // Ignore retransmitted and empty frames.
+        // Update with the previous incomplete frame first
+        if (_waitingForCompletion.latestPacketTime >= 0)
+        {
+            UpdateJitterAndDelayEstimates(_waitingForCompletion, true);
+        }
+        // Then wait for this one to get complete
+        _waitingForCompletion.frameSize = oldestFrame->Length();
+        _waitingForCompletion.latestPacketTime = oldestFrame->LatestPacketTimeMs();
+        _waitingForCompletion.timestamp = oldestFrame->TimeStamp();
+        oldestFrame->SetState(kStateDecoding);
+    }
+    _frameBuffersTSOrder.Erase(oldestFrameListItem);
+    oldestFrameListItem = NULL;
+
+    CleanUpOldFrames();
+    CleanUpSizeZeroFrames();
+
+    VerifyAndSetPreviousFrameLost(*oldestFrame);
+
+    // store current time
+    _lastDecodedTimeStamp = oldestFrame->TimeStamp();
+
+    // store seqnum
+    _lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
+
+    return oldestFrame;
+}
+
+VCMEncodedFrame*
+VCMJitterBuffer::GetFrameForDecodingNACK()
+{
+    // when we use NACK we don't release non complete frames
+    // unless we have a complete key frame.
+    // In hybrid mode, we may release decodable frames (non-complete)
+
+    // Clean up old frames and empty frames
+    CleanUpOldFrames();
+    CleanUpSizeZeroFrames();
+
+    // First look for a complete _continuous_ frame.
+    VCMFrameListItem* oldestFrameListItem = FindOldestCompleteContinuousFrame();
+    VCMFrameBuffer* oldestFrame = NULL;
+    if (oldestFrameListItem != NULL)
+    {
+        oldestFrame = oldestFrameListItem->GetItem();
+    }
+    bool continuous = true;
+    if (oldestFrame == NULL)
+    {
+        continuous = false;
+        // If we didn't find one we're good with a complete key/decodable frame.
+        oldestFrameListItem = _frameBuffersTSOrder.FindFrameListItem(
+                               CompleteDecodableKeyFrameCriteria);
+        if (oldestFrameListItem != NULL)
+        {
+            oldestFrame = oldestFrameListItem->GetItem();
+        }
+        if (oldestFrame == NULL)
+        {
+            return NULL;
+        }
+    }
+
+    // We have a complete/decodable continuous frame, decode it.
+    // store seqnum
+    _lastDecodedSeqNum = oldestFrame->GetHighSeqNum();
+    // store current time
+    _lastDecodedTimeStamp = oldestFrame->TimeStamp();
+
+    // Update jitter estimate
+    const bool retransmitted = (oldestFrame->GetNackCount() > 0);
+    if (retransmitted)
+    {
+        _jitterEstimate.FrameNacked();
+    }
+    else if (oldestFrame->Length() > 0)
+    {
+        // Ignore retransmitted and empty frames.
+        UpdateJitterAndDelayEstimates(*oldestFrame, false);
+    }
+
+    // This needs to be done before we clean up old frames,
+    // otherwise we might release the frame we want to decode right now.
+    oldestFrame->SetState(kStateDecoding);
+    _frameBuffersTSOrder.Erase(oldestFrameListItem);
+
+    // Clean up old frames and empty frames
+    CleanUpOldFrames();
+    CleanUpSizeZeroFrames();
+
+    return oldestFrame;
+}
+
+// Must be called under the critical section _critSect. Should never be called with
+// retransmitted frames, they must be filtered out before this function is called.
+void
+VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMJitterSample& sample, bool incompleteFrame)
+{
+    if (sample.latestPacketTime == -1)
+    {
+        return;
+    }
+    if (incompleteFrame)
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                   "Received incomplete frame timestamp %u frame size %u at time %u",
+                   sample.timestamp, sample.frameSize,
+                   MaskWord64ToUWord32(sample.latestPacketTime));
+    }
+    else
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                   "Received complete frame timestamp %u frame size %u at time %u",
+                   sample.timestamp, sample.frameSize,
+                   MaskWord64ToUWord32(sample.latestPacketTime));
+    }
+    UpdateJitterAndDelayEstimates(sample.latestPacketTime,
+                                  sample.timestamp,
+                                  sample.frameSize,
+                                  incompleteFrame);
+}
+
+// Must be called under the critical section _critSect. Should never be called with
+// retransmitted frames, they must be filtered out before this function is called.
+void
+VCMJitterBuffer::UpdateJitterAndDelayEstimates(VCMFrameBuffer& frame, bool incompleteFrame)
+{
+    if (frame.LatestPacketTimeMs() == -1)
+    {
+        return;
+    }
+    // No retransmitted frames should be a part of the jitter
+    // estimate.
+    if (incompleteFrame)
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                   "Received incomplete frame timestamp %u frame type %d frame size %u"
+                   " at time %u, jitter estimate was %u",
+                   frame.TimeStamp(), frame.FrameType(), frame.Length(),
+                   MaskWord64ToUWord32(frame.LatestPacketTimeMs()),
+                   GetEstimatedJitterMsInternal());
+    }
+    else
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                   "Received complete frame timestamp %u frame type %d frame size %u "
+                   "at time %u, jitter estimate was %u",
+                   frame.TimeStamp(), frame.FrameType(), frame.Length(),
+                   MaskWord64ToUWord32(frame.LatestPacketTimeMs()),
+                   GetEstimatedJitterMsInternal());
+    }
+    UpdateJitterAndDelayEstimates(frame.LatestPacketTimeMs(), frame.TimeStamp(),
+                                  frame.Length(), incompleteFrame);
+}
+
+// Must be called under the critical section _critSect. Should never be called with
+// retransmitted frames, they must be filtered out before this function is called.
+void
+VCMJitterBuffer::UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs,
+                                               WebRtc_UWord32 timestamp,
+                                               WebRtc_UWord32 frameSize,
+                                               bool incompleteFrame)
+{
+    if (latestPacketTimeMs == -1)
+    {
+        return;
+    }
+    WebRtc_Word64 frameDelay;
+    // Calculate the delay estimate
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+               "Packet received and sent to jitter estimate with: timestamp=%u wallClock=%u",
+               timestamp, MaskWord64ToUWord32(latestPacketTimeMs));
+    bool notReordered = _delayEstimate.CalculateDelay(timestamp, &frameDelay, latestPacketTimeMs);
+    // Filter out frames which have been reordered in time by the network
+    if (notReordered)
+    {
+        // Update the jitter estimate with the new samples
+        _jitterEstimate.UpdateEstimate(frameDelay, frameSize, incompleteFrame);
+    }
+}
+
+WebRtc_UWord16*
+VCMJitterBuffer::GetNackList(WebRtc_UWord16& nackSize,bool& listExtended)
+{
+    return CreateNackList(nackSize,listExtended);
+}
+
+// Assume called internally with critsect
+WebRtc_Word32
+VCMJitterBuffer::GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum,
+                                           WebRtc_Word32& highSeqNum) const
+{
+    int i = 0;
+    int seqNum = -1;
+
+    highSeqNum = -1;
+    lowSeqNum = _lastDecodedSeqNum;
+
+    // find highest seq numbers
+    for (i = 0; i < _maxNumberOfFrames; ++i)
+    {
+        seqNum = _frameBuffers[i]->GetHighSeqNum();
+
+        // Ignore free / empty frames
+        VCMFrameBufferStateEnum state = _frameBuffers[i]->GetState();
+
+        if ((kStateFree != state) &&
+            (kStateEmpty != state) &&
+            (kStateDecoding != state) &&
+             seqNum != -1)
+        {
+            if (highSeqNum == -1)
+            {
+                // first
+                highSeqNum = seqNum;
+            }
+            else if (seqNum < 0x0fff && highSeqNum > 0xf000)
+            {
+                // wrap
+                highSeqNum = seqNum;
+            }
+            else if(seqNum > 0xf000 && highSeqNum < 0x0fff)
+            {
+                // Do nothing since it is a wrap and this one is older
+            }
+            else if (seqNum > highSeqNum)
+            {
+                highSeqNum = seqNum;
+            }
+        }
+    } // for
+    return 0;
+}
+
+
+WebRtc_UWord16*
+VCMJitterBuffer::CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended)
+{
+    CriticalSectionScoped cs(_critSect);
+    int i = 0;
+    WebRtc_Word32 lowSeqNum = -1;
+    WebRtc_Word32 highSeqNum = -1;
+    listExtended = false;
+
+    // don't create list, if we won't wait for it
+    if (!WaitForNack())
+    {
+        nackSize = 0;
+        return NULL;
+    }
+
+    // Find the lowest (last decoded) sequence number and
+    // the highest (highest sequence number of the newest frame)
+    // sequence number. The nack list is a subset of the range
+    // between those two numbers.
+    GetLowHighSequenceNumbers(lowSeqNum, highSeqNum);
+
+    // write a list of all seq num we have
+    if (lowSeqNum == -1 || highSeqNum == -1)
+    {
+        //This happens if we lose the first packet, nothing is popped
+        if (highSeqNum == -1)
+        {
+            // we have not received any packets yet
+            nackSize = 0;
+        }
+        else
+        {
+            // signal that we want a key frame request to be sent
+            nackSize = 0xffff;
+        }
+        return NULL;
+    }
+
+    int numberOfSeqNum = 0;
+    if (lowSeqNum > highSeqNum)
+    {
+        if (lowSeqNum - highSeqNum > 0x00ff)
+        {
+            // wrap
+            numberOfSeqNum = (0xffff-lowSeqNum) + highSeqNum + 1;
+        }
+    }
+    else
+    {
+        numberOfSeqNum = highSeqNum - lowSeqNum;
+    }
+
+    if (numberOfSeqNum > kNackHistoryLength)
+    {
+        // Nack list is too big, flush and try to restart.
+        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
+                     VCMId(_vcmId, _receiverId),
+                     "Nack list too large, try to find a key frame and restart "
+                     "from seq: %d. Lowest seq in jb %d", highSeqNum,lowSeqNum);
+
+        // This nack size will trigger a key request...
+        bool foundIFrame = false;
+
+        while (numberOfSeqNum > kNackHistoryLength)
+        {
+            foundIFrame = RecycleFramesUntilKeyFrame();
+
+            if (!foundIFrame)
+            {
+                break;
+            }
+
+            // Check if we still have too many packets in JB
+            lowSeqNum = -1;
+            highSeqNum = -1;
+            GetLowHighSequenceNumbers(lowSeqNum, highSeqNum);
+
+            if (highSeqNum == -1)
+            {
+                assert(lowSeqNum != -1); // This should never happen
+                // We can't calculate the nack list length...
+                return NULL;
+            }
+
+            numberOfSeqNum = 0;
+            if (lowSeqNum > highSeqNum)
+            {
+                if (lowSeqNum - highSeqNum > 0x00ff)
+                {
+                    // wrap
+                    numberOfSeqNum = (0xffff-lowSeqNum) + highSeqNum + 1;
+                    highSeqNum=lowSeqNum;
+                }
+            }
+            else
+            {
+                numberOfSeqNum = highSeqNum - lowSeqNum;
+            }
+
+        } // end while
+
+        if (!foundIFrame)
+        {
+            // No I frame in JB.
+
+            // Set the last decoded sequence number to current high.
+            // This is to not get a large nack list again right away
+            _lastDecodedSeqNum = highSeqNum;
+            // Set to trigger key frame signal
+            nackSize = 0xffff;
+            listExtended = true;
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1,
+                    "\tNo key frame found, request one. _lastDecodedSeqNum[0] %d",
+                    _lastDecodedSeqNum);
+        }
+        else
+        {
+            // We have cleaned up the jb and found a key frame
+            // The function itself has set last decoded seq.
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, -1,
+                    "\tKey frame found. _lastDecodedSeqNum[0] %d",
+                    _lastDecodedSeqNum);
+            nackSize = 0;
+        }
+
+        return NULL;
+    }
+
+    WebRtc_UWord16 seqNumberIterator = (WebRtc_UWord16)(lowSeqNum + 1);
+    for (i = 0; i < numberOfSeqNum; i++)
+    {
+        _NACKSeqNumInternal[i] = seqNumberIterator;
+        seqNumberIterator++;
+    }
+
+    // now we have a list of all sequence numbers that could have been sent
+
+    // zero out the ones we have received
+    for (i = 0; i < _maxNumberOfFrames; i++)
+    {
+        // loop all created frames
+        // We don't need to check if frame is decoding since lowSeqNum is based
+        // on _lastDecodedSeqNum
+        // Ignore free frames
+        VCMFrameBufferStateEnum state = _frameBuffers[i]->GetState();
+
+        if ((kStateFree != state) &&
+            (kStateEmpty != state) &&
+            (kStateDecoding != state))
+        {
+            // Reaching thus far means we are going to update the nack list
+            // When in hybrid mode, we also need to check empty frames, so as
+            // not to add empty packets to the nack list
+            if (_nackMode == kNackHybrid)
+            {
+                // build external rttScore based on RTT value
+                float rttScore = 1.0f;
+                _frameBuffers[i]->ZeroOutSeqNumHybrid(_NACKSeqNumInternal,
+                                                      numberOfSeqNum,
+                                                      rttScore);
+                if (_frameBuffers[i]->IsRetransmitted() == false)
+                {
+                    // if no retransmission required,set the state to decodable
+                    // meaning that we will not wait for NACK
+                    _frameBuffers[i]->SetState(kStateDecodable);
+                }
+            }
+            else
+            {
+                // used when the frame is being processed by the decoding thread
+                // don't need to use that info in this loop
+                _frameBuffers[i]->ZeroOutSeqNum(_NACKSeqNumInternal,
+                                                numberOfSeqNum);
+            }
+        }
+    }
+
+    // compress list
+    int emptyIndex = -1;
+    for (i = 0; i < numberOfSeqNum; i++)
+    {
+        if (_NACKSeqNumInternal[i] == -1 || _NACKSeqNumInternal[i] == -2 )
+        {
+            // this is empty
+            if (emptyIndex == -1)
+            {
+                // no empty index before, remember this position
+                emptyIndex = i;
+            }
+        }
+        else
+        {
+            // this is not empty
+            if (emptyIndex == -1)
+            {
+                // no empty index, continue
+            }
+            else
+            {
+                _NACKSeqNumInternal[emptyIndex] = _NACKSeqNumInternal[i];
+                _NACKSeqNumInternal[i] = -1;
+                emptyIndex++;
+            }
+        }
+    } // for
+
+    if (emptyIndex == -1)
+    {
+        // no empty
+        nackSize = numberOfSeqNum;
+    }
+    else
+    {
+        nackSize = emptyIndex;
+    }
+    // convert to unsigned short 16 bit and store in a list to be used externally.
+    if (nackSize > _NACKSeqNumLength)
+    {
+        // Larger list means that the nack list was extended since the last call.
+        listExtended = true;
+    }
+
+    for (WebRtc_UWord32 j = 0; j < nackSize; j++)
+    {
+        // Check if the list has been extended since it was last created. I.e,
+        // new items have been added
+        if (_NACKSeqNumLength > j && !listExtended)
+        {
+            WebRtc_UWord32 k = 0;
+            for (k = j; k < _NACKSeqNumLength; k++)
+            {
+                // Found the item in the last list, i.e, no new items found yet.
+                if (_NACKSeqNum[k] == (WebRtc_UWord16)_NACKSeqNumInternal[j])
+                {
+                   break;
+                }
+            }
+            if (k == _NACKSeqNumLength) // New item not found in last list.
+            {
+                listExtended = true;
+            }
+        }
+        else
+        {
+            listExtended = true;
+        }
+        _NACKSeqNum[j] = (WebRtc_UWord16)_NACKSeqNumInternal[j];
+    }
+
+    _NACKSeqNumLength = nackSize;
+
+    return _NACKSeqNum;
+}
+
+// Release frame (when done with decoding), forwards to internal function
+void
+VCMJitterBuffer::ReleaseFrame(VCMEncodedFrame* frame)
+{
+    CriticalSectionScoped cs(_critSect);
+    ReleaseFrameInternal(static_cast<VCMFrameBuffer*>(frame));
+}
+
+WebRtc_Word64
+VCMJitterBuffer::LastPacketTime(VCMEncodedFrame* frame, bool& retransmitted) const
+{
+    CriticalSectionScoped cs(_critSect);
+    retransmitted = (static_cast<VCMFrameBuffer*>(frame)->GetNackCount() > 0);
+    return static_cast<VCMFrameBuffer*>(frame)->LatestPacketTimeMs();
+}
+
+WebRtc_Word64
+VCMJitterBuffer::LastDecodedTimestamp() const
+{
+    CriticalSectionScoped cs(_critSect);
+    return _lastDecodedTimeStamp;
+}
+
+// Insert packet
+// Takes crit sect, and inserts packet in frame buffer, possibly does logging
+VCMFrameBufferEnum
+VCMJitterBuffer::InsertPacket(VCMEncodedFrame* buffer, const VCMPacket& packet)
+{
+    CriticalSectionScoped cs(_critSect);
+    WebRtc_Word64 nowMs = VCMTickTime::MillisecondTimestamp();
+    VCMFrameBufferEnum bufferReturn = kSizeError;
+    VCMFrameBufferEnum ret = kSizeError;
+    VCMFrameBuffer* frame = static_cast<VCMFrameBuffer*>(buffer);
+
+    // Empty packets may bias the jitter estimate (lacking size component),
+    // therefore don't let empty packet trigger the following updates:
+    if (packet.frameType != kFrameEmpty)
+    {
+        if (_firstPacket)
+        {
+            // Now it's time to start estimating jitter
+            // reset the delay estimate.
+            _delayEstimate.Reset();
+            _firstPacket = false;
+        }
+
+        if (_waitingForCompletion.timestamp == packet.timestamp)
+        {
+            // This can get bad if we have a lot of duplicate packets,
+            // we will then count some packet multiple times.
+            _waitingForCompletion.frameSize += packet.sizeBytes;
+            _waitingForCompletion.latestPacketTime = nowMs;
+        }
+        else if (_waitingForCompletion.latestPacketTime >= 0 &&
+                 _waitingForCompletion.latestPacketTime + 2000 <= nowMs)
+        {
+            // A packet should never be more than two seconds late
+            UpdateJitterAndDelayEstimates(_waitingForCompletion, true);
+            _waitingForCompletion.latestPacketTime = -1;
+            _waitingForCompletion.frameSize = 0;
+            _waitingForCompletion.timestamp = 0;
+        }
+    }
+
+    if (frame != NULL)
+    {
+        VCMFrameBufferStateEnum state = frame->GetState();
+        if (state == kStateDecoding && packet.sizeBytes == 0)
+        {
+            // Filler packet, make sure we update the last decoded seq num
+            // since this packet should've been a part of the frame being decoded.
+            // If the filler packet belongs to a very old frame (already decoded
+            // and freed) a new frame will be created for the filler packet.
+            // That frame will be empty and later on cleaned up.
+            UpdateLastDecodedWithFiller(packet);
+        }
+
+        // Insert packet
+        bufferReturn = frame->InsertPacket(packet, nowMs);
+        ret = bufferReturn;
+
+        if (bufferReturn > 0)
+        {
+            _incomingBitCount += packet.sizeBytes << 3;
+
+            // Has this packet been nacked or is it about to be nacked?
+            if (IsPacketRetransmitted(packet))
+            {
+                frame->IncrementNackCount();
+            }
+
+            // First packet of a frame
+            if (state == kStateEmpty)
+            {
+                if (bufferReturn > 0)
+                {
+                    ret = kFirstPacket;
+                }
+                _frameBuffersTSOrder.Insert(frame);
+            }
+        }
+    }
+    switch(bufferReturn)
+    {
+    case kStateError:
+    case kTimeStampError:
+    case kSizeError:
+        {
+            // This will trigger a release in CleanUpSizeZeroFrames
+            if (frame != NULL)
+            {
+                frame->Reset();
+                frame->SetState(kStateEmpty);
+            }
+            break;
+        }
+    case kCompleteSession:
+        {
+            UpdateFrameState(frame);
+            // Signal that we have a received packet
+            _packetEvent.Set();
+            break;
+        }
+    case kIncomplete:
+        {
+            // Signal that we have a received packet
+            _packetEvent.Set();
+            break;
+        }
+    case kNoError:
+    case kDuplicatePacket:
+        {
+            break;
+        }
+    default:
+        {
+            assert(!"JitterBuffer::InsertPacket: Undefined value");
+        }
+    }
+
+    return ret;
+}
+
+void
+VCMJitterBuffer::UpdateLastDecodedWithFiller(const VCMPacket& packet)
+{
+    // Empty packet (filler) inserted to a frame which
+    // is already decoding. Update the last decoded seq no.
+    if (_lastDecodedTimeStamp == packet.timestamp &&
+        (packet.seqNum > _lastDecodedSeqNum ||
+        (packet.seqNum < 0x0fff && _lastDecodedSeqNum > 0xf000)))
+    {
+        _lastDecodedSeqNum = packet.seqNum;
+    }
+}
+
+// Must be called from within _critSect
+void
+VCMJitterBuffer::UpdateOldJitterSample(const VCMPacket& packet)
+{
+    if (_waitingForCompletion.timestamp != packet.timestamp &&
+        LatestTimestamp(_waitingForCompletion.timestamp, packet.timestamp) ==
+        packet.timestamp)
+    {
+        // This is a newer frame than the one waiting for completion.
+        _waitingForCompletion.frameSize = packet.sizeBytes;
+        _waitingForCompletion.timestamp = packet.timestamp;
+    }
+    else
+    {
+        // This can get bad if we have a lot of duplicate packets,
+        // we will then count some packet multiple times.
+        _waitingForCompletion.frameSize += packet.sizeBytes;
+        _jitterEstimate.UpdateMaxFrameSize(_waitingForCompletion.frameSize);
+    }
+}
+
+// Must be called from within _critSect
+bool
+VCMJitterBuffer::IsPacketRetransmitted(const VCMPacket& packet) const
+{
+    if (_NACKSeqNum && _NACKSeqNumLength > 0)
+    {
+        for (WebRtc_UWord16 i = 0; i < _NACKSeqNumLength; i++)
+        {
+            if (packet.seqNum == _NACKSeqNum[i])
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// Get nack status (enabled/disabled)
+VCMNackMode
+VCMJitterBuffer::GetNackMode() const
+{
+    CriticalSectionScoped cs(_critSect);
+    return _nackMode;
+}
+
+// Set NACK mode
+void
+VCMJitterBuffer::SetNackMode(VCMNackMode mode)
+{
+    CriticalSectionScoped cs(_critSect);
+    _nackMode = mode;
+    if (_nackMode == kNoNack)
+    {
+        _jitterEstimate.ResetNackCount();
+    }
+}
+
+
+// Recycle oldest frames up to a key frame, used if JB is completely full
+bool
+VCMJitterBuffer::RecycleFramesUntilKeyFrame()
+{
+    // Throw at least one frame.
+    VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
+    VCMFrameBuffer* oldestFrame = NULL;
+    if (oldestFrameListItem != NULL)
+    {
+        oldestFrame = oldestFrameListItem->GetItem();
+    }
+
+    // Remove up to oldest key frame
+    bool foundIFrame = false;
+    while (oldestFrameListItem != NULL && !foundIFrame)
+    {
+        // Throw at least one frame.
+        _dropCount++;
+        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding,
+                     VCMId(_vcmId, _receiverId),
+                     "Jitter buffer drop count:%d, lowSeq %d", _dropCount,
+                     oldestFrame->GetLowSeqNum());
+        _frameBuffersTSOrder.Erase(oldestFrameListItem);
+        RecycleFrame(oldestFrame);
+
+        oldestFrameListItem = _frameBuffersTSOrder.First();
+        if (oldestFrameListItem != NULL)
+        {
+            oldestFrame = oldestFrameListItem->GetItem();
+        }
+
+        if(oldestFrame != NULL)
+        {
+            foundIFrame = foundIFrame ||
+                          (oldestFrame->FrameType() != kVideoFrameDelta);
+            if (foundIFrame)
+            {
+                // fake the last played out to match the start of this key frame
+                _lastDecodedSeqNum = (WebRtc_UWord16)((WebRtc_UWord16)
+                                     (oldestFrame->GetLowSeqNum()) - 1);
+                _lastDecodedTimeStamp = (WebRtc_UWord32)
+                                        (oldestFrame->TimeStamp() - 1);
+                break;
+            }
+        }
+    }
+    _lastDecodedSeqNum = -1;
+    return foundIFrame;
+}
+
+// Must be called under the critical section _critSect.
+void
+VCMJitterBuffer::CleanUpOldFrames()
+{
+    VCMFrameListItem* oldestFrameListItem = _frameBuffersTSOrder.First();
+    VCMFrameBuffer* oldestFrame = NULL;
+
+    if (_lastDecodedTimeStamp == -1)
+    {
+        return;
+    }
+
+    while (oldestFrameListItem != NULL)
+    {
+        oldestFrame = oldestFrameListItem->GetItem();
+        WebRtc_UWord32 frameTimeStamp = oldestFrame->TimeStamp();
+
+        // Release the frame if it's older than the last decoded frame.
+        if (_lastDecodedTimeStamp > -1 &&
+            LatestTimestamp(static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp),
+                            frameTimeStamp)
+                         == static_cast<WebRtc_UWord32>(_lastDecodedTimeStamp))
+        {
+            const WebRtc_Word32 frameLowSeqNum = oldestFrame->GetLowSeqNum();
+            const WebRtc_Word32 frameHighSeqNum = oldestFrame->GetHighSeqNum();
+            if (frameTimeStamp == _lastDecodedTimeStamp &&
+                ((frameLowSeqNum == (_lastDecodedSeqNum + 1)) ||
+                ((frameLowSeqNum == 0) &&
+                (_lastDecodedSeqNum == 0xffff))))
+            {
+                // Could happen when sending filler data.
+                // Filler packet (size = 0) belonging to last decoded frame.
+                // Frame: | packet | packet | packet M=1 |
+                // filler data (size = 0) | filler data (size = 0)| ...
+
+                // This frame follows the last decoded frame
+                _lastDecodedSeqNum = frameHighSeqNum;
+            }
+
+            _frameBuffersTSOrder.Erase(oldestFrameListItem);
+            ReleaseFrameInternal(oldestFrame);
+            oldestFrameListItem = _frameBuffersTSOrder.First();
+        }
+        else
+        {
+            break;
+        }
+    }
+}
+
+// This function has changed to use sequence numbers
+// Using timestamp won't work since can get
+// nack requests with a higher time stamp than
+// the following encoded frame, but with a lower sequence number.
+// Must be called under _critSect.
+void
+VCMJitterBuffer::CleanUpSizeZeroFrames()
+{
+    VCMFrameListItem* frameListItem = FindOldestSequenceNum();
+
+    while (frameListItem != NULL)
+    {
+        VCMFrameBuffer* ptrTempBuffer = frameListItem->GetItem();
+
+        // pop frame if its size zero but store seqnum
+        if (ptrTempBuffer->Length() == 0)
+        {
+            WebRtc_Word32 frameHighSeqNum = ptrTempBuffer->GetHighSeqNum();
+            if (frameHighSeqNum == -1)
+            {
+                // This frame has been Reset for this function to clean it up
+                _frameBuffersTSOrder.Erase(frameListItem);
+                ReleaseFrameInternal(ptrTempBuffer);
+                frameListItem = FindOldestSequenceNum();
+            }
+            else
+            {
+                bool releaseFrame = false;
+                const WebRtc_Word32 frameHighSeqNum = ptrTempBuffer->GetHighSeqNum();
+                const WebRtc_Word32 frameLowSeqNum = ptrTempBuffer->GetLowSeqNum();
+
+                if ((frameLowSeqNum == (_lastDecodedSeqNum + 1)) || // Frame is next in line
+                    ((frameLowSeqNum == 0) && (_lastDecodedSeqNum== 0xffff)))
+                {
+                    // This frame follows the last decoded frame, release it.
+                    _lastDecodedSeqNum = frameHighSeqNum;
+                    releaseFrame = true;
+                }
+                // If frameHighSeqNum < _lastDecodedSeqNum but need to take wrap into account.
+                else if(frameHighSeqNum < _lastDecodedSeqNum)
+                {
+                    if (frameHighSeqNum < 0x0fff &&
+                        _lastDecodedSeqNum> 0xf000)
+                    {
+                        // Wrap, we don't want release this one. It's newer...
+                    }
+                    else
+                    {
+                        // This frame has lower seq than last decoded,
+                        // and we have no wrap -> it's older.
+                        releaseFrame = true;
+                    }
+                }
+                else if(frameHighSeqNum > _lastDecodedSeqNum &&
+                        _lastDecodedSeqNum < 0x0fff &&
+                        frameHighSeqNum > 0xf000)
+                {
+                    // Higher seq than last decoded,
+                    // but last decoded has recently wrapped.
+                    releaseFrame = true;
+                }
+
+                if (releaseFrame)
+                {
+                    _frameBuffersTSOrder.Erase(frameListItem);
+                    ReleaseFrameInternal(ptrTempBuffer);
+                    frameListItem = FindOldestSequenceNum();
+                }
+                else
+                {
+                    // We couldn't release this one and we're using nack,
+                    // stop trying...
+                    frameListItem = NULL;
+                }
+            }
+        }
+        else
+        {
+            // we have a length
+            break;
+        }
+    }
+}
+
+// used in GetFrameForDecoding
+void
+VCMJitterBuffer::VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame)
+{
+    frame.MakeSessionDecodable(); // make sure the session can be decoded.
+    if (_lastDecodedSeqNum == -1)
+    {
+        // First frame
+        frame.SetPreviousFrameLoss();
+    }
+    else if (frame.GetLowSeqNum() != ((WebRtc_UWord16)_lastDecodedSeqNum +
+                                      (WebRtc_UWord16)1))
+    {
+        // Frame loss
+        frame.SetPreviousFrameLoss();
+    }
+}
+
+bool
+VCMJitterBuffer::WaitForNack()
+{
+     // NACK disabled -> can't wait
+     if (_nackMode == kNoNack)
+     {
+         return false;
+     }
+     // NACK only -> always wait
+     else if (_nackMode == kNackInfinite)
+     {
+         return true;
+     }
+     // else: hybrid mode, evaluate
+     // RTT high, don't wait
+     if (_rttMs >= kHighRttNackMs)
+     {
+         return false;
+     }
+     // Either NACK only or hybrid
+     return true;
+}
+
+
+}
diff --git a/src/modules/video_coding/main/source/jitter_buffer.h b/src/modules/video_coding/main/source/jitter_buffer.h
new file mode 100644
index 0000000..ab88f38
--- /dev/null
+++ b/src/modules/video_coding/main/source/jitter_buffer.h
@@ -0,0 +1,236 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_H_
+
+#include "typedefs.h"
+#include "critical_section_wrapper.h"
+#include "module_common_types.h"
+#include "video_coding_defines.h"
+#include "inter_frame_delay.h"
+#include "event.h"
+#include "frame_list.h"
+#include "jitter_buffer_common.h"
+#include "jitter_estimator.h"
+
+namespace webrtc
+{
+
+enum VCMNackMode
+{
+    kNackInfinite,
+    kNackHybrid,
+    kNoNack
+};
+
+// forward declarations
+class VCMFrameBuffer;
+class VCMPacket;
+class VCMEncodedFrame;
+
+class VCMJitterSample
+{
+public:
+    VCMJitterSample() : timestamp(0), frameSize(0), latestPacketTime(-1) {}
+    WebRtc_UWord32 timestamp;
+    WebRtc_UWord32 frameSize;
+    WebRtc_Word64 latestPacketTime;
+};
+
+class VCMJitterBuffer
+{
+public:
+    VCMJitterBuffer(WebRtc_Word32 vcmId = -1,
+                    WebRtc_Word32 receiverId = -1,
+                    bool master = true);
+    virtual ~VCMJitterBuffer();
+
+    VCMJitterBuffer& operator=(const VCMJitterBuffer& rhs);
+
+    // We need a start and stop to break out of the wait event
+    // used in GetCompleteFrameForDecoding
+    void Start();
+    void Stop();
+    bool Running() const;
+
+    // Empty the Jitter buffer of all its data
+    void Flush();
+
+    // Statistics, Get received key and delta frames
+    WebRtc_Word32 GetFrameStatistics(WebRtc_UWord32& receivedDeltaFrames,
+                                     WebRtc_UWord32& receivedKeyFrames) const;
+
+    // Statistics, Calculate frame and bit rates
+    WebRtc_Word32 GetUpdate(WebRtc_UWord32& frameRate, WebRtc_UWord32& bitRate);
+
+    // Wait for the first packet in the next frame to arrive, blocks for <= maxWaitTimeMS ms
+    WebRtc_Word64 GetNextTimeStamp(WebRtc_UWord32 maxWaitTimeMS,
+                                   FrameType& incomingFrameType,
+                                   WebRtc_Word64& renderTimeMs);
+
+    // Will the packet sequence be complete if the next frame is grabbed
+    // for decoding right now? That is, have we lost a frame between the
+    // last decoded frame and the next, or is the next frame missing one
+    // or more packets?
+    bool CompleteSequenceWithNextFrame();
+
+    // Wait maxWaitTimeMS for a complete frame to arrive. After timeout NULL is returned.
+    VCMEncodedFrame* GetCompleteFrameForDecoding(WebRtc_UWord32 maxWaitTimeMS);
+
+    // Get a frame for decoding (even an incomplete) without delay.
+    VCMEncodedFrame* GetFrameForDecoding();
+
+    VCMEncodedFrame* GetFrameForDecodingNACK();
+
+    // Release frame (when done with decoding)
+    void ReleaseFrame(VCMEncodedFrame* frame);
+
+    // Get frame to use for this timestamp
+    WebRtc_Word32 GetFrame(const VCMPacket& packet, VCMEncodedFrame*&);
+    VCMEncodedFrame* GetFrame(const VCMPacket& packet); // deprecated
+
+    // Returns the time in ms when the latest packet was inserted into the frame.
+    // Retransmitted is set to true if any of the packets belonging to the frame
+    // has been retransmitted.
+    WebRtc_Word64 LastPacketTime(VCMEncodedFrame* frame, bool& retransmitted) const;
+
+    // Insert a packet into a frame
+    VCMFrameBufferEnum InsertPacket(VCMEncodedFrame* frame, const VCMPacket& packet);
+
+    // Sync
+    WebRtc_UWord32 GetEstimatedJitterMS();
+    void UpdateRtt(WebRtc_UWord32 rttMs);
+
+    // NACK
+    void SetNackMode(VCMNackMode mode); // Enable/disable nack
+    VCMNackMode GetNackMode() const;    // Get nack mode
+    // Get list of missing sequence numbers (size in number of elements)
+    WebRtc_UWord16* GetNackList(WebRtc_UWord16& nackSize, bool& listExtended);
+
+    WebRtc_Word64 LastDecodedTimestamp() const;
+    static WebRtc_UWord32 LatestTimestamp(const WebRtc_UWord32 existingTimestamp,
+                                          const WebRtc_UWord32 newTimestamp);
+
+protected:
+
+    // Misc help functions
+    // Recycle (release) frame, used if we didn't receive whole frame
+    void RecycleFrame(VCMFrameBuffer* frame);
+    void ReleaseFrameInternal(VCMFrameBuffer* frame);
+    // Flush and reset the jitter buffer. Call under critical section.
+    void FlushInternal();
+    VCMFrameListItem* FindOldestSequenceNum() const;
+
+    // Help functions for insert packet
+    // Get empty frame, creates new (i.e. increases JB size) if necessary
+    VCMFrameBuffer* GetEmptyFrame();
+    // Recycle oldest frames up to a key frame, used if JB is completely full
+    bool RecycleFramesUntilKeyFrame();
+    // Update frame state (set as complete or reconstructable if conditions are met)
+    void UpdateFrameState(VCMFrameBuffer* frameListItem);
+
+    // Help functions for getting a frame
+    // Find oldest complete frame, used for getting next frame to decode
+    VCMFrameListItem* FindOldestCompleteContinuousFrame();
+
+    // Check if a frame is missing the markerbit but is complete
+    bool CheckForCompleteFrame(VCMFrameListItem* oldestFrameItem);
+
+
+    void CleanUpOldFrames();
+    void CleanUpSizeZeroFrames();
+
+    void VerifyAndSetPreviousFrameLost(VCMFrameBuffer& frame);
+    bool IsPacketRetransmitted(const VCMPacket& packet) const;
+    void UpdateJitterAndDelayEstimates(VCMJitterSample& sample, bool incompleteFrame);
+    void UpdateJitterAndDelayEstimates(VCMFrameBuffer& frame, bool incompleteFrame);
+    void UpdateJitterAndDelayEstimates(WebRtc_Word64 latestPacketTimeMs,
+                                       WebRtc_UWord32 timestamp,
+                                       WebRtc_UWord32 frameSize,
+                                       bool incompleteFrame);
+    void UpdateOldJitterSample(const VCMPacket& packet);
+    WebRtc_UWord32 GetEstimatedJitterMsInternal();
+
+    // NACK help
+    WebRtc_UWord16* CreateNackList(WebRtc_UWord16& nackSize, bool& listExtended);
+    WebRtc_Word32 GetLowHighSequenceNumbers(WebRtc_Word32& lowSeqNum,
+                                            WebRtc_Word32& highSeqNum) const;
+
+    void UpdateLastDecodedWithFiller(const VCMPacket& packet);
+
+private:
+
+    static bool FrameEqualTimestamp(VCMFrameBuffer* frame, const void* timestamp);
+    static bool CompleteDecodableKeyFrameCriteria(VCMFrameBuffer* frame,
+                                                  const void* notUsed);
+    // Decide whether should wait for NACK (mainly relevant for hybrid mode)
+    bool WaitForNack();
+
+    WebRtc_Word32                 _vcmId;
+    WebRtc_Word32                 _receiverId;
+    // If we are running (have started) or not
+    bool                          _running;
+    CriticalSectionWrapper&       _critSect;
+    bool                          _master;
+    // Event to signal when we have a frame ready for decoder
+    VCMEvent                      _frameEvent;
+    // Event to signal when we have received a packet
+    VCMEvent                      _packetEvent;
+    // Number of allocated frames
+    WebRtc_Word32                 _maxNumberOfFrames;
+    // Array of pointers to the frames in JB
+    VCMFrameBuffer*               _frameBuffers[kMaxNumberOfFrames];
+    VCMFrameListTimestampOrderAsc _frameBuffersTSOrder;
+
+    // timing
+    // Sequence number of last frame that was given to decoder
+    WebRtc_Word32           _lastDecodedSeqNum;
+    // Timestamp of last frame that was given to decoder
+    WebRtc_Word64           _lastDecodedTimeStamp;
+
+    // Statistics
+    // Frame counter for each type (key, delta, golden, key-delta)
+    WebRtc_UWord8           _receiveStatistics[4];
+    // Latest calculated frame rates of incoming stream
+    WebRtc_UWord8           _incomingFrameRate;
+    // Frame counter, reset in GetUpdate
+    WebRtc_UWord32          _incomingFrameCount;
+    // Real time for last _frameCount reset
+    WebRtc_Word64           _timeLastIncomingFrameCount;
+    // Received bits counter, reset in GetUpdate
+    WebRtc_UWord32          _incomingBitCount;
+    WebRtc_UWord32          _incomingBitRate;
+    WebRtc_UWord32          _dropCount;            // Frame drop counter
+    // Number of frames in a row that have been too old
+    WebRtc_UWord32          _numConsecutiveOldFrames;
+    // Number of packets in a row that have been too old
+    WebRtc_UWord32          _numConsecutiveOldPackets;
+    // Filters for estimating jitter
+    VCMJitterEstimator      _jitterEstimate;
+    // Calculates network delays used for jitter calculations
+    VCMInterFrameDelay      _delayEstimate;
+    VCMJitterSample         _waitingForCompletion;
+    WebRtc_UWord32          _rttMs;
+
+    // NACK
+    VCMNackMode             _nackMode;
+    // Holds the internal nack list (the missing seqence numbers)
+    WebRtc_Word32           _NACKSeqNumInternal[kNackHistoryLength];
+    WebRtc_UWord16          _NACKSeqNum[kNackHistoryLength];
+    WebRtc_UWord32          _NACKSeqNumLength;
+
+    bool                    _missingMarkerBits;
+    bool                    _firstPacket;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_H_
diff --git a/src/modules/video_coding/main/source/jitter_buffer_common.h b/src/modules/video_coding/main/source/jitter_buffer_common.h
new file mode 100644
index 0000000..035a3c1
--- /dev/null
+++ b/src/modules/video_coding/main/source/jitter_buffer_common.h
@@ -0,0 +1,67 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_
+#define WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_
+
+namespace webrtc
+{
+
+enum { kMaxNumberOfFrames     = 100 };
+enum { kStartNumberOfFrames   = 6 };    // in packets, 6 packets are approximately 198 ms,
+                                        // we need at least one more for process
+enum { kMaxVideoDelayMs       = 2000 }; // in ms
+
+enum VCMJitterBufferEnum
+{
+    kMaxConsecutiveOldFrames        = 60,
+    kMaxConsecutiveOldPackets       = 300,
+    kMaxPacketsInJitterBuffer       = 800,
+    kBufferIncStepSizeBytes         = 30000,       // >20 packets
+    kMaxJBFrameSizeBytes            = 4000000      // sanity don't go above 4Mbyte
+};
+
+enum VCMFrameBufferEnum
+{
+    kStateError           = -4,
+    kTimeStampError       = -2,
+    kSizeError            = -1,
+    kNoError              = 0,
+    kIncomplete           = 1,    // Frame incomplete
+    kFirstPacket          = 2,
+    kCompleteSession      = 3,    // at least one layer in the frame complete
+    kDuplicatePacket      = 5     // We're receiving a duplicate packet.
+};
+
+enum VCMFrameBufferStateEnum
+{
+    kStateFree,               // Unused frame in the JB
+    kStateEmpty,              // frame popped by the RTP receiver
+    kStateIncomplete,         // frame that have one or more packet(s) stored
+    kStateComplete,           // frame that have all packets
+    kStateDecoding,           // frame popped by the decoding thread
+    kStateDecodable           // Hybrid mode - frame can be decoded
+};
+
+enum { kH264StartCodeLengthBytes = 4};
+
+// Used to indicate if a received packet contain a complete NALU (or equivalent)
+enum VCMNaluCompleteness
+{
+    kNaluUnset = 0,       //Packet has not been filled.
+    kNaluComplete = 1,    //Packet can be decoded as is.
+    kNaluStart,           // Packet contain beginning of NALU
+    kNaluIncomplete,      //Packet is not beginning or end of NALU
+    kNaluEnd,             // Packet is the end of a NALU
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_JITTER_BUFFER_COMMON_H_
diff --git a/src/modules/video_coding/main/source/jitter_estimator.cc b/src/modules/video_coding/main/source/jitter_estimator.cc
new file mode 100644
index 0000000..233fad4
--- /dev/null
+++ b/src/modules/video_coding/main/source/jitter_estimator.cc
@@ -0,0 +1,422 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "trace.h"
+#include "internal_defines.h"
+#include "jitter_estimator.h"
+#include "rtt_filter.h"
+#include "tick_time.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace webrtc {
+
+VCMJitterEstimator::VCMJitterEstimator(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId) :
+_vcmId(vcmId),
+_receiverId(receiverId),
+_phi(0.97),
+_psi(0.9999),
+_alphaCountMax(400),
+_beta(0.9994),
+_thetaLow(0.000001),
+_nackLimit(3),
+_numStdDevDelayOutlier(15),
+_numStdDevFrameSizeOutlier(3),
+_noiseStdDevs(2.33), // ~Less than 1% chance
+                     // (look up in normal distribution table)...
+_noiseStdDevOffset(30.0), // ...of getting 30 ms freezes
+_rttFilter(vcmId, receiverId)
+{
+    Reset();
+}
+
+VCMJitterEstimator&
+VCMJitterEstimator::operator=(const VCMJitterEstimator& rhs)
+{
+    if (this != &rhs)
+    {
+        memcpy(_thetaCov, rhs._thetaCov, sizeof(_thetaCov));
+        memcpy(_Qcov, rhs._Qcov, sizeof(_Qcov));
+
+        _vcmId = rhs._vcmId;
+        _receiverId = rhs._receiverId;
+        _avgFrameSize = rhs._avgFrameSize;
+        _varFrameSize = rhs._varFrameSize;
+        _maxFrameSize = rhs._maxFrameSize;
+        _fsSum = rhs._fsSum;
+        _fsCount = rhs._fsCount;
+        _lastUpdateT = rhs._lastUpdateT;
+        _prevEstimate = rhs._prevEstimate;
+        _prevFrameSize = rhs._prevFrameSize;
+        _avgNoise = rhs._avgNoise;
+        _alphaCount = rhs._alphaCount;
+        _filterJitterEstimate = rhs._filterJitterEstimate;
+        _startupCount = rhs._startupCount;
+        _latestNackTimestamp = rhs._latestNackTimestamp;
+        _nackCount = rhs._nackCount;
+        _rttFilter = rhs._rttFilter;
+    }
+    return *this;
+}
+
+// Resets the JitterEstimate
+void
+VCMJitterEstimator::Reset()
+{
+    _theta[0] = 1/(512e3/8);
+    _theta[1] = 0;
+    _varNoise = 4.0;
+
+    _thetaCov[0][0] = 1e-4;
+    _thetaCov[1][1] = 1e2;
+    _thetaCov[0][1] = _thetaCov[1][0] = 0;
+    _Qcov[0][0] = 2.5e-10;
+    _Qcov[1][1] = 1e-10;
+    _Qcov[0][1] = _Qcov[1][0] = 0;
+    _avgFrameSize = 500;
+    _maxFrameSize = 500;
+    _varFrameSize = 100;
+    _lastUpdateT = -1;
+    _prevEstimate = -1.0;
+    _prevFrameSize = 0;
+    _avgNoise = 0.0;
+    _alphaCount = 1;
+    _filterJitterEstimate = 0.0;
+    _latestNackTimestamp = 0;
+    _nackCount = 0;
+    _fsSum = 0;
+    _fsCount = 0;
+    _startupCount = 0;
+    _rttFilter.Reset();
+}
+
+void
+VCMJitterEstimator::ResetNackCount()
+{
+    _nackCount = 0;
+}
+
+// Updates the estimates with the new measurements
+void
+VCMJitterEstimator::UpdateEstimate(WebRtc_Word64 frameDelayMS, WebRtc_UWord32 frameSizeBytes,
+                                            bool incompleteFrame /* = false */)
+{
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding,
+               VCMId(_vcmId, _receiverId),
+               "Jitter estimate updated with: frameSize=%d frameDelayMS=%d",
+               frameSizeBytes, frameDelayMS);
+    if (frameSizeBytes == 0)
+    {
+        return;
+    }
+    int deltaFS = frameSizeBytes - _prevFrameSize;
+    if (_fsCount < kFsAccuStartupSamples)
+    {
+        _fsSum += frameSizeBytes;
+        _fsCount++;
+    }
+    else if (_fsCount == kFsAccuStartupSamples)
+    {
+        // Give the frame size filter
+        _avgFrameSize = static_cast<double>(_fsSum) /
+                        static_cast<double>(_fsCount);
+        _fsCount++;
+    }
+    if (!incompleteFrame || frameSizeBytes > _avgFrameSize)
+    {
+        double avgFrameSize = _phi * _avgFrameSize +
+                              (1 - _phi) * frameSizeBytes;
+        if (frameSizeBytes < _avgFrameSize + 2 * sqrt(_varFrameSize))
+        {
+            // Only update the average frame size if this sample wasn't a
+            // key frame
+            _avgFrameSize = avgFrameSize;
+        }
+        // Update the variance anyway since we want to capture cases where we only get
+        // key frames.
+        _varFrameSize = VCM_MAX(_phi * _varFrameSize + (1 - _phi) *
+                                (frameSizeBytes - avgFrameSize) *
+                                (frameSizeBytes - avgFrameSize), 1.0);
+    }
+
+    // Update max frameSize estimate
+    _maxFrameSize = VCM_MAX(_psi * _maxFrameSize, static_cast<double>(frameSizeBytes));
+
+    if (_prevFrameSize == 0)
+    {
+        _prevFrameSize = frameSizeBytes;
+        return;
+    }
+    _prevFrameSize = frameSizeBytes;
+
+    // Only update the Kalman filter if the sample is not considered
+    // an extreme outlier. Even if it is an extreme outlier from a
+    // delay point of view, if the frame size also is large the
+    // deviation is probably due to an incorrect line slope.
+    double deviation = DeviationFromExpectedDelay(frameDelayMS, deltaFS);
+
+    if (abs(deviation) < _numStdDevDelayOutlier * sqrt(_varNoise) ||
+        frameSizeBytes > _avgFrameSize + _numStdDevFrameSizeOutlier * sqrt(_varFrameSize))
+    {
+        // Update the variance of the deviation from the
+        // line given by the Kalman filter
+        EstimateRandomJitter(deviation, incompleteFrame);
+        // Prevent updating with frames which have been congested by a large
+        // frame, and therefore arrives almost at the same time as that frame.
+        // This can occur when we receive a large frame (key frame) which
+        // has been delayed. The next frame is of normal size (delta frame),
+        // and thus deltaFS will be << 0. This removes all frame samples
+        // which arrives after a key frame.
+        if ((!incompleteFrame || deviation >= 0.0) &&
+            static_cast<double>(deltaFS) > - 0.25 * _maxFrameSize)
+        {
+            // Update the Kalman filter with the new data
+            KalmanEstimateChannel(frameDelayMS, deltaFS);
+        }
+    }
+    else
+    {
+        int nStdDev = (deviation >= 0) ? _numStdDevDelayOutlier : -_numStdDevDelayOutlier;
+        EstimateRandomJitter(nStdDev * sqrt(_varNoise), incompleteFrame);
+    }
+    // Post process the total estimated jitter
+    if (_startupCount >= kStartupDelaySamples)
+    {
+        PostProcessEstimate();
+    }
+    else
+    {
+        _startupCount++;
+    }
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+               "Framesize statistics: max=%f average=%f", _maxFrameSize, _avgFrameSize);
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+               "The estimated slope is: theta=(%f, %f)", _theta[0], _theta[1]);
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+               "Random jitter: mean=%f variance=%f", _avgNoise, _varNoise);
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+               "Current jitter estimate: %f", _filterJitterEstimate);
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+               "Current max RTT: %u", _rttFilter.RttMs());
+}
+
+// Updates the nack/packet ratio
+void
+VCMJitterEstimator::FrameNacked()
+{
+    // Wait until _nackLimit retransmissions has been received,
+    // then always add ~1 RTT delay.
+    // TODO(holmer): Should we ever remove the additional delay if the
+    // the packet losses seem to have stopped? We could for instance scale
+    // the number of RTTs to add with the amount of retransmissions in a given
+    // time interval, or similar.
+    if (_nackCount < _nackLimit)
+    {
+        _nackCount++;
+    }
+}
+
+// Updates Kalman estimate of the channel
+// The caller is expected to sanity check the inputs.
+void
+VCMJitterEstimator::KalmanEstimateChannel(WebRtc_Word64 frameDelayMS,
+                                          WebRtc_Word32 deltaFSBytes)
+{
+    double Mh[2];
+    double hMh_sigma;
+    double kalmanGain[2];
+    double measureRes;
+    double t00, t01;
+
+    // Kalman filtering
+
+    // Prediction
+    // M = M + Q
+    _thetaCov[0][0] += _Qcov[0][0];
+    _thetaCov[0][1] += _Qcov[0][1];
+    _thetaCov[1][0] += _Qcov[1][0];
+    _thetaCov[1][1] += _Qcov[1][1];
+
+    // Kalman gain
+    // K = M*h'/(sigma2n + h*M*h') = M*h'/(1 + h*M*h')
+    // h = [dFS 1]
+    // Mh = M*h'
+    // hMh_sigma = h*M*h' + R
+    Mh[0] = _thetaCov[0][0] * deltaFSBytes + _thetaCov[0][1];
+    Mh[1] = _thetaCov[1][0] * deltaFSBytes + _thetaCov[1][1];
+    // sigma weights measurements with a small deltaFS as noisy and
+    // measurements with large deltaFS as good
+    if (_maxFrameSize < 1.0)
+    {
+        return;
+    }
+    double sigma = (300.0 * exp(-abs(static_cast<double>(deltaFSBytes)) /
+                   (1e0 * _maxFrameSize)) + 1) * sqrt(_varNoise);
+    if (sigma < 1.0)
+    {
+        sigma = 1.0;
+    }
+    hMh_sigma = deltaFSBytes * Mh[0] + Mh[1] + sigma;
+    if ((hMh_sigma < 1e-9 && hMh_sigma >= 0) || (hMh_sigma > -1e-9 && hMh_sigma <= 0))
+    {
+        assert(false);
+        return;
+    }
+    kalmanGain[0] = Mh[0] / hMh_sigma;
+    kalmanGain[1] = Mh[1] / hMh_sigma;
+
+    // Correction
+    // theta = theta + K*(dT - h*theta)
+    measureRes = frameDelayMS - (deltaFSBytes * _theta[0] + _theta[1]);
+    _theta[0] += kalmanGain[0] * measureRes;
+    _theta[1] += kalmanGain[1] * measureRes;
+
+    if (_theta[0] < _thetaLow)
+    {
+        _theta[0] = _thetaLow;
+    }
+
+    // M = (I - K*h)*M
+    t00 = _thetaCov[0][0];
+    t01 = _thetaCov[0][1];
+    _thetaCov[0][0] = (1 - kalmanGain[0] * deltaFSBytes) * t00 -
+                      kalmanGain[0] * _thetaCov[1][0];
+    _thetaCov[0][1] = (1 - kalmanGain[0] * deltaFSBytes) * t01 -
+                      kalmanGain[0] * _thetaCov[1][1];
+    _thetaCov[1][0] = _thetaCov[1][0] * (1 - kalmanGain[1]) -
+                      kalmanGain[1] * deltaFSBytes * t00;
+    _thetaCov[1][1] = _thetaCov[1][1] * (1 - kalmanGain[1]) -
+                      kalmanGain[1] * deltaFSBytes * t01;
+
+    // Covariance matrix, must be positive semi-definite
+    assert(_thetaCov[0][0] + _thetaCov[1][1] >= 0 &&
+           _thetaCov[0][0] * _thetaCov[1][1] - _thetaCov[0][1] * _thetaCov[1][0] >= 0 &&
+           _thetaCov[0][0] >= 0);
+}
+
+// Calculate difference in delay between a sample and the
+// expected delay estimated by the Kalman filter
+double
+VCMJitterEstimator::DeviationFromExpectedDelay(WebRtc_Word64 frameDelayMS,
+                                               WebRtc_Word32 deltaFSBytes) const
+{
+    return frameDelayMS - (_theta[0] * deltaFSBytes + _theta[1]);
+}
+
+// Estimates the random jitter by calculating the variance of the
+// sample distance from the line given by theta.
+void
+VCMJitterEstimator::EstimateRandomJitter(double d_dT, bool incompleteFrame)
+{
+    double alpha;
+    if (_alphaCount == 0)
+    {
+        assert(_alphaCount > 0);
+        return;
+    }
+    alpha = static_cast<double>(_alphaCount - 1) / static_cast<double>(_alphaCount);
+    _alphaCount++;
+    if (_alphaCount > _alphaCountMax)
+    {
+        _alphaCount = _alphaCountMax;
+    }
+    double avgNoise = alpha * _avgNoise + (1 - alpha) * d_dT;
+    double varNoise = alpha * _varNoise +
+                      (1 - alpha) * (d_dT - _avgNoise) * (d_dT - _avgNoise);
+    if (!incompleteFrame || varNoise > _varNoise)
+    {
+        _avgNoise = avgNoise;
+        _varNoise = varNoise;
+    }
+    if (_varNoise < 1.0)
+    {
+        // The variance should never be zero, since we might get
+        // stuck and consider all samples as outliers.
+        _varNoise = 1.0;
+    }
+}
+
+double
+VCMJitterEstimator::NoiseThreshold() const
+{
+    double noiseThreshold = _noiseStdDevs * sqrt(_varNoise) - _noiseStdDevOffset;
+    if (noiseThreshold < 1.0)
+    {
+        noiseThreshold = 1.0;
+    }
+    return noiseThreshold;
+}
+
+// Calculates the current jitter estimate from the filtered estimates
+double
+VCMJitterEstimator::CalculateEstimate()
+{
+    double ret = _theta[0] * (_maxFrameSize - _avgFrameSize) + NoiseThreshold();
+
+    // A very low estimate (or negative) is neglected
+    if (ret < 1.0) {
+        if (_prevEstimate <= 0.01)
+        {
+            ret = 1.0;
+        }
+        else
+        {
+            ret = _prevEstimate;
+        }
+    }
+    if (ret > 10000.0) // Sanity
+    {
+        ret = 10000.0;
+    }
+    _prevEstimate = ret;
+    return ret;
+}
+
+void
+VCMJitterEstimator::PostProcessEstimate()
+{
+    _filterJitterEstimate = CalculateEstimate();
+}
+
+void
+VCMJitterEstimator::UpdateRtt(WebRtc_UWord32 rttMs)
+{
+    _rttFilter.Update(rttMs);
+}
+
+void
+VCMJitterEstimator::UpdateMaxFrameSize(WebRtc_UWord32 frameSizeBytes)
+{
+    if (_maxFrameSize < frameSizeBytes)
+    {
+        _maxFrameSize = frameSizeBytes;
+    }
+}
+
+// Returns the current filtered estimate if available,
+// otherwise tries to calculate an estimate.
+double
+VCMJitterEstimator::GetJitterEstimate(double rttMultiplier)
+{
+    double jitterMS = CalculateEstimate();
+    if (_filterJitterEstimate > jitterMS)
+    {
+        jitterMS = _filterJitterEstimate;
+    }
+    if (_nackCount >= _nackLimit)
+    {
+        return jitterMS + _rttFilter.RttMs() * rttMultiplier;
+    }
+    return jitterMS;
+}
+
+}
diff --git a/src/modules/video_coding/main/source/jitter_estimator.h b/src/modules/video_coding/main/source/jitter_estimator.h
new file mode 100644
index 0000000..6fc4703
--- /dev/null
+++ b/src/modules/video_coding/main/source/jitter_estimator.h
@@ -0,0 +1,155 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_JITTER_ESTIMATOR_H_
+#define WEBRTC_MODULES_VIDEO_CODING_JITTER_ESTIMATOR_H_
+
+#include "typedefs.h"
+#include "rtt_filter.h"
+
+namespace webrtc
+{
+
+class VCMJitterEstimator
+{
+public:
+    VCMJitterEstimator(WebRtc_Word32 vcmId = 0, WebRtc_Word32 receiverId = 0);
+
+    VCMJitterEstimator& operator=(const VCMJitterEstimator& rhs);
+
+    // Resets the estimate to the initial state
+    void Reset();
+    void ResetNackCount();
+
+    // Updates the jitter estimate with the new data.
+    //
+    // Input:
+    //          - frameDelay      : Delay-delta calculated by UTILDelayEstimate in milliseconds
+    //          - frameSize       : Frame size of the current frame.
+    //          - incompleteFrame : Flags if the frame is used to update the estimate before it
+    //                              was complete. Default is false.
+    void UpdateEstimate(WebRtc_Word64 frameDelayMS,
+                        WebRtc_UWord32 frameSizeBytes,
+                        bool incompleteFrame = false);
+
+    // Returns the current jitter estimate in milliseconds and adds
+    // also adds an RTT dependent term in cases of retransmission.
+    //  Input:
+    //          - rttMultiplier  : RTT param multiplier (when applicable).
+    //
+    // Return value                   : Jitter estimate in milliseconds
+    double GetJitterEstimate(double rttMultiplier);
+
+    // Updates the nack counter.
+    void FrameNacked();
+
+    // Updates the RTT filter.
+    //
+    // Input:
+    //          - rttMs               : RTT in ms
+    void UpdateRtt(WebRtc_UWord32 rttMs);
+
+    void UpdateMaxFrameSize(WebRtc_UWord32 frameSizeBytes);
+
+    // A constant describing the delay from the jitter buffer
+    // to the delay on the receiving side which is not accounted
+    // for by the jitter buffer nor the decoding delay estimate.
+    static const WebRtc_UWord32 OPERATING_SYSTEM_JITTER = 10;
+
+protected:
+    // These are protected for better testing possibilities
+    double              _theta[2]; // Estimated line parameters (slope, offset)
+    double              _varNoise; // Variance of the time-deviation from the line
+
+private:
+    // Updates the Kalman filter for the line describing
+    // the frame size dependent jitter.
+    //
+    // Input:
+    //          - frameDelayMS    : Delay-delta calculated by UTILDelayEstimate in milliseconds
+    //          - deltaFSBytes    : Frame size delta, i.e.
+    //                            : frame size at time T minus frame size at time T-1
+    void KalmanEstimateChannel(WebRtc_Word64 frameDelayMS, WebRtc_Word32 deltaFSBytes);
+
+    // Updates the random jitter estimate, i.e. the variance
+    // of the time deviations from the line given by the Kalman filter.
+    //
+    // Input:
+    //          - d_dT              : The deviation from the kalman estimate
+    //          - incompleteFrame   : True if the frame used to update the estimate
+    //                                with was incomplete
+    void EstimateRandomJitter(double d_dT, bool incompleteFrame);
+
+    double NoiseThreshold() const;
+
+    // Calculates the current jitter estimate.
+    //
+    // Return value                 : The current jitter estimate in milliseconds
+    double CalculateEstimate();
+
+    // Post process the calculated estimate
+    void PostProcessEstimate();
+
+    // Calculates the difference in delay between a sample and the
+    // expected delay estimated by the Kalman filter.
+    //
+    // Input:
+    //          - frameDelayMS    : Delay-delta calculated by UTILDelayEstimate in milliseconds
+    //          - deltaFS         : Frame size delta, i.e. frame size at time
+    //                              T minus frame size at time T-1
+    //
+    // Return value                 : The difference in milliseconds
+    double DeviationFromExpectedDelay(WebRtc_Word64 frameDelayMS,
+                                      WebRtc_Word32 deltaFSBytes) const;
+
+    // Constants, filter parameters
+    WebRtc_Word32         _vcmId;
+    WebRtc_Word32         _receiverId;
+    const double          _phi;
+    const double          _psi;
+    const WebRtc_UWord32  _alphaCountMax;
+    const double          _beta;
+    const double          _thetaLow;
+    const WebRtc_UWord32  _nackLimit;
+    const WebRtc_Word32   _numStdDevDelayOutlier;
+    const WebRtc_Word32   _numStdDevFrameSizeOutlier;
+    const double          _noiseStdDevs;
+    const double          _noiseStdDevOffset;
+
+    double                _thetaCov[2][2]; // Estimate covariance
+    double                _Qcov[2][2];     // Process noise covariance
+    double                _avgFrameSize;   // Average frame size
+    double                _varFrameSize;   // Frame size variance
+    double                _maxFrameSize;   // Largest frame size received (descending
+                                           // with a factor _psi)
+    WebRtc_UWord32        _fsSum;
+    WebRtc_UWord32        _fsCount;
+
+    WebRtc_Word64         _lastUpdateT;
+    double                _prevEstimate;         // The previously returned jitter estimate
+    WebRtc_UWord32        _prevFrameSize;        // Frame size of the previous frame
+    double                _avgNoise;             // Average of the random jitter
+    WebRtc_UWord32        _alphaCount;
+    double                _filterJitterEstimate; // The filtered sum of jitter estimates
+
+    WebRtc_UWord32        _startupCount;
+
+    WebRtc_Word64         _latestNackTimestamp;  // Timestamp in ms when the latest nack was seen
+    WebRtc_UWord32        _nackCount;            // Keeps track of the number of nacks received,
+                                                 // but never goes above _nackLimit
+    VCMRttFilter          _rttFilter;
+
+    enum { kStartupDelaySamples = 30 };
+    enum { kFsAccuStartupSamples = 5 };
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_JITTER_ESTIMATOR_H_
diff --git a/src/modules/video_coding/main/source/media_opt_util.cc b/src/modules/video_coding/main/source/media_opt_util.cc
new file mode 100644
index 0000000..a0937b6
--- /dev/null
+++ b/src/modules/video_coding/main/source/media_opt_util.cc
@@ -0,0 +1,943 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "video_coding_defines.h"
+#include "fec_tables_xor.h"
+#include "er_tables_xor.h"
+#include "nack_fec_tables.h"
+#include "qm_select_data.h"
+#include "media_opt_util.h"
+
+#include <math.h>
+#include <float.h>
+#include <limits.h>
+
+namespace webrtc {
+
+bool
+VCMProtectionMethod::BetterThan(VCMProtectionMethod *pm)
+{
+  if (pm == NULL)
+  {
+      return true;
+  }
+  return pm->_score > _score;
+}
+
+bool
+VCMNackFecMethod::ProtectionFactor(const VCMProtectionParameters* /*parameters*/)
+{
+    // use FEC model with modification with RTT for now
+    return true;
+}
+
+bool
+VCMNackFecMethod::EffectivePacketLoss(const
+                                      VCMProtectionParameters* /*parameters*/)
+{
+    // use FEC model with modification with RTT for now
+    return true;
+}
+
+bool
+VCMNackFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+{
+    // Hybrid Nack FEC has three operational modes:
+    // 1. Low RTT - Nack only (Set FEC rates to zero)
+    // 2. High RTT - FEC Only
+    // 3. Medium RTT values - Hybrid ; in hybrid mode, we will only nack the
+    //    residual following the decoding of the FEC (refer to JB logic)
+
+    // Low RTT - NACK only mode
+    if (parameters->rtt < kLowRttNackMs)
+    {
+        // Set the FEC parameters to 0
+        _protectionFactorK = 0;
+        _protectionFactorD = 0;
+
+        // assume packets will be restored via NACK
+        // TODO: relax this assumption?
+        _effectivePacketLoss = 0;
+        _score = _efficiency;
+        return true;
+    }
+    // otherwise: we count on FEC; if the RTT is below a threshold, then we can
+    // nack the residual, based on a decision made in the JB.
+    // TODO(mikhal): adapt the FEC rate based on the RTT, i.e. the the level on
+    // which we will rely on NACK, e.g. less as we approach upper threshold.
+    VCMFecMethod fecMethod;
+
+    const WebRtc_UWord8 plossMax = 129;
+
+    // Compute the protection factor
+    fecMethod.ProtectionFactor(parameters);
+
+    // Compute the effective packet loss
+    fecMethod.EffectivePacketLoss(parameters);
+
+    WebRtc_UWord8 protFactorK = fecMethod._protectionFactorK;
+    WebRtc_UWord8 protFactorD = fecMethod._protectionFactorD;
+    WebRtc_UWord8 effPacketLoss = fecMethod._effectivePacketLoss;
+    float resPacketLoss = fecMethod._residualPacketLoss;
+
+    // Correct FEC rates based on the RTT ( NACK effectiveness)
+    WebRtc_Word16 rttIndex= (WebRtc_UWord16) parameters->rtt;
+    float softnessRtt = 1.0;
+    if (parameters->rtt < kHighRttNackMs)
+    {
+        // TODO(mikhal): update table
+         softnessRtt = (float)VCMNackFecTable[rttIndex] / (float)4096.0;
+
+        // soften ER with NACK on
+        // table depends on RTT relative to rttMax (NACK Threshold)
+        _effectivePacketLoss = (WebRtc_UWord8)(effPacketLoss * softnessRtt);
+
+        // soften FEC with NACK on
+        // table depends on RTT relative to rttMax (NACK Threshold)
+        _protectionFactorK = (WebRtc_UWord8) (protFactorK * softnessRtt);
+        _protectionFactorD = (WebRtc_UWord8) (protFactorD * softnessRtt);
+    }
+    // else - NACK is disabled, rely on FEC only
+
+
+    // make sure I frame protection is at least larger than P frame protection,
+    // and at least as high as received loss
+    WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
+    _protectionFactorK = static_cast<WebRtc_UWord8> (VCM_MAX(packetLoss,
+        VCM_MAX(_scaleProtKey * protFactorD, protFactorK)));
+
+    // check limit on amount of protection for I frame: 50% is max
+    if (_protectionFactorK >= plossMax)
+        _protectionFactorK = plossMax - 1;
+
+    // Bit cost for NackFec
+
+    // NACK cost: based on residual packet loss (since we should only NACK
+    // packets not recovered by FEC)
+    _efficiency = 0.0f;
+    if (parameters->rtt < kHighRttNackMs)
+    {
+        _efficiency = parameters->bitRate * resPacketLoss /
+                                  (1.0f + resPacketLoss);
+    }
+    else
+    {
+        // efficiency based on FEC only
+        // add FEC cost: ignore I frames for now
+        float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
+        if (fecRate >= 0.0f)
+            _efficiency += parameters->bitRate * fecRate;
+    }
+    _score = _efficiency;
+
+    // Protection/fec rates obtained above are defined relative to total number
+    // of packets (total rate: source + fec) FEC in RTP module assumes
+    // protection factor is defined relative to source number of packets so we
+    // should convert the factor to reduce mismatch between mediaOpt's rate and
+    // the actual one
+    WebRtc_UWord8 codeRate = protFactorK;
+    _protectionFactorK = fecMethod.ConvertFECRate(codeRate);
+    codeRate = protFactorD;
+    _protectionFactorD = fecMethod.ConvertFECRate(codeRate);
+
+    return true;
+}
+
+bool
+VCMNackMethod::EffectivePacketLoss(WebRtc_UWord8 effPacketLoss,
+                                   WebRtc_UWord16 rttTime)
+{
+    WebRtc_UWord16 rttMax = MaxRttNack();
+
+    // For large RTT, we should rely on some Error Resilience, so we set
+    // packetLossEnc = 0 for RTT less than the NACK threshold
+    if (rttTime < rttMax)
+    {
+        effPacketLoss = 0; //may want a softer transition here
+    }
+    _effectivePacketLoss = effPacketLoss;
+
+    return true;
+}
+
+bool
+VCMNackMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+{
+    // Compute the effective packet loss for ER
+    WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
+    WebRtc_UWord16 rttTime = (WebRtc_UWord16) parameters->rtt;
+    EffectivePacketLoss(effPacketLoss, rttTime);
+
+    // Compute the NACK bit cost
+    _efficiency = parameters->bitRate * parameters->lossPr /
+                              (1.0f + parameters->lossPr);
+    _score = _efficiency;
+    if (parameters->rtt > _NACK_MAX_RTT)
+    {
+        _score = 0.0f;
+        return false;
+    }
+    return true;
+}
+
+WebRtc_UWord8
+VCMFecMethod::BoostCodeRateKey(WebRtc_UWord8 packetFrameDelta,
+                               WebRtc_UWord8 packetFrameKey) const
+{
+    WebRtc_UWord8 boostRateKey = 2;
+    // default: ratio scales the FEC protection up for I frames
+    WebRtc_UWord8 ratio = 1;
+
+    if (packetFrameDelta > 0)
+    {
+        ratio = (WebRtc_Word8) (packetFrameKey / packetFrameDelta);
+    }
+    ratio = VCM_MAX(boostRateKey, ratio);
+
+    return ratio;
+}
+
+WebRtc_UWord8
+VCMFecMethod::ConvertFECRate(WebRtc_UWord8 codeRateRTP) const
+{
+    return static_cast<WebRtc_UWord8> (VCM_MIN(255,(0.5 + 255.0 * codeRateRTP /
+                                      (float)(255 - codeRateRTP))));
+}
+
+// AvgRecoveryFEC: average recovery from FEC, assuming random packet loss model
+// Computed offline for a range of FEC code parameters and loss rates
+float
+VCMFecMethod::AvgRecoveryFEC(const VCMProtectionParameters* parameters) const
+{
+    // Total (avg) bits available per frame: total rate over actual/sent frame
+    // rate units are kbits/frame
+    const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16>
+                        (parameters->bitRate / (parameters->frameRate));
+
+    // Total (avg) number of packets per frame (source and fec):
+    const WebRtc_UWord8 avgTotPackets = 1 +
+                        (WebRtc_UWord8) ((float) bitRatePerFrame * 1000.0
+                        / (float) (8.0 * _maxPayloadSize) + 0.5);
+
+    // parameters for tables
+    const WebRtc_UWord8 codeSize = 24;
+    const WebRtc_UWord8 plossMax = 129;
+    const WebRtc_UWord16 maxErTableSize = 38700;
+
+    // Get index for table
+    const float protectionFactor = (float) _protectionFactorD / (float) 255;
+    WebRtc_UWord8 fecPacketsPerFrame = (WebRtc_UWord8) (0.5 + protectionFactor
+                                                        * avgTotPackets);
+    WebRtc_UWord8 sourcePacketsPerFrame = avgTotPackets - fecPacketsPerFrame;
+
+    if (fecPacketsPerFrame == 0)
+    {
+        return 0.0; // no protection, so avg. recov from FEC == 0
+    }
+
+    // table defined up to codeSizexcodeSize code
+    if (sourcePacketsPerFrame > codeSize)
+    {
+        sourcePacketsPerFrame = codeSize;
+    }
+
+    // check: protection factor is maxed at 50%, so this should never happen
+    if (sourcePacketsPerFrame < 1)
+    {
+        assert("average number of source packets below 1\n");
+    }
+
+    // index for ER tables: up to codeSizexcodeSize mask
+    WebRtc_UWord16 codeIndexTable[codeSize * codeSize];
+    WebRtc_UWord16 k = -1;
+    for (WebRtc_UWord8 i = 1; i <= codeSize; i++)
+    {
+        for (WebRtc_UWord8 j = 1; j <= i; j++)
+        {
+            k += 1;
+            codeIndexTable[(j - 1) * codeSize + i - 1] = k;
+        }
+    }
+
+    const WebRtc_UWord8 lossRate = (WebRtc_UWord8) (255.0 *
+                                    parameters->lossPr + 0.5f);
+
+    const WebRtc_UWord16 codeIndex = (fecPacketsPerFrame - 1) * codeSize
+                                      + (sourcePacketsPerFrame - 1);
+    const WebRtc_UWord16 indexTable = codeIndexTable[codeIndex] * plossMax
+                                      + lossRate;
+
+    const WebRtc_UWord16 codeIndex2 = (fecPacketsPerFrame) * codeSize
+                                      + (sourcePacketsPerFrame);
+    WebRtc_UWord16 indexTable2 = codeIndexTable[codeIndex2] * plossMax
+                                 + lossRate;
+
+    // checks on table index
+    if (indexTable >= maxErTableSize)
+    {
+        assert("ER table index too large\n");
+    }
+
+    if (indexTable2 >= maxErTableSize)
+    {
+        indexTable2 = indexTable;
+    }
+
+    // Get the average effective packet loss recovery from FEC
+    // this is from tables, computed using random loss model
+    WebRtc_UWord8 avgFecRecov1 = 0;
+    WebRtc_UWord8 avgFecRecov2 = 0;
+    float avgFecRecov = 0;
+
+    if (fecPacketsPerFrame > 0)
+    {
+        avgFecRecov1 = VCMAvgFECRecoveryXOR[indexTable];
+        avgFecRecov2 = VCMAvgFECRecoveryXOR[indexTable2];
+    }
+
+    // interpolate over two FEC codes
+    const float weightRpl = (float) (0.5 + protectionFactor * avgTotPackets)
+        - (float) fecPacketsPerFrame;
+    avgFecRecov = (float) weightRpl * (float) avgFecRecov2 + (float)
+                  (1.0 - weightRpl) * (float) avgFecRecov1;
+
+    return avgFecRecov;
+}
+
+bool
+VCMFecMethod::ProtectionFactor(const VCMProtectionParameters* parameters)
+{
+    // FEC PROTECTION SETTINGS: varies with packet loss and bitrate
+
+    WebRtc_UWord8 packetLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
+
+    // No protection if (filtered) packetLoss is 0
+    if (packetLoss == 0)
+    {
+        _protectionFactorK = 0;
+        _protectionFactorD = 0;
+         return true;
+    }
+
+    // Size of tables
+    const WebRtc_UWord16 maxFecTableSize = 6450;
+    // Parameters for range of rate and packet loss for tables
+    const WebRtc_UWord8 ratePar1 = 5;
+    const WebRtc_UWord8 ratePar2 = 49;
+    const WebRtc_UWord8 plossMax = 129;
+
+    const float bitRate = parameters->bitRate;
+
+    // Total (avg) bits available per frame: total rate over actual/frame_rate.
+    // Units are kbits/frame
+    const WebRtc_UWord16 bitRatePerFrame = static_cast<WebRtc_UWord16>
+                                                     (bitRate /
+                                                     (parameters->frameRate));
+
+    // TODO (marpan): Incorporate frame size (bpp) into FEC setting
+
+    // Total (avg) number of packets per frame (source and fec):
+    const WebRtc_UWord8 avgTotPackets = 1 + (WebRtc_UWord8)
+                                        ((float) bitRatePerFrame * 1000.0
+                                       / (float) (8.0 * _maxPayloadSize) + 0.5);
+
+
+    // First partition protection: ~ 20%
+    WebRtc_UWord8 firstPartitionProt = (WebRtc_UWord8) (255 * 0.20);
+
+    // Threshold on packetLoss and bitRrate/frameRate (=average #packets),
+    // above which we allocate protection to cover at least roughly
+    // first partition size.
+    WebRtc_UWord8 lossThr = 0;
+    WebRtc_UWord8 packetNumThr = 1;
+
+    // Modulation of protection with available bits/frame (or avgTotpackets)
+    float weight1 = 0.5;
+    float weight2 = 0.5;
+    if (avgTotPackets > 4)
+    {
+        weight1 = 0.75;
+        weight2 = 0.25;
+    }
+    if (avgTotPackets > 6)
+    {
+        weight1 = 1.5;
+        weight2 = 0.;
+    }
+
+    // FEC rate parameters: for P and I frame
+    WebRtc_UWord8 codeRateDelta = 0;
+    WebRtc_UWord8 codeRateKey = 0;
+
+    // Get index for table: the FEC protection depends on the (average)
+    // available bits/frame. The range on the rate index corresponds to rates
+    // (bps) from 200k to 8000k, for 30fps
+    WebRtc_UWord8 rateIndexTable =
+        (WebRtc_UWord8) VCM_MAX(VCM_MIN((bitRatePerFrame - ratePar1) /
+                                        ratePar1, ratePar2), 0);
+
+    // Restrict packet loss range to 50:
+    // current tables defined only up to 50%
+    if (packetLoss >= plossMax)
+    {
+        packetLoss = plossMax - 1;
+    }
+    WebRtc_UWord16 indexTable = rateIndexTable * plossMax + packetLoss;
+
+    // Check on table index
+    assert(indexTable < maxFecTableSize);
+
+    // Protection factor for P frame
+    codeRateDelta = VCMCodeRateXORTable[indexTable];
+
+    if (packetLoss > lossThr && avgTotPackets > packetNumThr)
+    {
+        // Average with minimum protection level given by (average) total
+        // number of packets
+        codeRateDelta = static_cast<WebRtc_UWord8>((weight1 *
+            (float) codeRateDelta + weight2 * 255.0 / (float) avgTotPackets));
+
+        // Set a minimum based on first partition size.
+        if (codeRateDelta < firstPartitionProt)
+        {
+            codeRateDelta = firstPartitionProt;
+        }
+    }
+
+    // Check limit on amount of protection for P frame; 50% is max.
+    if (codeRateDelta >= plossMax)
+    {
+        codeRateDelta = plossMax - 1;
+    }
+
+    // For Key frame:
+    // Effectively at a higher rate, so we scale/boost the rate
+    // The boost factor may depend on several factors: ratio of packet
+    // number of I to P frames, how much protection placed on P frames, etc.
+    const WebRtc_UWord8 packetFrameDelta = (WebRtc_UWord8)
+                                           (0.5 + parameters->packetsPerFrame);
+    const WebRtc_UWord8 packetFrameKey = (WebRtc_UWord8)
+                                         (0.5 + parameters->packetsPerFrameKey);
+    const WebRtc_UWord8 boostKey = BoostCodeRateKey(packetFrameDelta,
+                                                    packetFrameKey);
+
+    rateIndexTable = (WebRtc_UWord8) VCM_MAX(VCM_MIN(
+                      1 + (boostKey * bitRatePerFrame - ratePar1) /
+                      ratePar1,ratePar2),0);
+    WebRtc_UWord16 indexTableKey = rateIndexTable * plossMax + packetLoss;
+
+    indexTableKey = VCM_MIN(indexTableKey, maxFecTableSize);
+
+    // Check on table index
+    assert(indexTableKey < maxFecTableSize);
+
+    // Protection factor for I frame
+    codeRateKey = VCMCodeRateXORTable[indexTableKey];
+
+    // Boosting for Key frame.
+    WebRtc_UWord32 boostKeyProt = _scaleProtKey * codeRateDelta;
+    if ( boostKeyProt >= plossMax)
+    {
+        boostKeyProt = plossMax - 1;
+    }
+
+    // Make sure I frame protection is at least larger than P frame protection,
+    // and at least as high as filtered packet loss.
+    codeRateKey = static_cast<WebRtc_UWord8> (VCM_MAX(packetLoss,
+            VCM_MAX(boostKeyProt, codeRateKey)));
+
+    // Check limit on amount of protection for I frame: 50% is max.
+    if (codeRateKey >= plossMax)
+    {
+        codeRateKey = plossMax - 1;
+    }
+
+    _protectionFactorK = codeRateKey;
+    _protectionFactorD = codeRateDelta;
+
+    // DONE WITH FEC PROTECTION SETTINGS
+    return true;
+}
+
+bool
+VCMFecMethod::EffectivePacketLoss(const VCMProtectionParameters* parameters)
+{
+    // ER SETTINGS:
+    // Effective packet loss to encoder is based on RPL (residual packet loss)
+    // this is a soft setting based on degree of FEC protection
+    // RPL = received/input packet loss - average_FEC_recovery
+    // note: received/input packet loss may be filtered based on FilteredLoss
+
+    // The input packet loss:
+    WebRtc_UWord8 effPacketLoss = (WebRtc_UWord8) (255 * parameters->lossPr);
+
+    float scaleErRS = 0.5;
+    float scaleErXOR = 0.5;
+    float minErLevel = (float) 0.025;
+    // float scaleErRS = 1.0;
+    // float scaleErXOR = 1.0;
+    // float minErLevel = (float) 0.0;
+
+    float avgFecRecov = 0.;
+    // Effective packet loss for ER:
+    float scaleEr = scaleErXOR;
+    avgFecRecov = AvgRecoveryFEC(parameters);
+
+    // Residual Packet Loss:
+    _residualPacketLoss = (float) (effPacketLoss - avgFecRecov) / (float) 255.0;
+
+    //Effective Packet Loss for encoder:
+    _effectivePacketLoss = 0;
+    if (effPacketLoss > 0) {
+      _effectivePacketLoss = VCM_MAX((effPacketLoss -
+              (WebRtc_UWord8)(scaleEr * avgFecRecov)),
+          static_cast<WebRtc_UWord8>(minErLevel * 255));
+    }
+
+    // DONE WITH ER SETTING
+    return true;
+}
+
+bool
+VCMFecMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+{
+    // Compute the protection factor
+    ProtectionFactor(parameters);
+
+    // Compute the effective packet loss
+    EffectivePacketLoss(parameters);
+
+    // Compute the bit cost
+    // Ignore key frames for now.
+    float fecRate = static_cast<float> (_protectionFactorD) / 255.0f;
+    if (fecRate >= 0.0f)
+    {
+        // use this formula if the fecRate (protection factor) is defined
+        // relative to number of source packets
+        // this is the case for the previous tables:
+        // _efficiency = parameters->bitRate * ( 1.0 - 1.0 / (1.0 + fecRate));
+
+        // in the new tables, the fecRate is defined relative to total number of
+        // packets (total rate), so overhead cost is:
+        _efficiency = parameters->bitRate * fecRate;
+    }
+    else
+    {
+        _efficiency = 0.0f;
+    }
+    _score = _efficiency;
+
+    // Protection/fec rates obtained above is defined relative to total number
+    // of packets (total rate: source+fec) FEC in RTP module assumes protection
+    // factor is defined relative to source number of packets so we should
+    // convert the factor to reduce mismatch between mediaOpt suggested rate and
+    // the actual rate
+    _protectionFactorK = ConvertFECRate(_protectionFactorK);
+    _protectionFactorD = ConvertFECRate(_protectionFactorD);
+
+    return true;
+}
+
+bool
+VCMIntraReqMethod::UpdateParameters(const VCMProtectionParameters* parameters)
+{
+    float packetRate = parameters->packetsPerFrame * parameters->frameRate;
+    // Assume that all lost packets cohere to different frames
+    float lossRate = parameters->lossPr * packetRate;
+    if (parameters->keyFrameSize <= 1e-3)
+    {
+        _score = FLT_MAX;
+        return false;
+    }
+    _efficiency = lossRate * parameters->keyFrameSize;
+    _score = _efficiency;
+    if (parameters->lossPr >= 1.0f / parameters->keyFrameSize ||
+        parameters->rtt > _IREQ_MAX_RTT)
+    {
+        return false;
+    }
+    return true;
+}
+
+bool
+VCMPeriodicIntraMethod::UpdateParameters(const
+                                        VCMProtectionParameters* /*parameters*/)
+{
+    // Periodic I-frames. The last thing we want to use.
+    _efficiency = 0.0f;
+    _score = FLT_MAX;
+    return true;
+}
+
+bool
+VCMMbIntraRefreshMethod::UpdateParameters(const
+                                          VCMProtectionParameters* parameters)
+{
+    // Assume optimal for now.
+    _efficiency = parameters->bitRate * parameters->lossPr /
+                  (1.0f + parameters->lossPr);
+    _score = _efficiency;
+    if (parameters->bitRate < _MBREF_MIN_BITRATE)
+    {
+        return false;
+    }
+    return true;
+}
+
+WebRtc_UWord16
+VCMNackMethod::MaxRttNack() const
+{
+    return _NACK_MAX_RTT;
+}
+
+VCMLossProtectionLogic::~VCMLossProtectionLogic()
+{
+    ClearLossProtections();
+}
+
+void
+VCMLossProtectionLogic::ClearLossProtections()
+{
+    ListItem *item;
+    while ((item = _availableMethods.First()) != 0) {
+      VCMProtectionMethod *method = static_cast<VCMProtectionMethod*>
+                                    (item->GetItem());
+      if (method != NULL)
+      {
+          delete method;
+      }
+      _availableMethods.PopFront();
+    }
+    _selectedMethod = NULL;
+}
+
+bool
+VCMLossProtectionLogic::AddMethod(VCMProtectionMethod *newMethod)
+{
+    VCMProtectionMethod *method;
+    ListItem *item;
+    if (newMethod == NULL)
+    {
+        return false;
+    }
+    for (item = _availableMethods.First(); item != NULL;
+        item = _availableMethods.Next(item))
+    {
+        method = static_cast<VCMProtectionMethod *> (item->GetItem());
+        if (method != NULL && method->Type() == newMethod->Type())
+        {
+            return false;
+        }
+    }
+    _availableMethods.PushBack(newMethod);
+    return true;
+}
+bool
+VCMLossProtectionLogic::RemoveMethod(VCMProtectionMethodEnum methodType)
+{
+    VCMProtectionMethod *method;
+    ListItem *item;
+    bool foundAndRemoved = false;
+    for (item = _availableMethods.First(); item != NULL;
+         item = _availableMethods.Next(item))
+    {
+        method = static_cast<VCMProtectionMethod *> (item->GetItem());
+        if (method != NULL && method->Type() == methodType)
+        {
+            if (_selectedMethod != NULL &&
+                _selectedMethod->Type() == method->Type())
+            {
+                _selectedMethod = NULL;
+            }
+            _availableMethods.Erase(item);
+            item = NULL;
+            delete method;
+            foundAndRemoved = true;
+        }
+    }
+    return foundAndRemoved;
+}
+
+VCMProtectionMethod*
+VCMLossProtectionLogic::FindMethod(VCMProtectionMethodEnum methodType) const
+{
+    VCMProtectionMethod *method;
+    ListItem *item;
+    for (item = _availableMethods.First(); item != NULL;
+         item = _availableMethods.Next(item))
+    {
+        method = static_cast<VCMProtectionMethod *> (item->GetItem());
+        if (method != NULL && method->Type() == methodType)
+        {
+            return method;
+        }
+    }
+    return NULL;
+}
+
+float
+VCMLossProtectionLogic::HighestOverhead() const
+{
+    VCMProtectionMethod *method;
+    ListItem *item;
+    float highestOverhead = 0.0f;
+    for (item = _availableMethods.First(); item != NULL;
+         item = _availableMethods.Next(item))
+    {
+        method = static_cast<VCMProtectionMethod *> (item->GetItem());
+        if (method != NULL && method->RequiredBitRate() > highestOverhead)
+        {
+            highestOverhead = method->RequiredBitRate();
+        }
+    }
+    return highestOverhead;
+}
+
+void
+VCMLossProtectionLogic::UpdateRtt(WebRtc_UWord32 rtt)
+{
+    _rtt = rtt;
+}
+
+void
+VCMLossProtectionLogic::UpdateResidualPacketLoss(float residualPacketLoss)
+{
+    _residualPacketLoss = residualPacketLoss;
+}
+
+void
+VCMLossProtectionLogic::UpdateFecType(VCMFecTypes fecType)
+{
+    _fecType = fecType;
+}
+
+void
+VCMLossProtectionLogic::UpdateLossPr(WebRtc_UWord8 lossPr255)
+{
+    const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
+    UpdateMaxLossHistory(lossPr255, now);
+    _lossPr255.Apply(static_cast<float> (now - _lastPrUpdateT),
+                     static_cast<float> (lossPr255));
+    _lastPrUpdateT = now;
+    _lossPr = _lossPr255.Value() / 255.0f;
+}
+
+void
+VCMLossProtectionLogic::UpdateMaxLossHistory(WebRtc_UWord8 lossPr255,
+                                             WebRtc_Word64 now)
+{
+    if (_lossPrHistory[0].timeMs >= 0 &&
+        now - _lossPrHistory[0].timeMs < kLossPrShortFilterWinMs)
+    {
+        if (lossPr255 > _shortMaxLossPr255)
+        {
+            _shortMaxLossPr255 = lossPr255;
+        }
+    }
+    else
+    {
+        // Only add a new value to the history once a second
+        if (_lossPrHistory[0].timeMs == -1)
+        {
+            // First, no shift
+            _shortMaxLossPr255 = lossPr255;
+        }
+        else
+        {
+            // Shift
+            for (WebRtc_Word32 i = (kLossPrHistorySize - 2); i >= 0; i--)
+            {
+                _lossPrHistory[i + 1].lossPr255 = _lossPrHistory[i].lossPr255;
+                _lossPrHistory[i + 1].timeMs = _lossPrHistory[i].timeMs;
+            }
+        }
+        if (_shortMaxLossPr255 == 0)
+        {
+            _shortMaxLossPr255 = lossPr255;
+        }
+
+        _lossPrHistory[0].lossPr255 = _shortMaxLossPr255;
+        _lossPrHistory[0].timeMs = now;
+        _shortMaxLossPr255 = 0;
+    }
+}
+
+WebRtc_UWord8
+VCMLossProtectionLogic::MaxFilteredLossPr(WebRtc_Word64 nowMs) const
+{
+    WebRtc_UWord8 maxFound = _shortMaxLossPr255;
+    if (_lossPrHistory[0].timeMs == -1)
+    {
+        return maxFound;
+    }
+    for (WebRtc_Word32 i = 0; i < kLossPrHistorySize; i++)
+    {
+        if (_lossPrHistory[i].timeMs == -1)
+        {
+            break;
+        }
+        if (nowMs - _lossPrHistory[i].timeMs >
+            kLossPrHistorySize * kLossPrShortFilterWinMs)
+        {
+            // This sample (and all samples after this) is too old
+            break;
+        }
+        if (_lossPrHistory[i].lossPr255 > maxFound)
+        {
+            // This sample is the largest one this far into the history
+            maxFound = _lossPrHistory[i].lossPr255;
+        }
+    }
+    return maxFound;
+}
+
+WebRtc_UWord8
+VCMLossProtectionLogic::FilteredLoss() const
+{
+    //take the average received loss
+    //return static_cast<WebRtc_UWord8>(_lossPr255.Value() + 0.5f);
+
+    //TODO: Update for hybrid
+    //take the windowed max of the received loss
+    if (_selectedMethod != NULL && _selectedMethod->Type() == kFEC)
+    {
+        return MaxFilteredLossPr(VCMTickTime::MillisecondTimestamp());
+    }
+    else
+    {
+        return static_cast<WebRtc_UWord8> (_lossPr255.Value() + 0.5);
+    }
+}
+
+void
+VCMLossProtectionLogic::UpdateFilteredLossPr(WebRtc_UWord8 packetLossEnc)
+{
+    _lossPr = (float) packetLossEnc / (float) 255.0;
+}
+
+void
+VCMLossProtectionLogic::UpdateBitRate(float bitRate)
+{
+    _bitRate = bitRate;
+}
+
+void
+VCMLossProtectionLogic::UpdatePacketsPerFrame(float nPackets)
+{
+    const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
+    _packetsPerFrame.Apply(static_cast<float>(now - _lastPacketPerFrameUpdateT),
+                           nPackets);
+    _lastPacketPerFrameUpdateT = now;
+}
+
+void
+VCMLossProtectionLogic::UpdatePacketsPerFrameKey(float nPackets)
+{
+    const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
+    _packetsPerFrameKey.Apply(static_cast<float>(now -
+                              _lastPacketPerFrameUpdateTKey), nPackets);
+    _lastPacketPerFrameUpdateTKey = now;
+}
+
+void
+VCMLossProtectionLogic::UpdateKeyFrameSize(float keyFrameSize)
+{
+    _keyFrameSize = keyFrameSize;
+}
+
+void
+VCMLossProtectionLogic::UpdateFrameSize(WebRtc_UWord16 width,
+                                        WebRtc_UWord16 height)
+{
+    _codecWidth = width;
+    _codecHeight = height;
+}
+
+bool
+VCMLossProtectionLogic::UpdateMethod(VCMProtectionMethod *newMethod /*=NULL */)
+{
+    _currentParameters.rtt = _rtt;
+    _currentParameters.lossPr = _lossPr;
+    _currentParameters.bitRate = _bitRate;
+    _currentParameters.frameRate = _frameRate; // rename actual frame rate?
+    _currentParameters.keyFrameSize = _keyFrameSize;
+    _currentParameters.fecRateDelta = _fecRateDelta;
+    _currentParameters.fecRateKey = _fecRateKey;
+    _currentParameters.packetsPerFrame = _packetsPerFrame.Value();
+    _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.Value();
+    _currentParameters.residualPacketLoss = _residualPacketLoss;
+    _currentParameters.fecType = _fecType;
+    _currentParameters.codecWidth = _codecWidth;
+    _currentParameters.codecHeight = _codecHeight;
+
+    if (newMethod == NULL)
+    {
+        //_selectedMethod = _bestNotOkMethod = NULL;
+        VCMProtectionMethod *method;
+        ListItem *item;
+        for (item = _availableMethods.First(); item != NULL;
+             item = _availableMethods.Next(item))
+        {
+            method = static_cast<VCMProtectionMethod *> (item->GetItem());
+            if (method != NULL)
+            {
+                if (method->Type() == kFEC)
+                {
+                      _selectedMethod = method;
+                }
+                if (method->Type() == kNACK)
+                {
+                    _selectedMethod = method;
+                }
+                if (method->Type() == kNackFec)
+                {
+                    _selectedMethod = method;
+                }
+                method->UpdateParameters(&_currentParameters);
+            }
+        }
+        if (_selectedMethod != NULL && _selectedMethod->Type() != kFEC)
+        {
+            _selectedMethod = method;
+        }
+     }
+     else
+     {
+         _selectedMethod = newMethod;
+         _selectedMethod->UpdateParameters(&_currentParameters);
+     }
+    return true;
+}
+
+VCMProtectionMethod*
+VCMLossProtectionLogic::SelectedMethod() const
+{
+    return _selectedMethod;
+}
+
+void VCMLossProtectionLogic::Reset()
+{
+    const WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
+    _lastPrUpdateT = now;
+    _lastPacketPerFrameUpdateT = now;
+    _lastPacketPerFrameUpdateTKey = now;
+    _lossPr255.Reset(0.9999f);
+    _packetsPerFrame.Reset(0.9999f);
+    _fecRateDelta = _fecRateKey = 0;
+    for (WebRtc_Word32 i = 0; i < kLossPrHistorySize; i++)
+    {
+        _lossPrHistory[i].lossPr255 = 0;
+        _lossPrHistory[i].timeMs = -1;
+    }
+    _shortMaxLossPr255 = 0;
+    ClearLossProtections();
+}
+
+}
diff --git a/src/modules/video_coding/main/source/media_opt_util.h b/src/modules/video_coding/main/source/media_opt_util.h
new file mode 100644
index 0000000..8298406
--- /dev/null
+++ b/src/modules/video_coding/main/source/media_opt_util.h
@@ -0,0 +1,392 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_MEDIA_OPT_UTIL_H_
+#define WEBRTC_MODULES_VIDEO_CODING_MEDIA_OPT_UTIL_H_
+
+#include "typedefs.h"
+#include "list_wrapper.h"
+#include "trace.h"
+#include "exp_filter.h"
+#include "internal_defines.h"
+#include "tick_time.h"
+
+#include <cmath>
+#include <cstdlib>
+
+
+namespace webrtc
+{
+class ListWrapper;
+
+enum { kLossPrHistorySize = 30 }; // 30 time periods
+enum { kLossPrShortFilterWinMs = 1000 }; // 1000 ms, total filter length is 30 000 ms
+
+enum VCMFecTypes
+{
+    kXORFec
+};
+
+// Thresholds for hybrid NACK/FEC
+// common to media optimization and the jitter buffer.
+enum HybridNackTH {
+    kHighRttNackMs = 100,
+    kLowRttNackMs = 20
+};
+
+struct VCMProtectionParameters
+{
+    VCMProtectionParameters() : rtt(0), lossPr(0), bitRate(0), packetsPerFrame(0),
+        frameRate(0), keyFrameSize(0), fecRateDelta(0), fecRateKey(0),
+        residualPacketLoss(0.0), fecType(kXORFec), codecWidth(0),
+        codecHeight(0) {}
+
+    WebRtc_UWord32      rtt;
+    float               lossPr;
+    float               bitRate;
+    float               packetsPerFrame;
+    float               packetsPerFrameKey;
+    float               frameRate;
+    float               keyFrameSize;
+    WebRtc_UWord8       fecRateDelta;
+    WebRtc_UWord8       fecRateKey;
+    float               residualPacketLoss;
+    VCMFecTypes         fecType;
+    WebRtc_UWord16      codecWidth;
+    WebRtc_UWord16      codecHeight;
+
+};
+
+
+/******************************/
+/* VCMProtectionMethod class    */
+/****************************/
+
+enum VCMProtectionMethodEnum
+{
+    kNACK,
+    kFEC,
+    kNackFec,
+    kIntraRequest, // I-frame request
+    kPeriodicIntra, // I-frame refresh
+    kMBIntraRefresh, // Macro block refresh
+    kNone
+};
+
+class VCMLossProbabilitySample
+{
+public:
+    VCMLossProbabilitySample() : lossPr255(0), timeMs(-1) {};
+
+    WebRtc_UWord8     lossPr255;
+    WebRtc_Word64     timeMs;
+};
+
+
+
+class VCMProtectionMethod
+{
+public:
+    //friend VCMProtectionMethod;
+    VCMProtectionMethod(VCMProtectionMethodEnum type) : _protectionFactorK(0),
+        _protectionFactorD(0), _residualPacketLoss(0.0), _scaleProtKey(2.0),
+        _maxPayloadSize(1460), _efficiency(0), _score(0), _type(type) {}
+    virtual ~VCMProtectionMethod() {}
+
+    // Updates the efficiency of the method using the parameters provided
+    //
+    // Input:
+    //         - parameters         : Parameters used to calculate the efficiency
+    //
+    // Return value                 : True if this method is recommended in
+    //                                the given conditions.
+    virtual bool UpdateParameters(const VCMProtectionParameters* parameters) = 0;
+
+    // Returns the protection type
+    //
+    // Return value                 : The protection type
+    enum VCMProtectionMethodEnum Type() const { return _type; }
+
+    // Evaluates if this protection method is considered
+    // better than the provided method.
+    //
+    // Input:
+    //          - pm                : The protection method to compare with
+    bool BetterThan(VCMProtectionMethod *pm);
+
+    // Returns the bit rate required by this protection method
+    // during these conditions.
+    //
+    // Return value                 : Required bit rate
+    virtual float RequiredBitRate() { return _efficiency; }
+
+    // Returns the effective packet loss for ER, required by this protection method
+    //
+    // Return value                 : Required effective packet loss
+    virtual WebRtc_UWord8 RequiredPacketLossER() { return _effectivePacketLoss; }
+
+    // Extracts the FEC protection factor for Key frame, required by this protection method
+    //
+    // Return value                 : Required protectionFactor for Key frame
+    virtual WebRtc_UWord8 RequiredProtectionFactorK() { return _protectionFactorK; }
+
+    // Extracts the FEC protection factor for Delta frame, required by this protection method
+    //
+    // Return value                 : Required protectionFactor for delta frame
+    virtual WebRtc_UWord8 RequiredProtectionFactorD() { return _protectionFactorD; }
+
+    WebRtc_UWord8                        _effectivePacketLoss;
+    WebRtc_UWord8                        _protectionFactorK;
+    WebRtc_UWord8                        _protectionFactorD;
+    float                                _residualPacketLoss;
+    float                                _scaleProtKey;
+    WebRtc_Word32                        _maxPayloadSize;
+
+protected:
+    float                                _efficiency;
+    float                                _score;
+
+private:
+    const enum VCMProtectionMethodEnum   _type;
+
+};
+
+class VCMNackMethod : public VCMProtectionMethod
+{
+public:
+    VCMNackMethod() : VCMProtectionMethod(kNACK), _NACK_MAX_RTT(200) {}
+    virtual ~VCMNackMethod() {}
+    virtual bool UpdateParameters(const VCMProtectionParameters* parameters);
+    //get the effective packet loss for ER
+    bool EffectivePacketLoss(WebRtc_UWord8 effPacketLoss, WebRtc_UWord16 rttTime);
+    //get the threshold for NACK
+    WebRtc_UWord16 MaxRttNack() const;
+private:
+    const WebRtc_UWord16 _NACK_MAX_RTT;
+};
+
+class VCMFecMethod : public VCMProtectionMethod
+{
+public:
+    VCMFecMethod() : VCMProtectionMethod(kFEC) {}
+    virtual ~VCMFecMethod() {}
+    virtual bool UpdateParameters(const VCMProtectionParameters* parameters);
+    //get the effective packet loss for ER
+    bool EffectivePacketLoss(const VCMProtectionParameters* parameters);
+    //get the FEC protection factors
+    bool ProtectionFactor(const VCMProtectionParameters* parameters);
+    //get the boost for key frame protection
+    WebRtc_UWord8 BoostCodeRateKey(WebRtc_UWord8 packetFrameDelta,
+                                   WebRtc_UWord8 packetFrameKey) const;
+    //convert the rates: defined relative to total# packets or source# packets
+    WebRtc_UWord8 ConvertFECRate(WebRtc_UWord8 codeRate) const;
+    //get the average effective recovery from FEC: for random loss model
+    float AvgRecoveryFEC(const VCMProtectionParameters* parameters) const;
+};
+
+
+class VCMNackFecMethod : public VCMProtectionMethod
+{
+public:
+    VCMNackFecMethod() : VCMProtectionMethod(kNackFec) {}
+    virtual bool UpdateParameters(const VCMProtectionParameters* parameters);
+    //get the effective packet loss for ER
+    bool EffectivePacketLoss(const VCMProtectionParameters* parameters);
+    //get the FEC protection factors
+    bool ProtectionFactor(const VCMProtectionParameters* parameters);
+
+};
+
+
+class VCMIntraReqMethod : public VCMProtectionMethod
+{
+public:
+    VCMIntraReqMethod() : VCMProtectionMethod(kIntraRequest), _IREQ_MAX_RTT(150) {}
+    virtual bool UpdateParameters(const VCMProtectionParameters* parameters);
+private:
+    const WebRtc_UWord32 _IREQ_MAX_RTT;
+};
+
+class VCMPeriodicIntraMethod : public VCMProtectionMethod
+{
+public:
+    VCMPeriodicIntraMethod() : VCMProtectionMethod(kPeriodicIntra) {}
+    virtual bool UpdateParameters(const VCMProtectionParameters* parameters);
+};
+
+class VCMMbIntraRefreshMethod : public VCMProtectionMethod
+{
+public:
+    VCMMbIntraRefreshMethod() :
+        VCMProtectionMethod(kMBIntraRefresh), _MBREF_MIN_BITRATE(150) {}
+    virtual bool UpdateParameters(const VCMProtectionParameters* parameters);
+    virtual float RequiredBitRate() { return 0.0; }
+private:
+    const WebRtc_UWord32 _MBREF_MIN_BITRATE;
+};
+
+class VCMLossProtectionLogic
+{
+public:
+    VCMLossProtectionLogic() : _availableMethods(), _selectedMethod(NULL),
+        _bestNotOkMethod(NULL), _rtt(0), _lossPr(0.0f), _bitRate(0.0f), _frameRate(0.0f),
+        _keyFrameSize(0.0f), _fecRateKey(0), _fecRateDelta(0), _lastPrUpdateT(0),
+        _lossPr255(0.9999f), _lossPrHistory(), _shortMaxLossPr255(0),
+        _packetsPerFrame(0.9999f), _packetsPerFrameKey(0.9999f), _residualPacketLoss(0),
+        _boostRateKey(2), _codecWidth(0), _codecHeight(0)
+    { Reset(); }
+
+    ~VCMLossProtectionLogic();
+
+    void ClearLossProtections();
+    bool AddMethod(VCMProtectionMethod *newMethod);
+    bool RemoveMethod(VCMProtectionMethodEnum methodType);
+    VCMProtectionMethod* FindMethod(VCMProtectionMethodEnum methodType) const;
+    float HighestOverhead() const;
+
+    // Update the round-trip time
+    //
+    // Input:
+    //          - rtt           : Round-trip time in seconds.
+    void UpdateRtt(WebRtc_UWord32 rtt);
+
+    // Update residual packet loss
+    //
+    // Input:
+    //          - residualPacketLoss  : residual packet loss: effective loss after FEC recovery
+    void UpdateResidualPacketLoss(float residualPacketLoss);
+
+    // Update fecType
+    //
+    // Input:
+    //          - fecType           : kXORFec for generic XOR FEC
+    void UpdateFecType(VCMFecTypes fecType);
+
+    // Update the loss probability.
+    //
+    // Input:
+    //          - lossPr255        : The packet loss probability in the interval [0, 255],
+    //                               reported by RTCP.
+    void UpdateLossPr(WebRtc_UWord8 lossPr255);
+
+    // Update the filtered packet loss.
+    //
+    // Input:
+    //          - packetLossEnc :  The reported packet loss filtered (max window or average)
+    void UpdateFilteredLossPr(WebRtc_UWord8 packetLossEnc);
+
+    // Update the current target bit rate.
+    //
+    // Input:
+    //          - bitRate          : The current target bit rate in kbits/s
+    void UpdateBitRate(float bitRate);
+
+    // Update the number of packets per frame estimate, for delta frames
+    //
+    // Input:
+    //          - nPackets         : Number of packets used to send the latest frame.
+    void UpdatePacketsPerFrame(float nPackets);
+
+   // Update the number of packets per frame estimate, for key frames
+    //
+    // Input:
+    //          - nPackets         : Number of packets used to send the latest frame.
+    void UpdatePacketsPerFrameKey(float nPackets);
+
+    // Update the keyFrameSize estimate
+    //
+    // Input:
+    //          - keyFrameSize     : The size of the latest sent key frame.
+    void UpdateKeyFrameSize(float keyFrameSize);
+
+    // Update the frame rate
+    //
+    // Input:
+    //          - frameRate        : The current target frame rate.
+    void UpdateFrameRate(float frameRate) { _frameRate = frameRate; }
+
+    // Update the frame size
+    //
+    // Input:
+    //          - width        : The codec frame width.
+    //          - height       : The codec frame height.
+    void UpdateFrameSize(WebRtc_UWord16 width, WebRtc_UWord16 height);
+
+    // The amount of packet loss to cover for with FEC.
+    //
+    // Input:
+    //          - fecRateKey      : Packet loss to cover for with FEC when sending key frames.
+    //          - fecRateDelta    : Packet loss to cover for with FEC when sending delta frames.
+    void UpdateFECRates(WebRtc_UWord8 fecRateKey, WebRtc_UWord8 fecRateDelta)
+                       { _fecRateKey = fecRateKey; _fecRateDelta = fecRateDelta; }
+
+    // Update the protection methods with the current VCMProtectionParameters and
+    // choose the best method available. The update involves computing the robustness settings
+    // for the protection method.
+    //
+    // Input:
+    //          - newMethod         : If not NULL, this is method will be selected by force.
+    //
+    // Return value     : True if the selected method is recommended using these settings,
+    //                    false if it's the best method, but still not recommended to be used.
+    //                    E.g. if NACK is the best available, but the RTT is too large, false
+    //                    will be returned.
+    bool UpdateMethod(VCMProtectionMethod *newMethod = NULL);
+
+    // Returns the method currently selected.
+    //
+    // Return value                 : The protection method currently selected.
+    VCMProtectionMethod* SelectedMethod() const;
+
+    // Returns the filtered loss probability in the interval [0, 255].
+    //
+    // Return value                 : The filtered loss probability
+    WebRtc_UWord8 FilteredLoss() const;
+
+    // Get constraint on NACK
+    //
+    // return value                : RTT threshold for using NACK
+   WebRtc_UWord8  GetNackThreshold() const;
+
+    void Reset();
+
+private:
+    // Sets the available loss protection methods.
+    void UpdateMaxLossHistory(WebRtc_UWord8 lossPr255, WebRtc_Word64 now);
+    WebRtc_UWord8 MaxFilteredLossPr(WebRtc_Word64 nowMs) const;
+    ListWrapper               _availableMethods;
+    VCMProtectionMethod*      _selectedMethod;
+    VCMProtectionMethod*      _bestNotOkMethod;
+    VCMProtectionParameters   _currentParameters;
+    WebRtc_UWord32            _rtt;
+    float                     _lossPr;
+    float                     _bitRate;
+    float                     _frameRate;
+    float                     _keyFrameSize;
+    WebRtc_UWord8             _fecRateKey;
+    WebRtc_UWord8             _fecRateDelta;
+    WebRtc_Word64             _lastPrUpdateT;
+    WebRtc_Word64             _lastPacketPerFrameUpdateT;
+    WebRtc_Word64             _lastPacketPerFrameUpdateTKey;
+    VCMExpFilter              _lossPr255;
+    VCMLossProbabilitySample  _lossPrHistory[kLossPrHistorySize];
+    WebRtc_UWord8             _shortMaxLossPr255;
+    VCMExpFilter              _packetsPerFrame;
+    VCMExpFilter              _packetsPerFrameKey;
+    float                     _residualPacketLoss;
+    WebRtc_UWord8             _boostRateKey;
+    VCMFecTypes               _fecType;
+    WebRtc_UWord16            _codecWidth;
+    WebRtc_UWord16            _codecHeight;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_MEDIA_OPT_UTIL_H_
diff --git a/src/modules/video_coding/main/source/media_optimization.cc b/src/modules/video_coding/main/source/media_optimization.cc
new file mode 100644
index 0000000..e215986
--- /dev/null
+++ b/src/modules/video_coding/main/source/media_optimization.cc
@@ -0,0 +1,707 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "media_optimization.h"
+#include "content_metrics_processing.h"
+#include "frame_dropper.h"
+#include "qm_select.h"
+
+namespace webrtc {
+
+VCMMediaOptimization::VCMMediaOptimization(WebRtc_Word32 id):
+_id(id),
+_maxBitRate(0),
+_sendCodecType(kVideoCodecUnknown),
+_codecWidth(0),
+_codecHeight(0),
+_userFrameRate(0),
+_lossProtOverhead(0),
+_packetLossEnc(0),
+_fractionLost(0),
+_sendStatisticsZeroEncode(0),
+_maxPayloadSize(1460),
+_lastBitRate(0),
+_targetBitRate(0),
+_incomingFrameRate(0),
+_enableQm(false),
+_videoProtectionCallback(NULL),
+_videoQMSettingsCallback(NULL),
+_encodedFrameSamples(),
+_avgSentBitRateBps(0.0f),
+_keyFrameCnt(0),
+_deltaFrameCnt(0),
+_lastQMUpdateTime(0),
+_lastChangeTime(0)
+{
+    memset(_sendStatistics, 0, sizeof(_sendStatistics));
+    memset(_incomingFrameTimes, -1, sizeof(_incomingFrameTimes));
+
+    _frameDropper  = new VCMFrameDropper(_id);
+    _lossProtLogic = new VCMLossProtectionLogic();
+    _content = new VCMContentMetricsProcessing();
+    _qms = new VCMQmSelect();
+}
+
+VCMMediaOptimization::~VCMMediaOptimization(void)
+{
+    _lossProtLogic->ClearLossProtections();
+    delete _lossProtLogic;
+    delete _frameDropper;
+    delete _content;
+    delete _qms;
+}
+
+WebRtc_Word32
+VCMMediaOptimization::Reset()
+{
+    memset(_incomingFrameTimes, -1, sizeof(_incomingFrameTimes));
+    InputFrameRate(); // Resets _incomingFrameRate
+    _frameDropper->Reset();
+    _lossProtLogic->Reset();
+    _frameDropper->SetRates(0, 0);
+    _content->Reset();
+    _qms->Reset();
+    _lossProtLogic->UpdateFrameRate(_incomingFrameRate);
+    _lossProtLogic->Reset();
+    _sendStatisticsZeroEncode = 0;
+    _lastBitRate = 0;
+    _targetBitRate = 0;
+    _lossProtOverhead = 0;
+    _codecWidth = 0;
+    _codecHeight = 0;
+    _userFrameRate = 0;
+    _keyFrameCnt = 0;
+    _deltaFrameCnt = 0;
+    _lastQMUpdateTime = 0;
+    _lastChangeTime = 0;
+    for (WebRtc_Word32 i = 0; i < kBitrateMaxFrameSamples; i++)
+    {
+        _encodedFrameSamples[i]._sizeBytes = -1;
+        _encodedFrameSamples[i]._timeCompleteMs = -1;
+    }
+    _avgSentBitRateBps = 0.0f;
+    return VCM_OK;
+}
+
+WebRtc_UWord32
+VCMMediaOptimization::SetTargetRates(WebRtc_UWord32 bitRate,
+                                     WebRtc_UWord8 &fractionLost,
+                                     WebRtc_UWord32 roundTripTimeMs)
+{
+    VCMProtectionMethod *selectedMethod = _lossProtLogic->SelectedMethod();
+    _lossProtLogic->UpdateBitRate(static_cast<float>(bitRate));
+    _lossProtLogic->UpdateLossPr(fractionLost);
+    _lossProtLogic->UpdateRtt(roundTripTimeMs);
+    _lossProtLogic->UpdateResidualPacketLoss(static_cast<float>(fractionLost));
+
+    VCMFecTypes fecType = kXORFec;  // generic FEC
+    _lossProtLogic->UpdateFecType(fecType);
+
+    // Get frame rate for encoder: this is the actual/sent frame rate
+    float actualFrameRate = SentFrameRate();
+
+    // sanity
+    if (actualFrameRate  < 1.0)
+    {
+        actualFrameRate = 1.0;
+    }
+
+    // Update frame rate for the loss protection logic class: frame rate should
+    // be the actual/sent rate
+    _lossProtLogic->UpdateFrameRate(actualFrameRate);
+
+    _fractionLost = fractionLost;
+
+    // The effective packet loss may be the received loss or filtered, i.e.,
+    // average or max filter may be used.
+    // We should think about which filter is appropriate for low/high bit rates,
+    // low/high loss rates, etc.
+    WebRtc_UWord8 packetLossEnc = _lossProtLogic->FilteredLoss();
+
+    //For now use the filtered loss for computing the robustness settings
+    _lossProtLogic->UpdateFilteredLossPr(packetLossEnc);
+
+    // Rate cost of the protection methods
+    _lossProtOverhead = 0;
+
+    if (selectedMethod && (selectedMethod->Type() == kFEC ||
+        selectedMethod->Type() == kNackFec ))
+    {
+
+        // Update method will compute the robustness settings for the given
+        // protection method and the overhead cost
+        // the protection method is set by the user via SetVideoProtection.
+        // The robustness settings are: the effective packet loss for ER and the
+        // FEC protection settings
+        _lossProtLogic->UpdateMethod();
+
+        // Get the code rate for Key frames
+        const WebRtc_UWord8 codeRateKeyRTP  = selectedMethod->RequiredProtectionFactorK();
+
+        // Get the code rate for Delta frames
+        const WebRtc_UWord8 codeRateDeltaRTP = selectedMethod->RequiredProtectionFactorD();
+
+        // Get the effective packet loss for ER
+        packetLossEnc = selectedMethod->RequiredPacketLossER();
+
+        // NACK is on for NACK and NackFec protection method: off for FEC method
+        bool nackStatus = (selectedMethod->Type() == kNackFec ||
+                           selectedMethod->Type() == kNACK);
+
+        if(_videoProtectionCallback)
+        {
+            _videoProtectionCallback->ProtectionRequest(codeRateDeltaRTP,
+                                                        codeRateKeyRTP,
+                                                        nackStatus);
+        }
+    }
+
+    // Get the bit cost of protection method
+    _lossProtOverhead = static_cast<WebRtc_UWord32>(_lossProtLogic->HighestOverhead() + 0.5f);
+
+    // Update effective packet loss for encoder: note: fractionLost was passed as reference
+    fractionLost = packetLossEnc;
+
+    WebRtc_UWord32 nackBitRate=0;
+    if(selectedMethod && _lossProtLogic->FindMethod(kNACK) != NULL)
+    {
+        // TODO(mikhal): update frame dropper with bit rate including both nack and fec
+        // Make sure we don't over-use the channel momentarily. This is
+        // necessary for NACK since it can be very bursty.
+        nackBitRate = (_lastBitRate * fractionLost) / 255;
+        if (nackBitRate > _targetBitRate)
+        {
+            nackBitRate = _targetBitRate;
+        }
+        _frameDropper->SetRates(static_cast<float>(bitRate - nackBitRate), 0);
+    }
+    else
+    {
+        _frameDropper->SetRates(static_cast<float>(bitRate - _lossProtOverhead), 0);
+    }
+
+    // This may be used for UpdateEncoderBitRate: lastBitRate is total rate,
+    // before compensation
+    _lastBitRate = _targetBitRate;
+
+    //Source coding rate: total rate - protection overhead
+    _targetBitRate = bitRate - _lossProtOverhead;
+
+    if (_enableQm)
+    {
+        //Update QM with rates
+        _qms->UpdateRates((float)_targetBitRate, _avgSentBitRateBps,
+                          _incomingFrameRate, _fractionLost);
+        //Check for QM selection
+        bool selectQM = checkStatusForQMchange();
+        if (selectQM)
+        {
+            SelectQuality();
+        }
+        // Reset the short-term averaged content data.
+        _content->ResetShortTermAvgData();
+    }
+
+    return _targetBitRate;
+}
+
+
+bool
+VCMMediaOptimization::DropFrame()
+{
+    // leak appropriate number of bytes
+    _frameDropper->Leak((WebRtc_UWord32)(InputFrameRate() + 0.5f));
+    return _frameDropper->DropFrame();
+}
+
+WebRtc_Word32
+VCMMediaOptimization::SentFrameCount(VCMFrameCount &frameCount) const
+{
+    frameCount.numDeltaFrames = _deltaFrameCnt;
+    frameCount.numKeyFrames = _keyFrameCnt;
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMMediaOptimization::SetEncodingData(VideoCodecType sendCodecType, WebRtc_Word32 maxBitRate,
+                                      WebRtc_UWord32 frameRate, WebRtc_UWord32 bitRate,
+                                      WebRtc_UWord16 width, WebRtc_UWord16 height)
+{
+    // Everything codec specific should be reset here since this means the codec has changed.
+    // If native dimension values have changed, then either user initiated change, or QM
+    // initiated change. Will be able to determine only after the processing of the first frame
+    _lastChangeTime = VCMTickTime::MillisecondTimestamp();
+    _content->Reset();
+    _content->UpdateFrameRate(frameRate);
+
+    _maxBitRate = maxBitRate;
+    _sendCodecType = sendCodecType;
+    _targetBitRate = bitRate;
+    _lossProtLogic->UpdateBitRate(static_cast<float>(bitRate));
+    _lossProtLogic->UpdateFrameRate(static_cast<float>(frameRate));
+    _lossProtLogic->UpdateFrameSize(width, height);
+    _frameDropper->Reset();
+    _frameDropper->SetRates(static_cast<float>(bitRate), static_cast<float>(frameRate));
+    _userFrameRate = (float)frameRate;
+    _codecWidth = width;
+    _codecHeight = height;
+    WebRtc_Word32 ret = VCM_OK;
+    ret = _qms->Initialize((float)_targetBitRate, _userFrameRate, _codecWidth, _codecHeight);
+    return ret;
+}
+
+WebRtc_Word32
+VCMMediaOptimization::RegisterProtectionCallback(VCMProtectionCallback* protectionCallback)
+{
+    _videoProtectionCallback = protectionCallback;
+    return VCM_OK;
+
+}
+
+
+void
+VCMMediaOptimization::EnableFrameDropper(bool enable)
+{
+    _frameDropper->Enable(enable);
+}
+
+
+void
+VCMMediaOptimization::EnableNack(bool enable)
+{
+    // Add NACK to the list of loss protection methods
+    bool updated = false;
+    if (enable)
+    {
+        VCMProtectionMethod *nackMethod = new VCMNackMethod();
+        updated = _lossProtLogic->AddMethod(nackMethod);
+        if (!updated)
+        {
+            delete nackMethod;
+        }
+    }
+    else
+    {
+        updated = _lossProtLogic->RemoveMethod(kNACK);
+    }
+    if (updated)
+    {
+        _lossProtLogic->UpdateMethod();
+    }
+}
+
+bool
+VCMMediaOptimization::IsNackEnabled()
+{
+    return (_lossProtLogic->FindMethod(kNACK) != NULL);
+}
+
+void
+VCMMediaOptimization::EnableFEC(bool enable)
+{
+    // Add FEC to the list of loss protection methods
+    bool updated = false;
+    if (enable)
+    {
+        VCMProtectionMethod *fecMethod = new VCMFecMethod();
+        updated = _lossProtLogic->AddMethod(fecMethod);
+        if (!updated)
+        {
+            delete fecMethod;
+        }
+    }
+    else
+    {
+        updated = _lossProtLogic->RemoveMethod(kFEC);
+    }
+    if (updated)
+    {
+        _lossProtLogic->UpdateMethod();
+    }
+}
+void
+VCMMediaOptimization::EnableNackFEC(bool enable)
+{
+    // Add NackFec to the list of loss protection methods
+    bool updated = false;
+    if (enable)
+    {
+        VCMProtectionMethod *nackfecMethod = new VCMNackFecMethod();
+        updated = _lossProtLogic->AddMethod(nackfecMethod);
+        if (!updated)
+        {
+            delete nackfecMethod;
+        }
+    }
+    else
+    {
+        updated = _lossProtLogic->RemoveMethod(kNackFec);
+    }
+    if (updated)
+    {
+        _lossProtLogic->UpdateMethod();
+    }
+}
+
+bool
+VCMMediaOptimization::IsFecEnabled()
+{
+    return (_lossProtLogic->FindMethod(kFEC) != NULL);
+}
+
+bool
+VCMMediaOptimization::IsNackFecEnabled()
+{
+    return (_lossProtLogic->FindMethod(kNackFec) != NULL);
+}
+
+void
+VCMMediaOptimization::SetMtu(WebRtc_Word32 mtu)
+{
+    _maxPayloadSize = mtu;
+}
+
+float
+VCMMediaOptimization::SentFrameRate()
+{
+    if(_frameDropper)
+    {
+        return _frameDropper->ActualFrameRate((WebRtc_UWord32)(InputFrameRate() + 0.5f));
+    }
+
+    return VCM_CODEC_ERROR;
+}
+
+float
+VCMMediaOptimization::SentBitRate()
+{
+    UpdateBitRateEstimate(-1, VCMTickTime::MillisecondTimestamp());
+    return _avgSentBitRateBps / 1000.0f;
+}
+
+WebRtc_Word32
+VCMMediaOptimization::MaxBitRate()
+{
+    return _maxBitRate;
+}
+
+WebRtc_Word32
+VCMMediaOptimization::UpdateWithEncodedData(WebRtc_Word32 encodedLength,
+                                            FrameType encodedFrameType)
+{
+    // look into the ViE version - debug mode - needs also number of layers.
+    UpdateBitRateEstimate(encodedLength, VCMTickTime::MillisecondTimestamp());
+    if(encodedLength > 0)
+    {
+        const bool deltaFrame = (encodedFrameType != kVideoFrameKey &&
+                                 encodedFrameType != kVideoFrameGolden);
+
+        _frameDropper->Fill(encodedLength, deltaFrame);
+        if (_maxPayloadSize > 0 && encodedLength > 0)
+        {
+            const float minPacketsPerFrame = encodedLength /
+                                             static_cast<float>(_maxPayloadSize);
+            if (deltaFrame)
+            {
+                _lossProtLogic->UpdatePacketsPerFrame(minPacketsPerFrame);
+            }
+            else
+            {
+                _lossProtLogic->UpdatePacketsPerFrameKey(minPacketsPerFrame);
+            }
+
+            if (_enableQm)
+            {
+                // update quality select with encoded length
+                _qms->UpdateEncodedSize(encodedLength, encodedFrameType);
+            }
+        }
+        if (!deltaFrame && encodedLength > 0)
+        {
+            _lossProtLogic->UpdateKeyFrameSize(static_cast<float>(encodedLength));
+        }
+
+        // updating counters
+        if (deltaFrame){
+            _deltaFrameCnt++;
+        } else {
+            _keyFrameCnt++;
+        }
+
+    }
+
+     return VCM_OK;
+
+}
+
+void VCMMediaOptimization::UpdateBitRateEstimate(WebRtc_Word64 encodedLength,
+                                                 WebRtc_Word64 nowMs)
+{
+    int i = kBitrateMaxFrameSamples - 1;
+    WebRtc_UWord32 frameSizeSum = 0;
+    WebRtc_Word64 timeOldest = -1;
+    // Find an empty slot for storing the new sample and at the same time
+    // accumulate the history.
+    for (; i >= 0; i--)
+    {
+        if (_encodedFrameSamples[i]._sizeBytes == -1)
+        {
+            // Found empty slot
+            break;
+        }
+        if (nowMs - _encodedFrameSamples[i]._timeCompleteMs < kBitrateAverageWinMs)
+        {
+            frameSizeSum += static_cast<WebRtc_UWord32>(_encodedFrameSamples[i]._sizeBytes);
+            if (timeOldest == -1)
+            {
+                timeOldest = _encodedFrameSamples[i]._timeCompleteMs;
+            }
+        }
+    }
+    if (encodedLength > 0)
+    {
+        if (i < 0)
+        {
+            // No empty slot, shift
+            for (i = kBitrateMaxFrameSamples - 2; i >= 0; i--)
+            {
+                _encodedFrameSamples[i + 1] = _encodedFrameSamples[i];
+            }
+            i++;
+        }
+        // Insert new sample
+        _encodedFrameSamples[i]._sizeBytes = encodedLength;
+        _encodedFrameSamples[i]._timeCompleteMs = nowMs;
+    }
+    if (timeOldest > -1)
+    {
+        // Update average bit rate
+        float denom = static_cast<float>(nowMs - timeOldest);
+        if (denom < 1.0)
+        {
+            denom = 1.0;
+        }
+        _avgSentBitRateBps = (frameSizeSum + encodedLength) * 8 * 1000 / denom;
+    }
+    else if (encodedLength > 0)
+    {
+        _avgSentBitRateBps = static_cast<float>(encodedLength * 8);
+    }
+    else
+    {
+        _avgSentBitRateBps = 0;
+    }
+}
+
+
+WebRtc_Word32
+VCMMediaOptimization::RegisterVideoQMCallback(VCMQMSettingsCallback *videoQMSettings)
+{
+    _videoQMSettingsCallback = videoQMSettings;
+    // Callback setting controls QM
+    if (_videoQMSettingsCallback != NULL)
+    {
+        _enableQm = true;
+    }
+    else
+    {
+        _enableQm = false;
+    }
+    return VCM_OK;
+}
+
+void
+VCMMediaOptimization::updateContentData(const VideoContentMetrics *contentMetrics)
+{
+    //Updating content metrics
+    if (contentMetrics == NULL)
+    {
+         //No QM if metrics are NULL
+         _enableQm = false;
+         _qms->Reset();
+    }
+    else
+    {
+        _content->UpdateContentData(contentMetrics);
+    }
+}
+
+WebRtc_Word32
+VCMMediaOptimization::SelectQuality()
+{
+    // Reset quantities for QM select
+    _qms->ResetQM();
+
+    // Update QM will long-term averaged content metrics.
+    _qms->UpdateContent(_content->LongTermAvgData());
+
+    // Select quality mode
+    VCMQualityMode* qm = NULL;
+    WebRtc_Word32 ret = _qms->SelectQuality(&qm);
+    if (ret < 0)
+    {
+          return ret;
+    }
+
+    // Check for updates to spatial/temporal modes
+    QMUpdate(qm);
+
+    // Reset all the rate and related frame counters quantities
+    _qms->ResetRates();
+
+    // Reset counters
+    _lastQMUpdateTime = VCMTickTime::MillisecondTimestamp();
+
+    // Reset content metrics
+    _content->Reset();
+
+    return VCM_OK;
+}
+
+
+// Check timing constraints and look for significant change in:
+// (1) scene content
+// (2) target bit rate
+
+bool
+VCMMediaOptimization::checkStatusForQMchange()
+{
+
+    bool status  = true;
+
+    // Check that we do not call QMSelect too often, and that we waited some time
+    // (to sample the metrics) from the event lastChangeTime
+    // lastChangeTime is the time where user changed the size/rate/frame rate
+    // (via SetEncodingData)
+    WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
+    if ((now - _lastQMUpdateTime) < kQmMinIntervalMs ||
+        (now  - _lastChangeTime) <  kQmMinIntervalMs)
+    {
+        status = false;
+    }
+
+    return status;
+
+}
+
+bool
+VCMMediaOptimization::QMUpdate(VCMQualityMode* qm)
+{
+    // Check for no change
+    if (qm->spatialHeightFact == 1 &&
+        qm->spatialWidthFact == 1 &&
+        qm->temporalFact == 1)
+    {
+        return false;
+    }
+
+    // Content metrics hold native values
+    VideoContentMetrics* cm = _content->LongTermAvgData();
+
+    // Temporal
+    WebRtc_UWord32 frameRate  = static_cast<WebRtc_UWord32>(_incomingFrameRate + 0.5f);
+    // Check if go back up in temporal resolution
+    if (qm->temporalFact == 0)
+    {
+        frameRate = (WebRtc_UWord32) 2 * _incomingFrameRate;
+    }
+    // go down in temporal resolution
+    else
+    {
+        frameRate = (WebRtc_UWord32)(_incomingFrameRate / qm->temporalFact + 1);
+    }
+
+    // Spatial
+    WebRtc_UWord32 height = _codecHeight;
+    WebRtc_UWord32 width = _codecWidth;
+    // Check if go back up in spatial resolution
+    if (qm->spatialHeightFact == 0 && qm->spatialWidthFact == 0)
+    {
+       height = cm->nativeHeight;
+       width = cm->nativeWidth;
+    }
+    else
+    {
+        height = _codecHeight / qm->spatialHeightFact;
+        width = _codecWidth / qm->spatialWidthFact;
+    }
+
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, _id,
+               "Quality Mode Update: W = %d, H = %d, FR = %f",
+               width, height, frameRate);
+
+    // Update VPM with new target frame rate and size
+    _videoQMSettingsCallback->SetVideoQMSettings(frameRate, width, height);
+
+    return true;
+}
+
+
+
+void
+VCMMediaOptimization::UpdateIncomingFrameRate()
+{
+    WebRtc_Word64 now = VCMTickTime::MillisecondTimestamp();
+    if(_incomingFrameTimes[0] == 0)
+    {
+        // first no shift
+    } else
+    {
+        // shift
+        for(WebRtc_Word32 i = (kFrameCountHistorySize - 2); i >= 0 ; i--)
+        {
+            _incomingFrameTimes[i+1] = _incomingFrameTimes[i];
+        }
+    }
+    _incomingFrameTimes[0] = now;
+    ProcessIncomingFrameRate(now);
+}
+
+// allowing VCM to keep track of incoming frame rate
+void
+VCMMediaOptimization::ProcessIncomingFrameRate(WebRtc_Word64 now)
+{
+    WebRtc_Word32 num = 0;
+    WebRtc_Word32 nrOfFrames = 0;
+    for (num = 1; num < (kFrameCountHistorySize - 1); num++)
+    {
+        if (_incomingFrameTimes[num] <= 0 ||
+            // don't use data older than 2 s
+            now - _incomingFrameTimes[num] > kFrameHistoryWinMs)
+        {
+            break;
+        } else
+        {
+            nrOfFrames++;
+        }
+    }
+    if (num > 1)
+    {
+        const WebRtc_Word64 diff = now - _incomingFrameTimes[num-1];
+        _incomingFrameRate = 1.0;
+        if(diff >0)
+        {
+            _incomingFrameRate = nrOfFrames * 1000.0f / static_cast<float>(diff);
+        }
+    }
+    else
+    {
+        _incomingFrameRate = static_cast<float>(nrOfFrames);
+    }
+}
+
+WebRtc_UWord32
+VCMMediaOptimization::InputFrameRate()
+{
+    ProcessIncomingFrameRate(VCMTickTime::MillisecondTimestamp());
+    return WebRtc_UWord32 (_incomingFrameRate + 0.5f);
+}
+
+}
diff --git a/src/modules/video_coding/main/source/media_optimization.h b/src/modules/video_coding/main/source/media_optimization.h
new file mode 100644
index 0000000..8a9993e
--- /dev/null
+++ b/src/modules/video_coding/main/source/media_optimization.h
@@ -0,0 +1,220 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_MEDIA_OPTIMIZATION_H_
+#define WEBRTC_MODULES_VIDEO_CODING_MEDIA_OPTIMIZATION_H_
+
+#include "list_wrapper.h"
+#include "module_common_types.h"
+#include "video_coding.h"
+#include "trace.h"
+#include "media_opt_util.h"
+#include "qm_select.h"
+
+namespace webrtc
+{
+
+enum { kBitrateMaxFrameSamples = 60 };
+enum { kBitrateAverageWinMs    = 1000 };
+
+class VCMContentMetricsProcessing;
+class VCMFrameDropper;
+
+struct VCMEncodedFrameSample
+{
+    VCMEncodedFrameSample() : _sizeBytes(-1), _timeCompleteMs(-1) {}
+
+    WebRtc_Word64     _sizeBytes;
+    WebRtc_Word64     _timeCompleteMs;
+};
+
+class VCMMediaOptimization
+{
+public:
+    VCMMediaOptimization(WebRtc_Word32 id);
+    ~VCMMediaOptimization(void);
+    /*
+    * Reset the Media Optimization module
+    */
+    WebRtc_Word32 Reset();
+    /**
+    * Set target Rates for the encoder given the channel parameters
+    * Inputs:       bitRate - target bitRate, in the conference case this is the rate
+    *                         between the sending client and the server
+    *               fractionLost - packet loss in % in the network
+    *               roundTripTimeMs - round trip time in miliseconds
+    *               minBitRate - the bit rate of the end-point with lowest rate
+    *               maxBitRate - the bit rate of the end-point with highest rate
+    */
+    WebRtc_UWord32 SetTargetRates(WebRtc_UWord32 bitRate,
+                                  WebRtc_UWord8 &fractionLost,
+                                  WebRtc_UWord32 roundTripTimeMs);
+
+    /**
+    * Inform media optimization of initial encoding state
+    */
+    WebRtc_Word32 SetEncodingData(VideoCodecType sendCodecType,
+                                  WebRtc_Word32 maxBitRate,
+                                  WebRtc_UWord32 frameRate,
+                                  WebRtc_UWord32 bitRate,
+                                  WebRtc_UWord16 width,
+                                  WebRtc_UWord16 height);
+    /**
+    * Enable NACK and update error resilience parameters
+    */
+    void EnableNack(bool enable);
+    /**
+    * Returns weather or not NACK is enabled
+    */
+    bool IsNackEnabled();
+    /**
+    * Enable FEC and update error resilience parameters
+    */
+    void EnableFEC(bool enable);
+    /**
+    * Returns weather or not FEC is enabled
+    */
+    bool IsFecEnabled();
+    /**
+    * Returns weather or not NackFec is enabled
+    */
+    bool IsNackFecEnabled();
+    /**
+    * Updates the max pay load size
+    */
+     /**
+    * Enable NackFec and update error resilience parameters
+    */
+    void EnableNackFEC(bool enable);
+
+    void SetMtu(WebRtc_Word32 mtu);
+
+    /*
+    * Get actual input frame rate
+    */
+    WebRtc_UWord32 InputFrameRate();
+
+    /*
+    * Get actual sent frame rate
+    */
+    float SentFrameRate();
+    /*
+    * Get actual sent bit rate
+    */
+    float SentBitRate();
+    /*
+    * Get maximum allowed bit rate
+    */
+    WebRtc_Word32 MaxBitRate();
+    /*
+    * Inform Media Optimization of encoding output: Length and frame type
+    */
+    WebRtc_Word32 UpdateWithEncodedData(WebRtc_Word32 encodedLength,
+                                        FrameType encodedFrameType);
+    /*
+    * Register a protection callback to be used to inform the user about the
+    * protection methods used
+    */
+    WebRtc_Word32 RegisterProtectionCallback(VCMProtectionCallback* protectionCallback);
+    /*
+    * Register a quality settings callback to be used to inform VPM/user about the optimal
+    * quality settings (frame rate/dimension) required
+    */
+    WebRtc_Word32 RegisterVideoQMCallback(VCMQMSettingsCallback* videoQMSettings);
+    void EnableFrameDropper(bool enable);
+
+    bool DropFrame();
+
+      /*
+    * Get number of key/delta frames encoded
+    */
+    WebRtc_Word32 SentFrameCount(VCMFrameCount &frameCount) const;
+
+    /*
+    *  update incoming frame rate value
+    */
+    void UpdateIncomingFrameRate();
+
+    /**
+    * Update content metric Data
+    */
+    void updateContentData(const VideoContentMetrics* contentMetrics);
+
+    /**
+    * Compute new Quality Mode
+    */
+    WebRtc_Word32 SelectQuality();
+
+private:
+
+    void UpdateBitRateEstimate(WebRtc_Word64 encodedLength, WebRtc_Word64 nowMs);
+    /*
+    * verify if QM settings differ from default, i.e. if an update is required
+    * Compute actual values, as will be sent to the encoder
+    */
+    bool QMUpdate(VCMQualityMode* qm);
+    /**
+    * check if we should make a QM change
+    * will return 1 if yes, 0 otherwise
+    */
+    bool checkStatusForQMchange();
+
+    void ProcessIncomingFrameRate(WebRtc_Word64 now);
+
+    enum { kFrameCountHistorySize = 90};
+    enum { kFrameHistoryWinMs = 2000};
+
+    WebRtc_Word32                     _id;
+
+    WebRtc_Word32                     _maxBitRate;
+    VideoCodecType                    _sendCodecType;
+    WebRtc_UWord16                    _codecWidth;
+    WebRtc_UWord16                    _codecHeight;
+    float                             _userFrameRate;
+
+    VCMFrameDropper*                  _frameDropper;
+    VCMLossProtectionLogic*           _lossProtLogic;
+    WebRtc_UWord32                    _lossProtOverhead;
+    WebRtc_UWord8                     _packetLossEnc;
+    WebRtc_UWord8                     _fractionLost;
+
+
+    WebRtc_UWord32                    _sendStatistics[4];
+    WebRtc_UWord32                    _sendStatisticsZeroEncode;
+    WebRtc_Word32                     _maxPayloadSize;
+    WebRtc_UWord32                    _lastBitRate;
+    WebRtc_UWord32                    _targetBitRate;
+
+    float                             _incomingFrameRate;
+    WebRtc_Word64                     _incomingFrameTimes[kFrameCountHistorySize];
+
+    bool                              _enableQm;
+
+    VCMProtectionCallback*            _videoProtectionCallback;
+    VCMQMSettingsCallback*            _videoQMSettingsCallback;
+
+    VCMEncodedFrameSample             _encodedFrameSamples[kBitrateMaxFrameSamples];
+    float                             _avgSentBitRateBps;
+
+    WebRtc_UWord32                    _keyFrameCnt;
+    WebRtc_UWord32                    _deltaFrameCnt;
+
+    VCMContentMetricsProcessing*      _content;
+    VCMQmSelect*                      _qms;
+
+    WebRtc_Word64                     _lastQMUpdateTime;
+    WebRtc_Word64                     _lastChangeTime; // content or user triggered
+
+
+}; // end of VCMMediaOptimization class definition
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_MEDIA_OPTIMIZATION_H_
diff --git a/src/modules/video_coding/main/source/nack_fec_tables.h b/src/modules/video_coding/main/source/nack_fec_tables.h
new file mode 100644
index 0000000..40cf0b5
--- /dev/null
+++ b/src/modules/video_coding/main/source/nack_fec_tables.h
@@ -0,0 +1,226 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_SOURCE_NACK_FEC_TABLES_H_
+#define WEBRTC_MODULES_VIDEO_CODING_SOURCE_NACK_FEC_TABLES_H_
+
+namespace webrtc
+{
+
+// Table for softening FEC rate for NACK/FEC protection method
+const WebRtc_UWord16 VCMNackFecTable[200] = {
+
+27,
+28,
+30,
+31,
+33,
+35,
+36,
+38,
+40,
+42,
+45,
+47,
+49,
+52,
+54,
+57,
+60,
+63,
+66,
+70,
+73,
+77,
+81,
+85,
+89,
+94,
+98,
+103,
+108,
+114,
+120,
+126,
+132,
+138,
+145,
+152,
+160,
+168,
+176,
+185,
+194,
+203,
+213,
+223,
+234,
+246,
+257,
+270,
+283,
+296,
+310,
+325,
+340,
+356,
+373,
+390,
+408,
+427,
+446,
+467,
+488,
+510,
+532,
+556,
+581,
+606,
+632,
+659,
+688,
+717,
+747,
+778,
+810,
+843,
+877,
+912,
+948,
+985,
+1022,
+1061,
+1101,
+1142,
+1183,
+1226,
+1269,
+1314,
+1359,
+1404,
+1451,
+1498,
+1546,
+1594,
+1643,
+1693,
+1743,
+1793,
+1843,
+1894,
+1945,
+1996,
+2048,
+2099,
+2150,
+2201,
+2252,
+2302,
+2352,
+2402,
+2452,
+2501,
+2549,
+2597,
+2644,
+2691,
+2736,
+2781,
+2826,
+2869,
+2912,
+2953,
+2994,
+3034,
+3073,
+3110,
+3147,
+3183,
+3218,
+3252,
+3285,
+3317,
+3348,
+3378,
+3407,
+3436,
+3463,
+3489,
+3514,
+3539,
+3563,
+3585,
+3607,
+3628,
+3649,
+3668,
+3687,
+3705,
+3722,
+3739,
+3755,
+3770,
+3785,
+3799,
+3812,
+3825,
+3838,
+3849,
+3861,
+3872,
+3882,
+3892,
+3901,
+3910,
+3919,
+3927,
+3935,
+3943,
+3950,
+3957,
+3963,
+3969,
+3975,
+3981,
+3987,
+3992,
+3997,
+4001,
+4006,
+4010,
+4014,
+4018,
+4022,
+4025,
+4029,
+4032,
+4035,
+4038,
+4041,
+4043,
+4046,
+4048,
+4050,
+4053,
+4055,
+4057,
+4059,
+4060,
+4062,
+4064,
+4065,
+4067,
+
+
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_SOURCE_NACK_FEC_TABLES_H_
diff --git a/src/modules/video_coding/main/source/packet.cc b/src/modules/video_coding/main/source/packet.cc
new file mode 100644
index 0000000..f5077e4
--- /dev/null
+++ b/src/modules/video_coding/main/source/packet.cc
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "packet.h"
+#include "module_common_types.h"
+
+#include <assert.h>
+
+namespace webrtc {
+
+VCMPacket::VCMPacket(const WebRtc_UWord8* ptr,
+                               const WebRtc_UWord32 size,
+                               const WebRtcRTPHeader& rtpHeader) :
+    payloadType(rtpHeader.header.payloadType),
+    timestamp(rtpHeader.header.timestamp),
+    seqNum(rtpHeader.header.sequenceNumber),
+    dataPtr(ptr),
+    sizeBytes(size),
+    markerBit(rtpHeader.header.markerBit),
+
+    frameType(rtpHeader.frameType),
+    codec(kVideoCodecUnknown),
+    isFirstPacket(rtpHeader.type.Video.isFirstPacket),
+    completeNALU(kNaluComplete),
+    insertStartCode(false),
+    bits(false)
+{
+    CopyCodecSpecifics(rtpHeader.type.Video);
+}
+
+VCMPacket::VCMPacket(const WebRtc_UWord8* ptr, WebRtc_UWord32 size, WebRtc_UWord16 seq, WebRtc_UWord32 ts, bool mBit) :
+    payloadType(0),
+    timestamp(ts),
+    seqNum(seq),
+    dataPtr(ptr),
+    sizeBytes(size),
+    markerBit(mBit),
+
+    frameType(kVideoFrameDelta),
+    codec(kVideoCodecUnknown),
+    isFirstPacket(false),
+    completeNALU(kNaluComplete),
+    insertStartCode(false),
+    bits(false)
+{}
+
+void VCMPacket::CopyCodecSpecifics(const RTPVideoHeader& videoHeader)
+{
+    RTPVideoTypeHeader codecHeader = videoHeader.codecHeader;
+    switch(videoHeader.codec)
+    {
+        case kRTPVideoVP8:
+            {
+                codec = kVideoCodecVP8;
+                break;
+            }
+        case kRTPVideoI420:
+            {
+                codec = kVideoCodecI420;
+                break;
+            }
+        default:
+            {
+                codec = kVideoCodecUnknown;
+                break;
+            }
+    }
+}
+
+}
diff --git a/src/modules/video_coding/main/source/packet.h b/src/modules/video_coding/main/source/packet.h
new file mode 100644
index 0000000..f1fdfd1
--- /dev/null
+++ b/src/modules/video_coding/main/source/packet.h
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_PACKET_H_
+#define WEBRTC_MODULES_VIDEO_CODING_PACKET_H_
+
+#include "typedefs.h"
+#include "module_common_types.h"
+#include "jitter_buffer_common.h"
+
+namespace webrtc
+{
+
+class VCMPacket
+{
+public:
+    VCMPacket(const WebRtc_UWord8* ptr,
+                   const WebRtc_UWord32 size,
+                   const WebRtcRTPHeader& rtpHeader);
+    VCMPacket(const WebRtc_UWord8* ptr,
+                   WebRtc_UWord32 size,
+                   WebRtc_UWord16 seqNum,
+                   WebRtc_UWord32 timestamp,
+                   bool markerBit);
+
+    WebRtc_UWord8           payloadType;
+    WebRtc_UWord32          timestamp;
+    WebRtc_UWord16          seqNum;
+    const WebRtc_UWord8*    dataPtr;
+    WebRtc_UWord32          sizeBytes;
+    bool                    markerBit;
+
+    FrameType               frameType;
+    webrtc::VideoCodecType  codec;
+
+    bool isFirstPacket;                 // Is this first packet in a frame.
+    VCMNaluCompleteness completeNALU;   // Default is kNaluIncomplete.
+    bool insertStartCode;               // True if a start code should be inserted before this
+                                        // packet.
+    bool bits;                          // The first bits of this packets are zero and the
+                                        // first
+                                        // byte should be ORed with the last packet of the
+                                        // previous frame.
+
+protected:
+    void CopyCodecSpecifics(const RTPVideoHeader& videoHeader);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_PACKET_H_
diff --git a/src/modules/video_coding/main/source/qm_select.cc b/src/modules/video_coding/main/source/qm_select.cc
new file mode 100644
index 0000000..3220db0
--- /dev/null
+++ b/src/modules/video_coding/main/source/qm_select.cc
@@ -0,0 +1,734 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "qm_select.h"
+#include "internal_defines.h"
+#include "qm_select_data.h"
+
+#include "module_common_types.h"
+#include "video_coding_defines.h"
+#include "trace.h"
+
+#include <math.h>
+
+namespace webrtc {
+
+VCMQmSelect::VCMQmSelect()
+{
+    _qm = new VCMQualityMode();
+    _contentMetrics = new VideoContentMetrics();
+     Reset();
+}
+
+VCMQmSelect::~VCMQmSelect()
+{
+    delete _qm;
+    delete _contentMetrics;
+}
+
+void
+VCMQmSelect::ResetQM()
+{
+    _motion.Reset();
+    _spatial.Reset();
+    _coherence.Reset();
+    _stationaryMotion = 0;
+    _aspectRatio = 1;
+    _maxRateQM = 0;
+    _imageType = 1;
+    _userResolutionPref = 50; // Neutral
+    _qm->Reset();
+    return;
+}
+
+void
+VCMQmSelect::ResetRates()
+{
+    _sumEncodedBytes = 0;
+    _sumTargetRate = 0.0f;
+    _sumIncomingFrameRate = 0.0f;
+    _sumFrameRateMM = 0.0f;
+    _sumSeqRateMM = 0.0f;
+    _sumPacketLoss = 0.0f;
+    _frameCnt = 0;
+    _frameCntDelta = 0;
+    _lowBufferCnt = 0;
+    _updateRateCnt = 0;
+    return;
+}
+
+void
+VCMQmSelect::Reset()
+{
+    _stateDecFactorSpatial = 1;
+    _stateDecFactorTemp  = 1;
+    _bufferLevel = 0.0f;
+    _targetBitRate = 0.0f;
+    _incomingFrameRate = 0.0f;
+    _userFrameRate = 0.0f;
+    _perFrameBandwidth =0.0f;
+    _prevTotalRate = 0.0f;
+    _prevRttTime = 0;
+    _prevPacketLoss = 0;
+     ResetQM();
+     ResetRates();
+     return;
+}
+
+//Initialize after reset of encoder
+WebRtc_Word32
+VCMQmSelect::Initialize(float bitRate, float userFrameRate,
+                        WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+    if (userFrameRate == 0.0f || width == 0 || height == 0)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    _targetBitRate = bitRate;
+    _userFrameRate = userFrameRate;
+
+    // Encoder width and height
+    _width = width;
+    _height = height;
+
+    // Initial buffer level
+    _bufferLevel = INIT_BUFFER_LEVEL * _targetBitRate;
+
+    // Per-frame bandwidth
+    if ( _incomingFrameRate == 0 )
+    {
+        _perFrameBandwidth = _targetBitRate / _userFrameRate;
+        _incomingFrameRate = _userFrameRate;
+    }
+    else
+    {
+    // Take average: this is due to delay in update of new encoder frame rate:
+    // userFrameRate is the new one,
+    // incomingFrameRate is the old one (based on previous ~ 1sec/RTCP report)
+        _perFrameBandwidth = 0.5 *( _targetBitRate / _userFrameRate +
+            _targetBitRate / _incomingFrameRate );
+    }
+    _init  = true;
+
+
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VCMQmSelect::SetPreferences(WebRtc_Word8 resolPref)
+{
+    // Preference setting for temporal over spatial resolution
+    // 100 means temporal, 0 means spatial, 50 is neutral
+    _userResolutionPref = resolPref;
+
+    return VCM_OK;
+}
+
+//Update after every encoded frame
+void
+VCMQmSelect::UpdateEncodedSize(WebRtc_Word64 encodedSize,
+                               FrameType encodedFrameType)
+{
+    // Update encoded size;
+    _sumEncodedBytes += encodedSize;
+    _frameCnt++;
+
+    // Convert to Kbps
+    float encodedSizeKbits = (float)((encodedSize * 8.0) / 1000.0);
+
+    // Update the buffer level:
+    // per_frame_BW is updated when encoder is updated, every RTCP reports
+    _bufferLevel += _perFrameBandwidth - encodedSizeKbits;
+
+    // Mismatch here is based on difference of actual encoded frame size and
+    // per-frame bandwidth, for delta frames
+    // This is a much stronger condition on rate mismatch than sumSeqRateMM
+    // Note: not used in this version
+    /*
+    const bool deltaFrame = (encodedFrameType != kVideoFrameKey &&
+                             encodedFrameType != kVideoFrameGolden);
+
+    // Sum the frame mismatch:
+    if (deltaFrame)
+    {
+         _frameCntDelta++;
+         if (encodedSizeKbits > 0)
+            _sumFrameRateMM +=
+            (float) (fabs(encodedSizeKbits - _perFrameBandwidth) /
+            encodedSizeKbits);
+    }
+    */
+
+    // Counter for occurrences of low buffer level
+    if (_bufferLevel <= PERC_BUFFER_THR * INIT_BUFFER_LEVEL * _targetBitRate)
+    {
+        _lowBufferCnt++;
+    }
+
+}
+
+//Update various quantities after SetTargetRates in MediaOpt
+void
+VCMQmSelect::UpdateRates(float targetBitRate, float avgSentBitRate,
+                         float incomingFrameRate, WebRtc_UWord8 packetLoss)
+{
+
+    // Sum the target bitrate and incoming frame rate:
+    // these values are the encoder rates (from previous update ~1sec),
+    // i.e, before the update for next ~1sec
+    _sumTargetRate += _targetBitRate;
+    _sumIncomingFrameRate  += _incomingFrameRate;
+    _updateRateCnt++;
+
+    // Sum the received (from RTCP reports) packet loss rates
+    _sumPacketLoss += (float) packetLoss / 255.0f;
+
+    // Convert average sent bitrate to kbps
+    float avgSentBitRatekbps = avgSentBitRate / 1000.0f;
+
+    // Sum the sequence rate mismatch:
+    // Mismatch here is based on difference between target rate the encoder
+    // used (in previous ~1sec) and the average actual
+    // encoding rate measured at current time
+    if (fabs(_targetBitRate - avgSentBitRatekbps) <  THRESH_SUM_MM &&
+        _targetBitRate > 0.0 )
+    {
+        _sumSeqRateMM += (float)
+            (fabs(_targetBitRate - avgSentBitRatekbps) / _targetBitRate );
+    }
+
+    // Update QM with the current new target and frame rate:
+    // these values are ones the encoder will use for the current/next ~1sec
+    _targetBitRate =  targetBitRate;
+    _incomingFrameRate = incomingFrameRate;
+
+    // Update QM with an (average) encoder per_frame_bandwidth:
+    // this is the per_frame_bw for the current/next ~1sec
+    _perFrameBandwidth  = 0.0f;
+    if (_incomingFrameRate > 0.0f)
+    {
+        _perFrameBandwidth = _targetBitRate / _incomingFrameRate;
+    }
+
+}
+
+// Adjust the FEC rate based on the content and the network state
+// (packet loss rate, total rate/bandwidth, round trip time).
+// Note that packetLoss here is the filtered loss value.
+WebRtc_UWord8
+VCMQmSelect::AdjustFecFactor(WebRtc_UWord8 codeRateDelta, float totalRate,
+                             float frameRate,WebRtc_UWord16 rttTime,
+                             WebRtc_UWord8 packetLoss)
+{
+    // Default: no adjustment
+    WebRtc_UWord8 codeRateDeltaAdjust = codeRateDelta;
+    float adjustFec =  1.0f;
+
+    // TODO (marpan):
+    // Set FEC adjustment factor
+
+    codeRateDeltaAdjust = static_cast<WebRtc_UWord8>(codeRateDelta * adjustFec);
+
+     // Keep track of previous values of network state:
+     // adjustment may be also based on pattern of changes in network state
+    _prevTotalRate = totalRate;
+    _prevRttTime = rttTime;
+    _prevPacketLoss = packetLoss;
+
+    return codeRateDeltaAdjust;
+}
+
+void
+VCMQmSelect::UpdateContent(const VideoContentMetrics*  contentMetrics)
+{
+     _contentMetrics = contentMetrics;
+}
+
+// Select the resolution factors: frame size and frame rate change: (QM modes)
+// Selection is for going back up in resolution, or going down in.
+WebRtc_Word32
+VCMQmSelect::SelectQuality(VCMQualityMode** qm)
+{
+    if (!_init)
+    {
+        return VCM_UNINITIALIZED;
+    }
+    if (_contentMetrics == NULL)
+    {
+        Reset(); //default values
+        *qm =  _qm;
+        return VCM_OK;
+    }
+
+    // Default settings
+    _qm->spatialWidthFact = 1;
+    _qm->spatialHeightFact = 1;
+    _qm->temporalFact = 1;
+
+
+    // Update native values
+    _nativeWidth = _contentMetrics->nativeWidth;
+    _nativeHeight = _contentMetrics->nativeHeight;
+    _nativeFrameRate = _contentMetrics->nativeFrameRate;
+
+    // Aspect ratio: used for selection of 1x2,2x1,2x2
+    _aspectRatio = (float)_width / (float)_height;
+
+    float avgTargetRate = 0.0f;
+    float avgIncomingFrameRate = 0.0f;
+    float ratioBufferLow = 0.0f;
+    float rateMisMatch = 0.0f;
+    float avgPacketLoss = 0.0f;
+    if (_frameCnt > 0)
+    {
+        ratioBufferLow = (float)_lowBufferCnt / (float)_frameCnt;
+    }
+    if (_updateRateCnt > 0)
+    {
+        // Use seq-rate mismatch for now
+        rateMisMatch = (float)_sumSeqRateMM / (float)_updateRateCnt;
+        //rateMisMatch = (float)_sumFrameRateMM / (float)_frameCntDelta;
+
+        // Average target and incoming frame rates
+        avgTargetRate = (float)_sumTargetRate / (float)_updateRateCnt;
+        avgIncomingFrameRate = (float)_sumIncomingFrameRate /
+            (float)_updateRateCnt;
+
+        // Average received packet loss rate
+        avgPacketLoss =  (float)_sumPacketLoss / (float)_updateRateCnt;
+    }
+
+    // For QM selection below, may want to weight the average encoder rates
+    // with the current (for next ~1sec) rate values.
+    // Uniform average for now:
+    float w1 = 0.5f;
+    float w2 = 0.5f;
+    avgTargetRate = w1 * avgTargetRate + w2 * _targetBitRate;
+    avgIncomingFrameRate = w1 * avgIncomingFrameRate + w2 * _incomingFrameRate;
+
+    // Set the maximum transitional rate and image type:
+    // for up-sampled spatial dimensions.
+    // This is needed to get the transRate for going back up in
+    // spatial resolution (only 2x2 allowed in this version).
+    SetMaxRateForQM(2 * _width, 2 * _height);
+    WebRtc_UWord8  imageType2  = _imageType;
+    WebRtc_UWord32 maxRateQM2 = _maxRateQM;
+
+    // Set the maximum transitional rate and image type:
+    // for the encoder spatial dimensions.
+    SetMaxRateForQM(_width, _height);
+
+    // Compute class state of the content.
+    MotionNFD();
+    Spatial();
+
+    //
+    // Get transitional rate from table, based on image type and content class.
+    //
+
+    // Get image class and content class: for going down spatially
+    WebRtc_UWord8 imageClass = 1;
+    if (_imageType <= 3) imageClass = 0;
+    WebRtc_UWord8 contentClass  = 3 * _motion.level + _spatial.level;
+    WebRtc_UWord8 tableIndex = imageClass * 9 + contentClass;
+    float scaleTransRate = kScaleTransRateQm[tableIndex];
+
+    // Get image class and content class: for going up spatially
+    WebRtc_UWord8 imageClass2 = 1;
+    if (imageType2 <= 3) imageClass2 = 0;
+    WebRtc_UWord8 tableIndex2 = imageClass2 * 9 + contentClass;
+    float scaleTransRate2 = kScaleTransRateQm[tableIndex2];
+
+    // Transitonal rate for going down
+    WebRtc_UWord32 estimatedTransRateDown = static_cast<WebRtc_UWord32>
+        (_incomingFrameRate * scaleTransRate * _maxRateQM / 30);
+
+    // Transitional rate for going up temporally
+    WebRtc_UWord32 estimatedTransRateUpT = static_cast<WebRtc_UWord32>
+        (TRANS_RATE_SCALE_UP_TEMP * 2 * _incomingFrameRate *
+         scaleTransRate * _maxRateQM / 30);
+
+   // Transitional rate for going up spatially
+    WebRtc_UWord32 estimatedTransRateUpS = static_cast<WebRtc_UWord32>
+        (TRANS_RATE_SCALE_UP_SPATIAL * _incomingFrameRate *
+        scaleTransRate2 * maxRateQM2 / 30);
+
+    //
+    // Done with transitional rates
+    //
+
+    //
+    //CHECK FOR GOING BACK UP IN RESOLUTION
+    //
+    bool selectedUp = false;
+    // Check if native has been spatially down-sampled
+    if (_stateDecFactorSpatial > 1)
+    {
+        // Check conditions on buffer level and rate_mismatch
+        if ( (avgTargetRate > estimatedTransRateUpS) &&
+             (ratioBufferLow < MAX_BUFFER_LOW) && (rateMisMatch < MAX_RATE_MM))
+        {
+            // width/height scaled back up:
+            // setting 0 indicates scaling back to native
+            _qm->spatialHeightFact = 0;
+            _qm->spatialWidthFact = 0;
+            selectedUp = true;
+        }
+    }
+    //Check if native has been temporally down-sampled
+    if (_stateDecFactorTemp > 1)
+    {
+        if ( (avgTargetRate > estimatedTransRateUpT) &&
+             (ratioBufferLow < MAX_BUFFER_LOW) && (rateMisMatch < MAX_RATE_MM))
+        {
+            // temporal scale back up:
+            // setting 0 indicates scaling back to native
+            _qm->temporalFact = 0;
+            selectedUp = true;
+        }
+    }
+
+    // Leave QM if we selected to go back up in either spatial or temporal
+    if (selectedUp == true)
+    {
+        // Update down-sampling state
+        // Note: only temp reduction by 2 is allowed
+        if (_qm->temporalFact == 0)
+        {
+            _stateDecFactorTemp = _stateDecFactorTemp / 2;
+        }
+        // Update down-sampling state
+        // Note: only spatial reduction by 2x2 is allowed
+        if (_qm->spatialHeightFact == 0 && _qm->spatialWidthFact == 0 )
+        {
+            _stateDecFactorSpatial = _stateDecFactorSpatial / 4;
+        }
+       *qm = _qm;
+       return VCM_OK;
+    }
+
+    //
+    // Done with checking for going back up in resolution
+    //
+
+    //
+    //CHECK FOR RESOLUTION REDUCTION
+    //
+
+    // Resolution reduction if:
+    // (1) target rate is lower than transitional rate, or
+    // (2) buffer level is not stable, or
+    // (3) rate mismatch is larger than threshold
+
+    // Bias down-sampling based on packet loss conditions
+    if (avgPacketLoss > LOSS_THR)
+    {
+        estimatedTransRateDown = LOSS_RATE_FAC * estimatedTransRateDown;
+    }
+
+    if ((avgTargetRate < estimatedTransRateDown ) ||
+        (ratioBufferLow > MAX_BUFFER_LOW)
+        || (rateMisMatch > MAX_RATE_MM))
+    {
+
+        WebRtc_UWord8 spatialFact = 1;
+        WebRtc_UWord8 tempFact = 1;
+
+        // Get the action
+        spatialFact = kSpatialAction[contentClass];
+        tempFact = kTemporalAction[contentClass];
+
+        switch(spatialFact)
+        {
+        case 4:
+            _qm->spatialWidthFact = 2;
+            _qm->spatialHeightFact = 2;
+            break;
+        case 2:
+             //default is 1x2 (H)
+            _qm->spatialWidthFact = 2;
+            _qm->spatialHeightFact = 1;
+            // Select 1x2,2x1, or back to 2x2
+            // Note: directional selection not used in this version
+            // SelectSpatialDirectionMode((float) estimatedTransRateDown);
+            break;
+        default:
+            _qm->spatialWidthFact = 1;
+            _qm->spatialHeightFact = 1;
+            break;
+        }
+        _qm->temporalFact = tempFact;
+
+        // Sanity check on ST QM selection:
+        // override the settings for too small image size and frame rate
+        // Also check the limit on current down-sampling state
+
+        // No spatial sampling if image size is too small (QCIF)
+        if ( (_width * _height) <= MIN_IMAGE_SIZE  ||
+            _stateDecFactorSpatial >= MAX_SPATIAL_DOWN_FACT)
+        {
+            _qm->spatialWidthFact = 1;
+            _qm->spatialHeightFact = 1;
+        }
+
+        // No frame rate reduction below some point:
+        // use the (average) incoming frame rate
+        if ( avgIncomingFrameRate <= MIN_FRAME_RATE_QM  ||
+            _stateDecFactorTemp >= MAX_TEMP_DOWN_FACT)
+        {
+            _qm->temporalFact = 1;
+        }
+
+        // No down-sampling if current downsampling state is above threshold
+        if (_stateDecFactorTemp * _stateDecFactorSpatial >=
+            MAX_SPATIAL_TEMP_DOWN_FACT)
+        {
+            _qm->spatialWidthFact = 1;
+            _qm->spatialHeightFact = 1;
+            _qm->temporalFact = 1;
+        }
+        //
+        // Done with sanity checks on ST QM selection
+        //
+
+        // Update down-sampling states
+        _stateDecFactorSpatial = _stateDecFactorSpatial * _qm->spatialWidthFact
+            * _qm->spatialHeightFact;
+        _stateDecFactorTemp = _stateDecFactorTemp * _qm->temporalFact;
+
+        if (_qm->spatialWidthFact != 1 || _qm->spatialHeightFact != 1 ||
+            _qm->temporalFact != 1)
+        {
+
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo, -1,
+                         "Resolution reduction occurred"
+                         "Content Metrics are: Motion = %d , Spatial = %d, "
+                         "Rates are: Est. Trans. BR = %d, Avg.Target BR = %f",
+                         _motion.level, _spatial.level,
+                         estimatedTransRateDown, avgTargetRate);
+        }
+
+    }
+    else
+    {
+      *qm = _qm;
+      return VCM_OK;
+    }
+    // Done with checking for resolution reduction
+
+    *qm = _qm;
+    return VCM_OK;
+
+
+}
+
+WebRtc_Word32
+VCMQmSelect::SelectSpatialDirectionMode(float transRate)
+{
+    // Default is 1x2 (H)
+
+    // For bit rates well below transitional rate, we select 2x2
+    if ( _targetBitRate < transRate * RATE_RED_SPATIAL_2X2 )
+    {
+        _qm->spatialWidthFact = 2;
+        _qm->spatialHeightFact = 2;
+        return VCM_OK;
+    }
+
+    // Otherwise check prediction errors, aspect ratio, horizontalness
+
+    float spatialErr = _contentMetrics->spatialPredErr;
+    float spatialErrH = _contentMetrics->spatialPredErrH;
+    float spatialErrV = _contentMetrics->spatialPredErrV;
+
+    // Favor 1x2 if aspect_ratio is 16:9
+    if (_aspectRatio >= 16.0f / 9.0f )
+    {
+        //check if 1x2 has lowest prediction error
+        if (spatialErrH < spatialErr && spatialErrH < spatialErrV)
+        {
+            return VCM_OK;
+        }
+    }
+
+    // Check for 2x2 selection: favor 2x2 over 1x2 and 2x1
+    if (spatialErr < spatialErrH * (1.0f + SPATIAL_ERR_2X2_VS_H) &&
+        spatialErr < spatialErrV * (1.0f + SPATIAL_ERR_2X2_VS_V))
+    {
+        _qm->spatialWidthFact = 2;
+        _qm->spatialHeightFact = 2;
+         return VCM_OK;
+    }
+
+    // Check for 2x1 selection:
+    if (spatialErrV < spatialErrH * (1.0f - SPATIAL_ERR_V_VS_H) &&
+        spatialErrV < spatialErr * (1.0f - SPATIAL_ERR_2X2_VS_V))
+    {
+        _qm->spatialWidthFact = 1;
+        _qm->spatialHeightFact = 2;
+         return VCM_OK;
+    }
+
+    return VCM_OK;
+}
+
+void
+VCMQmSelect::Coherence()
+{
+    float horizNZ  = _contentMetrics->motionHorizontalness;
+    float distortionNZ  = _contentMetrics->motionClusterDistortion;
+
+    // Coherence measure: combine horizontalness with cluster distortion
+    _coherence.value = COH_MAX;
+    if (distortionNZ > 0.)
+    {
+        _coherence.value = horizNZ / distortionNZ;
+    }
+    _coherence.value = VCM_MIN(COH_MAX, _coherence.value);
+
+    if (_coherence.value < COHERENCE_THR)
+    {
+        _coherence.level = kLow;
+    }
+    else
+    {
+        _coherence.level = kHigh;
+    }
+
+}
+
+void
+VCMQmSelect::MotionNFD()
+{
+    _motion.value = _contentMetrics->motionMagnitudeNZ;
+
+    // Determine motion level
+    if (_motion.value < LOW_MOTION_NFD)
+    {
+        _motion.level = kLow;
+    }
+    else if (_motion.value > HIGH_MOTION_NFD)
+    {
+        _motion.level  = kHigh;
+    }
+    else
+    {
+        _motion.level = kDefault;
+    }
+
+}
+
+void
+VCMQmSelect::Motion()
+{
+
+    float sizeZeroMotion = _contentMetrics->sizeZeroMotion;
+    float motionMagNZ = _contentMetrics->motionMagnitudeNZ;
+
+    // Take product of size and magnitude with equal weight
+    _motion.value = (1.0f - sizeZeroMotion) * motionMagNZ;
+
+    // Stabilize: motionMagNZ could be large when only a
+    // few motion blocks are non-zero
+    _stationaryMotion = false;
+    if (sizeZeroMotion > HIGH_ZERO_MOTION_SIZE)
+    {
+        _motion.value = 0.0f;
+        _stationaryMotion = true;
+    }
+    // Determine motion level
+    if (_motion.value < LOW_MOTION)
+    {
+        _motion.level = kLow;
+    }
+    else if (_motion.value > HIGH_MOTION)
+    {
+        _motion.level  = kHigh;
+    }
+    else
+    {
+        _motion.level = kDefault;
+    }
+}
+
+
+void
+VCMQmSelect::Spatial()
+{
+    float spatialErr =  _contentMetrics->spatialPredErr;
+    float spatialErrH = _contentMetrics->spatialPredErrH;
+    float spatialErrV = _contentMetrics->spatialPredErrV;
+    // Spatial measure: take average of 3 prediction errors
+    _spatial.value = (spatialErr + spatialErrH + spatialErrV) / 3.0f;
+
+    float scale = 1.0f;
+    // Reduce thresholds for HD scenes
+    if (_imageType > 3)
+    {
+        scale = (float)SCALE_TEXTURE_HD;
+    }
+
+    if (_spatial.value > scale * HIGH_TEXTURE)
+    {
+        _spatial.level = kHigh;
+    }
+    else if (_spatial.value < scale * LOW_TEXTURE)
+    {
+        _spatial.level = kLow;
+    }
+    else
+    {
+         _spatial.level = kDefault;
+    }
+}
+
+
+WebRtc_Word32
+VCMQmSelect::SetMaxRateForQM(WebRtc_UWord32 width, WebRtc_UWord32 height)
+{
+    // Match image type
+    WebRtc_UWord32 imageSize = width * height;
+
+    if (imageSize < kFrameSizeTh[0])
+    {
+        _imageType  = 0;
+    }
+    else if (imageSize < kFrameSizeTh[1])
+    {
+        _imageType  = 1;
+    }
+    else if (imageSize < kFrameSizeTh[2])
+    {
+        _imageType  = 2;
+    }
+    else if (imageSize < kFrameSizeTh[3])
+    {
+        _imageType  = 3;
+    }
+    else if (imageSize < kFrameSizeTh[4])
+    {
+        _imageType  = 4;
+    }
+    else if (imageSize < kFrameSizeTh[5])
+    {
+        _imageType  = 5;
+    }
+    else
+    {
+        _imageType  = 6;
+    }
+
+    // Set max rate based on image size
+    _maxRateQM = kMaxRateQm[_imageType];
+
+    return VCM_OK;
+}
+
+} // end of namespace
diff --git a/src/modules/video_coding/main/source/qm_select.h b/src/modules/video_coding/main/source/qm_select.h
new file mode 100644
index 0000000..3bca4bc
--- /dev/null
+++ b/src/modules/video_coding/main/source/qm_select.h
@@ -0,0 +1,182 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_QM_SELECT_H_
+#define WEBRTC_MODULES_VIDEO_CODING_QM_SELECT_H_
+
+#include "typedefs.h"
+#include "common_types.h"
+/************************/
+/* Quality Modes       */
+/**********************/
+
+namespace webrtc
+{
+
+struct VideoContentMetrics;
+
+struct VCMQualityMode
+{
+    VCMQualityMode():spatialWidthFact(1), spatialHeightFact(1),
+        temporalFact(1){}
+    void Reset()
+    {
+        spatialWidthFact = 1;
+        spatialHeightFact = 1;
+        temporalFact = 1;
+    }
+
+    WebRtc_UWord16  spatialWidthFact;
+    WebRtc_UWord16  spatialHeightFact;
+    WebRtc_UWord16  temporalFact;
+};
+
+enum VCMMagValues
+{
+    kLow,
+    kHigh,
+    kDefault //default do nothing mode
+};
+
+struct VCMContFeature
+{
+    VCMContFeature(): value(0.0f), level(kDefault){}
+
+    void Reset()
+    {
+        value = 0.0f;
+        level = kDefault;
+    }
+
+    float value;
+    VCMMagValues level;
+};
+
+class VCMQmSelect
+{
+public:
+    VCMQmSelect();
+    ~VCMQmSelect();
+
+    // Initialize:
+    WebRtc_Word32 Initialize(float bitRate, float userFrameRate,
+                             WebRtc_UWord32 width, WebRtc_UWord32 height);
+
+    // Allow the user to set preferences: favor frame rate/resolution
+    WebRtc_Word32 SetPreferences(WebRtc_Word8 resolPref);
+
+    // Extract ST (spatio-temporal) QM behavior and make decision
+    // Inputs: qm: Reference to the quality modes pointer
+    WebRtc_Word32 SelectQuality(VCMQualityMode** qm);
+
+    // Update QM with actual bit rate
+    // (size of the latest encoded frame) and frame type.
+    void UpdateEncodedSize(WebRtc_Word64 encodedSize,
+                           FrameType encodedFrameType);
+
+    // Update QM with new bit/frame/loss rates from SetTargetRates
+    void UpdateRates(float targetBitRate, float avgSentRate,
+                     float incomingFrameRate, WebRtc_UWord8 packetLoss);
+
+    // Update QM with the content metrics
+    void UpdateContent(const VideoContentMetrics*  contentMetrics);
+
+    // Adjust FEC rate based on content
+    WebRtc_UWord8  AdjustFecFactor(WebRtc_UWord8 codeRateDelta, float totalRate,
+                                   float frameRate, WebRtc_UWord16 rttTime,
+                                   WebRtc_UWord8 packetLoss);
+
+
+    // Select 1x2,2x2,2x2 spatial sampling mode
+    WebRtc_Word32 SelectSpatialDirectionMode(float transRate);
+
+    // Reset values prior to QMSelect
+    void ResetQM();
+
+    // Reset rate quantities and counter values after every QMSelect call
+    void ResetRates();
+
+    // Reset all
+    void Reset();
+private:
+
+    // Compute spatial texture magnitude and level
+    void Spatial();
+
+    // Compute motion magnitude and level
+    void Motion();
+
+    // Compute motion magnitude and level for NFD metric
+    void MotionNFD();
+
+    // Compute coherence magnitude and level
+    void Coherence();
+
+    // Set the max rate for QM selection
+    WebRtc_Word32 SetMaxRateForQM(WebRtc_UWord32 width, WebRtc_UWord32 height);
+
+    // Content Data
+    const VideoContentMetrics*    _contentMetrics;
+
+    // Encoder rate control parameters, network parameters
+    float                        _targetBitRate;
+    float                        _userFrameRate;
+    float                        _incomingFrameRate;
+    float                        _perFrameBandwidth;
+    float                        _bufferLevel;
+    float                        _sumTargetRate;
+    float                        _sumIncomingFrameRate;
+    float                        _sumSeqRateMM;
+    float                        _sumFrameRateMM;
+    float                        _sumPacketLoss;
+    float                        _prevTotalRate;
+    WebRtc_UWord16               _prevRttTime;
+    WebRtc_UWord8                _prevPacketLoss;
+    WebRtc_Word64                _sumEncodedBytes;
+
+    // Encoder and native frame sizes
+    WebRtc_UWord32               _width;
+    WebRtc_UWord32               _height;
+    WebRtc_UWord32               _nativeWidth;
+    WebRtc_UWord32               _nativeHeight;
+    WebRtc_UWord8                _stateDecFactorSpatial;
+
+    WebRtc_UWord32               _nativeFrameRate;
+    WebRtc_UWord8                _stateDecFactorTemp;
+
+    // Counters
+    WebRtc_UWord32               _frameCnt;
+    WebRtc_UWord32               _frameCntDelta;
+    WebRtc_UWord32               _updateRateCnt;
+    WebRtc_UWord32               _lowBufferCnt;
+
+    // Content L/M/H values
+    VCMContFeature               _motion;
+    VCMContFeature               _spatial;
+    VCMContFeature               _coherence;
+    bool                         _stationaryMotion;
+
+    // Aspect ratio
+    float                        _aspectRatio;
+
+    // Max rate to saturate the transitionalRate
+    WebRtc_UWord32               _maxRateQM;
+    WebRtc_UWord8                _imageType;
+
+    // User preference for resolution or qmax change
+    WebRtc_UWord8                _userResolutionPref;
+    bool                         _init;
+    VCMQualityMode*              _qm;
+
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_QM_SELECT_H_
diff --git a/src/modules/video_coding/main/source/qm_select_data.h b/src/modules/video_coding/main/source/qm_select_data.h
new file mode 100644
index 0000000..813c110
--- /dev/null
+++ b/src/modules/video_coding/main/source/qm_select_data.h
@@ -0,0 +1,185 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_SOURCE_QM_SELECT_DATA_H_
+#define WEBRTC_MODULES_VIDEO_CODING_SOURCE_QM_SELECT_DATA_H_
+
+/***************************************************************
+*QMSelectData.h
+* This file includes parameters for content-aware media optimization
+****************************************************************/
+
+#include "typedefs.h"
+
+namespace webrtc
+{
+
+//
+// PARAMETERS FOR RESOLUTION ADAPTATION
+//
+
+// Initial level of buffer in secs: should corresponds to wrapper settings
+#define INIT_BUFFER_LEVEL 0.5
+
+// Threshold of (max) buffer size below which we consider too low (underflow)
+#define PERC_BUFFER_THR  0.10
+
+// Threshold on rate mismatch
+#define MAX_RATE_MM  0.5
+
+// Avoid outliers in seq-rate MM
+#define THRESH_SUM_MM 1000
+
+// Threshold on the occurrences of low buffer levels
+#define MAX_BUFFER_LOW 0.5
+
+// Factor for transitional rate for going back up in resolution
+#define TRANS_RATE_SCALE_UP_SPATIAL     1.25
+#define TRANS_RATE_SCALE_UP_TEMP        1.25
+
+// Threshold on packet loss rate, above which favor resolution reduction
+#define LOSS_THR 0.1
+
+// Factor for reducing transitonal bitrate under packet loss
+#define LOSS_RATE_FAC 1.0
+
+// Maximum possible transitional rate for down-sampling:
+// (units in kbps), for 30fps
+const WebRtc_UWord16 kMaxRateQm[7] = {
+    100,  //QCIF
+    500,  //CIF
+    800,  //VGA
+    1500, //4CIF
+    2000, //720 HD 4:3,
+    2500, //720 HD 16:9
+    3000  //1080HD
+};
+
+// Scale for transitional rate: based on content class
+// motion=L/H/D,spatial==L/H/D: for low, high, middle levels
+const float kScaleTransRateQm[18] = {
+    //4CIF and lower
+    0.25f,       // L, L
+    0.75f,       // L, H
+    0.75f,       // L, D
+    0.75f,       // H ,L
+    0.50f,       // H, H
+    0.50f,       // H, D
+    0.50f,       // D, L
+    0.63f,       // D, D
+    0.25f,       // D, H
+
+    //over 4CIF: WHD, HD
+    0.25f,       // L, L
+    0.75f,       // L, H
+    0.75f,       // L, D
+    0.75f,       // H ,L
+    0.50f,       // H, H
+    0.50f,       // H, D
+    0.50f,       // D, L
+    0.63f,       // D, D
+    0.25f        // D, H
+};
+
+// Action for down-sampling:
+// motion=L/H/D,spatial==L/H/D: for low, high, middle levels
+const WebRtc_UWord8 kSpatialAction[9] = {
+      1,       // L, L
+      1,       // L, H
+      1,       // L, D
+      4,       // H ,L
+      1,       // H, H
+      4,       // H, D
+      4,       // D, L
+      1,       // D, D
+      1,       // D, H
+};
+
+const WebRtc_UWord8 kTemporalAction[9] = {
+      1,       // L, L
+      2,       // L, H
+      2,       // L, D
+      1,       // H ,L
+      2,       // H, H
+      1,       // H, D
+      1,       // D, L
+      2,       // D, D
+      1,       // D, H
+};
+
+// Control the total amount of down-sampling allowed
+#define MAX_SPATIAL_DOWN_FACT       4
+#define MAX_TEMP_DOWN_FACT          4
+#define MAX_SPATIAL_TEMP_DOWN_FACT  8
+
+// Minimum image size for a spatial down-sampling:
+// no spatial down-sampling if input size <= MIN_IMAGE_SIZE
+#define MIN_IMAGE_SIZE  25344 //176*144
+
+// Minimum frame rate for temporal down-sampling:
+// no frame rate reduction if incomingFrameRate <= MIN_FRAME_RATE
+#define MIN_FRAME_RATE_QM  8
+
+// Boundaries for the closest standard frame size
+const WebRtc_UWord32 kFrameSizeTh[6] = {
+    63360,    //between 176*144 and 352*288
+    204288,   //between 352*288 and 640*480
+    356352,   //between 640*480 and 704*576
+    548352,   //between 704*576 and 960*720
+    806400,   //between 960*720 and 1280*720
+    1497600,  // between 1280*720 and 1920*1080
+};
+
+
+//
+// PARAMETERS FOR FEC ADJUSTMENT: TODO (marpan)
+//
+
+
+//
+// PARAMETETS FOR SETTING LOW/HIGH STATES OF CONTENT METRICS:
+//
+
+// Threshold to determine if high amount of zero_motion
+#define HIGH_ZERO_MOTION_SIZE 0.95
+
+// Thresholds for motion:
+// motion level is derived from motion vectors: motion = size_nz*magn_nz
+#define HIGH_MOTION 0.7
+#define LOW_MOTION  0.4
+
+// Thresholds for motion: motion level is from NFD
+#define HIGH_MOTION_NFD 0.075
+#define LOW_MOTION_NFD  0.04
+
+// Thresholds for spatial prediction error:
+// this is appLied on the min(2x2,1x2,2x1)
+#define HIGH_TEXTURE 0.035
+#define LOW_TEXTURE  0.025
+
+// Used to reduce thresholds for HD scenes: correction factor since higher
+// correlation in HD scenes means lower spatial prediction error
+#define SCALE_TEXTURE_HD 0.9;
+
+// Thresholds for distortion and horizontalness:
+// applied on product: horiz_nz/dist_nz
+#define COHERENCE_THR   1.0
+#define COH_MAX 10
+
+// percentage reduction in transitional bitrate for 2x2 selected over 1x2/2x1
+#define RATE_RED_SPATIAL_2X2    0.6
+
+#define SPATIAL_ERR_2X2_VS_H    0.1  //percentage to favor 2x2
+#define SPATIAL_ERR_2X2_VS_V    0.1  //percentage to favor 2x2 over V
+#define SPATIAL_ERR_V_VS_H      0.1  //percentage to favor H over V
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_SOURCE_QM_SELECT_DATA_H_
diff --git a/src/modules/video_coding/main/source/receiver.cc b/src/modules/video_coding/main/source/receiver.cc
new file mode 100644
index 0000000..676bab8
--- /dev/null
+++ b/src/modules/video_coding/main/source/receiver.cc
@@ -0,0 +1,452 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "video_coding.h"
+#include "trace.h"
+#include "encoded_frame.h"
+#include "internal_defines.h"
+#include "receiver.h"
+#include "tick_time.h"
+
+#include <assert.h>
+
+namespace webrtc {
+
+VCMReceiver::VCMReceiver(VCMTiming& timing,
+                         WebRtc_Word32 vcmId,
+                         WebRtc_Word32 receiverId,
+                         bool master)
+:
+_critSect(*CriticalSectionWrapper::CreateCriticalSection()),
+_vcmId(vcmId),
+_receiverId(receiverId),
+_master(master),
+_jitterBuffer(vcmId, receiverId, master),
+_timing(timing),
+_renderWaitEvent(*new VCMEvent()),
+_state(kPassive)
+{
+}
+
+VCMReceiver::~VCMReceiver()
+{
+    _renderWaitEvent.Set();
+    delete &_renderWaitEvent;
+    delete &_critSect;
+}
+
+WebRtc_Word32
+VCMReceiver::Initialize()
+{
+    CriticalSectionScoped cs(_critSect);
+    if (!_jitterBuffer.Running())
+    {
+        _jitterBuffer.Start();
+    }
+    else
+    {
+        _jitterBuffer.Flush();
+    }
+    _renderWaitEvent.Reset();
+    if (_master)
+    {
+        _state = kReceiving;
+    }
+    else
+    {
+        _state = kPassive;
+        SetNackMode(kNoNack);
+    }
+    return VCM_OK;
+}
+
+void VCMReceiver::UpdateRtt(WebRtc_UWord32 rtt)
+{
+    _jitterBuffer.UpdateRtt(rtt);
+}
+
+WebRtc_Word32
+VCMReceiver::InsertPacket(const VCMPacket& packet,
+                          WebRtc_UWord16 frameWidth,
+                          WebRtc_UWord16 frameHeight)
+{
+    // Find an empty frame
+    VCMEncodedFrame *buffer = NULL;
+    const WebRtc_Word32 error = _jitterBuffer.GetFrame(packet, buffer);
+    if (error == VCM_OLD_PACKET_ERROR)
+    {
+        return VCM_OK;
+    }
+    else if (error < 0)
+    {
+        return error;
+    }
+
+    {
+        CriticalSectionScoped cs(_critSect);
+
+        if (frameWidth && frameHeight)
+        {
+            buffer->SetEncodedSize(static_cast<WebRtc_UWord32>(frameWidth),
+                                   static_cast<WebRtc_UWord32>(frameHeight));
+        }
+
+        if (_master)
+        {
+            // Only trace the primary receiver to make it possible
+            // to parse and plot the trace file.
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                       "Packet seqNo %u of frame %u at %u",
+                       packet.seqNum, packet.timestamp,
+                       MaskWord64ToUWord32(VCMTickTime::MillisecondTimestamp()));
+        }
+
+        const bool emptyFrame = (buffer->Length() == 0);
+        const WebRtc_Word64 nowMs = VCMTickTime::MillisecondTimestamp();
+
+        WebRtc_Word64 renderTimeMs = _timing.RenderTimeMs(packet.timestamp, nowMs);
+
+        if (renderTimeMs < 0)
+        {
+            // Render time error. Assume that this is due to some change in
+            // the incoming video stream and reset the JB and the timing.
+            _jitterBuffer.Flush();
+            _timing.Reset();
+            return VCM_OK;
+        }
+        else if (renderTimeMs < nowMs - kMaxVideoDelayMs)
+        {
+            WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                "This frame should have been rendered more than %u ms ago."
+                "Flushing jitter buffer and resetting timing.", kMaxVideoDelayMs);
+            _jitterBuffer.Flush();
+            _timing.Reset();
+            return VCM_OK;
+        }
+        else if (_timing.TargetVideoDelay() > kMaxVideoDelayMs)
+        {
+            WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                "More than %u ms target delay. Flushing jitter buffer and resetting timing.",
+                kMaxVideoDelayMs);
+            _jitterBuffer.Flush();
+            _timing.Reset();
+            return VCM_OK;
+        }
+
+        // First packet received belonging to this frame.
+        if (buffer->Length() == 0)
+        {
+            const WebRtc_Word64 nowMs = VCMTickTime::MillisecondTimestamp();
+            if (_master)
+            {
+                // Only trace the primary receiver to make it possible to parse and plot the trace file.
+                WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                           "First packet of frame %u at %u", packet.timestamp,
+                           MaskWord64ToUWord32(nowMs));
+            }
+            renderTimeMs = _timing.RenderTimeMs(packet.timestamp, nowMs);
+            if (renderTimeMs >= 0)
+            {
+                buffer->SetRenderTime(renderTimeMs);
+            }
+            else
+            {
+                buffer->SetRenderTime(nowMs);
+            }
+        }
+
+        // Insert packet into jitter buffer
+        // both media and empty packets
+        const VCMFrameBufferEnum ret = _jitterBuffer.InsertPacket(buffer, packet);
+
+        if (ret < 0)
+        {
+            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                       "Error inserting packet seqNo=%u, timeStamp=%u",
+                       packet.seqNum, packet.timestamp);
+            return VCM_JITTER_BUFFER_ERROR;
+        }
+    }
+    return VCM_OK;
+}
+
+VCMEncodedFrame*
+VCMReceiver::FrameForDecoding(WebRtc_UWord16 maxWaitTimeMs, WebRtc_Word64& nextRenderTimeMs,
+                              bool renderTiming, VCMReceiver* dualReceiver)
+{
+    // No need to enter the critical section here since the jitter buffer
+    // is thread-safe.
+    FrameType incomingFrameType = kVideoFrameDelta;
+    nextRenderTimeMs = -1;
+    const WebRtc_Word64 startTimeMs = VCMTickTime::MillisecondTimestamp();
+    WebRtc_Word64 ret = _jitterBuffer.GetNextTimeStamp(maxWaitTimeMs,
+                                                       incomingFrameType,
+                                                       nextRenderTimeMs);
+    if (ret < 0)
+    {
+        // No timestamp in jitter buffer at the moment
+        return NULL;
+    }
+    const WebRtc_UWord32 timeStamp = static_cast<WebRtc_UWord32>(ret);
+
+    // Update the timing
+    _timing.SetRequiredDelay(_jitterBuffer.GetEstimatedJitterMS());
+    _timing.UpdateCurrentDelay(timeStamp);
+
+    const WebRtc_Word32 tempWaitTime = maxWaitTimeMs -
+            static_cast<WebRtc_Word32>(VCMTickTime::MillisecondTimestamp() - startTimeMs);
+    WebRtc_UWord16 newMaxWaitTime = static_cast<WebRtc_UWord16>(VCM_MAX(tempWaitTime, 0));
+
+    VCMEncodedFrame* frame = NULL;
+
+    if (renderTiming)
+    {
+        frame = FrameForDecoding(newMaxWaitTime, nextRenderTimeMs, dualReceiver);
+    }
+    else
+    {
+        frame = FrameForRendering(newMaxWaitTime, nextRenderTimeMs, dualReceiver);
+    }
+
+    if (frame != NULL)
+    {
+        bool retransmitted = false;
+        const WebRtc_Word64 lastPacketTimeMs =
+                _jitterBuffer.LastPacketTime(frame, retransmitted);
+        if (lastPacketTimeMs >= 0 && !retransmitted)
+        {
+            // We don't want to include timestamps which have suffered from retransmission
+            // here, since we compensate with extra retransmission delay within
+            // the jitter estimate.
+            _timing.IncomingTimestamp(timeStamp, lastPacketTimeMs);
+        }
+        if (dualReceiver != NULL)
+        {
+            dualReceiver->UpdateState(*frame);
+        }
+    }
+    return frame;
+}
+
+VCMEncodedFrame*
+VCMReceiver::FrameForDecoding(WebRtc_UWord16 maxWaitTimeMs,
+                              WebRtc_Word64 nextRenderTimeMs,
+                              VCMReceiver* dualReceiver)
+{
+    // How long can we wait until we must decode the next frame
+    WebRtc_UWord32 waitTimeMs = _timing.MaxWaitingTime(nextRenderTimeMs,
+                                                       VCMTickTime::MillisecondTimestamp());
+
+    // Try to get a complete frame from the jitter buffer
+    VCMEncodedFrame* frame = _jitterBuffer.GetCompleteFrameForDecoding(0);
+
+    if (frame == NULL && maxWaitTimeMs == 0 && waitTimeMs > 0)
+    {
+        // If we're not allowed to wait for frames to get complete we must calculate if
+        // it's time to decode, and if it's not we will just return for now.
+        return NULL;
+    }
+
+    if (frame == NULL)
+    {
+        // Wait for a complete frame
+        waitTimeMs = VCM_MIN(waitTimeMs, maxWaitTimeMs);
+        frame = _jitterBuffer.GetCompleteFrameForDecoding(waitTimeMs);
+    }
+    if (frame == NULL)
+    {
+        // Get an incomplete frame
+        if (_timing.MaxWaitingTime(nextRenderTimeMs, VCMTickTime::MillisecondTimestamp()) > 0)
+        {
+            // Still time to wait for a complete frame
+            return NULL;
+        }
+
+        // No time left to wait, we must decode this frame now.
+        const bool dualReceiverEnabledAndPassive = dualReceiver != NULL &&
+                                                    dualReceiver->State() == kPassive &&
+                                                    dualReceiver->NackMode() == kNackInfinite;
+        if (dualReceiverEnabledAndPassive && !_jitterBuffer.CompleteSequenceWithNextFrame())
+        {
+            // Jitter buffer state might get corrupt with this frame.
+            dualReceiver->CopyJitterBufferStateFromReceiver(*this);
+        }
+
+        frame = _jitterBuffer.GetFrameForDecoding();
+    }
+    return frame;
+}
+
+VCMEncodedFrame*
+VCMReceiver::FrameForRendering(WebRtc_UWord16 maxWaitTimeMs,
+                               WebRtc_Word64 nextRenderTimeMs,
+                               VCMReceiver* dualReceiver)
+{
+    // How long MUST we wait until we must decode the next frame. This is different for the case
+    // where we have a renderer which can render at a specified time. Here we must wait as long
+    // as possible before giving the frame to the decoder, which will render the frame as soon
+    // as it has been decoded.
+    WebRtc_UWord32 waitTimeMs = _timing.MaxWaitingTime(nextRenderTimeMs,
+                                                       VCMTickTime::MillisecondTimestamp());
+    if (maxWaitTimeMs < waitTimeMs)
+    {
+        // If we're not allowed to wait until the frame is supposed to be rendered
+        // we will have to return NULL for now.
+        return NULL;
+    }
+    // Wait until it's time to render
+    _renderWaitEvent.Wait(waitTimeMs);
+
+    // Get a complete frame if possible
+    VCMEncodedFrame* frame = _jitterBuffer.GetCompleteFrameForDecoding(0);
+
+    if (frame == NULL)
+    {
+        // Get an incomplete frame
+        const bool dualReceiverEnabledAndPassive = dualReceiver != NULL &&
+                                                   dualReceiver->State() == kPassive &&
+                                                   dualReceiver->NackMode() == kNackInfinite;
+        if (dualReceiverEnabledAndPassive && !_jitterBuffer.CompleteSequenceWithNextFrame())
+        {
+            // Jitter buffer state might get corrupt with this frame.
+            dualReceiver->CopyJitterBufferStateFromReceiver(*this);
+        }
+
+        frame = _jitterBuffer.GetFrameForDecoding();
+    }
+    return frame;
+}
+
+void
+VCMReceiver::ReleaseFrame(VCMEncodedFrame* frame)
+{
+    _jitterBuffer.ReleaseFrame(frame);
+}
+
+WebRtc_Word32
+VCMReceiver::ReceiveStatistics(WebRtc_UWord32& bitRate, WebRtc_UWord32& frameRate)
+{
+    const WebRtc_Word32 ret = _jitterBuffer.GetUpdate(frameRate, bitRate);
+    bitRate /= 1000; // Should be in kbps
+    return ret;
+}
+
+WebRtc_Word32
+VCMReceiver::ReceivedFrameCount(VCMFrameCount& frameCount) const
+{
+    return _jitterBuffer.GetFrameStatistics(frameCount.numDeltaFrames,
+                                            frameCount.numKeyFrames);
+}
+
+void
+VCMReceiver::SetNackMode(VCMNackMode nackMode)
+{
+    CriticalSectionScoped cs(_critSect);
+    _jitterBuffer.SetNackMode(nackMode);
+    if (!_master)
+    {
+        _state = kPassive; // The dual decoder defaults to passive
+    }
+}
+
+VCMNackMode
+VCMReceiver::NackMode() const
+{
+    CriticalSectionScoped cs(_critSect);
+    return _jitterBuffer.GetNackMode();
+}
+
+VCMNackStatus
+VCMReceiver::NackList(WebRtc_UWord16* nackList, WebRtc_UWord16& size)
+{
+    bool extended = false;
+    WebRtc_UWord16 nackListSize = 0;
+    WebRtc_UWord16* internalNackList = _jitterBuffer.GetNackList(nackListSize, extended);
+    if (internalNackList == NULL && nackListSize == 0xffff)
+    {
+        // This combination is used to trigger key frame requests.
+        size = 0;
+        return kNackKeyFrameRequest;
+    }
+    if (nackListSize > size)
+    {
+        size = nackListSize;
+        return kNackNeedMoreMemory;
+    }
+    memcpy(nackList, internalNackList, nackListSize * sizeof(WebRtc_UWord16));
+    size = nackListSize;
+    return kNackOk;
+}
+
+// Decide whether we should change decoder state. This should be done if the dual decoder
+// has caught up with the decoder decoding with packet losses.
+bool
+VCMReceiver::DualDecoderCaughtUp(VCMEncodedFrame* dualFrame, VCMReceiver& dualReceiver) const
+{
+    if (dualFrame == NULL)
+    {
+        return false;
+    }
+    if (_jitterBuffer.LastDecodedTimestamp() == dualFrame->TimeStamp())
+    {
+        dualReceiver.UpdateState(kWaitForPrimaryDecode);
+        return true;
+    }
+    return false;
+}
+
+void
+VCMReceiver::CopyJitterBufferStateFromReceiver(const VCMReceiver& receiver)
+{
+    _jitterBuffer = receiver._jitterBuffer;
+}
+
+VCMReceiverState
+VCMReceiver::State() const
+{
+    CriticalSectionScoped cs(_critSect);
+    return _state;
+}
+
+void
+VCMReceiver::UpdateState(VCMReceiverState newState)
+{
+    CriticalSectionScoped cs(_critSect);
+    assert(!(_state == kPassive && newState == kWaitForPrimaryDecode));
+//    assert(!(_state == kReceiving && newState == kPassive));
+    _state = newState;
+}
+
+void
+VCMReceiver::UpdateState(VCMEncodedFrame& frame)
+{
+    if (_jitterBuffer.GetNackMode() == kNoNack)
+    {
+        // Dual decoder mode has not been enabled.
+        return;
+    }
+    // Update the dual receiver state
+    if (frame.Complete() && frame.FrameType() == kVideoFrameKey)
+    {
+        UpdateState(kPassive);
+    }
+    if (State() == kWaitForPrimaryDecode &&
+        frame.Complete() && !frame.MissingFrame())
+    {
+        UpdateState(kPassive);
+    }
+    if (frame.MissingFrame() || !frame.Complete())
+    {
+        // State was corrupted, enable dual receiver.
+        UpdateState(kReceiving);
+    }
+}
+
+}
diff --git a/src/modules/video_coding/main/source/receiver.h b/src/modules/video_coding/main/source/receiver.h
new file mode 100644
index 0000000..0ca6994
--- /dev/null
+++ b/src/modules/video_coding/main/source/receiver.h
@@ -0,0 +1,96 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_RECEIVER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_RECEIVER_H_
+
+#include "critical_section_wrapper.h"
+#include "jitter_buffer.h"
+#include "timing.h"
+#include "packet.h"
+
+namespace webrtc
+{
+
+class VCMEncodedFrame;
+
+enum VCMNackStatus
+{
+    kNackOk,
+    kNackNeedMoreMemory,
+    kNackKeyFrameRequest
+};
+
+
+enum VCMReceiverState
+{
+    kReceiving,
+    kPassive,
+    kWaitForPrimaryDecode
+};
+
+class VCMReceiver
+{
+public:
+    VCMReceiver(VCMTiming& timing,
+                WebRtc_Word32 vcmId = -1,
+                WebRtc_Word32 receiverId = -1,
+                bool master = true);
+    ~VCMReceiver();
+
+    WebRtc_Word32 Initialize();
+    void UpdateRtt(WebRtc_UWord32 rtt);
+    WebRtc_Word32 InsertPacket(const VCMPacket& packet,
+                               WebRtc_UWord16 frameWidth,
+                               WebRtc_UWord16 frameHeight);
+    VCMEncodedFrame* FrameForDecoding(WebRtc_UWord16 maxWaitTimeMs,
+                                      WebRtc_Word64& nextRenderTimeMs,
+                                      bool renderTiming = true,
+                                      VCMReceiver* dualReceiver = NULL);
+    void ReleaseFrame(VCMEncodedFrame* frame);
+    WebRtc_Word32 ReceiveStatistics(WebRtc_UWord32& bitRate, WebRtc_UWord32& frameRate);
+    WebRtc_Word32 ReceivedFrameCount(VCMFrameCount& frameCount) const;
+
+    // NACK
+    void SetNackMode(VCMNackMode nackMode);
+    VCMNackMode NackMode() const;
+    VCMNackStatus NackList(WebRtc_UWord16* nackList, WebRtc_UWord16& size);
+
+    // Dual decoder
+    bool DualDecoderCaughtUp(VCMEncodedFrame* dualFrame, VCMReceiver& dualReceiver) const;
+    VCMReceiverState State() const;
+
+private:
+    VCMEncodedFrame* FrameForDecoding(WebRtc_UWord16 maxWaitTimeMs,
+                                      WebRtc_Word64 nextrenderTimeMs,
+                                      VCMReceiver* dualReceiver);
+    VCMEncodedFrame* FrameForRendering(WebRtc_UWord16 maxWaitTimeMs,
+                                       WebRtc_Word64 nextrenderTimeMs,
+                                       VCMReceiver* dualReceiver);
+    void CopyJitterBufferStateFromReceiver(const VCMReceiver& receiver);
+    void UpdateState(VCMReceiverState newState);
+    void UpdateState(VCMEncodedFrame& frame);
+    static WebRtc_Word32 GenerateReceiverId();
+
+    CriticalSectionWrapper&    _critSect;
+    WebRtc_Word32           _vcmId;
+    WebRtc_Word32           _receiverId;
+    bool                    _master;
+    VCMJitterBuffer         _jitterBuffer;
+    VCMTiming&              _timing;
+    VCMEvent&               _renderWaitEvent;
+    VCMReceiverState        _state;
+
+    static WebRtc_Word32    _receiverIdCounter;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_RECEIVER_H_
diff --git a/src/modules/video_coding/main/source/rtt_filter.cc b/src/modules/video_coding/main/source/rtt_filter.cc
new file mode 100644
index 0000000..36f7660
--- /dev/null
+++ b/src/modules/video_coding/main/source/rtt_filter.cc
@@ -0,0 +1,214 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "trace.h"
+#include "internal_defines.h"
+#include "rtt_filter.h"
+
+#include <cmath>
+#include <stdlib.h>
+#include <string.h>
+
+namespace webrtc {
+
+VCMRttFilter::VCMRttFilter(WebRtc_Word32 vcmId, WebRtc_Word32 receiverId)
+:
+_vcmId(vcmId),
+_receiverId(receiverId),
+_filtFactMax(35),
+_jumpStdDevs(2.5),
+_driftStdDevs(3.5),
+_detectThreshold(kMaxDriftJumpCount)
+{
+    Reset();
+}
+
+VCMRttFilter&
+VCMRttFilter::operator=(const VCMRttFilter& rhs)
+{
+    if (this != &rhs)
+    {
+        _gotNonZeroUpdate = rhs._gotNonZeroUpdate;
+        _avgRtt = rhs._avgRtt;
+        _varRtt = rhs._varRtt;
+        _maxRtt = rhs._maxRtt;
+        _filtFactCount = rhs._filtFactCount;
+        _jumpCount = rhs._jumpCount;
+        _driftCount = rhs._driftCount;
+        memcpy(_jumpBuf, rhs._jumpBuf, sizeof(_jumpBuf));
+        memcpy(_driftBuf, rhs._driftBuf, sizeof(_driftBuf));
+    }
+    return *this;
+}
+
+void
+VCMRttFilter::Reset()
+{
+    _gotNonZeroUpdate = false;
+    _avgRtt = 0;
+    _varRtt = 0;
+    _maxRtt = 0;
+    _filtFactCount = 1;
+    _jumpCount = 0;
+    _driftCount = 0;
+    memset(_jumpBuf, 0, kMaxDriftJumpCount);
+    memset(_driftBuf, 0, kMaxDriftJumpCount);
+}
+
+void
+VCMRttFilter::Update(WebRtc_UWord32 rttMs)
+{
+    if (!_gotNonZeroUpdate)
+    {
+        if (rttMs == 0)
+        {
+            return;
+        }
+        _gotNonZeroUpdate = true;
+    }
+
+    // Sanity check
+    if (rttMs > 3000)
+    {
+        rttMs = 3000;
+    }
+
+    double filtFactor = 0;
+    if (_filtFactCount > 1)
+    {
+        filtFactor = static_cast<double>(_filtFactCount - 1) / _filtFactCount;
+    }
+    _filtFactCount++;
+    if (_filtFactCount > _filtFactMax)
+    {
+        // This prevents filtFactor from going above
+        // (_filtFactMax - 1) / _filtFactMax,
+        // e.g., _filtFactMax = 50 => filtFactor = 49/50 = 0.98
+        _filtFactCount = _filtFactMax;
+    }
+    double oldAvg = _avgRtt;
+    double oldVar = _varRtt;
+    _avgRtt = filtFactor * _avgRtt + (1 - filtFactor) * rttMs;
+    _varRtt = filtFactor * _varRtt + (1 - filtFactor) *
+                (rttMs - _avgRtt) * (rttMs - _avgRtt);
+    _maxRtt = VCM_MAX(rttMs, _maxRtt);
+    if (!JumpDetection(rttMs) || !DriftDetection(rttMs))
+    {
+        // In some cases we don't want to update the statistics
+        _avgRtt = oldAvg;
+        _varRtt = oldVar;
+    }
+    WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+               "RttFilter Update: sample=%u avgRtt=%f varRtt=%f maxRtt=%u",
+               rttMs, _avgRtt, _varRtt, _maxRtt);
+}
+
+bool
+VCMRttFilter::JumpDetection(WebRtc_UWord32 rttMs)
+{
+    double diffFromAvg = _avgRtt - rttMs;
+    if (abs(diffFromAvg) > _jumpStdDevs * sqrt(_varRtt))
+    {
+        int diffSign = (diffFromAvg >= 0) ? 1 : -1;
+        int jumpCountSign = (_jumpCount >= 0) ? 1 : -1;
+        if (diffSign != jumpCountSign)
+        {
+            // Since the signs differ the samples currently
+            // in the buffer is useless as they represent a
+            // jump in a different direction.
+            _jumpCount = 0;
+        }
+        if (abs(_jumpCount) < kMaxDriftJumpCount)
+        {
+            // Update the buffer used for the short time
+            // statistics.
+            // The sign of the diff is used for updating the counter since
+            // we want to use the same buffer for keeping track of when
+            // the RTT jumps down and up.
+            _jumpBuf[abs(_jumpCount)] = rttMs;
+            _jumpCount += diffSign;
+        }
+        if (abs(_jumpCount) >= _detectThreshold)
+        {
+            // Detected an RTT jump
+            ShortRttFilter(_jumpBuf, abs(_jumpCount));
+            _filtFactCount = _detectThreshold + 1;
+            _jumpCount = 0;
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                       "Detected an RTT jump");
+        }
+        else
+        {
+            return false;
+        }
+    }
+    else
+    {
+        _jumpCount = 0;
+    }
+    return true;
+}
+
+bool
+VCMRttFilter::DriftDetection(WebRtc_UWord32 rttMs)
+{
+    if (_maxRtt - _avgRtt > _driftStdDevs * sqrt(_varRtt))
+    {
+        if (_driftCount < kMaxDriftJumpCount)
+        {
+            // Update the buffer used for the short time
+            // statistics.
+            _driftBuf[_driftCount] = rttMs;
+            _driftCount++;
+        }
+        if (_driftCount >= _detectThreshold)
+        {
+            // Detected an RTT drift
+            ShortRttFilter(_driftBuf, _driftCount);
+            _filtFactCount = _detectThreshold + 1;
+            _driftCount = 0;
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _receiverId),
+                       "Detected an RTT drift");
+        }
+    }
+    else
+    {
+        _driftCount = 0;
+    }
+    return true;
+}
+
+void
+VCMRttFilter::ShortRttFilter(WebRtc_UWord32* buf, WebRtc_UWord32 length)
+{
+    if (length == 0)
+    {
+        return;
+    }
+    _maxRtt = 0;
+    _avgRtt = 0;
+    for (WebRtc_UWord32 i=0; i < length; i++)
+    {
+        if (buf[i] > _maxRtt)
+        {
+            _maxRtt = buf[i];
+        }
+        _avgRtt += buf[i];
+    }
+    _avgRtt = _avgRtt / static_cast<double>(length);
+}
+
+WebRtc_UWord32
+VCMRttFilter::RttMs() const
+{
+    return static_cast<WebRtc_UWord32>(_maxRtt + 0.5);
+}
+
+}
diff --git a/src/modules/video_coding/main/source/rtt_filter.h b/src/modules/video_coding/main/source/rtt_filter.h
new file mode 100644
index 0000000..5ec85fd
--- /dev/null
+++ b/src/modules/video_coding/main/source/rtt_filter.h
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_RTT_FILTER_H_
+#define WEBRTC_MODULES_VIDEO_CODING_RTT_FILTER_H_
+
+#include "typedefs.h"
+
+namespace webrtc
+{
+
+class VCMRttFilter
+{
+public:
+    VCMRttFilter(WebRtc_Word32 vcmId = 0, WebRtc_Word32 receiverId = 0);
+
+    VCMRttFilter& operator=(const VCMRttFilter& rhs);
+
+    // Resets the filter.
+    void Reset();
+    // Updates the filter with a new sample.
+    void Update(WebRtc_UWord32 rttMs);
+    // A getter function for the current RTT level in ms.
+    WebRtc_UWord32 RttMs() const;
+
+private:
+    // The size of the drift and jump memory buffers
+    // and thus also the detection threshold for these
+    // detectors in number of samples.
+    enum { kMaxDriftJumpCount = 5 };
+    // Detects RTT jumps by comparing the difference between
+    // samples and average to the standard deviation.
+    // Returns true if the long time statistics should be updated
+    // and false otherwise
+    bool JumpDetection(WebRtc_UWord32 rttMs);
+    // Detects RTT drifts by comparing the difference between
+    // max and average to the standard deviation.
+    // Returns true if the long time statistics should be updated
+    // and false otherwise
+    bool DriftDetection(WebRtc_UWord32 rttMs);
+    // Computes the short time average and maximum of the vector buf.
+    void ShortRttFilter(WebRtc_UWord32* buf, WebRtc_UWord32 length);
+
+    WebRtc_Word32         _vcmId;
+    WebRtc_Word32         _receiverId;
+    bool                  _gotNonZeroUpdate;
+    double                _avgRtt;
+    double                _varRtt;
+    WebRtc_UWord32        _maxRtt;
+    WebRtc_UWord32        _filtFactCount;
+    const WebRtc_UWord32  _filtFactMax;
+    const double          _jumpStdDevs;
+    const double          _driftStdDevs;
+    WebRtc_Word32         _jumpCount;
+    WebRtc_Word32         _driftCount;
+    const WebRtc_Word32   _detectThreshold;
+    WebRtc_UWord32        _jumpBuf[kMaxDriftJumpCount];
+    WebRtc_UWord32        _driftBuf[kMaxDriftJumpCount];
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_RTT_FILTER_H_
diff --git a/src/modules/video_coding/main/source/session_info.cc b/src/modules/video_coding/main/source/session_info.cc
new file mode 100644
index 0000000..7145b29
--- /dev/null
+++ b/src/modules/video_coding/main/source/session_info.cc
@@ -0,0 +1,833 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "packet.h"
+#include "session_info.h"
+
+#include <string.h>
+#include <cassert>
+
+namespace webrtc {
+
+VCMSessionInfo::VCMSessionInfo():
+    _haveFirstPacket(false),
+    _markerBit(false),
+    _sessionNACK(false),
+    _completeSession(false),
+    _frameType(kVideoFrameDelta),
+    _previousFrameLoss(false),
+    _lowSeqNum(-1),
+    _highSeqNum(-1),
+    _highestPacketIndex(0),
+    _emptySeqNumLow(-1),
+    _emptySeqNumHigh(-1),
+    _markerSeqNum(-1)
+{
+    memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
+    memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
+    memset(_ORwithPrevByte, 0, sizeof(_ORwithPrevByte));
+}
+
+VCMSessionInfo::~VCMSessionInfo()
+{
+}
+
+WebRtc_Word32
+VCMSessionInfo::GetLowSeqNum() const
+{
+    return _lowSeqNum;
+}
+
+WebRtc_Word32
+VCMSessionInfo::GetHighSeqNum() const
+{
+    if (_emptySeqNumHigh != -1)
+    {
+        return _emptySeqNumHigh;
+    }
+    return _highSeqNum;
+}
+
+void
+VCMSessionInfo::Reset()
+{
+    _lowSeqNum = -1;
+    _highSeqNum = -1;
+    _emptySeqNumLow = -1;
+    _emptySeqNumHigh = -1;
+    _markerBit = false;
+    _haveFirstPacket = false;
+    _completeSession = false;
+    _frameType = kVideoFrameDelta;
+    _previousFrameLoss = false;
+    _sessionNACK = false;
+    _highestPacketIndex = 0;
+    _markerSeqNum = -1;
+    memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
+    memset(_naluCompleteness, kNaluUnset, sizeof(_naluCompleteness));
+    memset(_ORwithPrevByte, 0, sizeof(_ORwithPrevByte));
+}
+
+WebRtc_UWord32 VCMSessionInfo::GetSessionLength()
+{
+    WebRtc_UWord32 length = 0;
+    for (WebRtc_Word32 i = 0; i <= _highestPacketIndex; ++i)
+    {
+        length += _packetSizeBytes[i];
+    }
+    return length;
+}
+
+void
+VCMSessionInfo::SetStartSeqNumber(WebRtc_UWord16 seqNumber)
+{
+    _lowSeqNum = seqNumber;
+    _highSeqNum = seqNumber;
+}
+
+bool
+VCMSessionInfo::HaveStartSeqNumber()
+{
+    if (_lowSeqNum == -1 || _highSeqNum == -1)
+    {
+        return false;
+    }
+    return true;
+}
+
+WebRtc_UWord32
+VCMSessionInfo::InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
+                             WebRtc_Word32 packetIndex,
+                             const VCMPacket& packet)
+{
+    WebRtc_UWord32 moveLength = 0;
+    WebRtc_UWord32 returnLength = 0;
+    int i = 0;
+
+    // need to calc offset before updating _packetSizeBytes
+    WebRtc_UWord32 offset = 0;
+    WebRtc_UWord32 packetSize = 0;
+
+    // Store this packet length. Add length since we could have data present
+    // already (e.g. multicall case).
+    if (packet.bits)
+    {
+        packetSize = packet.sizeBytes;
+    }
+    else
+    {
+        packetSize = packet.sizeBytes +
+                     (packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
+    }
+
+    _packetSizeBytes[packetIndex] += packetSize;
+
+    // count only the one in our layer
+    for (i = 0; i < packetIndex; ++i)
+    {
+        offset += _packetSizeBytes[i];
+    }
+    for (i = packetIndex + 1; i <= _highestPacketIndex; ++i)
+    {
+        moveLength += _packetSizeBytes[i];
+    }
+    if (moveLength > 0)
+    {
+        memmove((void*)(ptrStartOfLayer + offset + packetSize),
+                        ptrStartOfLayer + offset, moveLength);
+    }
+
+    if (packet.bits)
+    {
+        // Add the packet without ORing end and start bytes together.
+        // This is done when the frame is fetched for decoding by calling
+        // GlueTogether().
+        _ORwithPrevByte[packetIndex] = true;
+        if (packet.dataPtr != NULL)
+        {
+            memcpy((void*)(ptrStartOfLayer + offset), packet.dataPtr,
+                   packetSize);
+        }
+        returnLength = packetSize;
+    }
+    else
+    {
+        _ORwithPrevByte[packetIndex] = false;
+        if (packet.dataPtr != NULL)
+        {
+            const unsigned char startCode[] = {0, 0, 0, 1};
+            if(packet.insertStartCode)
+            {
+                memcpy((void*)(ptrStartOfLayer + offset), startCode,
+                       kH264StartCodeLengthBytes);
+            }
+            memcpy((void*)(ptrStartOfLayer + offset
+                + (packet.insertStartCode ? kH264StartCodeLengthBytes : 0)),
+                packet.dataPtr,
+                packet.sizeBytes);
+        }
+        returnLength = packetSize;
+    }
+
+    if (packet.isFirstPacket)
+    {
+        _haveFirstPacket = true;
+    }
+    if (packet.markerBit)
+    {
+        _markerBit = true;
+        _markerSeqNum = packet.seqNum;
+    }
+     // Store information about if the packet is decodable as is or not.
+     _naluCompleteness[packetIndex] = packet.completeNALU;
+
+    UpdateCompleteSession();
+
+    return returnLength;
+}
+
+void
+VCMSessionInfo::UpdateCompleteSession()
+{
+    if (_haveFirstPacket && _markerBit)
+    {
+        // Do we have all the packets in this session?
+        bool completeSession = true;
+
+        for (int i = 0; i <= _highestPacketIndex; ++i)
+        {
+            if (_naluCompleteness[i] == kNaluUnset)
+            {
+                completeSession = false;
+                break;
+            }
+        }
+        _completeSession = completeSession;
+    }
+}
+
+bool VCMSessionInfo::IsSessionComplete()
+{
+    return _completeSession;
+}
+
+// Find the start and end index of packetIndex packet.
+// startIndex -1 if start not found endIndex = -1 if end index not found
+void
+VCMSessionInfo::FindNaluBorder(WebRtc_Word32 packetIndex,
+                               WebRtc_Word32& startIndex,
+                               WebRtc_Word32& endIndex)
+{
+        if (_naluCompleteness[packetIndex] == kNaluStart ||
+            _naluCompleteness[packetIndex] == kNaluComplete)
+        {
+            startIndex = packetIndex;
+        }
+        else // Need to find the start
+        {
+            for (startIndex = packetIndex - 1; startIndex >= 0; --startIndex)
+            {
+
+                if ((_naluCompleteness[startIndex] == kNaluComplete &&
+                     _packetSizeBytes[startIndex] > 0) ||
+                     // Found previous NALU.
+                     (_naluCompleteness[startIndex] == kNaluEnd &&
+                      startIndex > 0))
+                {
+                    startIndex++;
+                    break;
+                }
+                // This is where the NALU start.
+                if (_naluCompleteness[startIndex] == kNaluStart)
+                {
+                    break;
+                }
+            }
+        }
+
+        if (_naluCompleteness[packetIndex] == kNaluEnd ||
+             _naluCompleteness[packetIndex] == kNaluComplete)
+        {
+            endIndex = packetIndex;
+        }
+        else
+        {
+            // Find the next NALU
+            for (endIndex = packetIndex + 1; endIndex <= _highestPacketIndex;
+                 ++endIndex)
+            {
+                if ((_naluCompleteness[endIndex] == kNaluComplete &&
+                    _packetSizeBytes[endIndex] > 0) ||
+                    // Found next NALU.
+                    _naluCompleteness[endIndex] == kNaluStart)
+                {
+                    endIndex--;
+                    break;
+                }
+                if ( _naluCompleteness[endIndex] == kNaluEnd)
+                {
+                    // This is where the NALU end.
+                    break;
+                }
+            }
+            if (endIndex > _highestPacketIndex)
+            {
+                endIndex = -1;
+            }
+        }
+}
+
+// Deletes all packets between startIndex and endIndex
+WebRtc_UWord32
+VCMSessionInfo::DeletePackets(WebRtc_UWord8* ptrStartOfLayer,
+                              WebRtc_Word32 startIndex,
+                              WebRtc_Word32 endIndex)
+{
+
+    //Get the number of bytes to delete.
+    //Clear the size of these packets.
+    WebRtc_UWord32 bytesToDelete = 0; /// The number of bytes to delete.
+    for (int j = startIndex;j <= endIndex; ++j)
+    {
+        bytesToDelete += _packetSizeBytes[j];
+        _packetSizeBytes[j] = 0;
+    }
+    if (bytesToDelete > 0)
+    {
+        // Get the offset we want to move to.
+        int destOffset = 0;
+        for (int j = 0;j < startIndex;j++)
+        {
+           destOffset += _packetSizeBytes[j];
+        }
+
+        //Get the number of bytes to move
+        WebRtc_UWord32 numberOfBytesToMove = 0;
+        for (int j = endIndex + 1; j <= _highestPacketIndex; ++j)
+        {
+            numberOfBytesToMove += _packetSizeBytes[j];
+        }
+
+        memmove((void*)(ptrStartOfLayer + destOffset),(void*)(ptrStartOfLayer +
+            destOffset+bytesToDelete), numberOfBytesToMove);
+
+    }
+
+    return bytesToDelete;
+}
+
+// Makes the layer decodable. Ie only contain decodable NALU
+// return the number of bytes deleted from the session. -1 if an error occurs
+WebRtc_UWord32
+VCMSessionInfo::MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer)
+{
+    if (_lowSeqNum < 0) // No packets in this session
+    {
+        return 0;
+    }
+
+    WebRtc_Word32 startIndex = 0;
+    WebRtc_Word32 endIndex = 0;
+    int packetIndex = 0;
+    WebRtc_UWord32 returnLength = 0;
+    for (packetIndex = 0; packetIndex <= _highestPacketIndex; ++packetIndex)
+    {
+        if (_naluCompleteness[packetIndex] == kNaluUnset) // Found a lost packet
+        {
+            FindNaluBorder(packetIndex, startIndex, endIndex);
+            if (startIndex == -1)
+            {
+                startIndex = 0;
+            }
+            if (endIndex == -1)
+            {
+                endIndex = _highestPacketIndex;
+            }
+
+            returnLength += DeletePackets(ptrStartOfLayer,
+                                          packetIndex, endIndex);
+            packetIndex = endIndex;
+        }// end lost packet
+    }
+
+    // Make sure the first packet is decodable (Either complete nalu or start
+    // of NALU)
+    if (_packetSizeBytes[0] > 0)
+    {
+        switch (_naluCompleteness[0])
+        {
+            case kNaluComplete: // Packet can be decoded as is.
+                break;
+
+            case kNaluStart:
+                // Packet contain beginning of NALU- No need to do anything.
+                break;
+            case kNaluIncomplete: //Packet is not beginning or end of NALU
+                // Need to find the end of this NALU and delete all packets.
+                FindNaluBorder(0,startIndex,endIndex);
+                if (endIndex == -1) // No end found. Delete
+                {
+                    endIndex = _highestPacketIndex;
+                }
+                // Delete this NALU.
+                returnLength += DeletePackets(ptrStartOfLayer, 0, endIndex);
+                break;
+            case kNaluEnd:    // Packet is the end of a NALU
+                // Delete this NALU
+                returnLength += DeletePackets(ptrStartOfLayer, 0, 0);
+                break;
+            default:
+                assert(false);
+        }
+    }
+
+    return returnLength;
+}
+
+WebRtc_Word32
+VCMSessionInfo::ZeroOutSeqNum(WebRtc_Word32* list,
+                              WebRtc_Word32 numberOfSeqNum)
+{
+    if ((NULL == list) || (numberOfSeqNum < 1))
+    {
+        return -1;
+    }
+    if (_lowSeqNum == -1)
+    {
+        // no packets in this frame
+        return 0;
+    }
+
+    // Find end point (index of entry that equals _lowSeqNum)
+    int index = 0;
+    for (; index < numberOfSeqNum; index++)
+    {
+        if (list[index] == _lowSeqNum)
+        {
+            list[index] = -1;
+            break;
+        }
+    }
+
+    // Zero out between first entry and end point
+    int i = 0;
+    while ( i <= _highestPacketIndex && index < numberOfSeqNum)
+    {
+        if (_naluCompleteness[i] != kNaluUnset)
+        {
+            list[index] = -1;
+        }
+        else
+        {
+            _sessionNACK = true;
+        }
+        i++;
+        index++;
+    }
+    if (!_haveFirstPacket)
+    {
+        _sessionNACK = true;
+    }
+    return 0;
+}
+
+WebRtc_Word32
+VCMSessionInfo::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
+                                    WebRtc_Word32 numberOfSeqNum,
+                                    float rttScore)
+{
+    if ((NULL == list) || (numberOfSeqNum < 1))
+    {
+        return -1;
+    }
+    if (_lowSeqNum == -1)
+    {
+        // no media packets in this frame
+        return 0;
+    }
+
+    WebRtc_Word32 index = 0;
+    // Find end point (index of entry that equals _lowSeqNum)
+    for (; index < numberOfSeqNum; index++)
+    {
+        if (list[index] == _lowSeqNum)
+        {
+            list[index] = -1;
+            break;
+        }
+    }
+
+    // TODO(mikhal): 1. update score based on RTT value 2. add partition data
+    // use the previous available
+    bool isBaseAvailable = false;
+    if ((index > 0) && (list[index] == -1))
+    {
+        // found first packet, for now let's go only one back
+        if ((list[index - 1] == -1) || (list[index - 1] == -2))
+        {
+            // this is indeed the first packet, as previous packet was populated
+            isBaseAvailable = true;
+        }
+    }
+    bool allowNack = false;
+    if (!_haveFirstPacket || !isBaseAvailable)
+    {
+        allowNack = true;
+    }
+
+    // Zero out between first entry and end point
+    int i = 0;
+    // Score place holder - based on RTT and partition (when available).
+    const float nackScoreTh = 0.25f;
+
+    WebRtc_Word32 highMediaPacket;
+    if (_markerSeqNum != -1)
+    {
+        highMediaPacket = _markerSeqNum;
+    }
+    else
+    {
+        highMediaPacket = _emptySeqNumLow - 1 > _highSeqNum ?
+                          _emptySeqNumLow - 1: _highSeqNum;
+    }
+
+    while (list[index] <= highMediaPacket && index < numberOfSeqNum)
+    {
+        if (_naluCompleteness[i] != kNaluUnset)
+        {
+            list[index] = -1;
+        }
+        else
+        {
+            // compute score of the packet
+            float score = 1.0f;
+            // multiply internal score (importance) by external score (RTT)
+            score *= rttScore;
+            if (score > nackScoreTh)
+            {
+                allowNack = true;
+            }
+            else
+            {
+                list[index] = -1;
+            }
+        }
+        i++;
+        index++;
+    }
+    // Empty packets follow the data packets, and therefore have a higher
+    // sequence number. We do not want to NACK empty packets.
+
+    if ((_emptySeqNumLow != -1) && (_emptySeqNumHigh != -1) &&
+        (index < numberOfSeqNum))
+    {
+        // first make sure that we are at least at the minimum value
+        // (if not we are missing last packet(s))
+        while (list[index] < _emptySeqNumLow && index < numberOfSeqNum)
+        {
+            index++;
+        }
+
+        // mark empty packets
+        while (list[index] <= _emptySeqNumHigh && index < numberOfSeqNum)
+        {
+            list[index] = -2;
+            index++;
+        }
+    }
+
+    _sessionNACK  = allowNack;
+    return 0;
+}
+
+WebRtc_Word32
+VCMSessionInfo::GetHighestPacketIndex()
+{
+    return _highestPacketIndex;
+}
+
+bool
+VCMSessionInfo::HaveLastPacket()
+{
+    return _markerBit;
+}
+
+void
+VCMSessionInfo::ForceSetHaveLastPacket()
+{
+    _markerBit = true;
+    UpdateCompleteSession();
+}
+
+bool
+VCMSessionInfo::IsRetransmitted()
+{
+    return _sessionNACK;
+}
+
+void
+VCMSessionInfo::UpdatePacketSize(WebRtc_Word32 packetIndex,
+                                 WebRtc_UWord32 length)
+{
+    // sanity
+    if (packetIndex >= kMaxPacketsInJitterBuffer || packetIndex < 0)
+    {
+        // not allowed
+        assert(!"SessionInfo::UpdatePacketSize Error: invalid packetIndex");
+        return;
+    }
+    _packetSizeBytes[packetIndex] = length;
+}
+
+WebRtc_Word64
+VCMSessionInfo::InsertPacket(const VCMPacket& packet,
+                             WebRtc_UWord8* ptrStartOfLayer)
+{
+    // not allowed
+    assert(!packet.insertStartCode || !packet.bits);
+    // Check if this is first packet (only valid for some codecs)
+    if (packet.isFirstPacket)
+    {
+        // the first packet in the frame always signals the frametype
+        _frameType = packet.frameType;
+    }
+    else if (_frameType == kFrameEmpty && packet.frameType != kFrameEmpty)
+    {
+        // Update the frame type with the first media packet
+        _frameType = packet.frameType;
+    }
+    if (packet.frameType == kFrameEmpty)
+    {
+        // update seq number as an empty packet
+        InformOfEmptyPacket(packet.seqNum);
+        return 0;
+    }
+
+    // Check sequence number and update highest and lowest sequence numbers
+    // received. Move data if this seq num is lower than previously lowest.
+
+    if (packet.seqNum > _highSeqNum)
+    {
+        // This packet's seq num is higher than previously highest seq num;
+        // normal case if we have a wrap, only update with wrapped values
+        if (!(_highSeqNum < 0x00ff && packet.seqNum > 0xff00))
+        {
+            _highSeqNum = packet.seqNum;
+        }
+    } else if (_highSeqNum > 0xff00 && packet.seqNum < 0x00ff)
+    {
+        // wrap
+        _highSeqNum = packet.seqNum;
+    }
+    int packetIndex = packet.seqNum - (WebRtc_UWord16)_lowSeqNum;
+    if (_lowSeqNum < 0x00ff && packet.seqNum > 0xff00)
+    {
+        // negative wrap
+        packetIndex = packet.seqNum - 0x10000 - _lowSeqNum;
+    }
+    if (packetIndex < 0)
+    {
+        if (_lowSeqNum > 0xff00 && packet.seqNum < 0x00ff)
+        {
+            // we have a false detect due to the wrap
+            packetIndex = (0xffff - (WebRtc_UWord16)_lowSeqNum) + packet.seqNum
+                          + (WebRtc_UWord16)1;
+        } else
+        {
+            // This packet's seq num is lower than previously lowest seq num,
+            // but no wrap We need to move the data in all arrays indexed by
+            // packetIndex and insert the new packet's info
+            // How many packets should we leave room for (positions to shift)?
+            // Example - this seq num is 3 lower than previously lowest seq num
+            // Before: |--prev packet with lowest seq num--|--|...|
+            // After:  |--new lowest seq num--|--|--|--prev packet with
+            // lowest seq num--|--|...|
+
+            WebRtc_UWord16 positionsToShift   = (WebRtc_UWord16)_lowSeqNum -
+                                                                packet.seqNum;
+            WebRtc_UWord16 numOfPacketsToMove = _highestPacketIndex + 1;
+
+            // sanity, do we have room for the shift?
+            if ((positionsToShift + numOfPacketsToMove) >
+                kMaxPacketsInJitterBuffer)
+            {
+                return -1;
+            }
+
+            // Shift _ORwithPrevByte array
+            memmove(&_ORwithPrevByte[positionsToShift],
+                &_ORwithPrevByte[0], numOfPacketsToMove*sizeof(bool));
+            memset(&_ORwithPrevByte[0], false, positionsToShift*sizeof(bool));
+
+            // Shift _packetSizeBytes array
+            memmove(&_packetSizeBytes[positionsToShift],
+                &_packetSizeBytes[0],
+                numOfPacketsToMove * sizeof(WebRtc_UWord32));
+            memset(&_packetSizeBytes[0], 0,
+                   positionsToShift * sizeof(WebRtc_UWord32));
+
+            // Shift _naluCompleteness
+            memmove(&_naluCompleteness[positionsToShift],
+                   &_naluCompleteness[0],
+                   numOfPacketsToMove * sizeof(WebRtc_UWord8));
+            memset(&_naluCompleteness[0], kNaluUnset,
+                   positionsToShift * sizeof(WebRtc_UWord8));
+
+            _highestPacketIndex += positionsToShift;
+            _lowSeqNum = packet.seqNum;
+            packetIndex = 0; // (seqNum - _lowSeqNum) = 0
+        }
+    } // if (_lowSeqNum > seqNum)
+
+    // sanity
+    if (packetIndex >= kMaxPacketsInJitterBuffer )
+    {
+        return -1;
+    }
+    if (packetIndex < 0 )
+    {
+        return -1;
+    }
+
+    // Check for duplicate packets
+    if (_packetSizeBytes[packetIndex] != 0)
+    {
+        // We have already received a packet with this seq number, ignore it.
+        return -2;
+    }
+
+    // update highest packet index
+    _highestPacketIndex = packetIndex > _highestPacketIndex ?
+                                        packetIndex :_highestPacketIndex;
+
+    return InsertBuffer(ptrStartOfLayer, packetIndex, packet);
+}
+
+
+WebRtc_Word32
+VCMSessionInfo::InformOfEmptyPacket(const WebRtc_UWord16 seqNum)
+{
+    // Empty packets may be FEC or filler packets. They are sequential and
+    // follow the data packets, therefore, we should only keep track of the high
+    // and low sequence numbers and may assume that the packets in between are
+    // empty packets belonging to the same frame (timestamp).
+
+  if (_emptySeqNumLow == -1 && _emptySeqNumHigh == -1)
+    {
+        _emptySeqNumLow = seqNum;
+        _emptySeqNumHigh = seqNum;
+    }
+    else
+    {
+        if (seqNum > _emptySeqNumHigh)
+        {
+            // This packet's seq num is higher than previously highest seq num;
+            // normal case if we have a wrap, only update with wrapped values
+            if (!(_emptySeqNumHigh < 0x00ff && seqNum > 0xff00))
+            {
+                _emptySeqNumHigh = seqNum;
+            }
+        }
+        else if (_emptySeqNumHigh > 0xff00 && seqNum < 0x00ff)
+        {
+             // wrap
+             _emptySeqNumHigh = seqNum;
+        }
+        if (_emptySeqNumLow < 0x00ff && seqNum > 0xff00)
+        {
+            // negative wrap
+            if (seqNum - 0x10000 - _emptySeqNumLow < 0)
+            {
+                _emptySeqNumLow = seqNum;
+            }
+        }
+    }
+    return 0;
+}
+
+WebRtc_UWord32
+VCMSessionInfo::PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer,
+                                 VideoCodecType codec)
+{
+    WebRtc_UWord32 currentPacketOffset = 0;
+    WebRtc_UWord32 length = GetSessionLength();
+    WebRtc_UWord32 idSum = 0;
+    WebRtc_UWord32 realDataBytes = 0;
+    if (length == 0)
+    {
+        return length;
+    }
+    bool previousLost = false;
+    for (int i = 0; i <= _highestPacketIndex; i++)
+    {
+        if (_ORwithPrevByte[i])
+        {
+            if (currentPacketOffset > 0)
+            {
+                WebRtc_UWord8* ptrFirstByte = ptrStartOfLayer +
+                                              currentPacketOffset;
+
+                if (_packetSizeBytes[i-1] == 0 || previousLost)
+                {
+                    // It is be better to throw away this packet if we are
+                    // missing the previous packet.
+                    memset(ptrFirstByte, 0, _packetSizeBytes[i]);
+                    previousLost = true;
+                }
+                else if (_packetSizeBytes[i] > 0) // Ignore if empty packet
+                {
+                    // Glue with previous byte
+                    // Move everything from [this packet start + 1,
+                    // end of buffer] one byte to the left
+                    WebRtc_UWord8* ptrPrevByte = ptrFirstByte - 1;
+                    *ptrPrevByte = (*ptrPrevByte) | (*ptrFirstByte);
+                    WebRtc_UWord32 lengthToEnd = length -
+                                                 (currentPacketOffset + 1);
+                    memmove((void*)ptrFirstByte, (void*)(ptrFirstByte + 1),
+                            lengthToEnd);
+                    _packetSizeBytes[i]--;
+                    length--;
+                    previousLost = false;
+                    realDataBytes += _packetSizeBytes[i];
+                }
+            }
+            else
+            {
+                memset(ptrStartOfLayer, 0, _packetSizeBytes[i]);
+                previousLost = true;
+            }
+        }
+        else if (_packetSizeBytes[i] == 0 && codec == kVideoCodecH263)
+        {
+            WebRtc_UWord8* ptrFirstByte = ptrStartOfLayer + currentPacketOffset;
+            memmove(ptrFirstByte + 10, ptrFirstByte,
+                    length - currentPacketOffset);
+            memset(ptrFirstByte, 0, 10);
+            _packetSizeBytes[i] = 10;
+            length += _packetSizeBytes[i];
+            previousLost = true;
+        }
+        else
+        {
+            realDataBytes += _packetSizeBytes[i];
+            previousLost = false;
+        }
+        currentPacketOffset += _packetSizeBytes[i];
+    }
+    if (realDataBytes == 0)
+    {
+        // Drop the frame since all it contains are zeros
+        length = 0;
+        memset(_packetSizeBytes, 0, sizeof(_packetSizeBytes));
+    }
+    return length;
+}
+
+}
diff --git a/src/modules/video_coding/main/source/session_info.h b/src/modules/video_coding/main/source/session_info.h
new file mode 100644
index 0000000..ff71def
--- /dev/null
+++ b/src/modules/video_coding/main/source/session_info.h
@@ -0,0 +1,102 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_
+#define WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_
+
+#include "typedefs.h"
+#include "module_common_types.h"
+#include "packet.h"
+
+namespace webrtc
+{
+
+class VCMSessionInfo
+{
+public:
+    VCMSessionInfo();
+    virtual ~VCMSessionInfo();
+
+    VCMSessionInfo(const VCMSessionInfo& rhs);
+
+    WebRtc_Word32 ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 numberOfSeqNum);
+    // Hybrid version: Zero out seq num for NACK list
+    // apply a score based on the packet location and the external rttScore
+    WebRtc_Word32 ZeroOutSeqNumHybrid(WebRtc_Word32* list,
+                                      WebRtc_Word32 numberOfSeqNum,
+                                      float rttScore);
+    virtual void Reset();
+
+    WebRtc_Word64 InsertPacket(const VCMPacket& packet, WebRtc_UWord8* ptrStartOfLayer);
+    WebRtc_Word32 InformOfEmptyPacket(const WebRtc_UWord16 seqNum);
+
+    virtual bool IsSessionComplete();
+    WebRtc_UWord32 MakeSessionDecodable(WebRtc_UWord8* ptrStartOfLayer);
+
+    WebRtc_UWord32 GetSessionLength();
+    bool HaveLastPacket();
+    void ForceSetHaveLastPacket();
+    bool IsRetransmitted();
+    webrtc::FrameType FrameType() const { return _frameType; }
+
+    virtual WebRtc_Word32 GetHighestPacketIndex();
+    virtual void UpdatePacketSize(WebRtc_Word32 packetIndex, WebRtc_UWord32 length);
+
+    void SetStartSeqNumber(WebRtc_UWord16 seqNumber);
+
+    bool HaveStartSeqNumber();
+
+    WebRtc_Word32 GetLowSeqNum() const;
+    // returns highest seqNum, media or empty
+    WebRtc_Word32 GetHighSeqNum() const;
+
+    WebRtc_UWord32 PrepareForDecode(WebRtc_UWord8* ptrStartOfLayer, VideoCodecType codec);
+
+    void SetPreviousFrameLoss() { _previousFrameLoss = true; }
+    bool PreviousFrameLoss() const { return _previousFrameLoss; }
+
+protected:
+    WebRtc_UWord32 InsertBuffer(WebRtc_UWord8* ptrStartOfLayer,
+                                WebRtc_Word32 packetIndex,
+                                const VCMPacket& packet);
+    void FindNaluBorder(WebRtc_Word32 packetIndex,
+                        WebRtc_Word32& startIndex,
+                        WebRtc_Word32& endIndex);
+    WebRtc_UWord32 DeletePackets(WebRtc_UWord8* ptrStartOfLayer,
+                                 WebRtc_Word32 startIndex,
+                                 WebRtc_Word32 endIndex);
+    void UpdateCompleteSession();
+
+    bool _haveFirstPacket;      // If we have inserted the first packet into this frame
+    bool _markerBit;            // If we have inserted a packet with markerbit into this frame
+    bool _sessionNACK;          // If this session has been NACKed by JB
+    bool _completeSession;
+    webrtc::FrameType  _frameType;
+    bool               _previousFrameLoss;
+
+    WebRtc_Word32      _lowSeqNum;          // Lowest packet sequence number in a session
+    WebRtc_Word32      _highSeqNum;         // Highest packet sequence number in a session
+
+    // Highest packet index in this frame
+    WebRtc_UWord16     _highestPacketIndex;
+    // Length of packet (used for reordering)
+    WebRtc_UWord32     _packetSizeBytes[kMaxPacketsInJitterBuffer];
+    // Completeness of packets. Used for deciding if the frame is decodable.
+    WebRtc_UWord8      _naluCompleteness[kMaxPacketsInJitterBuffer];
+    WebRtc_Word32      _emptySeqNumLow;
+    WebRtc_Word32      _emptySeqNumHigh;
+    // Store the sequence number that marks the last media packet
+    WebRtc_Word32      _markerSeqNum;
+    bool               _ORwithPrevByte[kMaxPacketsInJitterBuffer];
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_SESSION_INFO_H_
diff --git a/src/modules/video_coding/main/source/tick_time.h b/src/modules/video_coding/main/source/tick_time.h
new file mode 100644
index 0000000..47ac9f4
--- /dev/null
+++ b/src/modules/video_coding/main/source/tick_time.h
@@ -0,0 +1,55 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_TICK_TIME_H_
+#define WEBRTC_MODULES_VIDEO_CODING_TICK_TIME_H_
+
+#include "tick_util.h"
+
+#include <assert.h>
+
+namespace webrtc
+{
+
+//#define TICK_TIME_DEBUG
+
+class VCMTickTime : public TickTime
+{
+#ifdef TICK_TIME_DEBUG
+public:
+    /*
+    *   Get current time
+    */
+    static TickTime Now() { assert(false); };
+
+    /*
+    *   Get time in milli seconds
+    */
+    static WebRtc_Word64 MillisecondTimestamp() { return _timeNowDebug; };
+
+    /*
+    *   Get time in micro seconds
+    */
+    static WebRtc_Word64 MicrosecondTimestamp() { return _timeNowDebug * 1000LL; };
+
+    static void IncrementDebugClock() { _timeNowDebug++; };
+
+private:
+    static WebRtc_Word64     _timeNowDebug;
+
+#else
+public:
+    static void IncrementDebugClock() { assert(false); };
+#endif
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_TICK_TIME_H_
diff --git a/src/modules/video_coding/main/source/timestamp_extrapolator.cc b/src/modules/video_coding/main/source/timestamp_extrapolator.cc
new file mode 100644
index 0000000..5f589e1
--- /dev/null
+++ b/src/modules/video_coding/main/source/timestamp_extrapolator.cc
@@ -0,0 +1,259 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "internal_defines.h"
+#include "timestamp_extrapolator.h"
+#include "tick_time.h"
+#include "trace.h"
+
+namespace webrtc {
+
+VCMTimestampExtrapolator::VCMTimestampExtrapolator(WebRtc_Word32 vcmId, WebRtc_Word32 id)
+:
+_rwLock(*RWLockWrapper::CreateRWLock()),
+_vcmId(vcmId),
+_id(id),
+_startMs(0),
+_firstTimestamp(0),
+_wrapArounds(0),
+_prevTs90khz(0),
+_lambda(1),
+_firstAfterReset(true),
+_packetCount(0),
+_startUpFilterDelayInPackets(2),
+_detectorAccumulatorPos(0),
+_detectorAccumulatorNeg(0),
+_alarmThreshold(60e3),
+_accDrift(6600), // in timestamp ticks, i.e. 15 ms
+_accMaxError(7000),
+_P11(1e10)
+{
+    Reset(VCMTickTime::MillisecondTimestamp());
+}
+
+VCMTimestampExtrapolator::~VCMTimestampExtrapolator()
+{
+    delete &_rwLock;
+}
+
+void
+VCMTimestampExtrapolator::Reset(const WebRtc_Word64 nowMs /* = -1 */)
+{
+    WriteLockScoped wl(_rwLock);
+    if (nowMs > -1)
+    {
+        _startMs = nowMs;
+    }
+    else
+    {
+        _startMs = VCMTickTime::MillisecondTimestamp();
+    }
+    _prevMs = _startMs;
+    _firstTimestamp = 0;
+    _w[0] = 90.0;
+    _w[1] = 0;
+    _P[0][0] = 1;
+    _P[1][1] = _P11;
+    _P[0][1] = _P[1][0] = 0;
+    _firstAfterReset = true;
+    _prevTs90khz = 0;
+    _wrapArounds = 0;
+    _packetCount = 0;
+    _detectorAccumulatorPos = 0;
+    _detectorAccumulatorNeg = 0;
+}
+
+void
+VCMTimestampExtrapolator::Update(WebRtc_Word64 tMs, WebRtc_UWord32 ts90khz, bool trace)
+{
+
+    _rwLock.AcquireLockExclusive();
+    if (tMs - _prevMs > 10e3)
+    {
+        // Ten seconds without a complete frame.
+        // Reset the extrapolator
+        _rwLock.ReleaseLockExclusive();
+        Reset();
+        _rwLock.AcquireLockExclusive();
+    }
+    else
+    {
+        _prevMs = tMs;
+    }
+
+    // Remove offset to prevent badly scaled matrices
+    tMs -= _startMs;
+
+    WebRtc_Word32 prevWrapArounds = _wrapArounds;
+    CheckForWrapArounds(ts90khz);
+    WebRtc_Word32 wrapAroundsSincePrev = _wrapArounds - prevWrapArounds;
+
+    if (wrapAroundsSincePrev == 0 && ts90khz < _prevTs90khz)
+    {
+        _rwLock.ReleaseLockExclusive();
+        return;
+    }
+
+    if (_firstAfterReset)
+    {
+        // Make an initial guess of the offset,
+        // should be almost correct since tMs - _startMs
+        // should about zero at this time.
+        _w[1] = -_w[0] * tMs;
+        _firstTimestamp = ts90khz;
+        _firstAfterReset = false;
+    }
+
+    // Compensate for wraparounds by changing the line offset
+    _w[1] = _w[1] - wrapAroundsSincePrev * ((static_cast<WebRtc_Word64>(1)<<32) - 1);
+
+    double residual = (static_cast<double>(ts90khz) - _firstTimestamp) - static_cast<double>(tMs) * _w[0] - _w[1];
+    if (DelayChangeDetection(residual, trace) &&
+        _packetCount >= _startUpFilterDelayInPackets)
+    {
+        // A sudden change of average network delay has been detected.
+        // Force the filter to adjust its offset parameter by changing
+        // the offset uncertainty. Don't do this during startup.
+        _P[1][1] = _P11;
+    }
+    //T = [t(k) 1]';
+    //that = T'*w;
+    //K = P*T/(lambda + T'*P*T);
+    double K[2];
+    K[0] = _P[0][0] * tMs + _P[0][1];
+    K[1] = _P[1][0] * tMs + _P[1][1];
+    double TPT = _lambda + tMs * K[0] + K[1];
+    K[0] /= TPT;
+    K[1] /= TPT;
+    //w = w + K*(ts(k) - that);
+    _w[0] = _w[0] + K[0] * residual;
+    _w[1] = _w[1] + K[1] * residual;
+    //P = 1/lambda*(P - K*T'*P);
+    double p00 = 1 / _lambda * (_P[0][0] - (K[0] * tMs * _P[0][0] + K[0] * _P[1][0]));
+    double p01 = 1 / _lambda * (_P[0][1] - (K[0] * tMs * _P[0][1] + K[0] * _P[1][1]));
+    _P[1][0] = 1 / _lambda * (_P[1][0] - (K[1] * tMs * _P[0][0] + K[1] * _P[1][0]));
+    _P[1][1] = 1 / _lambda * (_P[1][1] - (K[1] * tMs * _P[0][1] + K[1] * _P[1][1]));
+    _P[0][0] = p00;
+    _P[0][1] = p01;
+    if (_packetCount < _startUpFilterDelayInPackets)
+    {
+        _packetCount++;
+    }
+    if (trace)
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _id),  "w[0]=%f w[1]=%f ts=%u tMs=%u", _w[0], _w[1], ts90khz, tMs);
+    }
+    _rwLock.ReleaseLockExclusive();
+}
+
+WebRtc_UWord32
+VCMTimestampExtrapolator::ExtrapolateTimestamp(WebRtc_Word64 tMs) const
+{
+    ReadLockScoped rl(_rwLock);
+    WebRtc_UWord32 timestamp = 0;
+    if (_packetCount == 0)
+    {
+        timestamp = 0;
+    }
+    else if (_packetCount < _startUpFilterDelayInPackets)
+    {
+        timestamp = static_cast<WebRtc_UWord32>(90.0 * (tMs - _prevMs) + _prevTs90khz + 0.5);
+    }
+    else
+    {
+        timestamp = static_cast<WebRtc_UWord32>(_w[0] * (tMs - _startMs) + _w[1] + _firstTimestamp + 0.5);
+    }
+    return timestamp;
+}
+
+WebRtc_Word64
+VCMTimestampExtrapolator::ExtrapolateLocalTime(WebRtc_UWord32 timestamp90khz) const
+{
+    ReadLockScoped rl(_rwLock);
+    WebRtc_Word64 localTimeMs = 0;
+    if (_packetCount == 0)
+    {
+        localTimeMs = -1;
+    }
+    else if (_packetCount < _startUpFilterDelayInPackets)
+    {
+        localTimeMs = _prevMs + static_cast<WebRtc_Word64>(static_cast<double>(timestamp90khz - _prevTs90khz) / 90.0 + 0.5);
+    }
+    else
+    {
+        if (_w[0] < 1e-3)
+        {
+            localTimeMs = _startMs;
+        }
+        else
+        {
+            double timestampDiff = static_cast<double>(timestamp90khz) - static_cast<double>(_firstTimestamp);
+            localTimeMs = static_cast<WebRtc_Word64>(static_cast<double>(_startMs) + (timestampDiff - _w[1]) / _w[0] + 0.5);
+        }
+    }
+    return localTimeMs;
+}
+
+// Investigates if the timestamp clock has overflowed since the last timestamp and
+// keeps track of the number of wrap arounds since reset.
+void
+VCMTimestampExtrapolator::CheckForWrapArounds(WebRtc_UWord32 ts90khz)
+{
+    if (_prevTs90khz == 0)
+    {
+        _prevTs90khz = ts90khz;
+        return;
+    }
+    if (ts90khz < _prevTs90khz)
+    {
+        // This difference will probably be less than -2^31 if we have had a wrap around
+        // (e.g. timestamp = 1, _previousTimestamp = 2^32 - 1). Since it is casted to a Word32,
+        // it should be positive.
+        if (static_cast<WebRtc_Word32>(ts90khz - _prevTs90khz) > 0)
+        {
+            // Forward wrap around
+            _wrapArounds++;
+        }
+    }
+    // This difference will probably be less than -2^31 if we have had a backward wrap around.
+    // Since it is casted to a Word32, it should be positive.
+    else if (static_cast<WebRtc_Word32>(_prevTs90khz - ts90khz) > 0)
+    {
+        // Backward wrap around
+        _wrapArounds--;
+    }
+    _prevTs90khz = ts90khz;
+}
+
+bool
+VCMTimestampExtrapolator::DelayChangeDetection(double error, bool trace)
+{
+    // CUSUM detection of sudden delay changes
+    error = (error > 0) ? VCM_MIN(error, _accMaxError) : VCM_MAX(error, -_accMaxError);
+    _detectorAccumulatorPos = VCM_MAX(_detectorAccumulatorPos + error - _accDrift, (double)0);
+    _detectorAccumulatorNeg = VCM_MIN(_detectorAccumulatorNeg + error + _accDrift, (double)0);
+    if (_detectorAccumulatorPos > _alarmThreshold || _detectorAccumulatorNeg < -_alarmThreshold)
+    {
+        // Alarm
+        if (trace)
+        {
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _id),  "g1=%f g2=%f alarm=1", _detectorAccumulatorPos, _detectorAccumulatorNeg);
+        }
+        _detectorAccumulatorPos = _detectorAccumulatorNeg = 0;
+        return true;
+    }
+    if (trace)
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _id),  "g1=%f g2=%f alarm=0", _detectorAccumulatorPos, _detectorAccumulatorNeg);
+    }
+    return false;
+}
+
+}
diff --git a/src/modules/video_coding/main/source/timestamp_extrapolator.h b/src/modules/video_coding/main/source/timestamp_extrapolator.h
new file mode 100644
index 0000000..a186504
--- /dev/null
+++ b/src/modules/video_coding/main/source/timestamp_extrapolator.h
@@ -0,0 +1,59 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_TIMESTAMP_EXTRAPOLATOR_H_
+#define WEBRTC_MODULES_VIDEO_CODING_TIMESTAMP_EXTRAPOLATOR_H_
+
+#include "typedefs.h"
+#include "rw_lock_wrapper.h"
+
+namespace webrtc
+{
+
+class VCMTimestampExtrapolator
+{
+public:
+    VCMTimestampExtrapolator(WebRtc_Word32 vcmId = 0, WebRtc_Word32 receiverId = 0);
+    ~VCMTimestampExtrapolator();
+    void Update(WebRtc_Word64 tMs, WebRtc_UWord32 ts90khz, bool trace = true);
+    WebRtc_UWord32 ExtrapolateTimestamp(WebRtc_Word64 tMs) const;
+    WebRtc_Word64 ExtrapolateLocalTime(WebRtc_UWord32 timestamp90khz) const;
+    void Reset(WebRtc_Word64 nowMs = -1);
+
+private:
+    void CheckForWrapArounds(WebRtc_UWord32 ts90khz);
+    bool DelayChangeDetection(double error, bool trace = true);
+    RWLockWrapper&         _rwLock;
+    WebRtc_Word32         _vcmId;
+    WebRtc_Word32         _id;
+    bool                _trace;
+    double              _w[2];
+    double              _P[2][2];
+    WebRtc_Word64         _startMs;
+    WebRtc_Word64         _prevMs;
+    WebRtc_UWord32        _firstTimestamp;
+    WebRtc_Word32         _wrapArounds;
+    WebRtc_UWord32        _prevTs90khz;
+    const double        _lambda;
+    bool                _firstAfterReset;
+    WebRtc_UWord32        _packetCount;
+    const WebRtc_UWord32  _startUpFilterDelayInPackets;
+
+    double              _detectorAccumulatorPos;
+    double              _detectorAccumulatorNeg;
+    const double        _alarmThreshold;
+    const double        _accDrift;
+    const double        _accMaxError;
+    const double        _P11;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_TIMESTAMP_EXTRAPOLATOR_H_
diff --git a/src/modules/video_coding/main/source/timestamp_map.cc b/src/modules/video_coding/main/source/timestamp_map.cc
new file mode 100644
index 0000000..f19819b
--- /dev/null
+++ b/src/modules/video_coding/main/source/timestamp_map.cc
@@ -0,0 +1,99 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "timestamp_map.h"
+#include <stdlib.h>
+#include <assert.h>
+
+namespace webrtc {
+
+// Constructor. Optional parameter specifies maximum number of
+// coexisting timers.
+VCMTimestampMap::VCMTimestampMap(WebRtc_Word32 length):
+    _nextAddIx(0),
+    _nextPopIx(0)
+{
+    if (length <= 0)
+    {
+        // default
+        length = 10;
+    }
+
+    _map = new VCMTimestampDataTuple[length];
+    _length = length;
+}
+
+// Destructor.
+VCMTimestampMap::~VCMTimestampMap()
+{
+    delete [] _map;
+}
+
+// Empty the list of timers.
+void
+VCMTimestampMap::Reset()
+{
+    _nextAddIx = 0;
+    _nextPopIx = 0;
+}
+
+WebRtc_Word32
+VCMTimestampMap::Add(WebRtc_UWord32 timestamp, void* data)
+{
+    _map[_nextAddIx].timestamp = timestamp;
+    _map[_nextAddIx].data = data;
+    _nextAddIx = (_nextAddIx + 1) % _length;
+
+    if (_nextAddIx == _nextPopIx)
+    {
+        // Circular list full; forget oldest entry
+        _nextPopIx = (_nextPopIx + 1) % _length;
+        return -1;
+    }
+    return 0;
+}
+
+void*
+VCMTimestampMap::Pop(WebRtc_UWord32 timestamp)
+{
+    while (!IsEmpty())
+    {
+        if (_map[_nextPopIx].timestamp == timestamp)
+        {
+            // found start time for this timestamp
+            void* data = _map[_nextPopIx].data;
+            _map[_nextPopIx].data = NULL;
+            _nextPopIx = (_nextPopIx + 1) % _length;
+            return data;
+        }
+        else if (_map[_nextPopIx].timestamp > timestamp)
+        {
+            // the timestamp we are looking for is not in the list
+            assert(_nextPopIx < _length && _nextPopIx >= 0);
+            return NULL;
+        }
+
+        // not in this position, check next (and forget this position)
+        _nextPopIx = (_nextPopIx + 1) % _length;
+    }
+
+    // could not find matching timestamp in list
+    assert(_nextPopIx < _length && _nextPopIx >= 0);
+    return NULL;
+}
+
+// Check if no timers are currently running
+bool
+VCMTimestampMap::IsEmpty() const
+{
+    return (_nextAddIx == _nextPopIx);
+}
+
+}
diff --git a/src/modules/video_coding/main/source/timestamp_map.h b/src/modules/video_coding/main/source/timestamp_map.h
new file mode 100644
index 0000000..fd532bc
--- /dev/null
+++ b/src/modules/video_coding/main/source/timestamp_map.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_TIMESTAMP_MAP_H_
+#define WEBRTC_MODULES_VIDEO_CODING_TIMESTAMP_MAP_H_
+
+#include "typedefs.h"
+
+namespace webrtc
+{
+
+struct VCMTimestampDataTuple
+{
+    WebRtc_UWord32    timestamp;
+    void*             data;
+};
+
+class VCMTimestampMap
+{
+public:
+    // Constructor. Optional parameter specifies maximum number of
+    // timestamps in map.
+    VCMTimestampMap(const WebRtc_Word32 length = 10);
+
+    // Destructor.
+    ~VCMTimestampMap();
+
+    // Empty the map
+    void Reset();
+
+    WebRtc_Word32 Add(WebRtc_UWord32 timestamp, void*  data);
+    void* Pop(WebRtc_UWord32 timestamp);
+
+private:
+    bool IsEmpty() const;
+
+    VCMTimestampDataTuple* _map;
+    WebRtc_Word32                   _nextAddIx;
+    WebRtc_Word32                   _nextPopIx;
+    WebRtc_Word32                   _length;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_TIMESTAMP_MAP_H_
diff --git a/src/modules/video_coding/main/source/timing.cc b/src/modules/video_coding/main/source/timing.cc
new file mode 100644
index 0000000..67214ec
--- /dev/null
+++ b/src/modules/video_coding/main/source/timing.cc
@@ -0,0 +1,333 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "trace.h"
+#include "internal_defines.h"
+#include "jitter_buffer_common.h"
+#include "timing.h"
+#include "timestamp_extrapolator.h"
+
+namespace webrtc {
+
+VCMTiming::VCMTiming(WebRtc_Word32 vcmId, WebRtc_Word32 timingId, VCMTiming* masterTiming)
+:
+_critSect(*CriticalSectionWrapper::CreateCriticalSection()),
+_vcmId(vcmId),
+_timingId(timingId),
+_master(false),
+_tsExtrapolator(),
+_codecTimer(),
+_renderDelayMs(kDefaultRenderDelayMs),
+_minTotalDelayMs(0),
+_requiredDelayMs(0),
+_currentDelayMs(0),
+_prevFrameTimestamp(0)
+{
+    if (masterTiming == NULL)
+    {
+        _master = true;
+        _tsExtrapolator = new VCMTimestampExtrapolator(vcmId, timingId);
+    }
+    else
+    {
+        _tsExtrapolator = masterTiming->_tsExtrapolator;
+    }
+}
+
+VCMTiming::~VCMTiming()
+{
+    if (_master)
+    {
+        delete _tsExtrapolator;
+    }
+    delete &_critSect;
+}
+
+void
+VCMTiming::Reset(WebRtc_Word64 nowMs /* = -1 */)
+{
+    CriticalSectionScoped cs(_critSect);
+    if (nowMs > -1)
+    {
+        _tsExtrapolator->Reset(nowMs);
+    }
+    else
+    {
+        _tsExtrapolator->Reset();
+    }
+    _codecTimer.Reset();
+    _renderDelayMs = kDefaultRenderDelayMs;
+    _minTotalDelayMs = 0;
+    _requiredDelayMs = 0;
+    _currentDelayMs = 0;
+    _prevFrameTimestamp = 0;
+}
+
+void VCMTiming::ResetDecodeTime()
+{
+    _codecTimer.Reset();
+}
+
+void
+VCMTiming::SetRenderDelay(WebRtc_UWord32 renderDelayMs)
+{
+    CriticalSectionScoped cs(_critSect);
+    _renderDelayMs = renderDelayMs;
+}
+
+void
+VCMTiming::SetMinimumTotalDelay(WebRtc_UWord32 minTotalDelayMs)
+{
+    CriticalSectionScoped cs(_critSect);
+    _minTotalDelayMs = minTotalDelayMs;
+}
+
+void
+VCMTiming::SetRequiredDelay(WebRtc_UWord32 requiredDelayMs)
+{
+    CriticalSectionScoped cs(_critSect);
+    if (requiredDelayMs != _requiredDelayMs)
+    {
+        if (_master)
+        {
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
+                    "Desired jitter buffer level: %u ms", requiredDelayMs);
+        }
+        _requiredDelayMs = requiredDelayMs;
+    }
+}
+
+void VCMTiming::UpdateCurrentDelay(WebRtc_UWord32 frameTimestamp)
+{
+    CriticalSectionScoped cs(_critSect);
+    WebRtc_UWord32 targetDelayMs = TargetDelayInternal();
+
+    // Make sure we try to sync with audio
+    if (targetDelayMs < _minTotalDelayMs)
+    {
+        targetDelayMs = _minTotalDelayMs;
+    }
+
+    if (_currentDelayMs == 0)
+    {
+        // Not initialized, set current delay to target.
+        _currentDelayMs = targetDelayMs;
+    }
+    else if (targetDelayMs != _currentDelayMs)
+    {
+        WebRtc_Word64 delayDiffMs = static_cast<WebRtc_Word64>(targetDelayMs) -
+                                    _currentDelayMs;
+        // Never change the delay with more than 100 ms every second. If we're changing the
+        // delay in too large steps we will get noticable freezes. By limiting the change we
+        // can increase the delay in smaller steps, which will be experienced as the video is
+        // played in slow motion. When lowering the delay the video will be played at a faster
+        // pace.
+        WebRtc_Word64 maxChangeMs = 0;
+        if (frameTimestamp < 0x0000ffff && _prevFrameTimestamp > 0xffff0000)
+        {
+            // wrap
+            maxChangeMs = kDelayMaxChangeMsPerS * (frameTimestamp +
+                         (static_cast<WebRtc_Word64>(1)<<32) - _prevFrameTimestamp) / 90000;
+        }
+        else
+        {
+            maxChangeMs = kDelayMaxChangeMsPerS *
+                          (frameTimestamp - _prevFrameTimestamp) / 90000;
+        }
+        if (maxChangeMs <= 0)
+        {
+            // Any changes less than 1 ms are truncated and
+            // will be postponed. Negative change will be due
+            // to reordering and should be ignored.
+            return;
+        }
+        else if (delayDiffMs < -maxChangeMs)
+        {
+            delayDiffMs = -maxChangeMs;
+        }
+        else if (delayDiffMs > maxChangeMs)
+        {
+            delayDiffMs = maxChangeMs;
+        }
+        _currentDelayMs = _currentDelayMs + static_cast<WebRtc_Word32>(delayDiffMs);
+    }
+    _prevFrameTimestamp = frameTimestamp;
+}
+
+void VCMTiming::UpdateCurrentDelay(WebRtc_Word64 renderTimeMs,
+                                   WebRtc_Word64 actualDecodeTimeMs)
+{
+    CriticalSectionScoped cs(_critSect);
+    WebRtc_UWord32 targetDelayMs = TargetDelayInternal();
+    // Make sure we try to sync with audio
+    if (targetDelayMs < _minTotalDelayMs)
+    {
+        targetDelayMs = _minTotalDelayMs;
+    }
+    WebRtc_Word64 delayedMs = actualDecodeTimeMs -
+                              (renderTimeMs - MaxDecodeTimeMs() - _renderDelayMs);
+    if (delayedMs < 0)
+    {
+        return;
+    }
+    else if (_currentDelayMs + delayedMs <= targetDelayMs)
+    {
+        _currentDelayMs += static_cast<WebRtc_UWord32>(delayedMs);
+    }
+    else
+    {
+        _currentDelayMs = targetDelayMs;
+    }
+}
+
+WebRtc_Word32
+VCMTiming::StopDecodeTimer(WebRtc_UWord32 timeStamp,
+                           WebRtc_Word64 startTimeMs,
+                           WebRtc_Word64 nowMs)
+{
+    CriticalSectionScoped cs(_critSect);
+    const WebRtc_Word32 maxDecTime = MaxDecodeTimeMs();
+    WebRtc_Word32 timeDiffMs = _codecTimer.StopTimer(startTimeMs, nowMs);
+    if (timeDiffMs < 0)
+    {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
+            "Codec timer error: %d", timeDiffMs);
+        return timeDiffMs;
+    }
+
+    if (_master)
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
+                "Frame decoded: timeStamp=%u decTime=%d maxDecTime=%u, at %u",
+                timeStamp, timeDiffMs, maxDecTime, MaskWord64ToUWord32(nowMs));
+    }
+    return 0;
+}
+
+void
+VCMTiming::IncomingTimestamp(WebRtc_UWord32 timeStamp, WebRtc_Word64 nowMs)
+{
+    CriticalSectionScoped cs(_critSect);
+    _tsExtrapolator->Update(nowMs, timeStamp, _master);
+}
+
+WebRtc_Word64
+VCMTiming::RenderTimeMs(WebRtc_UWord32 frameTimestamp, WebRtc_Word64 nowMs) const
+{
+    CriticalSectionScoped cs(_critSect);
+    const WebRtc_Word64 renderTimeMs = RenderTimeMsInternal(frameTimestamp, nowMs);
+    if (renderTimeMs < 0)
+    {
+        return renderTimeMs;
+    }
+    if (_master)
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
+            "Render frame %u at %u. Render delay %u, required delay %u,"
+                " max decode time %u, min total delay %u",
+            frameTimestamp, MaskWord64ToUWord32(renderTimeMs), _renderDelayMs,
+            _requiredDelayMs, MaxDecodeTimeMs(),_minTotalDelayMs);
+    }
+    return renderTimeMs;
+}
+
+WebRtc_Word64
+VCMTiming::RenderTimeMsInternal(WebRtc_UWord32 frameTimestamp, WebRtc_Word64 nowMs) const
+{
+    WebRtc_Word64 estimatedCompleteTimeMs =
+            _tsExtrapolator->ExtrapolateLocalTime(frameTimestamp);
+    if (estimatedCompleteTimeMs - nowMs > kMaxVideoDelayMs)
+    {
+        if (_master)
+        {
+            WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
+                    "Timestamp arrived 2 seconds early, reset statistics",
+                    frameTimestamp, estimatedCompleteTimeMs);
+        }
+        return -1;
+    }
+    if (_master)
+    {
+        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
+                "ExtrapolateLocalTime(%u)=%u ms",
+                frameTimestamp, MaskWord64ToUWord32(estimatedCompleteTimeMs));
+    }
+    if (estimatedCompleteTimeMs == -1)
+    {
+        estimatedCompleteTimeMs = nowMs;
+    }
+
+    return estimatedCompleteTimeMs + _currentDelayMs;
+}
+
+// Must be called from inside a critical section
+WebRtc_Word32
+VCMTiming::MaxDecodeTimeMs(FrameType frameType /*= kVideoFrameDelta*/) const
+{
+    const WebRtc_Word32 decodeTimeMs = _codecTimer.RequiredDecodeTimeMs(frameType);
+
+    if (decodeTimeMs < 0)
+    {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_vcmId, _timingId),
+            "Negative maximum decode time: %d", decodeTimeMs);
+        return -1;
+    }
+    return decodeTimeMs;
+}
+
+WebRtc_UWord32
+VCMTiming::MaxWaitingTime(WebRtc_Word64 renderTimeMs, WebRtc_Word64 nowMs) const
+{
+    CriticalSectionScoped cs(_critSect);
+
+    const WebRtc_Word64 maxWaitTimeMs = renderTimeMs - nowMs -
+                                        MaxDecodeTimeMs() - _renderDelayMs;
+
+    if (maxWaitTimeMs < 0)
+    {
+        return 0;
+    }
+    return static_cast<WebRtc_UWord32>(maxWaitTimeMs);
+}
+
+bool
+VCMTiming::EnoughTimeToDecode(WebRtc_UWord32 availableProcessingTimeMs) const
+{
+    CriticalSectionScoped cs(_critSect);
+    WebRtc_Word32 maxDecodeTimeMs = MaxDecodeTimeMs();
+    if (maxDecodeTimeMs < 0)
+    {
+        // Haven't decoded any frames yet, try decoding one to get an estimate
+        // of the decode time.
+        return true;
+    }
+    else if (maxDecodeTimeMs == 0)
+    {
+        // Decode time is less than 1, set to 1 for now since
+        // we don't have any better precision. Count ticks later?
+        maxDecodeTimeMs = 1;
+    }
+    return static_cast<WebRtc_Word32>(availableProcessingTimeMs) - maxDecodeTimeMs > 0;
+}
+
+WebRtc_UWord32
+VCMTiming::TargetVideoDelay() const
+{
+    CriticalSectionScoped cs(_critSect);
+    return TargetDelayInternal();
+}
+
+WebRtc_UWord32
+VCMTiming::TargetDelayInternal() const
+{
+    return _requiredDelayMs + MaxDecodeTimeMs() + _renderDelayMs;
+}
+
+}
diff --git a/src/modules/video_coding/main/source/timing.h b/src/modules/video_coding/main/source/timing.h
new file mode 100644
index 0000000..66d3ece
--- /dev/null
+++ b/src/modules/video_coding/main/source/timing.h
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_TIMING_H_
+#define WEBRTC_MODULES_VIDEO_CODING_TIMING_H_
+
+#include "typedefs.h"
+#include "critical_section_wrapper.h"
+#include "codec_timer.h"
+
+namespace webrtc
+{
+
+class VCMTimestampExtrapolator;
+
+class VCMTiming
+{
+public:
+    // The primary timing component should be passed
+    // if this is the dual timing component.
+    VCMTiming(WebRtc_Word32 vcmId = 0,
+              WebRtc_Word32 timingId = 0,
+              VCMTiming* masterTiming = NULL);
+    ~VCMTiming();
+
+    // Resets the timing to the initial state.
+    void Reset(WebRtc_Word64 nowMs = -1);
+    void ResetDecodeTime();
+
+    // The amount of time needed to render an image. Defaults to 10 ms.
+    void SetRenderDelay(WebRtc_UWord32 renderDelayMs);
+
+    // The minimum time the video must be delayed on the receiver to
+    // get the desired jitter buffer level.
+    void SetRequiredDelay(WebRtc_UWord32 requiredDelayMs);
+
+    // Minimum total delay required to sync video with audio.
+    void SetMinimumTotalDelay(WebRtc_UWord32 minTotalDelayMs);
+
+    // Increases or decreases the current delay to get closer to the target delay.
+    // Calculates how long it has been since the previous call to this function,
+    // and increases/decreases the delay in proportion to the time difference.
+    void UpdateCurrentDelay(WebRtc_UWord32 frameTimestamp);
+
+    // Increases or decreases the current delay to get closer to the target delay.
+    // Given the actual decode time in ms and the render time in ms for a frame, this
+    // function calculates how late the frame is and increases the delay accordingly.
+    void UpdateCurrentDelay(WebRtc_Word64 renderTimeMs, WebRtc_Word64 actualDecodeTimeMs);
+
+    // Stops the decoder timer, should be called when the decoder returns a frame
+    // or when the decoded frame callback is called.
+    WebRtc_Word32 StopDecodeTimer(WebRtc_UWord32 timeStamp,
+                                  WebRtc_Word64 startTimeMs,
+                                  WebRtc_Word64 nowMs);
+
+    // Used to report that a frame is passed to decoding. Updates the timestamp filter
+    // which is used to map between timestamps and receiver system time.
+    void IncomingTimestamp(WebRtc_UWord32 timeStamp, WebRtc_Word64 lastPacketTimeMs);
+
+    // Returns the receiver system time when the frame with timestamp frameTimestamp
+    // should be rendered, assuming that the system time currently is nowMs.
+    WebRtc_Word64 RenderTimeMs(WebRtc_UWord32 frameTimestamp, WebRtc_Word64 nowMs) const;
+
+    // Returns the maximum time in ms that we can wait for a frame to become complete
+    // before we must pass it to the decoder.
+    WebRtc_UWord32 MaxWaitingTime(WebRtc_Word64 renderTimeMs, WebRtc_Word64 nowMs) const;
+
+    // Returns the current target delay which is required delay + decode time + render
+    // delay.
+    WebRtc_UWord32 TargetVideoDelay() const;
+
+    // Calculates whether or not there is enough time to decode a frame given a
+    // certain amount of processing time.
+    bool EnoughTimeToDecode(WebRtc_UWord32 availableProcessingTimeMs) const;
+
+    enum { kDefaultRenderDelayMs = 10 };
+    enum { kDelayMaxChangeMsPerS = 100 };
+
+protected:
+    WebRtc_Word32 MaxDecodeTimeMs(FrameType frameType = kVideoFrameDelta) const;
+    WebRtc_Word64 RenderTimeMsInternal(WebRtc_UWord32 frameTimestamp,
+                                       WebRtc_Word64 nowMs) const;
+    WebRtc_UWord32 TargetDelayInternal() const;
+
+private:
+    CriticalSectionWrapper&          _critSect;
+    WebRtc_Word32                 _vcmId;
+    WebRtc_Word32                 _timingId;
+    bool                          _master;
+    VCMTimestampExtrapolator*     _tsExtrapolator;
+    VCMCodecTimer                 _codecTimer;
+    WebRtc_UWord32                _renderDelayMs;
+    WebRtc_UWord32                _minTotalDelayMs;
+    WebRtc_UWord32                _requiredDelayMs;
+    WebRtc_UWord32                _currentDelayMs;
+    WebRtc_UWord32                _prevFrameTimestamp;
+    WebRtc_Word64                 _startStoragePlaybackMs;
+    WebRtc_Word64                 _firstStoredRenderTimeMs;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_TIMING_H_
diff --git a/src/modules/video_coding/main/source/video_coding.gyp b/src/modules/video_coding/main/source/video_coding.gyp
new file mode 100644
index 0000000..f2431f4
--- /dev/null
+++ b/src/modules/video_coding/main/source/video_coding.gyp
@@ -0,0 +1,104 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../../../common_settings.gypi', # Common settings
+  ],
+  'targets': [
+    {
+      'target_name': 'webrtc_video_coding',
+      'type': '<(library)',
+      'dependencies': [
+        '../../codecs/i420/main/source/i420.gyp:webrtc_i420',
+        '../../codecs/vp8/main/source/vp8.gyp:webrtc_vp8',
+        '../../../../common_video/vplib/main/source/vplib.gyp:webrtc_vplib',
+        '../../../../system_wrappers/source/system_wrappers.gyp:system_wrappers',
+      ],
+      'include_dirs': [
+        '../interface',
+        '../../../interface',
+        '../../codecs/interface',
+        '../../../../common_video/interface',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '../interface',
+          '../../codecs/interface',
+        ],
+      },
+      'sources': [
+        # interfaces
+        '../interface/video_coding.h',
+        '../interface/video_coding_defines.h',
+
+        # headers
+        'codec_database.h',
+        'codec_timer.h',
+        'content_metrics_processing.h',
+        'encoded_frame.h',
+        'er_tables_xor.h',
+        'event.h',
+        'exp_filter.h',
+        'fec_tables_xor.h',
+        'frame_buffer.h',
+        'frame_dropper.h',
+        'frame_list.h',
+        'generic_decoder.h',
+        'generic_encoder.h',
+        'inter_frame_delay.h',
+        'internal_defines.h',
+        'jitter_buffer_common.h',
+        'jitter_buffer.h',
+        'jitter_estimator.h',
+        'media_opt_util.h',
+        'media_optimization.h',
+        'nack_fec_tables.h',
+        'packet.h',
+        'qm_select_data.h',
+        'qm_select.h',
+        'receiver.h',
+        'rtt_filter.h',
+        'session_info.h',
+        'tick_time.h',
+        'timestamp_extrapolator.h',
+        'timestamp_map.h',
+        'timing.h',
+        'video_coding_impl.h',
+
+        # sources
+        'codec_database.cc',
+        'codec_timer.cc',
+        'content_metrics_processing.cc',
+        'encoded_frame.cc',
+        'exp_filter.cc',
+        'frame_buffer.cc',
+        'frame_dropper.cc',
+        'frame_list.cc',
+        'generic_decoder.cc',
+        'generic_encoder.cc',
+        'inter_frame_delay.cc',
+        'jitter_buffer.cc',
+        'jitter_estimator.cc',
+        'media_opt_util.cc',
+        'media_optimization.cc',
+        'packet.cc',
+        'qm_select.cc',
+        'receiver.cc',
+        'rtt_filter.cc',
+        'session_info.cc',
+        'timestamp_extrapolator.cc',
+        'timestamp_map.cc',
+        'timing.cc',
+        'video_coding_impl.cc',
+      ], # source
+    },
+  ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/src/modules/video_coding/main/source/video_coding_impl.cc b/src/modules/video_coding/main/source/video_coding_impl.cc
new file mode 100644
index 0000000..48d2947
--- /dev/null
+++ b/src/modules/video_coding/main/source/video_coding_impl.cc
@@ -0,0 +1,1346 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "video_coding_impl.h"
+#include "common_types.h"
+#include "encoded_frame.h"
+#include "jitter_buffer.h"
+#include "packet.h"
+#include "trace.h"
+#include "video_codec_interface.h"
+
+namespace webrtc
+{
+
+//#define DEBUG_DECODER_BIT_STREAM
+//#define DEBUG_ENCODER_INPUT
+
+WebRtc_UWord32
+VCMProcessTimer::Period() const
+{
+    return _periodMs;
+}
+
+WebRtc_UWord32
+VCMProcessTimer::TimeUntilProcess() const
+{
+    return static_cast<WebRtc_UWord32>(VCM_MAX(static_cast<WebRtc_Word64>(_periodMs) -
+                                    (VCMTickTime::MillisecondTimestamp() - _latestMs), 0));
+}
+
+void
+VCMProcessTimer::Processed()
+{
+    _latestMs = VCMTickTime::MillisecondTimestamp();
+}
+
+VideoCodingModuleImpl::VideoCodingModuleImpl(const WebRtc_Word32 id)
+:
+_id(id),
+_receiveCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
+_receiverInited(false),
+_timing(id, 1),
+_dualTiming(id, 2, &_timing),
+_receiver(_timing, id, 1),
+_dualReceiver(_dualTiming, id, 2, false),
+_decodedFrameCallback(_timing),
+_dualDecodedFrameCallback(_dualTiming),
+_frameTypeCallback(NULL),
+_frameStorageCallback(NULL),
+_receiveStatsCallback(NULL),
+_packetRequestCallback(NULL),
+_decoder(NULL),
+_dualDecoder(NULL),
+_bitStreamBeforeDecoder(NULL),
+_frameFromFile(),
+_keyRequestMode(kKeyOnError),
+_scheduleKeyRequest(false),
+
+_sendCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
+_encoder(),
+_encodedFrameCallback(),
+_nextFrameType(kVideoFrameDelta),
+_mediaOpt(id),
+_sendCodecType(kVideoCodecUnknown),
+_sendStatsCallback(NULL),
+_encoderInputFile(NULL),
+
+_codecDataBase(id),
+_receiveStatsTimer(1000),
+_sendStatsTimer(1000),
+_retransmissionTimer(10),
+_keyRequestTimer(500)
+{
+#ifdef DEBUG_DECODER_BIT_STREAM
+    _bitStreamBeforeDecoder = fopen("decoderBitStream.bit", "wb");
+#endif
+#ifdef DEBUG_ENCODER_INPUT
+    _encoderInputFile = fopen("encoderInput.yuv", "wb");
+#endif
+}
+
+VideoCodingModuleImpl::~VideoCodingModuleImpl()
+{
+    if (_dualDecoder != NULL)
+    {
+        _codecDataBase.ReleaseDecoder(_dualDecoder);
+    }
+    delete &_receiveCritSect;
+    delete &_sendCritSect;
+#ifdef DEBUG_DECODER_BIT_STREAM
+    fclose(_bitStreamBeforeDecoder);
+#endif
+#ifdef DEBUG_ENCODER_INPUT
+    fclose(_encoderInputFile);
+#endif
+}
+
+VideoCodingModule*
+VideoCodingModule::Create(const WebRtc_Word32 id)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(id),
+               "VideoCodingModule::Create()");
+    return new VideoCodingModuleImpl(id);
+}
+
+void
+VideoCodingModule::Destroy(VideoCodingModule* module)
+{
+    if (module != NULL)
+    {
+        WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding,
+                   static_cast<VideoCodingModuleImpl*>(module)->Id(),
+                   "VideoCodingModule::Destroy()");
+        delete static_cast<VideoCodingModuleImpl*>(module);
+    }
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::Process()
+{
+    WebRtc_Word32 returnValue = VCM_OK;
+
+    // Receive-side statistics
+    if (_receiveStatsTimer.TimeUntilProcess() == 0)
+    {
+        _receiveStatsTimer.Processed();
+        if (_receiveStatsCallback != NULL)
+        {
+            WebRtc_UWord32 bitRate;
+            WebRtc_UWord32 frameRate;
+            const WebRtc_Word32 ret = _receiver.ReceiveStatistics(bitRate, frameRate);
+            if (ret == 0)
+            {
+                _receiveStatsCallback->ReceiveStatistics(bitRate, frameRate);
+            }
+            else if (returnValue == VCM_OK)
+            {
+                returnValue = ret;
+            }
+        }
+    }
+
+    // Send-side statistics
+    if (_sendStatsTimer.TimeUntilProcess() == 0)
+    {
+        _sendStatsTimer.Processed();
+        if (_sendStatsCallback != NULL)
+        {
+            WebRtc_UWord32 bitRate;
+            WebRtc_UWord32 frameRate;
+            {
+                CriticalSectionScoped cs(_sendCritSect);
+                bitRate = static_cast<WebRtc_UWord32>(_mediaOpt.SentBitRate() + 0.5f);
+                frameRate = static_cast<WebRtc_UWord32>(_mediaOpt.SentFrameRate() + 0.5f);
+            }
+            _sendStatsCallback->SendStatistics(bitRate, frameRate);
+        }
+    }
+
+    // Packet retransmission requests
+    if (_retransmissionTimer.TimeUntilProcess() == 0)
+    {
+        _retransmissionTimer.Processed();
+        if (_packetRequestCallback != NULL)
+        {
+            WebRtc_UWord16 nackList[kNackHistoryLength];
+            WebRtc_UWord16 length = kNackHistoryLength;
+            const WebRtc_Word32 ret = NackList(nackList, length);
+            if (ret != VCM_OK && returnValue == VCM_OK)
+            {
+                returnValue = ret;
+            }
+            if (length > 0)
+            {
+                _packetRequestCallback->ResendPackets(nackList, length);
+            }
+        }
+    }
+
+    // Key frame requests
+    if (_keyRequestTimer.TimeUntilProcess() == 0)
+    {
+        _keyRequestTimer.Processed();
+        if (_scheduleKeyRequest && _frameTypeCallback != NULL)
+        {
+            const WebRtc_Word32 ret = RequestKeyFrame();
+            if (ret != VCM_OK && returnValue == VCM_OK)
+            {
+                returnValue = ret;
+            }
+        }
+    }
+
+    return returnValue;
+}
+
+// Returns version of the module and its components
+WebRtc_Word32
+VideoCodingModuleImpl::Version(WebRtc_Word8* version,
+                                WebRtc_UWord32& remainingBufferInBytes,
+                                WebRtc_UWord32& position) const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Version()");
+    if (version == NULL)
+    {
+        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id),
+            "Invalid buffer pointer in argument to Version()");
+        return VCM_PARAMETER_ERROR;
+    }
+    WebRtc_Word8 ourVersion[] = "VideoCodingModule 1.1.0\n";
+    WebRtc_UWord32 ourLength = (WebRtc_UWord32)strlen(ourVersion);
+    if (remainingBufferInBytes < ourLength)
+    {
+        return VCM_MEMORY;
+    }
+    memcpy(&version[position], ourVersion, ourLength);
+    remainingBufferInBytes -= ourLength;
+    position += ourLength;
+
+    // Safe to truncate here.
+    WebRtc_Word32 ret = _codecDataBase.Version(version, remainingBufferInBytes, position);
+    if (ret < 0)
+    {
+        return ret;
+    }
+    // Ensure the strlen call is safe by terminating at the end of version.
+    version[position + remainingBufferInBytes - 1] = '\0';
+    ourLength = (WebRtc_UWord32)strlen(&version[position]);
+    remainingBufferInBytes -= (ourLength + 1); // include null termination.
+    position += (ourLength + 1);
+
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::Id() const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Id()");
+    CriticalSectionScoped receiveCs(_receiveCritSect);
+    {
+        CriticalSectionScoped sendCs(_sendCritSect);
+        return _id;
+    }
+}
+
+//  Change the unique identifier of this object
+WebRtc_Word32
+VideoCodingModuleImpl::ChangeUniqueId(const WebRtc_Word32 id)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ChangeUniqueId()");
+    CriticalSectionScoped receiveCs(_receiveCritSect);
+    {
+        CriticalSectionScoped sendCs(_sendCritSect);
+        _id = id;
+        return VCM_OK;
+    }
+}
+
+// Returns the number of milliseconds until the module wants a worker thread to call Process
+WebRtc_Word32
+VideoCodingModuleImpl::TimeUntilNextProcess()
+{
+    WebRtc_UWord32 timeUntilNextProcess = VCM_MIN(_receiveStatsTimer.TimeUntilProcess(),
+                                                  _sendStatsTimer.TimeUntilProcess());
+    if ((_receiver.NackMode() != kNoNack) || (_dualReceiver.State() != kPassive))
+    {
+        // We need a Process call more often if we are relying on retransmissions
+        timeUntilNextProcess = VCM_MIN(timeUntilNextProcess,
+                                       _retransmissionTimer.TimeUntilProcess());
+    }
+    timeUntilNextProcess = VCM_MIN(timeUntilNextProcess,
+                                   _keyRequestTimer.TimeUntilProcess());
+
+    return timeUntilNextProcess;
+}
+
+// Get number of supported codecs
+WebRtc_UWord8
+VideoCodingModule::NumberOfCodecs()
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, -1, "NumberOfCodecs()");
+    return VCMCodecDataBase::NumberOfCodecs();
+}
+
+// Get supported codec with id
+WebRtc_Word32
+VideoCodingModule::Codec(WebRtc_UWord8 listId, VideoCodec* codec)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, -1, "Codec()");
+    if (codec == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    return VCMCodecDataBase::Codec(listId, codec);
+}
+
+// Get supported codec with type
+WebRtc_Word32
+VideoCodingModule::Codec(VideoCodecType codecType, VideoCodec* codec)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, -1, "Codec()");
+    if (codec == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    return VCMCodecDataBase::Codec(codecType, codec);
+}
+
+/*
+*   Sender
+*/
+
+// Reset send side to initial state - all components
+WebRtc_Word32
+VideoCodingModuleImpl::InitializeSender()
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "InitializeSender()");
+    CriticalSectionScoped cs(_sendCritSect);
+    _codecDataBase.ResetSender();
+    _encoder = NULL;
+    _encodedFrameCallback.SetTransportCallback(NULL);
+    // setting default bitRate and frameRate to 0
+    _mediaOpt.SetEncodingData(kVideoCodecUnknown, 0, 0, 0, 0, 0);
+    _mediaOpt.Reset(); // Resetting frame dropper
+    return VCM_OK;
+}
+
+// Makes sure the encoder is in its initial state.
+WebRtc_Word32
+VideoCodingModuleImpl::ResetEncoder()
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ResetEncoder()");
+    CriticalSectionScoped cs(_sendCritSect);
+    if (_encoder != NULL)
+    {
+        return _encoder->Reset();
+    }
+    return VCM_OK;
+}
+
+// Register the send codec to be used.
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterSendCodec(const VideoCodec* sendCodec,
+                                         WebRtc_UWord32 numberOfCores,
+                                         WebRtc_UWord32 maxPayloadSize)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "RegisterSendCodec()");
+    CriticalSectionScoped cs(_sendCritSect);
+    if (sendCodec == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    WebRtc_Word32 ret = _codecDataBase.RegisterSendCodec(sendCodec,
+                                                         numberOfCores,
+                                                         maxPayloadSize);
+    if (ret < 0)
+    {
+        return ret;
+    }
+
+    _encoder = _codecDataBase.SetEncoder(sendCodec, &_encodedFrameCallback);
+    if (_encoder == NULL)
+    {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id),
+                   "Failed to initialize encoder");
+        return VCM_CODEC_ERROR;
+    }
+    _sendCodecType = sendCodec->codecType;
+    _mediaOpt.SetEncodingData(_sendCodecType,
+                              sendCodec->maxBitrate,
+                              sendCodec->maxFramerate,
+                              sendCodec->startBitrate,
+                              sendCodec->width,
+                              sendCodec->height);
+    _mediaOpt.SetMtu(maxPayloadSize);
+
+    return VCM_OK;
+}
+
+// Get current send codec
+WebRtc_Word32
+VideoCodingModuleImpl::SendCodec(VideoCodec* currentSendCodec) const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "SendCodec()");
+    CriticalSectionScoped cs(_sendCritSect);
+
+    if (currentSendCodec == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    return _codecDataBase.SendCodec(currentSendCodec);
+}
+
+// Get the current send codec type
+VideoCodecType
+VideoCodingModuleImpl::SendCodec() const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "SendCodec()");
+    CriticalSectionScoped cs(_sendCritSect);
+
+    return _codecDataBase.SendCodec();
+}
+
+// Register an external decoder object.
+// This can not be used together with external decoder callbacks.
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterExternalEncoder(VideoEncoder* externalEncoder,
+                                               WebRtc_UWord8 payloadType,
+                                               bool internalSource /*= false*/)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterExternalEncoder()");
+    CriticalSectionScoped cs(_sendCritSect);
+
+    if (externalEncoder == NULL)
+    {
+        bool wasSendCodec = false;
+        const WebRtc_Word32 ret = _codecDataBase.DeRegisterExternalEncoder(payloadType,
+                                                                           wasSendCodec);
+        if (wasSendCodec)
+        {
+            // Make sure the VCM doesn't use the de-registered codec
+            _encoder = NULL;
+        }
+        return ret;
+    }
+    return _codecDataBase.RegisterExternalEncoder(externalEncoder,
+                                                  payloadType,
+                                                  internalSource);
+}
+
+// Get codec config parameters
+WebRtc_Word32
+VideoCodingModuleImpl::CodecConfigParameters(WebRtc_UWord8* buffer, WebRtc_Word32 size)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "CodecConfigParameters()");
+    CriticalSectionScoped cs(_sendCritSect);
+    if (_encoder != NULL)
+    {
+        return _encoder->CodecConfigParameters(buffer, size);
+    }
+    return VCM_UNINITIALIZED;
+}
+
+// Get encode bitrate
+WebRtc_UWord32
+VideoCodingModuleImpl::Bitrate() const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Bitrate()");
+    CriticalSectionScoped cs(_sendCritSect);
+    // return the bit rate which the encoder is set to
+    if (_encoder != NULL)
+    {
+        return _encoder->BitRate();
+    }
+    return VCM_UNINITIALIZED;
+}
+
+// Get encode frame rate
+WebRtc_UWord32
+VideoCodingModuleImpl::FrameRate() const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "FrameRate()");
+    CriticalSectionScoped cs(_sendCritSect);
+    // input frame rate, not compensated
+    if (_encoder != NULL)
+    {
+        return _encoder->FrameRate();
+    }
+    return VCM_UNINITIALIZED;
+}
+
+// Set channel parameters
+WebRtc_Word32
+VideoCodingModuleImpl::SetChannelParameters(WebRtc_UWord32 availableBandWidth,
+                                            WebRtc_UWord8 lossRate,
+                                            WebRtc_UWord32 RTT)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "SetChannelParameters()");
+    WebRtc_Word32 ret = 0;
+    {
+        CriticalSectionScoped sendCs(_sendCritSect);
+        WebRtc_UWord32 targetRate = _mediaOpt.SetTargetRates(availableBandWidth,
+                                                             lossRate,
+                                                             RTT);
+        if (_encoder != NULL)
+        {
+            ret = _encoder->SetPacketLoss(lossRate);
+            if (ret < 0 )
+            {
+                return ret;
+            }
+            ret = (WebRtc_Word32)_encoder->SetRates(targetRate, _mediaOpt.InputFrameRate());
+            if (ret < 0)
+            {
+                return ret;
+            }
+        }
+        else
+        {
+            return VCM_UNINITIALIZED;
+        } // encoder
+    }// send side
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::SetReceiveChannelParameters(WebRtc_UWord32 RTT)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "SetReceiveChannelParameters()");
+    CriticalSectionScoped receiveCs(_receiveCritSect);
+    _receiver.UpdateRtt(RTT);
+    return 0;
+}
+
+// Register a transport callback which will be called to deliver the encoded buffers
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterTransportCallback(VCMPacketizationCallback* transport)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterTransportCallback()");
+    CriticalSectionScoped cs(_sendCritSect);
+    _encodedFrameCallback.SetMediaOpt(&_mediaOpt);
+    _encodedFrameCallback.SetTransportCallback(transport);
+    return VCM_OK;
+}
+
+// Register video output information callback which will be called to deliver information
+// about the video stream produced by the encoder, for instance the average frame rate and
+// bit rate.
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterSendStatisticsCallback(VCMSendStatisticsCallback* sendStats)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterSendStatisticsCallback()");
+    CriticalSectionScoped cs(_sendCritSect);
+    _sendStatsCallback = sendStats;
+    return VCM_OK;
+}
+
+// Register a video quality settings callback which will be called when frame rate/dimensions
+// need to be updated for video quality optimization
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterVideoQMCallback(VCMQMSettingsCallback* videoQMSettings)
+{
+    CriticalSectionScoped cs(_sendCritSect);
+    return _mediaOpt.RegisterVideoQMCallback(videoQMSettings);
+}
+
+
+// Register a video protection callback which will be called to deliver the requested FEC rate
+// and NACK status (on/off).
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterProtectionCallback(VCMProtectionCallback* protection)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterProtectionCallback()");
+    CriticalSectionScoped cs(_sendCritSect);
+    _mediaOpt.RegisterProtectionCallback(protection);
+    return VCM_OK;
+}
+
+// Enable or disable a video protection method.
+WebRtc_Word32
+VideoCodingModuleImpl::SetVideoProtection(VCMVideoProtection videoProtection, bool enable)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "SetVideoProtection()");
+
+    switch (videoProtection)
+    {
+
+    case kProtectionNack:
+        {
+            // Both send-side and receive-side
+            SetVideoProtection(kProtectionNackSender, enable);
+            SetVideoProtection(kProtectionNackReceiver, enable);
+            break;
+        }
+
+    case kProtectionNackSender:
+        {
+            // Send-side only
+            CriticalSectionScoped cs(_sendCritSect);
+            _mediaOpt.EnableNack(enable);
+            break;
+        }
+
+    case kProtectionNackReceiver:
+        {
+            // Receive-side only
+            CriticalSectionScoped cs(_receiveCritSect);
+            if (enable)
+            {
+                _receiver.SetNackMode(kNackInfinite);
+            }
+            else
+            {
+                _receiver.SetNackMode(kNoNack);
+            }
+            break;
+        }
+
+    case kProtectionDualDecoder:
+        {
+            CriticalSectionScoped cs(_receiveCritSect);
+            if (enable)
+            {
+                _receiver.SetNackMode(kNoNack);
+                _dualReceiver.SetNackMode(kNackInfinite);
+            }
+            else
+            {
+                _dualReceiver.SetNackMode(kNoNack);
+            }
+            break;
+        }
+
+    case kProtectionKeyOnLoss:
+        {
+            CriticalSectionScoped cs(_receiveCritSect);
+            if (enable)
+            {
+                _keyRequestMode = kKeyOnLoss;
+            }
+            else if (_keyRequestMode == kKeyOnLoss)
+            {
+                _keyRequestMode = kKeyOnError; // default mode
+            }
+            else
+            {
+                return VCM_PARAMETER_ERROR;
+            }
+            break;
+        }
+
+    case kProtectionKeyOnKeyLoss:
+        {
+            CriticalSectionScoped cs(_receiveCritSect);
+            if (enable)
+            {
+                _keyRequestMode = kKeyOnKeyLoss;
+            }
+            else if (_keyRequestMode == kKeyOnKeyLoss)
+            {
+                _keyRequestMode = kKeyOnError; // default mode
+            }
+            else
+            {
+                return VCM_PARAMETER_ERROR;
+            }
+            break;
+        }
+
+    case kProtectionNackFEC:
+        {
+            {
+              // Receive side
+                CriticalSectionScoped cs(_receiveCritSect);
+                if (enable)
+                {
+                    _receiver.SetNackMode(kNackHybrid);
+                }
+                else
+                {
+                    _receiver.SetNackMode(kNoNack);
+                }
+            }
+            // Send Side
+            {
+                CriticalSectionScoped cs(_sendCritSect);
+                _mediaOpt.EnableNackFEC(enable);
+            }
+            break;
+        }
+
+    case kProtectionFEC:
+        {
+            CriticalSectionScoped cs(_sendCritSect);
+            _mediaOpt.EnableFEC(enable);
+            break;
+        }
+
+    case kProtectionPeriodicKeyFrames:
+        {
+            CriticalSectionScoped cs(_sendCritSect);
+            return _codecDataBase.SetPeriodicKeyFrames(enable);
+            break;
+        }
+
+    default:
+        return VCM_PARAMETER_ERROR;
+    }
+    return VCM_OK;
+}
+
+// Add one raw video frame to the encoder, blocking.
+WebRtc_Word32
+VideoCodingModuleImpl::AddVideoFrame(const VideoFrame& videoFrame,
+                                     const VideoContentMetrics* _contentMetrics,
+                                     const CodecSpecificInfo* codecSpecificInfo)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "AddVideoFrame()");
+    CriticalSectionScoped cs(_sendCritSect);
+
+    if (_encoder == NULL)
+    {
+        return VCM_UNINITIALIZED;
+    }
+
+    if (_nextFrameType == kFrameEmpty)
+    {
+        return VCM_OK;
+    }
+
+    _mediaOpt.UpdateIncomingFrameRate();
+
+    if (_mediaOpt.DropFrame())
+    {
+        WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCoding, VCMId(_id),
+                   "Drop frame due to bitrate");
+    }
+    else
+    {
+        _mediaOpt.updateContentData(_contentMetrics);
+        const FrameType requestedFrameType = _nextFrameType;
+        _nextFrameType = kVideoFrameDelta; // default frame type
+        WebRtc_Word32 ret = _encoder->Encode(videoFrame,
+                                             codecSpecificInfo,
+                                             requestedFrameType);
+        if (_encoderInputFile != NULL)
+        {
+            fwrite(videoFrame.Buffer(), 1, videoFrame.Length(), _encoderInputFile);
+        }
+        if (ret < 0)
+        {
+            _nextFrameType = requestedFrameType;
+            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding,VCMId(_id),
+                       "Encode error: %d", ret);
+            return ret;
+        }
+    }
+
+    return VCM_OK;
+}
+
+// Next frame encoded should be of the type frameType
+// Good for only one frame
+WebRtc_Word32
+VideoCodingModuleImpl::FrameTypeRequest(FrameType frameType)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "FrameTypeRequest()");
+    CriticalSectionScoped cs(_sendCritSect);
+    _nextFrameType = frameType;
+    if (_encoder != NULL && _encoder->InternalSource())
+    {
+        // Try to request the frame if we have an external encoder with internal source
+        // since AddVideoFrame never will be called.
+        if (_encoder->RequestFrame(_nextFrameType) == WEBRTC_VIDEO_CODEC_OK)
+        {
+            _nextFrameType = kVideoFrameDelta;
+        }
+    }
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::EnableFrameDropper(bool enable)
+{
+    CriticalSectionScoped cs(_sendCritSect);
+    _mediaOpt.EnableFrameDropper(enable);
+    return VCM_OK;
+}
+
+
+WebRtc_Word32
+VideoCodingModuleImpl::SentFrameCount(VCMFrameCount &frameCount) const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "SentFrameCount()");
+    CriticalSectionScoped cs(_sendCritSect);
+    return _mediaOpt.SentFrameCount(frameCount);
+}
+
+// Initialize receiver, resets codec database etc
+WebRtc_Word32
+VideoCodingModuleImpl::InitializeReceiver()
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "InitializeReceiver()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    WebRtc_Word32 ret = _receiver.Initialize();
+    if (ret < 0)
+    {
+        return ret;
+    }
+
+    ret = _dualReceiver.Initialize();
+    if (ret < 0)
+    {
+        return ret;
+    }
+    _codecDataBase.ResetReceiver();
+    _timing.Reset();
+
+    _decoder = NULL;
+    _decodedFrameCallback.SetUserReceiveCallback(NULL);
+    _receiverInited = true;
+    _frameTypeCallback = NULL;
+    _frameStorageCallback = NULL;
+    _receiveStatsCallback = NULL;
+    _packetRequestCallback = NULL;
+    _keyRequestMode = kKeyOnError;
+    _scheduleKeyRequest = false;
+
+    return VCM_OK;
+}
+
+// Register a receive callback. Will be called whenever there is a new frame ready
+// for rendering.
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterReceiveCallback(VCMReceiveCallback* receiveCallback)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterReceiveCallback()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    _decodedFrameCallback.SetUserReceiveCallback(receiveCallback);
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterReceiveStatisticsCallback(
+                                     VCMReceiveStatisticsCallback* receiveStats)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterReceiveStatisticsCallback()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    _receiveStatsCallback = receiveStats;
+    return VCM_OK;
+}
+
+// Register an externally defined decoder/render object.
+// Can be a decoder only or a decoder coupled with a renderer.
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterExternalDecoder(VideoDecoder* externalDecoder,
+                                               WebRtc_UWord8 payloadType,
+                                               bool internalRenderTiming)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall,
+               webrtc::kTraceVideoCoding,
+               VCMId(_id),
+               "RegisterExternalDecoder()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    if (externalDecoder == NULL)
+    {
+        // Make sure the VCM updates the decoder next time it decodes.
+        _decoder = NULL;
+        return _codecDataBase.DeRegisterExternalDecoder(payloadType);
+    }
+    else
+    {
+        return _codecDataBase.RegisterExternalDecoder(externalDecoder,
+                                                      payloadType,
+                                                      internalRenderTiming);
+    }
+}
+
+// Register a frame type request callback.
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterFrameTypeCallback(VCMFrameTypeCallback* frameTypeCallback)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterFrameTypeCallback()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    _frameTypeCallback = frameTypeCallback;
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterFrameStorageCallback(VCMFrameStorageCallback* frameStorageCallback)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterFrameStorageCallback()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    _frameStorageCallback = frameStorageCallback;
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterPacketRequestCallback(VCMPacketRequestCallback* callback)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterPacketRequestCallback()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    _packetRequestCallback = callback;
+    return VCM_OK;
+}
+
+// Decode next frame, blocking.
+// Should be called as often as possible to get the most out of the decoder.
+WebRtc_Word32
+VideoCodingModuleImpl::Decode(WebRtc_UWord16 maxWaitTimeMs)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Decode()");
+    WebRtc_Word64 nextRenderTimeMs;
+
+    {
+        CriticalSectionScoped cs(_receiveCritSect);
+        if (!_receiverInited)
+        {
+            return VCM_UNINITIALIZED;
+        }
+        if (!_codecDataBase.DecoderRegistered())
+        {
+            return VCM_NO_CODEC_REGISTERED;
+        }
+    }
+
+    const bool dualReceiverEnabledNotReceiving = _dualReceiver.State() != kReceiving &&
+                                                 _dualReceiver.NackMode() == kNackInfinite;
+
+    VCMEncodedFrame* frame = _receiver.FrameForDecoding(maxWaitTimeMs,
+                                                        nextRenderTimeMs,
+                                                        _codecDataBase.RenderTiming(),
+                                                        &_dualReceiver);
+
+    if (dualReceiverEnabledNotReceiving && _dualReceiver.State() == kReceiving)
+    {
+        // Dual receiver is enabled (kNACK enabled), but was not receiving before the call to
+        // FrameForDecoding(). After the call the state changed to receiving, and therefore
+        // we must copy the primary decoder state to the dual decoder to make it possible
+        // for the dual decoder to start decoding retransmitted frames and recover.
+        CriticalSectionScoped cs(_receiveCritSect);
+        if (_dualDecoder != NULL)
+        {
+            _codecDataBase.ReleaseDecoder(_dualDecoder);
+        }
+        _dualDecoder = _codecDataBase.CreateDecoderCopy();
+        if (_dualDecoder != NULL)
+        {
+            _dualDecoder->RegisterDecodeCompleteCallback(&_dualDecodedFrameCallback);
+        }
+    }
+
+    if (frame != NULL)
+    {
+        CriticalSectionScoped cs(_receiveCritSect);
+
+        const WebRtc_UWord32 timestamp = frame->TimeStamp();
+
+        // If this frame was too late, we should adjust the delay accordingly
+        _timing.UpdateCurrentDelay(frame->RenderTimeMs(), VCMTickTime::MillisecondTimestamp());
+
+        if (_bitStreamBeforeDecoder != NULL)
+        {
+            // Write bit stream to file for debugging purposes
+            fwrite(frame->Buffer(), 1, frame->Length(), _bitStreamBeforeDecoder);
+        }
+        if (_frameStorageCallback != NULL)
+        {
+            WebRtc_Word32 ret = frame->Store(*_frameStorageCallback);
+            if (ret < 0)
+            {
+                return ret;
+            }
+        }
+
+        const WebRtc_Word32 ret = Decode(*frame);
+        _receiver.ReleaseFrame(frame);
+        frame = NULL;
+        if (ret != VCM_OK)
+        {
+            return ret;
+        }
+    }
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::RequestSliceLossIndication(const WebRtc_UWord64 pictureID) const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterSliceLossIndication()");
+    if (_frameTypeCallback != NULL)
+    {
+        const WebRtc_Word32 ret = _frameTypeCallback->SliceLossIndicationRequest(pictureID);
+        if (ret < 0)
+        {
+            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id),
+                "Failed to request key frame");
+            return ret;
+        }
+    } else
+    {
+        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id),
+            "No frame type request callback registered");
+        return VCM_MISSING_CALLBACK;
+    }
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::RequestKeyFrame()
+{
+    if (_frameTypeCallback != NULL)
+    {
+        const WebRtc_Word32 ret = _frameTypeCallback->FrameTypeRequest(kVideoFrameKey);
+        if (ret < 0)
+        {
+            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id),
+                "Failed to request key frame");
+            return ret;
+        }
+        _scheduleKeyRequest = false;
+    }
+    else
+    {
+        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id),
+            "No frame type request callback registered");
+        return VCM_MISSING_CALLBACK;
+    }
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::DecodeDualFrame(WebRtc_UWord16 maxWaitTimeMs)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "DecodeDualFrame()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    if (_dualReceiver.State() != kReceiving || _dualReceiver.NackMode() != kNackInfinite)
+    {
+        // The dual receiver is currently not receiving or dual decoder mode is disabled.
+        return VCM_OK;
+    }
+    WebRtc_Word64 dummyRenderTime;
+    WebRtc_Word32 decodeCount = 0;
+    VCMEncodedFrame* dualFrame = _dualReceiver.FrameForDecoding(maxWaitTimeMs,
+                                                                dummyRenderTime);
+    if (dualFrame != NULL && _dualDecoder != NULL)
+    {
+        WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCoding, VCMId(_id),
+                    "Decoding frame %u with dual decoder", dualFrame->TimeStamp());
+        // Decode dualFrame and try to catch up
+        WebRtc_Word32 ret = _dualDecoder->Decode(*dualFrame);
+        if (ret != WEBRTC_VIDEO_CODEC_OK)
+        {
+            WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id),
+                    "Failed to decode frame with dual decoder");
+            _dualReceiver.ReleaseFrame(dualFrame);
+            return VCM_CODEC_ERROR;
+        }
+        if (_receiver.DualDecoderCaughtUp(dualFrame, _dualReceiver))
+        {
+            // Copy the complete decoder state of the dual decoder
+            // to the primary decoder.
+            WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCoding, VCMId(_id),
+                    "Dual decoder caught up");
+            _codecDataBase.CopyDecoder(*_dualDecoder);
+            _codecDataBase.ReleaseDecoder(_dualDecoder);
+            _dualDecoder = NULL;
+        }
+        decodeCount++;
+    }
+    _dualReceiver.ReleaseFrame(dualFrame);
+    return decodeCount;
+}
+
+
+// Must be called from inside the receive side critical section.
+WebRtc_Word32
+VideoCodingModuleImpl::Decode(const VCMEncodedFrame& frame)
+{
+    // Change decoder if payload type has changed
+    const bool renderTimingBefore = _codecDataBase.RenderTiming();
+    _decoder = _codecDataBase.SetDecoder(frame.PayloadType(), _decodedFrameCallback);
+    if (renderTimingBefore != _codecDataBase.RenderTiming())
+    {
+        // Make sure we reset the decode time estimate since it will
+        // be zero for codecs without render timing.
+        _timing.ResetDecodeTime();
+    }
+    if (_decoder == NULL)
+    {
+        return VCM_NO_CODEC_REGISTERED;
+    }
+    // Decode a frame
+    WebRtc_Word32 ret = _decoder->Decode(frame);
+
+    // Check for failed decoding, run frame type request callback if needed.
+    if (ret < 0)
+    {
+        if (ret == VCM_ERROR_REQUEST_SLI)
+        {
+            return RequestSliceLossIndication(
+                    _decodedFrameCallback.LastReceivedPictureID() + 1);
+        }
+        else
+        {
+            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id),
+                "Failed to decode frame %u, requesting key frame", frame.TimeStamp());
+            ret = RequestKeyFrame();
+        }
+    }
+    else if (ret == VCM_REQUEST_SLI)
+    {
+        ret = RequestSliceLossIndication(_decodedFrameCallback.LastReceivedPictureID() + 1);
+    }
+    if (!frame.Complete() || frame.MissingFrame())
+    {
+        switch (_keyRequestMode)
+        {
+            case kKeyOnKeyLoss:
+            {
+                if (frame.FrameType() == kVideoFrameKey)
+                {
+                    _scheduleKeyRequest = true;
+                    return VCM_OK;
+                }
+                break;
+            }
+            case kKeyOnLoss:
+            {
+                _scheduleKeyRequest = true;
+                return VCM_OK;
+            }
+            default:
+                break;
+        }
+    }
+    return ret;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::DecodeFromStorage(const EncodedVideoData& frameFromStorage)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "DecodeFromStorage()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    WebRtc_Word32 ret = _frameFromFile.ExtractFromStorage(frameFromStorage);
+    if (ret < 0)
+    {
+        return ret;
+    }
+    return Decode(_frameFromFile);
+}
+
+// Reset the decoder state
+WebRtc_Word32
+VideoCodingModuleImpl::ResetDecoder()
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ResetDecoder()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    if (_decoder != NULL)
+    {
+        _receiver.Initialize();
+        _timing.Reset();
+        return _decoder->Reset();
+        _scheduleKeyRequest = false;
+    }
+    if (_dualReceiver.State() != kPassive)
+    {
+        _dualReceiver.Initialize();
+    }
+    if (_dualDecoder != NULL)
+    {
+        _codecDataBase.ReleaseDecoder(_dualDecoder);
+        _dualDecoder = NULL;
+    }
+    return VCM_OK;
+}
+
+// Register possible receive codecs, can be called multiple times
+WebRtc_Word32
+VideoCodingModuleImpl::RegisterReceiveCodec(const VideoCodec* receiveCodec,
+                                                WebRtc_Word32 numberOfCores,
+                                                bool requireKeyFrame)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "RegisterReceiveCodec()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    if (receiveCodec == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    return _codecDataBase.RegisterReceiveCodec(receiveCodec, numberOfCores, requireKeyFrame);
+}
+
+// Get current received codec
+WebRtc_Word32
+VideoCodingModuleImpl::ReceiveCodec(VideoCodec* currentReceiveCodec) const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ReceiveCodec()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    if (currentReceiveCodec == NULL)
+    {
+        return VCM_PARAMETER_ERROR;
+    }
+    return _codecDataBase.ReceiveCodec(currentReceiveCodec);
+}
+
+// Get current received codec
+VideoCodecType
+VideoCodingModuleImpl::ReceiveCodec() const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "ReceiveCodec()");
+    CriticalSectionScoped cs(_receiveCritSect);
+    return _codecDataBase.ReceiveCodec();
+}
+
+// Incoming packet from network parsed and ready for decode, non blocking.
+WebRtc_Word32
+VideoCodingModuleImpl::IncomingPacket(const WebRtc_UWord8* incomingPayload,
+                                    WebRtc_UWord32 payloadLength,
+                                    const WebRtcRTPHeader& rtpInfo)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "IncomingPacket()");
+    const VCMPacket packet(incomingPayload, payloadLength, rtpInfo);
+    WebRtc_Word32 ret;
+    if (_dualReceiver.State() != kPassive)
+    {
+        ret = _dualReceiver.InsertPacket(packet,
+                                         rtpInfo.type.Video.width,
+                                         rtpInfo.type.Video.height);
+        if (ret < 0)
+        {
+            return ret;
+        }
+    }
+    ret = _receiver.InsertPacket(packet, rtpInfo.type.Video.width, rtpInfo.type.Video.height);
+    if (ret < 0)
+    {
+        return ret;
+    }
+    return VCM_OK;
+}
+
+// Set codec config parameters
+WebRtc_Word32
+VideoCodingModuleImpl::SetCodecConfigParameters(WebRtc_UWord8 payloadType,
+                                                    const WebRtc_UWord8* buffer,
+                                                    WebRtc_Word32 length)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "SetCodecConfigParameters()");
+    CriticalSectionScoped cs(_receiveCritSect);
+
+    WebRtc_Word32 ret = _codecDataBase.SetCodecConfigParameters(payloadType, buffer, length);
+    if (ret < 0)
+    {
+        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id),
+                "SetCodecConfigParameters() failed, %d", ret);
+        return ret;
+    }
+    return VCM_OK;
+}
+
+// Minimum playout delay (used for lip-sync). This is the minimum delay required
+// to sync with audio. Not included in  VideoCodingModule::Delay()
+// Defaults to 0 ms.
+WebRtc_Word32
+VideoCodingModuleImpl::SetMinimumPlayoutDelay(WebRtc_UWord32 minPlayoutDelayMs)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+        "SetMininumPlayoutDelay(%u)", minPlayoutDelayMs);
+    _timing.SetMinimumTotalDelay(minPlayoutDelayMs);
+    return VCM_OK;
+}
+
+// The estimated delay caused by rendering, defaults to
+// kDefaultRenderDelayMs = 10 ms
+WebRtc_Word32
+VideoCodingModuleImpl::SetRenderDelay(WebRtc_UWord32 timeMS)
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "SetRenderDelay(%u)", timeMS);
+    _timing.SetRenderDelay(timeMS);
+    return VCM_OK;
+}
+
+// Current video delay
+WebRtc_Word32
+VideoCodingModuleImpl::Delay() const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id), "Delay()");
+    return _timing.TargetVideoDelay();
+}
+
+// Nack list
+WebRtc_Word32
+VideoCodingModuleImpl::NackList(WebRtc_UWord16* nackList, WebRtc_UWord16& size)
+{
+    VCMNackStatus nackStatus = kNackOk;
+    // Collect sequence numbers from the default receiver
+    // if in normal nack mode. Otherwise collect them from
+    // the dual receiver if the dual receiver is receiving.
+    if (_receiver.NackMode() != kNoNack)
+    {
+        nackStatus = _receiver.NackList(nackList, size);
+    }
+    else if (_dualReceiver.State() != kPassive)
+    {
+        nackStatus = _dualReceiver.NackList(nackList, size);
+    }
+    else
+    {
+        size = 0;
+    }
+
+    switch (nackStatus)
+    {
+    case kNackNeedMoreMemory:
+        {
+            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(_id),
+                    "Out of memory");
+            return VCM_MEMORY;
+        }
+    case kNackKeyFrameRequest:
+        {
+            CriticalSectionScoped cs(_receiveCritSect);
+            WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCoding, VCMId(_id),
+                    "Failed to get NACK list, requesting key frame");
+            return RequestKeyFrame();
+        }
+    default:
+        break;
+    }
+    return VCM_OK;
+}
+
+WebRtc_Word32
+VideoCodingModuleImpl::ReceivedFrameCount(VCMFrameCount& frameCount) const
+{
+    WEBRTC_TRACE(webrtc::kTraceModuleCall, webrtc::kTraceVideoCoding, VCMId(_id),
+               "ReceivedFrameCount()");
+    return _receiver.ReceivedFrameCount(frameCount);
+}
+
+}
diff --git a/src/modules/video_coding/main/source/video_coding_impl.h b/src/modules/video_coding/main/source/video_coding_impl.h
new file mode 100644
index 0000000..69f4493
--- /dev/null
+++ b/src/modules/video_coding/main/source/video_coding_impl.h
@@ -0,0 +1,276 @@
+/*
+ *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_VIDEO_CODING_VIDEO_CODING_IMPL_H_
+#define WEBRTC_MODULES_VIDEO_CODING_VIDEO_CODING_IMPL_H_
+
+#include "video_coding.h"
+#include "critical_section_wrapper.h"
+#include "frame_buffer.h"
+#include "receiver.h"
+#include "timing.h"
+#include "jitter_buffer.h"
+#include "codec_database.h"
+#include "generic_decoder.h"
+#include "generic_encoder.h"
+#include "media_optimization.h"
+
+#include <stdio.h>
+
+namespace webrtc
+{
+
+class VCMProcessTimer
+{
+public:
+    VCMProcessTimer(WebRtc_UWord32 periodMs) :
+        _periodMs(periodMs), _latestMs(VCMTickTime::MillisecondTimestamp()) {}
+    WebRtc_UWord32 Period() const;
+    WebRtc_UWord32 TimeUntilProcess() const;
+    void Processed();
+
+private:
+    WebRtc_UWord32        _periodMs;
+    WebRtc_Word64         _latestMs;
+};
+
+enum VCMKeyRequestMode
+{
+    kKeyOnError,       // Normal mode, request key frames on decoder error
+    kKeyOnKeyLoss,    // Request key frames on decoder error and on packet loss in key frames
+    kKeyOnLoss,        // Request key frames on decoder error and on packet loss in any frame
+};
+
+class VideoCodingModuleImpl : public VideoCodingModule
+{
+public:
+    VideoCodingModuleImpl(const WebRtc_Word32 id);
+
+    virtual ~VideoCodingModuleImpl();
+
+    // Returns version of the module and its components
+    WebRtc_Word32 Version(WebRtc_Word8* version,
+                          WebRtc_UWord32& remainingBufferInBytes,
+                          WebRtc_UWord32& position) const;
+
+    WebRtc_Word32 Id() const;
+
+    //  Change the unique identifier of this object
+    virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
+
+    // Returns the number of milliseconds until the module want a worker thread to call Process
+    virtual WebRtc_Word32 TimeUntilNextProcess();
+
+    virtual WebRtc_Word32 Process();
+
+    /*
+    *   Sender
+    */
+
+    // Initialize send codec
+    virtual WebRtc_Word32 InitializeSender();
+
+    // Makes sure the encoder is in its initial state.
+    virtual WebRtc_Word32 ResetEncoder();
+
+    // Register the send codec to be used.
+    virtual WebRtc_Word32 RegisterSendCodec(const VideoCodec* sendCodec,
+                                            WebRtc_UWord32 numberOfCores,
+                                            WebRtc_UWord32 maxPayloadSize);
+
+    // Get current send codec
+    virtual WebRtc_Word32 SendCodec(VideoCodec* currentSendCodec) const;
+
+    // Get current send codec type
+    virtual VideoCodecType SendCodec() const;
+
+    // Register an external encoder object.
+    virtual WebRtc_Word32 RegisterExternalEncoder(VideoEncoder* externalEncoder,
+                                                  WebRtc_UWord8 payloadType,
+                                                  bool internalSource = false);
+
+    // Get codec config parameters
+    virtual WebRtc_Word32 CodecConfigParameters(WebRtc_UWord8* buffer, WebRtc_Word32 size);
+
+    // Get encode bitrate
+    virtual WebRtc_UWord32 Bitrate() const;
+
+    // Get encode frame rate
+    virtual WebRtc_UWord32 FrameRate() const;
+
+    // Set channel parameters
+    virtual WebRtc_Word32 SetChannelParameters(WebRtc_UWord32 availableBandWidth,
+                                               WebRtc_UWord8 lossRate,
+                                               WebRtc_UWord32 RTT);
+    // Set recieve channel parameters
+    virtual WebRtc_Word32 SetReceiveChannelParameters(WebRtc_UWord32 RTT);
+
+    // Register a transport callback which will be called to deliver the encoded buffers
+    virtual WebRtc_Word32 RegisterTransportCallback(VCMPacketizationCallback* transport);
+
+    // Register a send statistics callback which will be called to deliver information
+    // about the video stream produced by the encoder,
+    // for instance the average frame rate and bit rate.
+    virtual WebRtc_Word32 RegisterSendStatisticsCallback(VCMSendStatisticsCallback* sendStats);
+
+    // Register a video quality settings callback which will be called when
+    // frame rate/dimensions need to be updated for video quality optimization
+    virtual WebRtc_Word32 RegisterVideoQMCallback(VCMQMSettingsCallback* videoQMSettings);
+
+    // Register a video protection callback which will be called to deliver
+    // the requested FEC rate and NACK status (on/off).
+    virtual WebRtc_Word32 RegisterProtectionCallback(VCMProtectionCallback* protection);
+
+    // Enable or disable a video protection method.
+   virtual WebRtc_Word32 SetVideoProtection(VCMVideoProtection videoProtection, bool enable);
+
+    // Add one raw video frame to the encoder, blocking.
+    virtual WebRtc_Word32 AddVideoFrame(
+        const VideoFrame& videoFrame,
+        const VideoContentMetrics* _contentMetrics = NULL,
+        const CodecSpecificInfo* codecSpecificInfo = NULL);
+
+    // Next frame encoded should be of the type frameType.
+    virtual WebRtc_Word32 FrameTypeRequest(FrameType frameType);
+
+    //Enable frame dropper
+    virtual WebRtc_Word32 EnableFrameDropper(bool enable);
+
+    // Sent frame counters
+    virtual WebRtc_Word32 SentFrameCount(VCMFrameCount& frameCount) const;
+
+    /*
+    *   Receiver
+    */
+
+    // Initialize receiver, resets codec database etc
+    virtual WebRtc_Word32 InitializeReceiver();
+
+    // Register possible reveive codecs, can be called multiple times
+    virtual WebRtc_Word32 RegisterReceiveCodec(const VideoCodec* receiveCodec,
+                                               WebRtc_Word32 numberOfCores,
+                                               bool requireKeyFrame = false);
+
+    // Register an externally defined decoder/render object.
+    // Can be a decoder only or a decoder coupled with a renderer.
+    virtual WebRtc_Word32 RegisterExternalDecoder(VideoDecoder* externalDecoder,
+                                                  WebRtc_UWord8 payloadType,
+                                                  bool internalRenderTiming);
+
+    // Register a receive callback. Will be called whenever there are a new frame ready
+    // for rendering.
+    virtual WebRtc_Word32 RegisterReceiveCallback(VCMReceiveCallback* receiveCallback);
+
+    // Register a receive statistics callback which will be called to deliver information
+    // about the video stream received by the receiving side of the VCM, for instance
+    //  the average frame rate and bit rate.
+    virtual WebRtc_Word32 RegisterReceiveStatisticsCallback(
+                                                VCMReceiveStatisticsCallback* receiveStats);
+
+    // Register a frame type request callback.
+    virtual WebRtc_Word32 RegisterFrameTypeCallback(VCMFrameTypeCallback* frameTypeCallback);
+
+    // Register a frame storage callback.
+    virtual WebRtc_Word32 RegisterFrameStorageCallback(
+                                                VCMFrameStorageCallback* frameStorageCallback);
+
+    // Nack callback
+    virtual WebRtc_Word32 RegisterPacketRequestCallback(VCMPacketRequestCallback* callback);
+
+    // Decode next frame, blocks for a maximum of maxWaitTimeMs milliseconds.
+    // Should be called as often as possible to get the most out of the decoder.
+    virtual WebRtc_Word32 Decode(WebRtc_UWord16 maxWaitTimeMs = 200);
+
+    // Decode next dual frame, blocks for a maximum of maxWaitTimeMs milliseconds.
+    virtual WebRtc_Word32 DecodeDualFrame(WebRtc_UWord16 maxWaitTimeMs = 200);
+
+    // Reset the decoder state
+    virtual WebRtc_Word32 ResetDecoder();
+
+    // Get current received codec
+    virtual WebRtc_Word32 ReceiveCodec(VideoCodec* currentReceiveCodec) const;
+
+    // Get current received codec type
+    virtual VideoCodecType ReceiveCodec() const;
+
+    // Incoming packet from network parsed and ready for decode, non blocking.
+    virtual WebRtc_Word32 IncomingPacket(const WebRtc_UWord8* incomingPayload,
+                                         WebRtc_UWord32 payloadLength,
+                                         const WebRtcRTPHeader& rtpInfo);
+
+    // A part of an encoded frame to be decoded.
+    // Used in conjunction with VCMFrameStorageCallback.
+    virtual WebRtc_Word32 DecodeFromStorage(const EncodedVideoData& frameFromStorage);
+
+    // Set codec config parameters
+    virtual WebRtc_Word32 SetCodecConfigParameters(WebRtc_UWord8 payloadType,
+                                                   const WebRtc_UWord8* buffer,
+                                                   WebRtc_Word32 length);
+
+    // Minimum playout delay (Used for lip-sync). This is the minimum delay required
+    // to sync with audio. Not included in  VideoCodingModule::Delay()
+    // Defaults to 0 ms.
+    virtual WebRtc_Word32 SetMinimumPlayoutDelay(WebRtc_UWord32 minPlayoutDelayMs);
+
+    // The estimated delay caused by rendering
+    virtual WebRtc_Word32 SetRenderDelay(WebRtc_UWord32 timeMS);
+
+    // Current delay
+    virtual WebRtc_Word32 Delay() const;
+
+    // Received frame counters
+    virtual WebRtc_Word32 ReceivedFrameCount(VCMFrameCount& frameCount) const;
+
+protected:
+    WebRtc_Word32 Decode(const webrtc::VCMEncodedFrame& frame);
+    WebRtc_Word32 RequestKeyFrame();
+    WebRtc_Word32 RequestSliceLossIndication(const WebRtc_UWord64 pictureID) const;
+    WebRtc_Word32 NackList(WebRtc_UWord16* nackList, WebRtc_UWord16& size);
+
+private:
+    WebRtc_Word32                       _id;
+    CriticalSectionWrapper&                _receiveCritSect; // Critical section for receive side
+    bool                                _receiverInited;
+    VCMTiming                           _timing;
+    VCMTiming                           _dualTiming;
+    VCMReceiver                         _receiver;
+    VCMReceiver                         _dualReceiver;
+    VCMDecodedFrameCallback             _decodedFrameCallback;
+    VCMDecodedFrameCallback             _dualDecodedFrameCallback;
+    VCMFrameTypeCallback*               _frameTypeCallback;
+    VCMFrameStorageCallback*            _frameStorageCallback;
+    VCMReceiveStatisticsCallback*       _receiveStatsCallback;
+    VCMPacketRequestCallback*           _packetRequestCallback;
+    VCMGenericDecoder*                  _decoder;
+    VCMGenericDecoder*                  _dualDecoder;
+    FILE*                               _bitStreamBeforeDecoder;
+    VCMFrameBuffer                      _frameFromFile;
+    VCMKeyRequestMode                   _keyRequestMode;
+    bool                                _scheduleKeyRequest;
+
+    CriticalSectionWrapper&                _sendCritSect; // Critical section for send side
+    VCMGenericEncoder*                  _encoder;
+    VCMEncodedFrameCallback             _encodedFrameCallback;
+    FrameType                           _nextFrameType;
+    VCMMediaOptimization                _mediaOpt;
+    VideoCodecType                      _sendCodecType;
+    VCMSendStatisticsCallback*          _sendStatsCallback;
+    FILE*                               _encoderInputFile;
+
+    VCMCodecDataBase                    _codecDataBase;
+    VCMProcessTimer                     _receiveStatsTimer;
+    VCMProcessTimer                     _sendStatsTimer;
+    VCMProcessTimer                     _retransmissionTimer;
+    VCMProcessTimer                     _keyRequestTimer;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_VIDEO_CODING_VIDEO_CODING_IMPL_H_
diff --git a/src/modules/video_coding/main/source/video_coding_test.gyp b/src/modules/video_coding/main/source/video_coding_test.gyp
new file mode 100644
index 0000000..89e62ef
--- /dev/null
+++ b/src/modules/video_coding/main/source/video_coding_test.gyp
@@ -0,0 +1,78 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'includes': [
+    '../../../../common_settings.gypi', # Common settings
+  ],
+  'targets': [
+    {
+      'target_name': 'video_coding_test',
+      'type': 'executable',
+      'dependencies': [
+         'video_coding.gyp:webrtc_video_coding',
+         '../../../rtp_rtcp/source/rtp_rtcp.gyp:rtp_rtcp',
+         '../../../utility/source/utility.gyp:webrtc_utility',
+         '../../../video_processing/main/source/video_processing.gyp:video_processing',
+         '../../../../common_video/vplib/main/source/vplib.gyp:webrtc_vplib',
+      ],
+      'include_dirs': [
+         '../../../interface',
+         '../../codecs/vp8/main/interface',
+         '../../../../system_wrappers/interface',
+          '../../../../common_video/interface',
+         '../source',
+      ],
+      'sources': [
+
+        # headers
+        '../test/codec_database_test.h',
+        '../test/generic_codec_test.h',
+        '../test/jitter_estimate_test.h',
+        '../test/media_opt_test.h',
+        '../test/normal_test.h',
+        '../test/quality_modes_test.h',
+        '../test/receiver_tests.h',
+        '../test/release_test.h',
+        '../test/rtp_player.h',
+        '../test/test_util.h',
+        '../test/video_source.h',
+
+        # sources
+        '../test/codec_database_test.cc',
+        '../test/decode_from_storage_test.cc',
+        '../test/generic_codec_test.cc',
+        '../test/jitter_buffer_test.cc',
+        '../test/media_opt_test.cc',
+        '../test/mt_rx_tx_test.cc',
+        '../test/normal_test.cc',
+        '../test/quality_modes_test.cc',
+        '../test/receiver_timing_tests.cc',
+        '../test/rtp_player.cc',
+        '../test/test_util.cc',
+        '../test/tester_main.cc',
+        '../test/video_rtp_play_mt.cc',
+        '../test/video_rtp_play.cc',
+        '../test/video_source.cc',
+
+      ], # source
+
+      'conditions': [
+
+        ['OS=="linux"', {
+          'cflags': [
+            '-fexceptions',
+          ],
+        }],
+
+      ], # conditions
+    },
+  ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2: