text:
using System;
using System.Collections.Generic;
using System.Numerics;

namespace DP_demos
{
    class Program
    {
        static List<BigInteger> fibonacciMemo = new List<BigInteger> { 1, 1 };

        static BigInteger Fibonacci(int n)
        {
            if(fibonacciMemo.Count <= n)
            {
                var result = Fibonacci(n - 1) + Fibonacci(n - 2);
                fibonacciMemo.Add(result);
            }

            return fibonacciMemo[n];
        }

        static void Main()
        {
            var n = 1000;
            var fibs = new BigInteger[n + 1];

            fibs[0] = 1;
            fibs[1] = 1;
            for (int i = 2; i <= n; ++i)
            {
                fibs[i] = fibs[i - 1] + fibs[i - 2];
            }

            Console.WriteLine(fibs[n]);

            BigInteger firstNumber = 1;
            BigInteger secondNumber = 1;
            for (int i = 2; i <= n; ++i)
            {
                var currentNumber = firstNumber + secondNumber;
                firstNumber = secondNumber;
                secondNumber = currentNumber;
            }

            Console.WriteLine(secondNumber);
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
<link type="text/css" href="<?php echo public_url()?>/site/royalslider/royalslider.css" rel="stylesheet">
<link type="text/css" href="<?php echo public_url()?>/site/royalslider/skins/minimal-white/rs-minimal-white.css" rel="stylesheet">

		        <?php foreach ($slide_list as $row):?>
		      	   <a href="<?php echo $row->link?>" target='_blank'>
		      	        <img src="<?php echo base_url('upload/slide/'.$row->image_link)?>" alt="<?php echo $row->name?>"/>

		      	<?php endforeach;?>


text:
NOTFOUND=0
CONVERT=$(which convert)
OPTIPNG=$(which optipng)

if [ ! -x "$CONVERT" ]; then
    echo ImageMagick not found
    echo Run "sudo apt-get install imagemagick" to install it
    NOTFOUND=$((NOTFOUND + 1))
fi

if [ ! -x "$OPTIPNG" ]; then
    echo optipng not found
    echo Run "sudo apt-get install optipng" to install it
    NOTFOUND=$((NOTFOUND + 1))
fi

if [ "$NOTFOUND" -gt 0 ]; then
    echo Some required software was not found.
    echo Install it and then rerun this script.
    exit 2
fi

OUTDIR=../../images/avatar
mkdir -p $OUTDIR
for animal in `cat animals.txt`
do
    inputfile="orig-${animal}.png"
    echo $animal
    for size in `cat sizes.txt`
    do
        for color in `cat light-colors.txt`
        do
            convert $inputfile -background $color -flatten -resize $size -gravity center -extent $size -depth 8 -colors 64 ${OUTDIR}/${color}-${animal}-${size}.png
            optipng -q -o7 ${OUTDIR}/${color}-${animal}-${size}.png
        done
        for color in `cat dark-colors.txt`
        do
            convert $inputfile -negate -background $color -flatten -resize $size -gravity center -extent $size -depth 8 -colors 64 ${OUTDIR}/${color}-${animal}-${size}.png
            optipng -q -o7 ${OUTDIR}/${color}-${animal}-${size}.png
        done
    done
done

# And also do 8x8 squares for the "pick a color" menu

size="8x8"
for color in `cat light-colors.txt dark-colors.txt`
do
    convert -size $size canvas:${color} ${OUTDIR}/${color}-square-${size}.png
done


text:
<?php

namespace ItvisionSy\EsMapper;

use Exception;
use Elasticsearch\Client;

/**
 * The main query class to make querying/fetching data from elasticsearch easy.
 *
 * It is a general class used for querying one specific index. If you are
 * looking for a general-index search, then use the official client sdk
 * libraries directly.
 *
 * @package ItvisionSy\EsMapper
 * @author Muhannad Shelleh <muhannad.shelleh@itvision-sy.com>
 *
 * @method Result query(string $type, array $parameters=[])
 * @method-static Result query(string $type, array $parameters=[])
 * @method AutoQueryBuilder builder()
 * @method-static AutoQueryBuilder builder()
 * @method Result all(string $type)
 * @method-static Result all(string $type)
 * @method Result find(string $type, int|string|int[]|string $id)
 * @method-static Result find(string $type, int|string|int[]|string $id)
 * @method IModel create(array $data, string $index, int|string $id, array $parameters=[])
 * @method-static IModel create(array $data, string $index, int|string $id, array $parameters=[])
 * @method array delete(string|string $index, string|string[] $type, int|string $id, array $parameters=[])
 * @method-static array delete(string|string $index, string|string[] $type, int|string $id, array $parameters=[])
 * @property-read Client $client
 */
abstract class Query {

    protected $config;
    protected $client;

    /**
     * Factory method for creating query objects
     *
     * @param array $config The config to use for the client
     * @return Query
     */
    public static function make(array $config = []) {
        return new static($config);
    }

    /**
     * Query object constructor
     *
     * @param array $config
     */
    public function __construct(array $config = []) {
        $config += $this->defaults();
        $this->config = $config;
        $this->establish($config, true);
    }

    /**
     * The index name to be used.
     * Should return a string ends with namespace separator path or
     * contains the {type} string as a placeholder for the actual model class name.
     *
     * i.e.
     *
     * return "\\";
     * //means the model classes for Foo and Bar will be \Foo and \Bar
     *
     * return "\\Models\\";
     * //means the model classes for Foo and Bar will be \Models\Foo and
     * //   \Models\Bar
     *
     * return "\\Models\\{type}Model";
     * //means the model classes for Foo and Bar will be \Models\FooModel and
     * //   \Models\BarModel
     *
     * @return string
     */
    abstract public function index();

    /**
     * Gets the namespace/class pattern will be used to create Model objects.
     * Should end with \\
     * Default value is \ means the root global namespace.
     *
     * @return string
     */
    public function modelClassNamePattern() {
        return "\\";
    }

    /**
     * Gets the index name for this query class
     * @return string
     */
    public function getIndex() {
        return $this->index();
    }

    /**
     * Gets the current ES client in use for the object.
     *
     * @return Client
     */
    public function getClient() {
        return $this->client;
    }

    /**
     * Establishes the ES client using the provided config.
     * Provided config values will take place over the object's config attribute.
     * Finally, the defaults() result will be used as a final config source.
     *
     * @param array $config Config value to override the general config params
     * @return Client
     */
    public function establish(array $config = [], $assign = false) {
        $client = new Client($config + $this->config + $this->defaults());
        if ($assign) {
            $this->client = $client;
        }
        return $client;
    }

    /**
     * A decorator class to get all index type documents.
     *
     * @param string $type
     * @return Result|Model[]
     */
    protected function _all($type) {
        return $this->__query($this->index(), $type);
    }

    /**
     * A decorator method to search for ES documents.
     *
     * @param string $type
     * @param array $query
     * @return Result|Model[]
     */
    protected function _query($type, array $query = []) {
        return $this->__query($this->index(), $type, $query);
    }

    /**
     * A decorator method to get specific document by its id.
     * If the id is and array of strings or integers,
     * then multiple documents will be retreived by id.
     *
     * @param string $type
     * @param mixed|string|integer|mixed[]|int[]|string[] $id
     * @return Model
     */
    protected function _find($type, $id) {
        if (is_array($id)) {
            return $this->__mfind($this->index(), $type, $id);
        } else {
            return $this->__find($this->index(), $type, $id);
        }
    }

    /**
     * Index a new document
     *
     * @param array $data the document data
     * @param string $type
     * @param string|number $id
     * @param array $parameters
     * @return array
     */
    protected function _create(array $data, $type, $id = null, array $parameters = []) {
        return $this->__create($data, $this->index(), $type, $id, $parameters);
    }

    /**
     * Index a new document
     *
     * @param array $data the document data
     * @param string $index
     * @param string $type
     * @param string|number $id
     * @param array $parameters
     * @return array
     */
    protected function __create(array $data, $index, $type, $id = null, array $parameters = []) {
        $parameters+=["api" => "create"];
        $api = strtolower($parameters["api"]) == "index" ? "index" : "create";
        unset($parameters["api"]);
        $result = $this->client->$api([
            'index' => $index,
            'type' => $type,
            'body' => $data] + ($id ? ['id' => $id] : []) + $parameters);
        if (array_key_exists('_shards', $result) && array_key_exists('failed', $result['_shards']) && $result['_shards']['failed'] > 0) {
            throw new Exception('Failed to create the document. Serialized results: ' + json_encode($result));
        } else {
            $result = $this->__find($result['_index'], $result['_type'], $result['_id']);
        }
        return $result;
    }

    /**
     * Deletes a document
     *
     * @param string $type
     * @param string|number $id
     * @param array $parameters
     * @return array
     */
    protected function _delete($type, $id = null, array $parameters = []) {
        return $this->__delete($this->index(), $type, $id, $parameters);
    }

    /**
     * Deletes a document
     *
     * @param string $index
     * @param string $type
     * @param string|number $id
     * @param array $parameters
     * @return array
     */
    protected function __delete($index, $type, $id, array $parameters = []) {
        $result = $this->client->delete([
            'index' => $index,
            'type' => $type,
            'id' => $id] + $parameters);
        return $result;
    }

    /**
     * Add fixed query part to the called query
     *
     * To add a fixed per-class condition. I.e. specific flag to be set to
     * specific value.
     *
     * Note that this is to be called for the query (not find) calls only.
     *
     * @return array The query part to be merged into the original part.
     */
    protected function additionalQuery() {
        return [];
    }

    /**
     * The actual method to call client's search method.
     * Returns Result object
     *
     * @param string $index
     * @param string $type if null, then all types will be searched
     * @param array $query
     * @return Result|Model[]
     */
    protected function __query($index, $type = null, array $query = []) {
        $result = $this->client->search([
            'index' => $index,
            'body' => array_merge_recursive($query, $this->additionalQuery())
                ] + ($type ? ['type' => $type] : []));
        return $this->_makeResult($result);
    }

    /**
     * The actual method to call client's get method.
     * Returns either a Model object or null on failure.
     *
     * @param string $index
     * @param string $type
     * @param sring|int $id
     * @return null|Model
     */
    protected function __find($index, $type, $id) {
        try {
            $result = $this->client->get([
                'index' => $index,
                'type' => $type,
                'id' => $id
            ]);
            if ($result['found']) {
                return $this->_makeModel($result);
            } else {
                return null;
            }
        } catch (\Exception $e) {
            trigger_error($e->getMessage(), E_USER_WARNING);
            return null;
        }
    }

    /**
     * The actual method to call client's mget method.
     * Returns either a result of Model objects or null on failure.
     *
     * @param string $index
     * @param string $type
     * @param sring[]|int[] $ids
     * @return null|Model
     */
    protected function __mfind($index, $type, $ids) {
        try {
            $docs = $this->client->mget([
                'index' => $index,
                'type' => $type,
                'body' => [
                    "ids" => $ids
                ]
            ]);
            $result = ['ids' => $ids, 'found' => [], 'missed' => [], 'docs' => []];
            $missed = [] + $ids;
            foreach ($docs['docs'] as $doc) {
                if ($doc['found']) {
                    $result['docs'][] = $doc;
                    $result['found'][] = $doc['_id'];
                    unset($missed[array_search($doc['_id'], $missed)]);
                }
            }
            $result['missed'] = $missed;
            return $this->_makeMultiGetResult($result);
        } catch (\Exception $e) {
            trigger_error($e->getMessage(), E_USER_WARNING);
            return null;
        }
    }

    /**
     * Creates a results set for ES query hits
     *
     * @param array $result
     * @return Result
     */
    protected function _makeResult(array $result) {
        return Result::make($result, $this->getClient())->setModelClass($this->_fullModelClassNamePattern());
    }

    /**
     * Creates a results set for ES query hits
     *
     * @param array $result
     * @return Result
     */
    protected function _makeMultiGetResult(array $result) {
        return MultiGetResult::make($result, $this->getClient())->setModelClass($this->_fullModelClassNamePattern());
    }

    /**
     * Creates a model object for a specific es result hits entry
     *
     * @param array $source
     * @return Model
     */
    protected function _makeModel(array $source) {
        return Model::MakeOfType($source, $this->_fullModelClassNamePattern(), $this->getClient());
    }

    /**
     * Returns the full namespace string for the model.
     * If the provided namespace contains {type} then use it,
     * otherwize add {type} to the end.
     *
     * @return string
     */
    protected function _fullModelClassNamePattern() {
        return stripos($this->modelClassNamePattern()? : "", '{type}') !== false ? $this->modelClassNamePattern() : "{$this->modelClassNamePattern()}{type}";
    }

    public static function __callStatic($name, $arguments) {

        if (array_search($name, static::_allowPublicAccess()) !== false) {
            //pass specific methods
            return call_user_func_array([new static(), $name], $arguments);
        }

        if (strpos($name, 'get', 0) === 0) {
            //pass getAll() as an internal query
            return call_user_func_array([new static(), $name], $arguments);
        }

        trigger_error("Call to undefined static method " . static::class . "::{$name}", E_USER_ERROR);
    }

    public function __call($name, $arguments) {
        if (array_search($name, static::_allowPublicAccess()) !== false) {
            //pass specific methods
            return call_user_func_array([$this, "_{$name}"], $arguments);
        }
        if (strpos($name, 'get', 0) === 0) {
            //pass getAll() as an internal query
            $methodName = lcfirst(substr($name, 3));
            return call_user_func_array([$this, "_{$methodName}"], $arguments);
        }
        trigger_error("Call to undefined method " . static::class . "::{$name}", E_USER_ERROR);
    }

    /**
     * The default values for the client
     *
     * @return array
     */
    protected function defaults() {
        return [
            'hosts' => [
                'http://localhost:9200/'
            ]
        ];
    }

    /**
     * Used to expose extra methods to the public static or public calls
     *
     * Should return an array of strings.
     * i.e.
     * return ['any','top'];
     * Will allow public static and public access to the two new methods:
     * protected _any() and protected _top($rows)
     *
     * Note that the protected methods should be prefixed with _
     *
     * When overriding in sub classes use this form:
     * protected _allowPublicAccess(){
     *     return array_merge(parent::_allowPublicAccess(), ['method',...,...]);
     * }
     * This way you will save the allowed methods from the parent.
     *
     * @return array
     */
    protected static function _allowPublicAccess() {
        return [
            'all',
            'query',
            'find',
            'meta',
            'create',
            'delete',
            'builder',
            'metaSettings',
            'metaAliases',
            'metaMappings',
            'metaWarmers'
        ];
    }

    /**
     * Retreives the meta data of an index
     * @param string|array $features a list of meta objects to fetch. null means
     *                     everything. Can be
     *                          * 1 string (i.e. '_settings'),
     *                          * csv (i.e. '_settings,_aliases'),
     *                          * array (i.e. ['_settings','_aliases']
     * @param array $options can contain:
     *          ['ignore_unavailable']
     *              (bool) Whether specified concrete indices should be ignored
     *              when unavailable (missing or closed)
     *          ['allow_no_indices']
     *              (bool) Whether to ignore if a wildcard indices expression
     *              resolves into no concrete indices. (This includes `_all`
     *              string or when no indices have been specified)
     *          ['expand_wildcards']
     *              (enum) Whether to expand wildcard expression to concrete
     *              indices that are open, closed or both.
     *          ['local']
     *              (bool) Return local information, do not retrieve the state
     *              from master node (default: false)
     * @return array
     */
    protected function _meta($features = null, array $options = []) {
        if ($features) {
            $features = join(',', array_map(function($item) {
                        return '_' . strtolower(trim($item, '_'));
                    }, is_scalar($features) ? explode(",", $features) : $features));
        }
        $options = ['index' => $this->index()] + $options + ($features ? ['feature' => $features] : []);
        $result = $this->client->indices()->get($options);
        $result = array_pop($result);
        return $result;
    }

    /**
     * Retreives just the settings of the index
     * @param array $options check _meta() for details
     * @return array
     */
    protected function _metaSettings(array $options = []) {
        $result = $this->_meta('_settings', $options);
        return array_pop($result);
    }

    /**
     * Retreives just the aliases of the index
     * @param array $options check _meta() for details
     * @return array
     */
    protected function _metaAliases(array $options = []) {
        $result = $this->_meta('_aliases', $options);
        return array_pop($result);
    }

    /**
     * Retreives just the mappings of the index
     * @param array $options check _meta() for details
     * @return array
     */
    protected function _metaMappings(array $options = []) {
        $result = $this->_meta('_mappings', $options);
        return array_pop($result);
    }

    /**
     * Retreives just the warmers of the index
     * @param array $options check _meta() for details
     * @return array
     */
    protected function _metaWarmers(array $options = []) {
        $result = $this->_meta('_warmers', $options);
        return array_pop($result);
    }

    /**
     * Creates a builder for this query
     *
     * @param array $query A query array to start using it
     * @return AutoQueryBuilder
     */
    protected function _builder(array $query = []) {
        return $this->__builder($query);
    }

    /**
     * Creates a builder for this query
     *
     * @param array $query A query array to start using it
     * @return AutoQueryBuilder
     */
    protected function __builder(array $query = []) {
        return AutoQueryBuilder::makeForQueryInstance($this, $query);
    }

}


text:
@interface TOWebViewController (JavaScriptWebView)

@end


text:
require 'active_support/version'
require 'active_record/version'

module Delayed
  module Heartbeat
    module Compatibility

      def self.mass_assignment_security_enabled?
        ::ActiveRecord::VERSION::MAJOR < 4 || defined?(::ActiveRecord::MassAssignmentSecurity)
      end

    end
  end
end


text:
function initializeCoreMod() {
    return {
        'enablestencilbuffer': {
            'target': {
                'type': 'METHOD',
                'class': 'net.minecraft.client.shader.Framebuffer',
                'methodName': Java.type("net.minecraftforge.coremod.api.ASMAPI").mapMethod('func_216492_b'),
                'methodDesc': '(IIZ)V'
            },
            'transformer': function (methodNode) {
                if (methodNode instanceof org.objectweb.asm.tree.MethodNode) { // Stupid way to cast in JS to avoid warnings and fix autocomplete
                    var ASM = Java.type('net.minecraftforge.coremod.api.ASMAPI');
                    var Opcodes = Java.type('org.objectweb.asm.Opcodes');
                    methodNode.instructions.insertBefore(
                        ASM.findFirstMethodCall(
                            methodNode,
                            ASM.MethodType.VIRTUAL,
                            'net/minecraft/client/shader/Framebuffer',
                            ASM.mapMethod('func_147611_b'),
                            '()V'
                            ),
                        ASM.listOf(
                            new org.objectweb.asm.tree.VarInsnNode(Opcodes.ALOAD, 0), // PUSH this TO THE TOP OF THE STACK
                            new org.objectweb.asm.tree.MethodInsnNode( // INVOKE tamaized.aov.asm.ASMHooks#enableStencilBuffer(Framebuffer)
                                Opcodes.INVOKESTATIC,
                                'tamaized/aov/asm/ASMHooks',
                                'enableStencilBuffer',
                                '(Lnet/minecraft/client/shader/Framebuffer;)V',
                                false
                                )
                            )
                        );
                }
                return methodNode;
            }
        }
    }
}


text:
using System;

namespace Azure.Messaging.EventGrid.SystemEvents
{
    internal static partial class MediaJobStateExtensions
    {
        public static string ToSerialString(this MediaJobState value) => value switch
        {
            MediaJobState.Canceled => "Canceled",
            MediaJobState.Canceling => "Canceling",
            MediaJobState.Error => "Error",
            MediaJobState.Finished => "Finished",
            MediaJobState.Processing => "Processing",
            MediaJobState.Queued => "Queued",
            MediaJobState.Scheduled => "Scheduled",
            _ => throw new ArgumentOutOfRangeException(nameof(value), value, "Unknown MediaJobState value.")
        };

        public static MediaJobState ToMediaJobState(this string value)
        {
            if (string.Equals(value, "Canceled", StringComparison.InvariantCultureIgnoreCase)) return MediaJobState.Canceled;
            if (string.Equals(value, "Canceling", StringComparison.InvariantCultureIgnoreCase)) return MediaJobState.Canceling;
            if (string.Equals(value, "Error", StringComparison.InvariantCultureIgnoreCase)) return MediaJobState.Error;
            if (string.Equals(value, "Finished", StringComparison.InvariantCultureIgnoreCase)) return MediaJobState.Finished;
            if (string.Equals(value, "Processing", StringComparison.InvariantCultureIgnoreCase)) return MediaJobState.Processing;
            if (string.Equals(value, "Queued", StringComparison.InvariantCultureIgnoreCase)) return MediaJobState.Queued;
            if (string.Equals(value, "Scheduled", StringComparison.InvariantCultureIgnoreCase)) return MediaJobState.Scheduled;
            throw new ArgumentOutOfRangeException(nameof(value), value, "Unknown MediaJobState value.");
        }
    }
}


text:
package com.azure.resourcemanager.security.implementation;

import com.azure.resourcemanager.security.fluent.models.SecureScoreControlDefinitionItemInner;
import com.azure.resourcemanager.security.models.AzureResourceLink;
import com.azure.resourcemanager.security.models.SecureScoreControlDefinitionItem;
import com.azure.resourcemanager.security.models.SecureScoreControlDefinitionSource;
import java.util.Collections;
import java.util.List;

public final class SecureScoreControlDefinitionItemImpl implements SecureScoreControlDefinitionItem {
    private SecureScoreControlDefinitionItemInner innerObject;

    private final com.azure.resourcemanager.security.SecurityManager serviceManager;

    SecureScoreControlDefinitionItemImpl(
        SecureScoreControlDefinitionItemInner innerObject,
        com.azure.resourcemanager.security.SecurityManager serviceManager) {
        this.innerObject = innerObject;
        this.serviceManager = serviceManager;
    }

    public String id() {
        return this.innerModel().id();
    }

    public String name() {
        return this.innerModel().name();
    }

    public String type() {
        return this.innerModel().type();
    }

    public String displayName() {
        return this.innerModel().displayName();
    }

    public String description() {
        return this.innerModel().description();
    }

    public Integer maxScore() {
        return this.innerModel().maxScore();
    }

    public SecureScoreControlDefinitionSource source() {
        return this.innerModel().source();
    }

    public List<AzureResourceLink> assessmentDefinitions() {
        List<AzureResourceLink> inner = this.innerModel().assessmentDefinitions();
        if (inner != null) {
            return Collections.unmodifiableList(inner);
        } else {
            return Collections.emptyList();
        }
    }

    public SecureScoreControlDefinitionItemInner innerModel() {
        return this.innerObject;
    }

    private com.azure.resourcemanager.security.SecurityManager manager() {
        return this.serviceManager;
    }
}


text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/et_new_name"
        android:layout_marginTop="15dp"
        android:hint="@string/new_name"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        style="@style/DemoTextStyleBigBlack"
        android:layout_width="match_parent"
        android:background="@drawable/rc_ed_public_service_search_selector"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_save"
       style="@style/DemoTextStyleMiddle"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="13dp"
        android:text="@string/good_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>


text: package restorable


text:
package com.github.alebabai.tg2vk.service.tg.update.query.callback.handler.impl;

import com.github.alebabai.tg2vk.domain.ChatSettings;
import com.github.alebabai.tg2vk.repository.UserRepository;
import com.github.alebabai.tg2vk.service.tg.common.TelegramService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Service;

@Service("muteCallbackQueryHandler")
public class TelegramCallbackMuteChatsQueryHandler extends AbstractTelegramCallbackMuteChatQueryHandler {

    @Autowired
    public TelegramCallbackMuteChatsQueryHandler(UserRepository userRepository,
                                                 TelegramService tgService,
                                                 MessageSourceAccessor messages) {
        super(userRepository, tgService, messages);
    }

    @Override
    protected String getCodePrefix() {
        return "tg.callback.chats.mute.msg.";
    }

    @Override
    protected boolean getState() {
        return false;
    }

    @Override
    protected boolean isProcessable(ChatSettings chatSettings) {
        return chatSettings.isStarted();
    }

}


text:
using System;
using System.Globalization;
using System.IO;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Drawing;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Windows.Forms;
using OpenLiveWriter.ApplicationFramework.Skinning;
using OpenLiveWriter.BlogClient;
using OpenLiveWriter.BlogClient.Clients;
using OpenLiveWriter.BlogClient.Detection;
using OpenLiveWriter.BlogClient.Providers;
using OpenLiveWriter.CoreServices.Diagnostics;
using OpenLiveWriter.Extensibility.BlogClient;
using OpenLiveWriter.HtmlEditor;
using OpenLiveWriter.HtmlEditor.Controls;
using OpenLiveWriter.HtmlParser.Parser;
using OpenLiveWriter.HtmlParser.Parser.FormAgent;
using OpenLiveWriter.CoreServices;
using System.Runtime.InteropServices;

using OpenLiveWriter.Interop.Com;
using OpenLiveWriter.Interop.Com.Ribbon;
using OpenLiveWriter.Interop.Com.StructuredStorage;
using OpenLiveWriter.Interop.Windows;
using OpenLiveWriter.Localization;
using OpenLiveWriter.Localization.Bidi;
using OpenLiveWriter.PostEditor.Commands;
using OpenLiveWriter.PostEditor.Configuration.Wizard;
using OpenLiveWriter.PostEditor.Configuration.Settings;
using OpenLiveWriter.PostEditor.ContentSources;
using OpenLiveWriter.PostEditor.JumpList;
using OpenLiveWriter.PostEditor.OpenPost;
using OpenLiveWriter.PostEditor.PostHtmlEditing;
using OpenLiveWriter.ApplicationFramework;
using OpenLiveWriter.Controls;
using OpenLiveWriter.PostEditor.SupportingFiles;
using OpenLiveWriter.PostEditor.Updates;
using OpenLiveWriter.SpellChecker;
using Timer = System.Windows.Forms.Timer;

// @RIBBON TODO: Cleanly remove obsolete code

namespace OpenLiveWriter.PostEditor
{
    internal enum ApplicationMode
    {
        Normal = 0,
        Preview = 1,
        LTR = 2,
        RTL = 3,
        NoPlugins = 4,
        HasPlugins = 5,
        Test = 31
    }

    internal class PostEditorMainControl : UserControl, IFormClosingHandler, IBlogPostEditor, IBlogPostEditingSite, IUIApplication, ISessionHandler
    {
        #region Private Data Declarations

        private IMainFrameWindow _mainFrameWindow;
        private BlogPostEditingManager _editingManager;

        private Command commandNewPost;
        private Command commandNewPage;
        private Command commandSavePost;
        private Command commandDeleteDraft;
        private Command commandPostAsDraft;
        private Command commandPostAsDraftAndEditOnline;

        private Command commandColorize;
        private CommandContextMenuDefinition _newPostContextMenuDefinition;
        private CommandContextMenuDefinition _savePostContextMenuDefinition;

        private Panel _mainEditorPanel;
        private HtmlStylePicker _styleComboControl;
        private BlogPostHtmlEditor _htmlEditor;

        private PostEditorPreferencesEditor _optionsEditor;
        private WeblogCommandManager _weblogCommandManager;

        //        private Bitmap statusNewPostBitmap = ResourceHelper.LoadAssemblyResourceBitmap("Images.StatusComposingPost.png");
        //        private Bitmap statusDraftPostBitmap = ResourceHelper.LoadAssemblyResourceBitmap("Images.StatusPosted.png");
        //        private Bitmap statusPublishedPostBitmap = ResourceHelper.LoadAssemblyResourceBitmap("Images.StatusPublished.png");

        private System.Windows.Forms.Timer _autoSaveTimer;
        private System.Windows.Forms.Timer _autoSaveMessageDismissTimer;

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private Container components = new Container();
        #endregion

        #region Initialization/Disposal

        public PostEditorMainControl(IMainFrameWindow mainFrameWindow, IBlogPostEditingContext editingContext)
        {
            Init(mainFrameWindow, editingContext);
        }

        private void Init(IMainFrameWindow mainFrameWindow, IBlogPostEditingContext editingContext)
        {
            // save reference to the frame window and workspace border manager
            _mainFrameWindow = mainFrameWindow;

            // This call is required by the Windows.Forms Form Designer.
            Font = Res.DefaultFont;
            InitializeComponent();

            // initialize UI
            InitializeUI();

            // Initialize the editing manager
            InitializeEditingManager();

            // initialize our commands
            InitializeCommands();

            //subscribe to global events
            BlogSettings.BlogSettingsDeleted += new BlogSettings.BlogSettingsListener(HandleBlogDeleted);

            // edit the post
            _editingManager.EditPost(editingContext, false);

            InitializeRibbon();
        }

        private void InitializeUI()
        {
            ColorizedResources.Instance.RegisterControlForBackColorUpdates(this);

            // initialize workspace
            InitializeWorkspace();

            // initialize the post property editors
            InitializePostPropertyEditors();

            // initialize the core editor
            InitializeHtmlEditor();

            // initialize options editor
            InitializeOptionsEditor();
        }

        private GalleryCommand<string> commandPluginsGallery = null;
        private void InitializeEditingManager()
        {
            _editingManager = new BlogPostEditingManager(
                this,
                new IBlogPostEditor[] { _htmlEditor, this },
                _htmlEditor
                );

            commandPluginsGallery = (GalleryCommand<string>)CommandManager.Get(CommandId.PluginsGallery);
            commandPluginsGallery.StateChanged += new EventHandler(commandPluginsGallery_StateChanged);
            _editingManager.BlogChanged += new EventHandler(_editingManager_BlogChanged);
            _editingManager.BlogSettingsChanged += new WeblogSettingsChangedHandler(_editingManager_BlogSettingsChanged);
            _editingManager.EditingStatusChanged += new EventHandler(_editingManager_EditingStatusChanged);
            _editingManager.UserSavedPost += new EventHandler(_editingManager_UserSavedPost);
            _editingManager.UserPublishedPost += new EventHandler(_editingManager_UserPublishedPost);
            _editingManager.UserDeletedPost += new EventHandler(_editingManager_UserDeletedPost);

            // initialize auto-save timer
            _autoSaveTimer = new System.Windows.Forms.Timer(this.components);
            _autoSaveTimer.Interval = 5000;
            _autoSaveTimer.Tick += new EventHandler(_autoSaveTimer_Tick);

            _autoSaveMessageDismissTimer = new Timer(components);
            _autoSaveMessageDismissTimer.Interval = 450;
            _autoSaveMessageDismissTimer.Tick += _autoSaveMessageDismissTimer_Tick;
        }

        void commandPluginsGallery_StateChanged(object sender, EventArgs e)
        {
            UpdateRibbonMode();
        }

        private void InitializeCommands()
        {
            _htmlEditor.CommandManager.BeginUpdate();

            commandNewPost = _htmlEditor.CommandManager.Add(CommandId.NewPost, commandNewPost_Execute);
            commandNewPage = _htmlEditor.CommandManager.Add(CommandId.NewPage, commandNewPage_Execute);

            // new context menu definition
            _newPostContextMenuDefinition = new CommandContextMenuDefinition(this.components);
            _newPostContextMenuDefinition.Entries.Add(CommandId.NewPost, false, false);
            _newPostContextMenuDefinition.Entries.Add(CommandId.NewPage, false, false);
            commandNewPost.CommandBarButtonContextMenuDropDown = true;

            _htmlEditor.CommandManager.Add(CommandId.OpenDrafts, commandOpenDrafts_Execute);
            _htmlEditor.CommandManager.Add(CommandId.OpenRecentPosts, commandOpenRecentPosts_Execute);
            _htmlEditor.CommandManager.Add(CommandId.OpenPost, commandOpenPost_Execute);
            commandSavePost = _htmlEditor.CommandManager.Add(CommandId.SavePost, commandSavePost_Execute);
            commandDeleteDraft = _htmlEditor.CommandManager.Add(CommandId.DeleteDraft, commandDeleteDraft_Execute);
            _htmlEditor.CommandManager.Add(CommandId.PostAndPublish, commandPostAndPublish_Execute);
            commandPostAsDraft = _htmlEditor.CommandManager.Add(CommandId.PostAsDraft, commandPostAsDraft_Execute);
            commandPostAsDraftAndEditOnline = _htmlEditor.CommandManager.Add(CommandId.PostAsDraftAndEditOnline, commandPostAsDraftAndEditOnline_Execute);

            DraftPostItemsGalleryCommand draftGallery = new DraftPostItemsGalleryCommand(this as IBlogPostEditingSite,
                                                                                CommandManager, false);
            draftGallery.Execute += commandOpenDrafts_Execute;
            DraftPostItemsGalleryCommand postGallery = new DraftPostItemsGalleryCommand(this as IBlogPostEditingSite,
                                                                                CommandManager, true);
            postGallery.Execute += commandOpenRecentPosts_Execute;

            // publish command bar context menu
            _savePostContextMenuDefinition = new CommandContextMenuDefinition(this.components);
            _savePostContextMenuDefinition.CommandBar = true;
            _savePostContextMenuDefinition.Entries.Add(CommandId.SavePost, false, true);
            _savePostContextMenuDefinition.Entries.Add(CommandId.PostAsDraft, false, false);
            _savePostContextMenuDefinition.Entries.Add(CommandId.PostAsDraftAndEditOnline, false, false);
            commandSavePost.CommandBarButtonContextMenuDropDown = true;

            if (ApplicationDiagnostics.TestMode)
            {
                _htmlEditor.CommandManager.Add(CommandId.DiagnosticsConsole, new EventHandler(commandDiagnosticsConsole_Execute));
                _htmlEditor.CommandManager.Add(CommandId.ShowBetaExpiredDialogs, new EventHandler(commandShowBetaExpiredDialogs_Execute));
                _htmlEditor.CommandManager.Add(CommandId.ShowWebLayoutWarning, delegate { new WebLayoutViewWarningForm().ShowDialog(this); });
                _htmlEditor.CommandManager.Add(CommandId.ShowErrorDialog, new EventHandler(commandErrorDialog_Execute));
                _htmlEditor.CommandManager.Add(CommandId.BlogClientOptions, new EventHandler(commandBlogClientOptions_Execute));
                _htmlEditor.CommandManager.Add(CommandId.ShowDisplayMessageTestForm, new EventHandler(commandShowDisplayMessageTestForm_Execute));
                _htmlEditor.CommandManager.Add(CommandId.ShowSupportingFilesForm, new EventHandler(commandShowSupportingFilesForm_Execute));
                _htmlEditor.CommandManager.Add(CommandId.InsertLoremIpsum, new EventHandler(commandInsertLoremIpsum_Execute));
                _htmlEditor.CommandManager.Add(CommandId.ValidateHtml, new EventHandler(commandValidateHtml_Execute));
                _htmlEditor.CommandManager.Add(CommandId.ValidateXhtml, new EventHandler(commandValidateXhtml_Execute));
                _htmlEditor.CommandManager.Add(CommandId.ValidateLocalizedResources, new EventHandler(commandValidateLocalizedResources_Execute));
                _htmlEditor.CommandManager.Add(CommandId.ShowAtomImageEndpointSelector, new EventHandler(commandShowAtomImageEndpointSelector_Execute));
                _htmlEditor.CommandManager.Add(CommandId.RaiseAssertion, delegate { Trace.Fail("You asked for it"); });
                _htmlEditor.CommandManager.Add(CommandId.ShowGoogleCaptcha, delegate { new GDataCaptchaForm().ShowDialog(this); });
                _htmlEditor.CommandManager.Add(CommandId.TerminateProcess, delegate { Process.GetCurrentProcess().Kill(); });
            }

            commandColorize = new Command(CommandId.Colorize);
            commandColorize.CommandBarButtonContextMenuHandler = new CommandBarButtonContextMenuHandler(new ColorizationContextHelper().Handler);
            _htmlEditor.CommandManager.Add(commandColorize);

            _htmlEditor.CommandManager.EndUpdate();

            // initialize the weblog menu commands
            _weblogCommandManager = new WeblogCommandManager(_editingManager, this);
            _weblogCommandManager.WeblogSelected += new WeblogHandler(_weblogMenuManager_WeblogSelected);
        }

        private void commandShowAtomImageEndpointSelector_Execute(object sender, EventArgs e)
        {
            OpenLiveWriter.Controls.Wizard.WizardController controller = new OpenLiveWriter.Controls.Wizard.WizardController();
            WeblogConfigurationWizardPanelSelectBlog selectBlogControl = new WeblogConfigurationWizardPanelSelectBlog();
            selectBlogControl.HeaderText = Res.Get(StringId.ConfigWizardSelectImageEndpoint);
            selectBlogControl.LabelText = Res.Get(StringId.CWSelectImageEndpointText);
            selectBlogControl.PrepareForAdd();
            controller.addWizardStep(new OpenLiveWriter.Controls.Wizard.WizardStep(selectBlogControl, StringId.ConfigWizardSelectImageEndpoint, null, null, null, null, null));

            using (OpenLiveWriter.Controls.Wizard.WizardForm form = new OpenLiveWriter.Controls.Wizard.WizardForm(controller))
            {
                form.Size = new Size((int)Math.Ceiling(DisplayHelper.ScaleX(460)), (int)Math.Ceiling(DisplayHelper.ScaleY(400)));
                form.Text = Res.Get(StringId.CWTitle);
                form.ShowDialog(this);
            }
        }

        private void MenuContextHandler(Control parent, Point menuLocation, int alternativeLocation, IDisposable disposeWhenDone)
        {
            Command cmd;
            using (disposeWhenDone)
            {
                ArrayList mainMenuItems = new ArrayList(_htmlEditor.CommandManager.BuildMenu(MenuType.Main));
                mainMenuItems.Add(new OwnerDrawMenuItem(MenuType.Context, "-"));
                Command commandShowMenu = _htmlEditor.CommandManager.Get(CommandId.ShowMenu);
                mainMenuItems.Add(new CommandOwnerDrawMenuItem(
                    MenuType.Context,
                    commandShowMenu,
                    commandShowMenu.Text));

                cmd = CommandContextMenu.ShowModal(this, menuLocation, alternativeLocation, (MenuItem[])mainMenuItems.ToArray(typeof(MenuItem)));
            }
            if (cmd != null)
                cmd.PerformExecute();
        }

        private class ColorizationContextHelper
        {
            private IDisposable _disposeWhenDone;

            public void Handler(Control parent, Point menuLocation, int alternativeLocation, IDisposable disposeWhenDone)
            {
                try
                {
                    ColorPickerForm form = new ColorPickerForm();
                    form.Color = ColorizedResources.AppColor;
                    form.ColorSelected += new ColorSelectedEventHandler(form_ColorSelected);
                    form.Closed += new EventHandler(form_Closed);

                    form.StartPosition = FormStartPosition.Manual;
                    Point startLocation = CommandBarButtonLightweightControl.PositionMenu(menuLocation, alternativeLocation, form.Size);
                    form.Location = startLocation;
                    _disposeWhenDone = disposeWhenDone;
                    IMiniFormOwner miniFormOwner = parent.FindForm() as IMiniFormOwner;
                    if (miniFormOwner != null)
                        form.FloatAboveOwner(miniFormOwner);
                    form.Show();
                }
                catch
                {
                    disposeWhenDone.Dispose();
                    throw;
                }
            }

            private void form_Closed(object sender, EventArgs e)
            {
                _disposeWhenDone.Dispose();
            }

            private void form_ColorSelected(object sender, ColorSelectedEventArgs args)
            {
                ColorizedResources.AppColor = args.SelectedColor;
            }
        }

        private void InitializeWorkspace()
        {
            if (!BidiHelper.IsRightToLeft)
                DockPadding.Left = 0;
            else
                DockPadding.Right = 0;

            _mainEditorPanel = new Panel();
            _mainEditorPanel.Dock = DockStyle.Fill;

            //Controls.Add(_publishBar);
            Controls.Add(_mainEditorPanel);
        }

        private static int ToAppMode(ApplicationMode m)
        {
            return Convert.ToInt32(1 << Convert.ToInt32(m, CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
        }

        private ApplicationMode TextDirection
        {
            get
            {
                return _htmlEditor.IsRTLTemplate || BidiHelper.IsRightToLeft ? ApplicationMode.RTL : ApplicationMode.LTR;
            }
        }

        private int mode = ToAppMode(ApplicationMode.Normal);
        public bool TestMode
        {
            get
            {
                return Convert.ToBoolean(mode & ToAppMode(ApplicationMode.Test));
            }

            set
            {
                if (TestMode != value)
                {
                    mode ^= ToAppMode(ApplicationMode.Test);
                    UpdateRibbonMode();
                }
            }
        }

        public bool PreviewMode
        {
            get
            {
                return Convert.ToBoolean(mode & ToAppMode(ApplicationMode.Preview));
            }

            set
            {
                if (PreviewMode != value)
                {
                    mode ^= ToAppMode(ApplicationMode.Preview);
                    mode ^= ToAppMode(ApplicationMode.Normal);
                    Debug.Assert(!(PreviewMode && Convert.ToBoolean(mode & ToAppMode(ApplicationMode.Normal))));
                    UpdateRibbonMode();
                }
            }
        }

        private void UpdateRibbonMode()
        {
            if (TextDirection == ApplicationMode.RTL)
            {
                mode |= ToAppMode(ApplicationMode.RTL);
                mode &= ~ToAppMode(ApplicationMode.LTR);
            }
            else
            {
                mode |= ToAppMode(ApplicationMode.LTR);
                mode &= ~ToAppMode(ApplicationMode.RTL);
            }

            if (commandPluginsGallery.Items.Count > 0)
            {
                mode |= ToAppMode(ApplicationMode.HasPlugins);
                mode &= ~ToAppMode(ApplicationMode.NoPlugins);
            }
            else
            {
                mode |= ToAppMode(ApplicationMode.NoPlugins);
                mode &= ~ToAppMode(ApplicationMode.HasPlugins);
            }

            if (_framework != null)
            {
                _framework.SetModes(mode);
            }
        }

        private void InvalidateCommand(CommandId commandId)
        {
            Command command = CommandManager.Get(commandId);
            if (command != null)
            {
                command.Invalidate();
            }
        }

        public void OnTestModeChanged(object sender, EventArgs e)
        {
            TestMode = ApplicationDiagnostics.TestMode;
        }

        [ComImport]
        [Guid("926749fa-2615-4987-8845-c33e65f2b957")]
        public class Framework
        {
        }

        public IUIFramework RibbonFramework
        {
            get
            {
                return _framework;
            }
        }

        private RibbonControl ribbonControl;
        private IUIFramework _framework;
        private IUIRibbon ribbon;
        private void InitializeRibbon()
        {

            IUIFramework framework = (IUIFramework)Activator.CreateInstance<Framework>();

            Trace.Assert(framework != null, "Failed to create IUIFramework.");

            ribbonControl = new RibbonControl(_htmlEditor.IHtmlEditorComponentContext, _htmlEditor);

            int initializeResult = framework.Initialize(_mainFrameWindow.Handle, this);
            Trace.Assert(initializeResult == HRESULT.S_OK, "Ribbon framework failed to initialize: " + initializeResult);

            _framework = framework;

            string nativeResourceDLL = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\OpenLiveWriter.Ribbon.dll";
            IntPtr hMod = Kernel32.LoadLibrary(nativeResourceDLL);

            using (new QuickTimer("IUIRibbonFramework::LoadUI"))
            {
                int loadResult = _framework.LoadUI(hMod, "RIBBON_RIBBON");
                Trace.Assert(loadResult == HRESULT.S_OK, "Ribbon failed to load: " + loadResult);
            }

            _framework.SetModes(mode);

            CommandManager.Invalidate(CommandId.MRUList);
            CommandManager.Invalidate(CommandId.OpenDraftSplit);
            CommandManager.Invalidate(CommandId.OpenPostSplit);

            ApplicationDiagnostics.TestModeChanged += OnTestModeChanged;
            TestMode = ApplicationDiagnostics.TestMode;
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);

            if (_mainEditorPanel != null && ribbon != null)
            {
                uint ribbonHeight = 0;
                if (ribbon != null)
                {
                    ribbon.GetHeight(out ribbonHeight);
                }
                _mainEditorPanel.DockPadding.Top = (int)ribbonHeight;
            }

            Invalidate(false);
            Update();
        }

        private void InitializeHtmlEditor()
        {
            // create the editor
            _htmlEditor = BlogPostHtmlEditor.Create(_mainFrameWindow, _mainEditorPanel, this as IBlogPostEditingSite);
            _htmlEditor.TitleFocusChanged += new EventHandler(htmlEditor_TitleFocusChanged);
            _htmlEditor.Dirty += new EventHandler(htmlEditor_Dirty);
            _htmlEditor.EditorLoaded += new EventHandler(_htmlEditor_EditingModeChanged);
            _htmlEditor.DocumentComplete += new EventHandler(_htmlEditor_DocumentComplete);
        }

        void _htmlEditor_DocumentComplete(object sender, EventArgs e)
        {
            _htmlEditor.FocusBody();
        }

        public void OnKeyboardLanguageChanged()
        {
            //// Sync dictionary language with keyboard language (if enabled)
            //ushort currentLangId = (ushort) (User32.GetKeyboardLayout(0) & 0xFFFF);
            //SpellingLanguageEntry[] langs = SpellingSettings.GetInstalledLanguages();
            //foreach (var v in langs)
            //{
            //    if (v.LCID == currentLangId)
            //    {
            //        SpellingSettings.Language = v.Language;
            //        SpellingSettings.FireChangedEvent();
            //        break;
            //    }
            //}
        }

        void _htmlEditor_EditingModeChanged(object sender, EventArgs e)
        {
            PreviewMode = _htmlEditor.CurrentEditingMode == EditingMode.Preview;
        }

        private void htmlEditor_Dirty(object sender, EventArgs e)
        {
            _autoSaveTimer.Stop();
            if (PostEditorSettings.AutoSaveDrafts)
                _autoSaveTimer.Start();
        }

        private void InitializeOptionsEditor()
        {

            _optionsEditor = new PostEditorPreferencesEditor(_mainFrameWindow, this);
        }

        public CommandManager CommandManager
        {
            get
            {
                return this._htmlEditor.CommandManager;
            }
        }

        private class PostContentEditor : IBlogPostContentEditor
        {
            public PostContentEditor(PostEditorMainControl parent) { _parent = parent; }
            public bool FullyEditableRegionActive { get { return _parent._htmlEditor.FullyEditableRegionActive; } }
            public string SelectedText { get { return _parent._htmlEditor.SelectedText; } }
            public string SelectedHtml { get { return _parent._htmlEditor.SelectedHtml; } }
            public void InsertHtml(string content, bool moveSelectionRight) { _parent._htmlEditor.InsertHtml(content, moveSelectionRight); }
            public void InsertLink(string url, string linkText, string linkTitle, string rel, bool newWindow) { _parent._htmlEditor.InsertLink(url, linkText, linkTitle, rel, newWindow); }
            private PostEditorMainControl _parent;
        }

        private void InitializePostPropertyEditors()
        {
            _styleComboControl = new HtmlStylePicker(this._htmlEditor);
            _styleComboControl.Enabled = false;
        }

        internal BlogPostEditingManager BlogPostEditingManager
        {
            get { return _editingManager; }
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_htmlEditor != null)
                    _htmlEditor.Dispose();

                if (_editingManager != null)
                    _editingManager.Dispose();

                if (_weblogCommandManager != null)
                    _weblogCommandManager.Dispose();

                if (_optionsEditor != null)
                    _optionsEditor.Dispose();

                if (components != null)
                {
                    components.Dispose();
                }

                _framework.Destroy();

                BlogSettings.BlogSettingsDeleted -= new BlogSettings.BlogSettingsListener(HandleBlogDeleted);
                commandPluginsGallery.StateChanged -= new EventHandler(commandPluginsGallery_StateChanged);
            }
            base.Dispose(disposing);
        }

        #endregion

        #region Command Handlers

        private void commandNewPost_Execute(object sender, EventArgs e)
        {
            WindowCascadeHelper.SetNextOpenedLocation(this._mainFrameWindow.Location);
            _editingManager.NewPost();
        }

        private void commandNewPage_Execute(object sender, EventArgs e)
        {
            WindowCascadeHelper.SetNextOpenedLocation(this._mainFrameWindow.Location);
            _editingManager.NewPage();
        }

        private void commandOpenDrafts_Execute(object sender, EventArgs e)
        {
            WindowCascadeHelper.SetNextOpenedLocation(this._mainFrameWindow.Location);
            _editingManager.OpenPost(OpenPostForm.OpenMode.Drafts);
        }

        private void commandOpenRecentPosts_Execute(object sender, EventArgs e)
        {
            WindowCascadeHelper.SetNextOpenedLocation(this._mainFrameWindow.Location);
            _editingManager.OpenPost(OpenPostForm.OpenMode.RecentPosts);
        }

        private void commandOpenPost_Execute(object sender, EventArgs e)
        {
            WindowCascadeHelper.SetNextOpenedLocation(this._mainFrameWindow.Location);
            _editingManager.OpenPost(OpenPostForm.OpenMode.Auto);
        }

        private void commandSavePost_Execute(object sender, EventArgs e)
        {
            // save the draft
            using (new PaddedWaitCursor(250))
            {
                _editingManager.SaveDraft();
            }
        }

        private void commandDeleteDraft_Execute(object sender, EventArgs e)
        {
            _editingManager.DeleteCurrentDraft();
        }

        private void commandPostAsDraft_Execute(object sender, EventArgs e)
        {
            if (_editingManager.PublishAsDraft())
            {
                // respect close settings
                if (CloseWindowOnPublish)
                    CloseMainFrameWindow();
            }
        }

        private void commandPostAsDraftAndEditOnline_Execute(object sender, EventArgs e)
        {
            if (_editingManager.PublishAsDraft())
            {
                // edit post online
                _editingManager.EditPostOnline(true);

                // respect close settings
                if (CloseWindowOnPublish)
                    CloseMainFrameWindow();
            }
        }

        private void commandPostAndPublish_Execute(object sender, EventArgs e)
        {
            if (_editingManager.Publish())
            {
                // respect post after publish
                if (PostEditorSettings.ViewPostAfterPublish)
                    _editingManager.ViewPost();

                // respect close settings
                if (CloseWindowOnPublish)
                    CloseMainFrameWindow();
            }
        }

        private void CloseMainFrameWindow()
        {
            // WinLive 164570: This function is called from inside a Ribbon execute handler, so we don't want to close
            // the current window (and thereby destroy the Ribbon) while we're still inside a call from the Ribbon.
            // Using BeginInvoke is basically just a wrapper around using User32.PostMessage, which puts the WM.CLOSE
            // message at the end of the message queue.
            this.BeginInvoke(new InvokeInUIThreadDelegate(() => this._mainFrameWindow.Close()), null);
        }

        private void commandDiagnosticsConsole_Execute(object sender, EventArgs e)
        {
            ApplicationEnvironment.ApplicationDiagnostics.ShowDiagnosticsConsole("test");
        }

        private void commandShowBetaExpiredDialogs_Execute(object sender, EventArgs e)
        {
            ExpirationForm.ShowExpiredDialog(20);
            ExpirationForm.ShowExpiredDialog(1);
            ExpirationForm.ShowExpiredDialog(-1);
        }

        private void commandErrorDialog_Execute(object sender, EventArgs e)
        {
            UnexpectedErrorMessage.Show(new ApplicationException("Force Error Dialog"));
        }

        private void commandBlogClientOptions_Execute(object sender, EventArgs e)
        {
            _editingManager.DisplayBlogClientOptions();
        }

        private void commandShowDisplayMessageTestForm_Execute(object sender, EventArgs e)
        {
            using (DisplayMessageTestForm form = new DisplayMessageTestForm())
            {
                form.ShowDialog(FindForm());
            }
        }

        private void commandShowSupportingFilesForm_Execute(object sender, EventArgs e)
        {
            SupportingFilesForm.ShowForm(_mainFrameWindow as Form, BlogPostEditingManager);
        }

        private void commandValidateLocalizedResources_Execute(object sender, EventArgs e)
        {
            string[] errors = Res.Validate();
            if (errors.Length > 0)
            {
                Trace.WriteLine("Localized resource validation errors:\r\n" + StringHelper.Join(errors, "\r\n"));
                MessageBox.Show(StringHelper.Join(errors, "\r\n\r\n"), ApplicationEnvironment.ProductNameQualified, MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, (BidiHelper.IsRightToLeft ? (MessageBoxOptions.RightAlign | MessageBoxOptions.RtlReading) : 0));
            }
            else
            {
                MessageBox.Show("No problems detected.", ApplicationEnvironment.ProductNameQualified, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, (BidiHelper.IsRightToLeft ? (MessageBoxOptions.RightAlign | MessageBoxOptions.RtlReading) : 0));
            }
        }

        private void commandInsertLoremIpsum_Execute(object sender, EventArgs e)
        {
            string loremIpsum = "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>";
            _htmlEditor.InsertHtml(loremIpsum, HtmlInsertionOptions.SuppressSpellCheck | HtmlInsertionOptions.MoveCursorAfter);
        }

        private void commandValidateXhtml_Execute(object sender, EventArgs e)
        {
            ValidateHtml(true);
        }
        private void commandValidateHtml_Execute(object sender, EventArgs e)
        {
            ValidateHtml(false);
        }

        private void ValidateHtml(bool xhtml)
        {
            const string XHTML_DOCTYPE =
                @"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">";
            const string HTML_DOCTYPE =
                @"<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"">";
            const string HTML_TEMPLATE = "<html><head><title>Untitled</title></head><body>{0}</body></html>";
            const string XHTML_TEMPLATE = "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"><head><title>Untitled</title></head><body>{0}</body></html>";
            const string VALIDATOR_URL = "http://validator.w3.org/";

            HtmlForm form;
            FormData data;

            string html = string.Format(CultureInfo.InvariantCulture, xhtml ? XHTML_TEMPLATE : HTML_TEMPLATE, _htmlEditor.Body);
            if (xhtml)
                html = XHTML_DOCTYPE + html;
            else
                html = HTML_DOCTYPE + html;

            HttpWebResponse response = HttpRequestHelper.SendRequest(VALIDATOR_URL);
            try
            {
                using (Stream s = response.GetResponseStream())
                {
                    FormFactory formFactory = new FormFactory(s);
                    formFactory.NextForm();
                    formFactory.NextForm();
                    form = formFactory.NextForm();
                    Textarea textarea = form.GetElementByIndex(0) as Textarea;
                    if (textarea == null)
                        throw new ArgumentException("Unexpected HTML: textarea element not found");
                    textarea.Value = html;
                    data = form.Submit(null);
                }
            }
            finally
            {
                response.Close();
            }

            using (Stream formData = data.ToStream())
            {
                HttpWebRequest request = HttpRequestHelper.CreateHttpWebRequest(UrlHelper.EscapeRelativeURL(UrlHelper.SafeToAbsoluteUri(response.ResponseUri), form.Action), false);
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = formData.Length;
                request.Method = form.Method.ToUpper(CultureInfo.InvariantCulture);
                using (Stream requestStream = request.GetRequestStream())
                    StreamHelper.Transfer(formData, requestStream);
                HttpWebResponse response2 = (HttpWebResponse)request.GetResponse();
                try
                {
                    using (Stream s2 = response2.GetResponseStream())
                    {
                        string resultsHtml = StreamHelper.AsString(s2, Encoding.UTF8);
                        resultsHtml = resultsHtml.Replace("<head>",
                                                          string.Format(CultureInfo.InvariantCulture, "<head><base href=\"{0}\"/>",
                                                                        HtmlUtils.EscapeEntities(UrlHelper.SafeToAbsoluteUri(response2.ResponseUri))));

                        string tempFile = TempFileManager.Instance.CreateTempFile("results.htm");
                        using (Stream fileStream = new FileStream(tempFile, FileMode.Create, FileAccess.Write))
                        {
                            byte[] bytes = Encoding.UTF8.GetBytes(resultsHtml);
                            fileStream.Write(bytes, 0, bytes.Length);
                        }
                        ShellHelper.LaunchUrl(tempFile);
                    }
                }
                finally
                {
                    response2.Close();
                }
            }
        }

        private bool CloseWindowOnPublish
        {
            get
            {
                return PostEditorSettings.CloseWindowOnPublish;
            }
        }

        private bool ValidateTitleSpecified()
        {

            if (_htmlEditor.Title == String.Empty)
            {
                if (_editingManager.BlogRequiresTitles)
                {
                    // show error
                    DisplayMessage.Show(MessageId.NoTitleSpecified, FindForm());

                    // focus the title and return false
                    _htmlEditor.FocusTitle();
                    return false;
                }
                else if (PostEditorSettings.TitleReminder)
                {
                    using (TitleReminderForm titleReminderForm = new TitleReminderForm(_editingManager.EditingPage))
                    {
                        if (titleReminderForm.ShowDialog(FindForm()) != DialogResult.Yes)
                        {
                            _htmlEditor.FocusTitle();
                            return false;
                        }
                    }
                }
            }

            // got this far so the title must be valid
            return true;
        }

        private bool CheckSpelling()
        {
            // do auto spell check
            if (SpellingSettings.CheckSpellingBeforePublish && _htmlEditor.CanSpellCheck)
            {
                if (!_htmlEditor.CheckSpelling())
                {
                    return (DialogResult.Yes == DisplayMessage.Show(MessageId.SpellCheckCancelledStillPost, _mainFrameWindow));
                }
            }
            return true;
        }

        #endregion

        #region Event handlers for UI state management

        /// <summary>
        /// Calling with null sender will cause a forced auto save if the post is dirty.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _autoSaveTimer_Tick(object sender, EventArgs e)
        {
            if (!_htmlEditor.SuspendAutoSave)
            {
                _autoSaveTimer.Stop();
                bool forceSave = sender == null && _editingManager.PostIsDirty;
                if (forceSave || _editingManager.ShouldAutoSave)
                {
                    _htmlEditor.StatusBar.PushStatusMessage(Res.Get(StringId.StatusAutoSaving));
                    try
                    {
                        _editingManager.AutoSaveIfRequired(forceSave);
                    }
                    catch
                    {
                        _htmlEditor.StatusBar.PopStatusMessage();
                        throw;
                    }
                    _autoSaveMessageDismissTimer.Start();
                }
            }
        }

        private void _autoSaveMessageDismissTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                _autoSaveMessageDismissTimer.Stop();
                _htmlEditor.StatusBar.PopStatusMessage();
            }
            catch (Exception ex)
            {
                Trace.Fail(ex.ToString());
            }
        }

        private void _weblogMenuManager_WeblogSelected(string blogId)
        {
            string currentBlogId = CurrentBlogId;

            _editingManager.SwitchBlog(blogId);

            // Only set the editor dirty if we actually switched blogs.
            if (blogId != currentBlogId)
                _htmlEditor.SetCurrentEditorDirty();
        }

        private void _editingManager_EditingStatusChanged(object sender, EventArgs e)
        {
            ManageCommands();
            UpdateFrameUI();
        }

        public void NotifyWeblogStylePreviewChanged()
        {
            _htmlEditor.CommandManager.Invalidate(CommandId.SemanticHtmlGallery);
        }

        private void _editingManager_BlogChanged(object sender, EventArgs e)
        {
            if (WeblogChanged != null)
                WeblogChanged(_editingManager.BlogId);

            UpdateRibbonMode();

            UpdateFrameUI();
        }

        private void _editingManager_BlogSettingsChanged(string blogId, bool templateChanged)
        {
            if (WeblogSettingsChanged != null)
                WeblogSettingsChanged(blogId, templateChanged);

            UpdateRibbonMode();

            UpdateFrameUI();
        }

        private void htmlEditor_TitleFocusChanged(object sender, EventArgs e)
        {
            UpdateFrameUI();
            ribbonControl.ManageCommands();
        }

        void IFormClosingHandler.OnClosing(CancelEventArgs e)
        {
            _editingManager.Closing(e);

            // if the control IsDirty then see if the user wants to publish their edits
            if (!e.Cancel && _editingManager.PostIsDirty)
            {
                _mainFrameWindow.Activate();
                DialogResult result = DisplayMessage.Show(MessageId.QueryForUnsavedChanges, _mainFrameWindow);
                if (result == DialogResult.Yes)
                {
                    using (new WaitCursor())
                        _editingManager.SaveDraft();
                }
                else if (result == DialogResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
        }

        void IFormClosingHandler.OnClosed()
        {
            _editingManager.OnClosed();
        }

        // implement IBlogPostEditor so we can participating in showing/hiding
        // the property editor control
        void IBlogPostEditor.Initialize(IBlogPostEditingContext editingContext, IBlogClientOptions clientOptions) { }
        void IBlogPostEditor.SaveChanges(BlogPost post, BlogPostSaveOptions options) { }
        bool IBlogPostEditor.ValidatePublish()
        {
            if (!ValidateTitleSpecified())
                return false;

            if (!CheckSpelling())
                return false;

            else
                return true;
        }
        void IBlogPostEditor.OnPublishSucceeded(BlogPost blogPost, PostResult postResult) { }
        bool IBlogPostEditor.IsDirty { get { return false; } }
        void IBlogPostEditor.OnBlogChanged(Blog newBlog)
        {
            AdaptToBlog(newBlog);
            CheckForServiceUpdates(newBlog);
        }

        void IBlogPostEditor.OnBlogSettingsChanged(bool templateChanged)
        {
            using (Blog blog = new Blog(_editingManager.BlogId))
                AdaptToBlog(blog);
        }

        private void AdaptToBlog(Blog newBlog)
        {
            // if the blog supports posting to draft or not
            commandPostAsDraft.Enabled = newBlog.ClientOptions.SupportsPostAsDraft;
            if (newBlog.ClientOptions.SupportsPostAsDraft)
                commandSavePost.CommandBarButtonContextMenuDefinition = _savePostContextMenuDefinition;
            else
                commandSavePost.CommandBarButtonContextMenuDefinition = null;

            // if the blog supports post draft and edit online
            commandPostAsDraftAndEditOnline.Enabled = newBlog.ClientOptions.SupportsPostAsDraft && (newBlog.ClientOptions.PostEditingUrl != String.Empty);

            // if the blog supports pages or not
            bool enablePages = newBlog.ClientOptions.SupportsPages;
            commandNewPage.Enabled = enablePages;
            if (enablePages)
                commandNewPost.CommandBarButtonContextMenuDefinition = _newPostContextMenuDefinition;
            else
                commandNewPost.CommandBarButtonContextMenuDefinition = null;
        }

        private void CheckForServiceUpdates(Blog blog)
        {
            if (_editingManager.BlogIsAutoUpdatable && !ApplicationDiagnostics.SuppressBackgroundRequests)
            {
                ServiceUpdateChecker checker = new ServiceUpdateChecker(blog.Id, new WeblogSettingsChangedHandler(FireWeblogSettingsChangedEvent));
                checker.Start();
            }
        }

        /// <summary>
        /// Responds to global blog deletion events.
        /// </summary>
        /// <param name="blogId"></param>
        private void HandleBlogDeleted(string blogId)
        {
            if (InvokeRequired)
                BeginInvoke(new InvokeInUIThreadDelegate(HandleMaybeBlogDeleted));
            else
                HandleMaybeBlogDeleted();
        }

        /// <summary>
        /// Updates the editor to use a new blog if the current blog has been deleted.
        /// </summary>
        private void HandleMaybeBlogDeleted()
        {
            Debug.Assert(!InvokeRequired, "This method must be invoked on the UI thread!");

            // if the current weblog got deleted as part of this operation then reselect the
            // new default weblog
            if (!BlogSettings.BlogIdIsValid(_editingManager.BlogId))
            {
                _editingManager.SwitchBlog(BlogSettings.DefaultBlogId);
            }
        }

        #endregion

        #region Private Helper Methods

        private void ManageCommands()
        {
            // Temporary work around for WinLive 51425.
            if (ApplicationDiagnostics.AutomationMode)
                commandDeleteDraft.Enabled = true;
            else
                commandDeleteDraft.Enabled = _editingManager.PostIsDraft && _editingManager.PostIsSaved;
        }

        /// <summary>
        /// Update the title and status bars as appropriate
        /// </summary>
        private void UpdateFrameUI()
        {
            // calculate the text that describes the post
            string title = _htmlEditor.Title;
            string postDescription = (title != String.Empty) ? title : Res.Get(StringId.Untitled);

            // update frame window
            _mainFrameWindow.Caption = String.Format(CultureInfo.CurrentCulture, Res.Get(StringId.WindowTitleFormat), postDescription, ApplicationEnvironment.ProductNameQualified);

            UpdatePostStatusUI();
        }

        private void UpdatePostStatusUI()
        {
            string statusText;
            if (_editingManager.PostIsDraft || string.IsNullOrEmpty(_editingManager.BlogPostId))
            {
                DateTime dateSaved = _editingManager.PostDateSaved ?? DateTime.MinValue;
                statusText = dateSaved != DateTime.MinValue
                                 ? String.Format(CultureInfo.CurrentCulture, Res.Get(StringId.StatusDraftSaved),
                                                   FormatUtcDate(dateSaved))
                                 : Res.Get(StringId.StatusDraftUnsaved);
            }
            else
            {
                statusText = string.Format(CultureInfo.CurrentCulture, Res.Get(StringId.StatusPublished), FormatUtcDate(_editingManager.PostDatePublished));
            }

            _htmlEditor.StatusBar.SetStatusMessage(statusText);
        }

        private string FormatUtcDate(DateTime dateTime)
        {
            DateTime localDateTime = DateTimeHelper.UtcToLocal(dateTime);
            return CultureHelper.GetDateTimeCombinedPattern(localDateTime.ToShortDateString(), localDateTime.ToShortTimeString());
        }

        #endregion

        #region Component Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            //
            // PostEditorMainControl
            //
            this.Name = "PostEditorMainControl";
            this.Size = new System.Drawing.Size(499, 276);

        }
        #endregion

        #region IBlogPostEditingSite Members

        IMainFrameWindow IBlogPostEditingSite.FrameWindow
        {
            get
            {
                return _mainFrameWindow;
            }
        }

        void IBlogPostEditingSite.ConfigureWeblog(string blogId, Type selectedPanel)
        {
            using (new WaitCursor())
            {
                // edit settings
                if (WeblogSettingsManager.EditSettings(FindForm(), blogId, selectedPanel))
                {
                    // broadcast event
                    FireWeblogSettingsChangedEvent(blogId, true);
                }
            }
        }

        void IBlogPostEditingSite.ConfigureWeblogFtpUpload(string blogId)
        {
            if (WeblogSettingsManager.EditFtpImageUpload(FindForm(), blogId))
            {
                // broadcast event
                FireWeblogSettingsChangedEvent(blogId, false);
            }
        }

        bool IBlogPostEditingSite.UpdateWeblogTemplate(string blogID)
        {
            if (_editingManager.VerifyBlogCredentials())
            {
                using (PostHtmlEditingSettings editSettings = new PostHtmlEditingSettings(blogID))
                {
                    using (BlogSettings settings = BlogSettings.ForBlogId(blogID))
                    {
                        Color? backgroundColor;
                        BlogEditingTemplateFile[] templates = BlogEditingTemplateDetector.DetectTemplate(
                            new BlogClientUIContextImpl(_mainFrameWindow, _mainFrameWindow),
                            this,
                            settings,
                            !_editingManager.BlogIsAutoUpdatable,
                            out backgroundColor); // only probe if we do not support auto-update

                        if (templates.Length != 0)
                        {
                            editSettings.EditorTemplateHtmlFiles = templates;
                            if (backgroundColor != null)
                            {
                                IDictionary hpo = settings.HomePageOverrides ?? new Hashtable();
                                hpo[BlogClientOptions.POST_BODY_BACKGROUND_COLOR] =
                                    backgroundColor.Value.ToArgb().ToString(CultureInfo.InvariantCulture);

                                settings.HomePageOverrides = hpo;
                            }
                            FireWeblogSettingsChangedEvent(blogID, true);
                            return true;
                        }

                    }
                }
            }

            return false;
        }

        void IBlogPostEditingSite.AddWeblog()
        {
            using (new WaitCursor())
            {
                bool switchToWeblog;
                string newBlogId = WeblogConfigurationWizardController.Add(this, true, out switchToWeblog);
                if (newBlogId != null)
                {
                    (this as IBlogPostEditingSite).NotifyWeblogAccountListEdited();
                    if (switchToWeblog)
                    {
                        _editingManager.SwitchBlog(newBlogId);
                    }
                }
            }
        }

        void IBlogPostEditingSite.NotifyWeblogSettingsChanged(bool templateChanged)
        {
            (this as IBlogPostEditingSite).NotifyWeblogSettingsChanged(_editingManager.BlogId, templateChanged);
        }

        void IBlogPostEditingSite.NotifyWeblogSettingsChanged(string blogId, bool templateChanged)
        {
            FireWeblogSettingsChangedEvent(blogId, templateChanged);
        }

        void IBlogPostEditingSite.NotifyWeblogAccountListEdited()
        {
            FireWeblogListChangedEvent();
        }

        private void weblogAccountManagementForm_WeblogSettingsEdited(string blogId, bool templateChanged)
        {
            FireWeblogSettingsChangedEvent(blogId, templateChanged);
        }

        void IBlogPostEditingSite.OpenLocalPost(PostInfo postInfo)
        {
            _editingManager.OpenLocalPost(postInfo);
        }

        void IBlogPostEditingSite.DeleteLocalPost(PostInfo postInfo)
        {
            try
            {
                _editingManager.DeleteLocalPost(postInfo);
            }
            catch (Exception ex)
            {
                DisplayableExceptionDisplayForm.Show(_mainFrameWindow, ex);
            }
        }

        string IBlogPostEditingSite.CurrentAccountId
        {
            get
            {
                if (_editingManager != null)
                    return _editingManager.BlogId;
                else
                    return null;
            }
        }

        public event WeblogHandler WeblogChanged;

        public event WeblogSettingsChangedHandler WeblogSettingsChanged;

        public event WeblogSettingsChangedHandler GlobalWeblogSettingsChanged
        {
            add
            {
                RegisterWeblogSettingsChangedListener(this, value);
            }
            remove
            {
                UnregisterWeblogSettingsChangedListener(this, value);
            }
        }

        public event EventHandler WeblogListChanged
        {
            add
            {
                RegisterWeblogListChangedListener(this, value);
            }
            remove
            {
                UnregisterWeblogListChangedListener(this, value);
            }
        }

        public event EventHandler PostListChanged
        {
            add
            {
                RegisterPostListChangedListener(this, value);
            }
            remove
            {
                UnregisterPostListChangedListener(this, value);
            }
        }

        #endregion

        #region Implementation of post list changed event

        private void _editingManager_UserSavedPost(object sender, EventArgs e)
        {
            FirePostListChangedEvent();
        }

        private void _editingManager_UserPublishedPost(object sender, EventArgs e)
        {
            FirePostListChangedEvent();
        }

        private void _editingManager_UserDeletedPost(object sender, EventArgs e)
        {
            FirePostListChangedEvent();
        }

        private static void RegisterPostListChangedListener(Control controlContext, EventHandler listener)
        {
            lock (_postListChangedListeners)
            {
                _postListChangedListeners[listener] = controlContext;
            }
        }
        private static void UnregisterPostListChangedListener(Control controlContext, EventHandler listener)
        {
            lock (_postListChangedListeners)
            {
                _postListChangedListeners.Remove(listener);
            }
        }

        public void FirePostListChangedEvent()
        {
            try
            {
                // notify listeners of post-list changed
                lock (_postListChangedListeners)
                {
                    // first refresh the post-list cache for high-performance refresh
                    PostListCache.Update();
                    WriterJumpList.Invalidate(Handle);

                    CommandManager.Invalidate(CommandId.MRUList);
                    CommandManager.Invalidate(CommandId.OpenDraftSplit);
                    CommandManager.Invalidate(CommandId.OpenPostSplit);

                    // now notify all of the listeners asynchronously
                    foreach (DictionaryEntry listener in _postListChangedListeners)
                    {
                        Control control = listener.Value as Control;
                        if (ControlHelper.ControlCanHandleInvoke(control))
                        {
                            control.BeginInvoke(listener.Key as EventHandler, new object[] { control, EventArgs.Empty });
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Trace.Fail("Unexpected exception firing post list changed event: " + ex.ToString());
            }
        }

        private static Hashtable _postListChangedListeners = new Hashtable();

        #endregion

        #region Implementation of weblog settings changed event

        private static void RegisterWeblogSettingsChangedListener(Control controlContext, WeblogSettingsChangedHandler listener)
        {
            lock (_weblogSettingsChangedListeners)
            {
                _weblogSettingsChangedListeners[listener] = controlContext;
            }
        }
        private static void UnregisterWeblogSettingsChangedListener(Control controlContext, WeblogSettingsChangedHandler listener)
        {
            lock (_weblogSettingsChangedListeners)
            {
                _weblogSettingsChangedListeners.Remove(listener);
            }
        }

        private static void RegisterWeblogListChangedListener(Control controlContext, EventHandler listener)
        {
            lock (_weblogListChangedListeners)
            {
                _weblogListChangedListeners[listener] = controlContext;
            }
        }
        private static void UnregisterWeblogListChangedListener(Control controlContext, EventHandler listener)
        {
            lock (_weblogListChangedListeners)
            {
                _weblogListChangedListeners.Remove(listener);
            }
        }

        private static void FireWeblogSettingsChangedEvent(string blogId, bool templateChanged)
        {
            try
            {
                // notify listeners of post-list changed
                lock (_weblogSettingsChangedListeners)
                {
                    // now notify all of the listeners asynchronously
                    foreach (DictionaryEntry listener in _weblogSettingsChangedListeners)
                    {
                        Control control = listener.Value as Control;

                        if (ControlHelper.ControlCanHandleInvoke(control))
                        {
                            try
                            {
                                control.BeginInvoke(listener.Key as WeblogSettingsChangedHandler, new object[] { blogId, templateChanged });
                            }
                            catch (Exception ex)
                            {
                                Trace.Fail("Unexpected error calling BeginInvoke: " + ex.ToString());
                            }
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Trace.Fail("Unexpected exception firing weblog settings changed event: " + ex.ToString());
            }
        }

        private static Hashtable _weblogSettingsChangedListeners = new Hashtable();

        private static Hashtable _weblogListChangedListeners = new Hashtable();
        private static void FireWeblogListChangedEvent()
        {
            try
            {
                // notify listeners of post-list changed
                lock (_weblogListChangedListeners)
                {
                    // now notify all of the listeners asynchronously
                    foreach (DictionaryEntry listener in _weblogListChangedListeners)
                    {
                        Control control = listener.Value as Control;

                        if (ControlHelper.ControlCanHandleInvoke(control))
                        {
                            try
                            {
                                control.BeginInvoke(listener.Key as EventHandler, EventArgs.Empty);
                            }
                            catch (Exception ex)
                            {
                                Trace.Fail("Unexpected error calling BeginInvoke: " + ex.ToString());
                            }
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Trace.Fail("Unexpected exception firing weblog settings changed event: " + ex.ToString());
            }
        }

        #endregion

        #region internal properties

        internal string CurrentBlogId
        {
            get
            {
                return this._editingManager.BlogId;
            }
        }

        #endregion

        #region Focus Methods
        internal IFocusableControl[] GetFocusPanes()
        {
            return _htmlEditor.GetFocusablePanes();
        }

        #endregion

        public void OnClosing(CancelEventArgs e)
        {
        }

        public void OnPostClosing(CancelEventArgs e)
        {

        }

        public void OnClosed() { }

        public void OnPostClosed() { }

        #region IBlogPostEditingSite Members

        public IHtmlStylePicker StyleControl
        {
            get { return _styleComboControl; }
        }

        #endregion

        public int OnViewChanged(uint viewId, CommandTypeID typeID, object view, ViewVerb verb, int uReasonCode)
        {
            if (ribbon == null)
            {
                ribbon = view as IUIRibbon;
            }

            if (ribbon != null)
            {
                switch (verb)
                {
                    case ViewVerb.Create:
                        LoadRibbonSettings();
                        break;
                    case ViewVerb.Destroy:
                        break;
                    case ViewVerb.Error:
                        Trace.Fail("Ribbon error: " + uReasonCode);
                        break;
                    case ViewVerb.Size:
                        uint ribbonHeight;
                        if (ComHelper.SUCCEEDED(ribbon.GetHeight(out ribbonHeight)))
                        {
                            Debug.Assert(ribbonHeight >= 0);
                            OnSizeChanged(EventArgs.Empty);
                        }
                        break;
                    default:
                        Debug.Assert(false, "Unexpected ViewVerb!");
                        break;
                }
            }
            return HRESULT.S_OK;
        }

        /// <summary>
        /// All instances of Writer use the same Ribbon.dat file, so we need to be careful of race conditions.
        /// </summary>
        private static object _ribbonSettingsLock = new object();
        private static bool _ribbonSettingsLoadSaveActive = false;

        public void LoadRibbonSettings()
        {
            lock (_ribbonSettingsLock)
            {
                try
                {
                    WithRibbonSettingsIStream(false, false, true, ribbon.LoadSettingsFromStream);
                }
                catch (Exception e)
                {
                    Trace.Fail("LoadRibbonSettings failed: " + e);
                }
            }
        }

        public void SaveRibbonSettings()
        {
            lock (_ribbonSettingsLock)
            {
                try
                {
                    WithRibbonSettingsIStream(true, true, false, ribbon.SaveSettingsToStream);
                }
                catch (Exception e)
                {
                    Trace.Fail("SaveRibbonSettings failed: " + e);
                }
            }
        }

        private DateTime? ribbonSettingsTimestamp;

        private delegate int WithIStreamAction(IStream stream);
        /// <summary>
        ///
        /// </summary>
        /// <param name="create">Create the stream if it doesn't exist, and make it writable.</param>
        /// <param name="onlyIfChanged"></param>
        /// <param name="action"></param>
        private void WithRibbonSettingsIStream(bool create, bool writable, bool onlyIfChanged, WithIStreamAction action)
        {
            // Re-entrancy check
            // We could have re-entrancy while loading/saving the settings because of CLR/COM pumping messages
            // while pinvoking and marshalling interface pointers.
            // If we are already in the process of saving/loading, then we can't do this action.
            // There is no user bad of skipping this in case of re-entrancy for the following reasons:
            //  - If this is a Load and the one before is a Save, then we can skip this since we haven't finished saving to load anything.
            //  - And vice-versa.
            if (_ribbonSettingsLoadSaveActive)
            {
                return;
            }

            try
            {
                // Flag this to prevent us from shooting ourselves on the foot in case of re-entrancy
                _ribbonSettingsLoadSaveActive = true;

                string ribbonFile = Path.Combine(ApplicationEnvironment.ApplicationDataDirectory, "Ribbon.dat");
                FileInfo fileInfo = new FileInfo(ribbonFile);
                if (onlyIfChanged && ribbonSettingsTimestamp != null && fileInfo.LastWriteTimeUtc == ribbonSettingsTimestamp)
                {
                    // We're up-to-date, skip the action
                    return;
                }

                IStream stream = CreateRibbonIStream(ribbonFile, writable, create);
                if (stream == null)
                    return;
                try
                {
                    int hr = action(stream);
                    if (hr != HRESULT.S_OK)
                        Trace.Fail("Ribbon state load/save operation failed: 0x" + hr.ToString("X8", CultureInfo.InvariantCulture));
                }
                catch (Exception)
                {
                    Trace.Fail("WithIStreamAction failed.");
                    throw;
                }
                finally
                {
                    Marshal.ReleaseComObject(stream);
                }

                // on successful completion, save the time
                fileInfo.Refresh();
                ribbonSettingsTimestamp = fileInfo.LastWriteTimeUtc;
            }
            catch (Exception)
            {
                Trace.Fail("Ribbon settings failure.  Check the ribbon.dat file.");
                throw;
            }
            finally
            {
                _ribbonSettingsLoadSaveActive = false;
            }
        }

        private static IStream CreateRibbonIStream(string filename, bool writable, bool create)
        {
            try
            {
                Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "Creating a {0} ribbon istream for {1}", writable ? "writable" : "readable", filename));
                STGM mode = writable ? STGM.WRITE : STGM.READ;
                if (create)
                    mode |= STGM.CREATE;
                const int FILE_ATTRIBUTE_NORMAL = 0x00000080;
                IStream stream;
                int hr = Shlwapi.SHCreateStreamOnFileEx(filename, (int)mode, FILE_ATTRIBUTE_NORMAL, create, IntPtr.Zero, out stream);
                if (hr != HRESULT.S_OK)
                {
                    Trace.WriteLine("Failed to create ribbon stream for " + filename + ": hr = " + hr.ToString("X8", CultureInfo.InvariantCulture));
                    return null;
                }

                return stream;
            }
            catch (Exception e)
            {
                Trace.Fail(e.ToString());
                return null;
            }
        }

        public int OnCreateUICommand(uint commandId, CommandTypeID typeID, out IUICommandHandler commandHandler)
        {
            commandHandler = _htmlEditor.CommandManager;
            return HRESULT.S_OK;
        }

        public int OnDestroyUICommand(uint commandId, CommandTypeID typeID, IUICommandHandler commandHandler)
        {
            return HRESULT.E_NOTIMPL;
        }

        #region Implementation of ISessionHandler

        public void OnEndSession()
        {
            _autoSaveTimer_Tick(null, EventArgs.Empty);
        }

        #endregion
    }
}


text:
import { includes, reduce, some } from "lodash";

// TODO: Revisit this implementation when migrating widget component to React

const WIDGET_SELECTOR = '[data-widgetid="{0}"]';
const WIDGET_CONTENT_SELECTOR = [
  ".widget-header", // header
  ".visualization-renderer", // visualization
  ".scrollbox .alert", // error state
  ".spinner-container", // loading state
  ".tile__bottom-control", // footer
].join(",");
const INTERVAL = 200;

export default class AutoHeightController {
  widgets = {};

  interval = null;

  onHeightChange = null;

  constructor(handler) {
    this.onHeightChange = handler;
  }

  update(widgets) {
    const newWidgetIds = widgets
      .filter(widget => widget.options.position.autoHeight)
      .map(widget => widget.id.toString());

    // added
    newWidgetIds.filter(id => !includes(Object.keys(this.widgets), id)).forEach(this.add);

    // removed
    Object.keys(this.widgets)
      .filter(id => !includes(newWidgetIds, id))
      .forEach(this.remove);
  }

  add = id => {
    if (this.isEmpty()) {
      this.start();
    }

    const selector = WIDGET_SELECTOR.replace("{0}", id);
    this.widgets[id] = [
      function getHeight() {
        const widgetEl = document.querySelector(selector);
        if (!widgetEl) {
          return undefined; // safety
        }

        // get all content elements
        const els = widgetEl.querySelectorAll(WIDGET_CONTENT_SELECTOR);

        // calculate accumulated height
        return reduce(
          els,
          (acc, el) => {
            const height = el ? el.getBoundingClientRect().height : 0;
            return acc + height;
          },
          0
        );
      },
    ];
  };

  remove = id => {
    // ignore if not an active autoHeight widget
    if (!this.exists(id)) {
      return;
    }

    // not actually deleting from this.widgets to prevent case of unwanted re-adding
    this.widgets[id.toString()] = false;

    if (this.isEmpty()) {
      this.stop();
    }
  };

  exists = id => !!this.widgets[id.toString()];

  isEmpty = () => !some(this.widgets);

  checkHeightChanges = () => {
    Object.keys(this.widgets)
      .filter(this.exists) // reject already removed items
      .forEach(id => {
        const [getHeight, prevHeight] = this.widgets[id];
        const height = getHeight();
        if (height && height !== prevHeight) {
          this.widgets[id][1] = height; // save
          this.onHeightChange(id, height); // dispatch
        }
      });
  };

  start = () => {
    this.stop();
    this.interval = setInterval(this.checkHeightChanges, INTERVAL);
  };

  stop = () => {
    clearInterval(this.interval);
  };

  resume = () => {
    if (!this.isEmpty()) {
      this.start();
    }
  };

  destroy = () => {
    this.stop();
    this.widgets = null;
  };
}