text:
using Google.Protobuf.Collections;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;

namespace Google.Protobuf
{
    /// <summary>
    /// Reads and decodes protocol message fields.
    /// </summary>
    /// <remarks>
    /// <para>
    /// This class is generally used by generated code to read appropriate
    /// primitives from the stream. It effectively encapsulates the lowest
    /// levels of protocol buffer format.
    /// </para>
    /// <para>
    /// Repeated fields and map fields are not handled by this class; use <see cref="RepeatedField{T}"/>
    /// and <see cref="MapField{TKey, TValue}"/> to serialize such fields.
    /// </para>
    /// </remarks>
    [SecuritySafeCritical]
    public sealed class CodedInputStream : IDisposable
    {
        /// <summary>
        /// Whether to leave the underlying stream open when disposing of this stream.
        /// This is always true when there's no stream.
        /// </summary>
        private readonly bool leaveOpen;

        /// <summary>
        /// Buffer of data read from the stream or provided at construction time.
        /// </summary>
        private readonly byte[] buffer;

        /// <summary>
        /// The stream to read further input from, or null if the byte array buffer was provided
        /// directly on construction, with no further data available.
        /// </summary>
        private readonly Stream input;

        /// <summary>
        /// The parser state is kept separately so that other parse implementations can reuse the same
        /// parsing primitives.
        /// </summary>
        private ParserInternalState state;

        internal const int DefaultRecursionLimit = 100;
        internal const int DefaultSizeLimit = Int32.MaxValue;
        internal const int BufferSize = 4096;

        #region Construction
        // Note that the checks are performed such that we don't end up checking obviously-valid things
        // like non-null references for arrays we've just created.

        /// <summary>
        /// Creates a new CodedInputStream reading data from the given byte array.
        /// </summary>
        public CodedInputStream(byte[] buffer) : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length, true)
        {
        }

        /// <summary>
        /// Creates a new <see cref="CodedInputStream"/> that reads from the given byte array slice.
        /// </summary>
        public CodedInputStream(byte[] buffer, int offset, int length)
            : this(null, ProtoPreconditions.CheckNotNull(buffer, "buffer"), offset, offset + length, true)
        {
            if (offset < 0 || offset > buffer.Length)
            {
                throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");
            }
            if (length < 0 || offset + length > buffer.Length)
            {
                throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");
            }
        }

        /// <summary>
        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream, which will be disposed
        /// when the returned object is disposed.
        /// </summary>
        /// <param name="input">The stream to read from.</param>
        public CodedInputStream(Stream input) : this(input, false)
        {
        }

        /// <summary>
        /// Creates a new <see cref="CodedInputStream"/> reading data from the given stream.
        /// </summary>
        /// <param name="input">The stream to read from.</param>
        /// <param name="leaveOpen"><c>true</c> to leave <paramref name="input"/> open when the returned
        /// <c cref="CodedInputStream"/> is disposed; <c>false</c> to dispose of the given stream when the
        /// returned object is disposed.</param>
        public CodedInputStream(Stream input, bool leaveOpen)
            : this(ProtoPreconditions.CheckNotNull(input, "input"), new byte[BufferSize], 0, 0, leaveOpen)
        {
        }

        /// <summary>
        /// Creates a new CodedInputStream reading data from the given
        /// stream and buffer, using the default limits.
        /// </summary>
        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, bool leaveOpen)
        {
            this.input = input;
            this.buffer = buffer;
            this.state.bufferPos = bufferPos;
            this.state.bufferSize = bufferSize;
            this.state.sizeLimit = DefaultSizeLimit;
            this.state.recursionLimit = DefaultRecursionLimit;
            SegmentedBufferHelper.Initialize(this, out this.state.segmentedBufferHelper);
            this.leaveOpen = leaveOpen;

            this.state.currentLimit = int.MaxValue;
        }

        /// <summary>
        /// Creates a new CodedInputStream reading data from the given
        /// stream and buffer, using the specified limits.
        /// </summary>
        /// <remarks>
        /// This chains to the version with the default limits instead of vice versa to avoid
        /// having to check that the default values are valid every time.
        /// </remarks>
        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit, bool leaveOpen)
            : this(input, buffer, bufferPos, bufferSize, leaveOpen)
        {
            if (sizeLimit <= 0)
            {
                throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");
            }
            if (recursionLimit <= 0)
            {
                throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");
            }
            this.state.sizeLimit = sizeLimit;
            this.state.recursionLimit = recursionLimit;
        }
        #endregion

        /// <summary>
        /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading
        /// from an input stream.
        /// </summary>
        /// <remarks>
        /// This method exists separately from the constructor to reduce the number of constructor overloads.
        /// It is likely to be used considerably less frequently than the constructors, as the default limits
        /// are suitable for most use cases.
        /// </remarks>
        /// <param name="input">The input stream to read from</param>
        /// <param name="sizeLimit">The total limit of data to read from the stream.</param>
        /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>
        /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size
        /// and recursion limits.</returns>
        public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)
        {
            // Note: we may want an overload accepting leaveOpen
            return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit, false);
        }

        /// <summary>
        /// Returns the current position in the input stream, or the position in the input buffer
        /// </summary>
        public long Position
        {
            get
            {
                if (input != null)
                {
                    return input.Position - ((state.bufferSize + state.bufferSizeAfterLimit) - state.bufferPos);
                }
                return state.bufferPos;
            }
        }

        /// <summary>
        /// Returns the last tag read, or 0 if no tags have been read or we've read beyond
        /// the end of the stream.
        /// </summary>
        internal uint LastTag { get { return state.lastTag; } }

        /// <summary>
        /// Returns the size limit for this stream.
        /// </summary>
        /// <remarks>
        /// This limit is applied when reading from the underlying stream, as a sanity check. It is
        /// not applied when reading from a byte array data source without an underlying stream.
        /// The default value is Int32.MaxValue.
        /// </remarks>
        /// <value>
        /// The size limit.
        /// </value>
        public int SizeLimit { get { return state.sizeLimit; } }

        /// <summary>
        /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,
        /// to avoid maliciously-recursive data.
        /// </summary>
        /// <remarks>
        /// The default limit is 100.
        /// </remarks>
        /// <value>
        /// The recursion limit for this stream.
        /// </value>
        public int RecursionLimit { get { return state.recursionLimit; } }

        /// <summary>
        /// Internal-only property; when set to true, unknown fields will be discarded while parsing.
        /// </summary>
        internal bool DiscardUnknownFields
        {
            get { return state.DiscardUnknownFields; }
            set { state.DiscardUnknownFields = value; }
        }

        /// <summary>
        /// Internal-only property; provides extension identifiers to compatible messages while parsing.
        /// </summary>
        internal ExtensionRegistry ExtensionRegistry
        {
            get { return state.ExtensionRegistry; }
            set { state.ExtensionRegistry = value; }
        }

        internal byte[] InternalBuffer => buffer;

        internal Stream InternalInputStream => input;

        internal ref ParserInternalState InternalState => ref state;

        /// <summary>
        /// Disposes of this instance, potentially closing any underlying stream.
        /// </summary>
        /// <remarks>
        /// As there is no flushing to perform here, disposing of a <see cref="CodedInputStream"/> which
        /// was constructed with the <c>leaveOpen</c> option parameter set to <c>true</c> (or one which
        /// was constructed to read from a byte array) has no effect.
        /// </remarks>
        public void Dispose()
        {
            if (!leaveOpen)
            {
                input.Dispose();
            }
        }

        #region Validation
        /// <summary>
        /// Verifies that the last call to ReadTag() returned tag 0 - in other words,
        /// we've reached the end of the stream when we expected to.
        /// </summary>
        /// <exception cref="InvalidProtocolBufferException">The
        /// tag read was not the one specified</exception>
        internal void CheckReadEndOfStreamTag()
        {
            ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref state);
        }
        #endregion

        #region Reading of tags etc

        /// <summary>
        /// Peeks at the next field tag. This is like calling <see cref="ReadTag"/>, but the
        /// tag is not consumed. (So a subsequent call to <see cref="ReadTag"/> will return the
        /// same value.)
        /// </summary>
        public uint PeekTag()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.PeekTag(ref span, ref state);
        }

        /// <summary>
        /// Reads a field tag, returning the tag of 0 for "end of stream".
        /// </summary>
        /// <remarks>
        /// If this method returns 0, it doesn't necessarily mean the end of all
        /// the data in this CodedInputStream; it may be the end of the logical stream
        /// for an embedded message, for example.
        /// </remarks>
        /// <returns>The next field tag, or 0 for end of stream. (0 is never a valid tag.)</returns>
        public uint ReadTag()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ParseTag(ref span, ref state);
        }

        /// <summary>
        /// Skips the data for the field with the tag we've just read.
        /// This should be called directly after <see cref="ReadTag"/>, when
        /// the caller wishes to skip an unknown field.
        /// </summary>
        /// <remarks>
        /// This method throws <see cref="InvalidProtocolBufferException"/> if the last-read tag was an end-group tag.
        /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the
        /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly
        /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.
        /// </remarks>
        /// <exception cref="InvalidProtocolBufferException">The last tag was an end-group tag</exception>
        /// <exception cref="InvalidOperationException">The last read operation read to the end of the logical stream</exception>
        public void SkipLastField()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            ParsingPrimitivesMessages.SkipLastField(ref span, ref state);
        }

        /// <summary>
        /// Skip a group.
        /// </summary>
        internal void SkipGroup(uint startGroupTag)
        {
            var span = new ReadOnlySpan<byte>(buffer);
            ParsingPrimitivesMessages.SkipGroup(ref span, ref state, startGroupTag);
        }

        /// <summary>
        /// Reads a double field from the stream.
        /// </summary>
        public double ReadDouble()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ParseDouble(ref span, ref state);
        }

        /// <summary>
        /// Reads a float field from the stream.
        /// </summary>
        public float ReadFloat()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ParseFloat(ref span, ref state);
        }

        /// <summary>
        /// Reads a uint64 field from the stream.
        /// </summary>
        public ulong ReadUInt64()
        {
            return ReadRawVarint64();
        }

        /// <summary>
        /// Reads an int64 field from the stream.
        /// </summary>
        public long ReadInt64()
        {
            return (long) ReadRawVarint64();
        }

        /// <summary>
        /// Reads an int32 field from the stream.
        /// </summary>
        public int ReadInt32()
        {
            return (int) ReadRawVarint32();
        }

        /// <summary>
        /// Reads a fixed64 field from the stream.
        /// </summary>
        public ulong ReadFixed64()
        {
            return ReadRawLittleEndian64();
        }

        /// <summary>
        /// Reads a fixed32 field from the stream.
        /// </summary>
        public uint ReadFixed32()
        {
            return ReadRawLittleEndian32();
        }

        /// <summary>
        /// Reads a bool field from the stream.
        /// </summary>
        public bool ReadBool()
        {
            return ReadRawVarint64() != 0;
        }

        /// <summary>
        /// Reads a string field from the stream.
        /// </summary>
        public string ReadString()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ReadString(ref span, ref state);
        }

        /// <summary>
        /// Reads an embedded message field value from the stream.
        /// </summary>
        public void ReadMessage(IMessage builder)
        {
            // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalMergeFrom method),
            // what we're doing here works fine, but could be more efficient.
            // What happends is that we first initialize a ParseContext from the current coded input stream only to parse the length of the message, at which point
            // we will need to switch back again to CodedInputStream-based parsing (which involves copying and storing the state) to be able to
            // invoke the legacy MergeFrom(CodedInputStream) method.
            // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it).
            var span = new ReadOnlySpan<byte>(buffer);
            ParseContext.Initialize(ref span, ref state, out ParseContext ctx);
            try
            {
                ParsingPrimitivesMessages.ReadMessage(ref ctx, builder);
            }
            finally
            {
                ctx.CopyStateTo(this);
            }
        }

        /// <summary>
        /// Reads an embedded group field from the stream.
        /// </summary>
        public void ReadGroup(IMessage builder)
        {
            ParseContext.Initialize(this, out ParseContext ctx);
            try
            {
                ParsingPrimitivesMessages.ReadGroup(ref ctx, builder);
            }
            finally
            {
                ctx.CopyStateTo(this);
            }
        }

        /// <summary>
        /// Reads a bytes field value from the stream.
        /// </summary>
        public ByteString ReadBytes()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ReadBytes(ref span, ref state);
        }

        /// <summary>
        /// Reads a uint32 field value from the stream.
        /// </summary>
        public uint ReadUInt32()
        {
            return ReadRawVarint32();
        }

        /// <summary>
        /// Reads an enum field value from the stream.
        /// </summary>
        public int ReadEnum()
        {
            // Currently just a pass-through, but it's nice to separate it logically from WriteInt32.
            return (int) ReadRawVarint32();
        }

        /// <summary>
        /// Reads an sfixed32 field value from the stream.
        /// </summary>
        public int ReadSFixed32()
        {
            return (int) ReadRawLittleEndian32();
        }

        /// <summary>
        /// Reads an sfixed64 field value from the stream.
        /// </summary>
        public long ReadSFixed64()
        {
            return (long) ReadRawLittleEndian64();
        }

        /// <summary>
        /// Reads an sint32 field value from the stream.
        /// </summary>
        public int ReadSInt32()
        {
            return ParsingPrimitives.DecodeZigZag32(ReadRawVarint32());
        }

        /// <summary>
        /// Reads an sint64 field value from the stream.
        /// </summary>
        public long ReadSInt64()
        {
            return ParsingPrimitives.DecodeZigZag64(ReadRawVarint64());
        }

        /// <summary>
        /// Reads a length for length-delimited data.
        /// </summary>
        /// <remarks>
        /// This is internally just reading a varint, but this method exists
        /// to make the calling code clearer.
        /// </remarks>
        public int ReadLength()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ParseLength(ref span, ref state);
        }

        /// <summary>
        /// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
        /// the tag is consumed and the method returns <c>true</c>; otherwise, the
        /// stream is left in the original position and the method returns <c>false</c>.
        /// </summary>
        public bool MaybeConsumeTag(uint tag)
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.MaybeConsumeTag(ref span, ref state, tag);
        }

#endregion

        #region Underlying reading primitives

        /// <summary>
        /// Reads a raw Varint from the stream.  If larger than 32 bits, discard the upper bits.
        /// This method is optimised for the case where we've got lots of data in the buffer.
        /// That means we can check the size just once, then just read directly from the buffer
        /// without constant rechecking of the buffer length.
        /// </summary>
        internal uint ReadRawVarint32()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ParseRawVarint32(ref span, ref state);
        }

        /// <summary>
        /// Reads a varint from the input one byte at a time, so that it does not
        /// read any bytes after the end of the varint. If you simply wrapped the
        /// stream in a CodedInputStream and used ReadRawVarint32(Stream)
        /// then you would probably end up reading past the end of the varint since
        /// CodedInputStream buffers its input.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        internal static uint ReadRawVarint32(Stream input)
        {
            return ParsingPrimitives.ReadRawVarint32(input);
        }

        /// <summary>
        /// Reads a raw varint from the stream.
        /// </summary>
        internal ulong ReadRawVarint64()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ParseRawVarint64(ref span, ref state);
        }

        /// <summary>
        /// Reads a 32-bit little-endian integer from the stream.
        /// </summary>
        internal uint ReadRawLittleEndian32()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ParseRawLittleEndian32(ref span, ref state);
        }

        /// <summary>
        /// Reads a 64-bit little-endian integer from the stream.
        /// </summary>
        internal ulong ReadRawLittleEndian64()
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ParseRawLittleEndian64(ref span, ref state);
        }
        #endregion

        #region Internal reading and buffer management

        /// <summary>
        /// Sets currentLimit to (current position) + byteLimit. This is called
        /// when descending into a length-delimited embedded message. The previous
        /// limit is returned.
        /// </summary>
        /// <returns>The old limit.</returns>
        internal int PushLimit(int byteLimit)
        {
            return SegmentedBufferHelper.PushLimit(ref state, byteLimit);
        }

        /// <summary>
        /// Discards the current limit, returning the previous limit.
        /// </summary>
        internal void PopLimit(int oldLimit)
        {
            SegmentedBufferHelper.PopLimit(ref state, oldLimit);
        }

        /// <summary>
        /// Returns whether or not all the data before the limit has been read.
        /// </summary>
        /// <returns></returns>
        internal bool ReachedLimit
        {
            get
            {
                return SegmentedBufferHelper.IsReachedLimit(ref state);
            }
        }

        /// <summary>
        /// Returns true if the stream has reached the end of the input. This is the
        /// case if either the end of the underlying input source has been reached or
        /// the stream has reached a limit created using PushLimit.
        /// </summary>
        public bool IsAtEnd
        {
            get
            {
                var span = new ReadOnlySpan<byte>(buffer);
                return SegmentedBufferHelper.IsAtEnd(ref span, ref state);
            }
        }

        /// <summary>
        /// Called when buffer is empty to read more bytes from the
        /// input.  If <paramref name="mustSucceed"/> is true, RefillBuffer() guarantees that
        /// either there will be at least one byte in the buffer when it returns
        /// or it will throw an exception.  If <paramref name="mustSucceed"/> is false,
        /// RefillBuffer() returns false if no more bytes were available.
        /// </summary>
        /// <param name="mustSucceed"></param>
        /// <returns></returns>
        private bool RefillBuffer(bool mustSucceed)
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return state.segmentedBufferHelper.RefillBuffer(ref span, ref state, mustSucceed);
        }

        /// <summary>
        /// Reads a fixed size of bytes from the input.
        /// </summary>
        /// <exception cref="InvalidProtocolBufferException">
        /// the end of the stream or the current limit was reached
        /// </exception>
        internal byte[] ReadRawBytes(int size)
        {
            var span = new ReadOnlySpan<byte>(buffer);
            return ParsingPrimitives.ReadRawBytes(ref span, ref state, size);
        }

        /// <summary>
        /// Reads a top-level message or a nested message after the limits for this message have been pushed.
        /// (parser will proceed until the end of the current limit)
        /// NOTE: this method needs to be public because it's invoked by the generated code - e.g. msg.MergeFrom(CodedInputStream input) method
        /// </summary>
        public void ReadRawMessage(IMessage message)
        {
            ParseContext.Initialize(this, out ParseContext ctx);
            try
            {
                ParsingPrimitivesMessages.ReadRawMessage(ref ctx, message);
            }
            finally
            {
                ctx.CopyStateTo(this);
            }
        }
#endregion
    }
}


text:
<?php use_helper('opAlbum') ?>

<?php if (count($albumList)): ?>
<div id="homeRecentList_<?php echo $gadget->getId() ?>" class="dparts homeRecentList">

<?php echo __('Recently Posted Albums of All') ?>

<?php foreach ($albumList as $album): ?>

<?php echo op_format_date($album->getCreatedAt(), 'XShortDateJa') ?><?php echo link_to($album->title, 'album_show', $album) ?> (<?php echo $album->getMember()->getName() ?>)

<?php endforeach; ?>

<?php echo link_to(__('More'), 'album_list') ?>

<?php endif; ?>

redpajama_set_name: RedPajamaGithub


text:
package org.onecmdb.service;

import org.onecmdb.dto.CiDTO;
import org.onecmdb.dto.ListFilter;
import org.onecmdb.dto.Path;

import java.util.List;

/**
 * 模型服务
 * Created by tom on 2017/8/10.
 */
public interface ModelService {
    /**
     *
     * @return
     */
    CiDTO getRoot();

    List<CiDTO> list(String alias, ListFilter listFilter);

    /**
     * 根据 id 获取Ci 对象
     * @param id
     * @return
     */
    CiDTO getCiById(Long id, boolean isRef);

    CiDTO getCiByPath(Path<String> path);
}


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Curr. Sci. 49(13): 523 (1980)

#### Original name
Mycosphaerella ruscicola A. Pande

### Remarks
null


text:
package de.ahus1.bdd.calculator.common;

import com.tngtech.jgiven.annotation.TagDescriptionGenerator;
import com.tngtech.jgiven.config.TagConfiguration;

import java.lang.annotation.Annotation;

public class StoryDescriptionGenerator implements TagDescriptionGenerator {
    @Override
    public String generateDescription(TagConfiguration tagConfiguration,
                                      Annotation annotation, Object value) {
        return String.format("Story: %s", value, value);
    }
}


text:
/*
    This file is part of the WebKit open source project.
    This file has been generated by generate-bindings.pl. DO NOT MODIFY!

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include "config.h"
#include "V8HTMLMeterElement.h"

#if ENABLE(METER_TAG)

#include "ExceptionCode.h"
#include "RuntimeEnabledFeatures.h"
#include "V8Binding.h"
#include "V8BindingMacros.h"
#include "V8BindingState.h"
#include "V8DOMWrapper.h"
#include "V8HTMLElement.h"
#include "V8HTMLFormElement.h"
#include "V8IsolatedContext.h"
#include "V8NodeList.h"
#include "V8Proxy.h"
#include <wtf/GetPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
#include <wtf/UnusedParam.h>

namespace WebCore {

WrapperTypeInfo V8HTMLMeterElement::info = { V8HTMLMeterElement::GetTemplate, V8HTMLMeterElement::derefObject, 0, &V8HTMLElement::info };

namespace HTMLMeterElementInternal {

template <typename T> void V8_USE(T) { }

static v8::Handle<v8::Value> valueAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.value._get");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    return v8::Number::New(imp->value());
}

static void valueAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.value._set");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    double v = static_cast<double>(value->NumberValue());
    ExceptionCode ec = 0;
    imp->setValue(v, ec);
    if (UNLIKELY(ec))
        V8Proxy::setDOMException(ec);
    return;
}

static v8::Handle<v8::Value> minAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.min._get");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    return v8::Number::New(imp->min());
}

static void minAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.min._set");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    double v = static_cast<double>(value->NumberValue());
    ExceptionCode ec = 0;
    imp->setMin(v, ec);
    if (UNLIKELY(ec))
        V8Proxy::setDOMException(ec);
    return;
}

static v8::Handle<v8::Value> maxAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.max._get");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    return v8::Number::New(imp->max());
}

static void maxAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.max._set");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    double v = static_cast<double>(value->NumberValue());
    ExceptionCode ec = 0;
    imp->setMax(v, ec);
    if (UNLIKELY(ec))
        V8Proxy::setDOMException(ec);
    return;
}

static v8::Handle<v8::Value> lowAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.low._get");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    return v8::Number::New(imp->low());
}

static void lowAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.low._set");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    double v = static_cast<double>(value->NumberValue());
    ExceptionCode ec = 0;
    imp->setLow(v, ec);
    if (UNLIKELY(ec))
        V8Proxy::setDOMException(ec);
    return;
}

static v8::Handle<v8::Value> highAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.high._get");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    return v8::Number::New(imp->high());
}

static void highAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.high._set");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    double v = static_cast<double>(value->NumberValue());
    ExceptionCode ec = 0;
    imp->setHigh(v, ec);
    if (UNLIKELY(ec))
        V8Proxy::setDOMException(ec);
    return;
}

static v8::Handle<v8::Value> optimumAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.optimum._get");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    return v8::Number::New(imp->optimum());
}

static void optimumAttrSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.optimum._set");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    double v = static_cast<double>(value->NumberValue());
    ExceptionCode ec = 0;
    imp->setOptimum(v, ec);
    if (UNLIKELY(ec))
        V8Proxy::setDOMException(ec);
    return;
}

static v8::Handle<v8::Value> formAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.form._get");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    return toV8(imp->form());
}

static v8::Handle<v8::Value> labelsAttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
    INC_STATS("DOM.HTMLMeterElement.labels._get");
    HTMLMeterElement* imp = V8HTMLMeterElement::toNative(info.Holder());
    return toV8(imp->labels());
}

} // namespace HTMLMeterElementInternal

static const BatchedAttribute HTMLMeterElementAttrs[] = {
    // Attribute 'value' (Type: 'attribute' ExtAttr: '')
    {"value", HTMLMeterElementInternal::valueAttrGetter, HTMLMeterElementInternal::valueAttrSetter, 0 /* no data */, static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None), 0 /* on instance */},
    // Attribute 'min' (Type: 'attribute' ExtAttr: '')
    {"min", HTMLMeterElementInternal::minAttrGetter, HTMLMeterElementInternal::minAttrSetter, 0 /* no data */, static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None), 0 /* on instance */},
    // Attribute 'max' (Type: 'attribute' ExtAttr: '')
    {"max", HTMLMeterElementInternal::maxAttrGetter, HTMLMeterElementInternal::maxAttrSetter, 0 /* no data */, static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None), 0 /* on instance */},
    // Attribute 'low' (Type: 'attribute' ExtAttr: '')
    {"low", HTMLMeterElementInternal::lowAttrGetter, HTMLMeterElementInternal::lowAttrSetter, 0 /* no data */, static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None), 0 /* on instance */},
    // Attribute 'high' (Type: 'attribute' ExtAttr: '')
    {"high", HTMLMeterElementInternal::highAttrGetter, HTMLMeterElementInternal::highAttrSetter, 0 /* no data */, static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None), 0 /* on instance */},
    // Attribute 'optimum' (Type: 'attribute' ExtAttr: '')
    {"optimum", HTMLMeterElementInternal::optimumAttrGetter, HTMLMeterElementInternal::optimumAttrSetter, 0 /* no data */, static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None), 0 /* on instance */},
    // Attribute 'form' (Type: 'readonly attribute' ExtAttr: '')
    {"form", HTMLMeterElementInternal::formAttrGetter, 0, 0 /* no data */, static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None), 0 /* on instance */},
    // Attribute 'labels' (Type: 'readonly attribute' ExtAttr: '')
    {"labels", HTMLMeterElementInternal::labelsAttrGetter, 0, 0 /* no data */, static_cast<v8::AccessControl>(v8::DEFAULT), static_cast<v8::PropertyAttribute>(v8::None), 0 /* on instance */},
};

static v8::Persistent<v8::FunctionTemplate> ConfigureV8HTMLMeterElementTemplate(v8::Persistent<v8::FunctionTemplate> desc)
{
    desc->ReadOnlyPrototype();

    v8::Local<v8::Signature> defaultSignature = configureTemplate(desc, "HTMLMeterElement", V8HTMLElement::GetTemplate(), V8HTMLMeterElement::internalFieldCount,
        HTMLMeterElementAttrs, WTF_ARRAY_LENGTH(HTMLMeterElementAttrs),
        0, 0);
    UNUSED_PARAM(defaultSignature); // In some cases, it will not be used.

    // Custom toString template
    desc->Set(getToStringName(), getToStringTemplate());
    return desc;
}

v8::Persistent<v8::FunctionTemplate> V8HTMLMeterElement::GetRawTemplate()
{
    V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
    V8BindingPerIsolateData::TemplateMap::iterator result = data->rawTemplateMap().find(&info);
    if (result != data->rawTemplateMap().end())
        return result->second;

    v8::HandleScope handleScope;
    v8::Persistent<v8::FunctionTemplate> templ = createRawTemplate();
    data->rawTemplateMap().add(&info, templ);
    return templ;
}

v8::Persistent<v8::FunctionTemplate> V8HTMLMeterElement::GetTemplate()
{
    V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
    V8BindingPerIsolateData::TemplateMap::iterator result = data->templateMap().find(&info);
    if (result != data->templateMap().end())
        return result->second;

    v8::HandleScope handleScope;
    v8::Persistent<v8::FunctionTemplate> templ =
        ConfigureV8HTMLMeterElementTemplate(GetRawTemplate());
    data->templateMap().add(&info, templ);
    return templ;
}

bool V8HTMLMeterElement::HasInstance(v8::Handle<v8::Value> value)
{
    return GetRawTemplate()->HasInstance(value);
}

v8::Handle<v8::Object> V8HTMLMeterElement::wrapSlow(HTMLMeterElement* impl)
{
    v8::Handle<v8::Object> wrapper;
    V8Proxy* proxy = 0;
    if (impl->document()) {
        proxy = V8Proxy::retrieve(impl->document()->frame());
        if (proxy && static_cast<Node*>(impl->document()) == static_cast<Node*>(impl)) {
            if (proxy->windowShell()->initContextIfNeeded()) {
                // initContextIfNeeded may have created a wrapper for the object, retry from the start.
                return V8HTMLMeterElement::wrap(impl);
            }
        }
    }

    v8::Handle<v8::Context> context;
    if (proxy)
        context = proxy->context();

    // Enter the node's context and create the wrapper in that context.
    if (!context.IsEmpty())
        context->Enter();
    wrapper = V8DOMWrapper::instantiateV8Object(proxy, &info, impl);
    // Exit the node's context if it was entered.
    if (!context.IsEmpty())
        context->Exit();
    if (wrapper.IsEmpty())
        return wrapper;

    impl->ref();
    v8::Persistent<v8::Object> wrapperHandle = v8::Persistent<v8::Object>::New(wrapper);

    if (!hasDependentLifetime)
        wrapperHandle.MarkIndependent();
    wrapperHandle.SetWrapperClassId(v8DOMSubtreeClassId);
    getDOMNodeMap().set(impl, wrapperHandle);
    return wrapper;
}

void V8HTMLMeterElement::derefObject(void* object)
{
    static_cast<HTMLMeterElement*>(object)->deref();
}

} // namespace WebCore

#endif // ENABLE(METER_TAG)


text:
Hola, {{htmlescape var=$order.getCustomerName()}}

                        Gracias por comprar en {{var store.getFrontendName()}}.
                        Puede comprobar el estado de su pedido al iniciar sesión en su cuenta.
                        Si tiene alguna duda respecto a su pedido, no deje de ponerse en contacto con nosotros en {{config path='trans_email/ident_support/email'}} o llámenos al {{config path='general/store_information/phone'}} de lunes a viernes,  de 8 a. m. a 5 p. m., hora estándar del Pacífico.

Su recordatorio de crédito #{{var creditmemo.increment_id}} para el pedido #{{var order.increment_id}}

                            Información de facturación:

                            Método de pago:

                                {{var order.billing_address.format('html')}}

                                {{var payment_html}}

                    {{depend order.getIsNotVirtual()}}

                            Información de envío:

                            Método de envío:

                                {{var order.shipping_address.format('html')}}

                                {{var order.shipping_description}}

                    {{/depend}}
                    {{layout handle="sales_email_order_creditmemo_items" creditmemo=$creditmemo order=$order}}

{{var comment}}

Gracias, {{var store.getFrontendName()}}


text:
import * as m from "mithril";
import * as Stream from "mithril/stream";
import {Notification, SystemNotifications} from "models/notifications/system_notifications";
import {SystemNotificationsWidget} from "views/components/notification_center/system_notifications_widget";

describe("SystemNotificationsWidget", () => {
  const simulateEvent = require("simulate-event");

  require("jasmine-jquery");
  require("jasmine-ajax");

  let $root: any, root: any;
  beforeEach(() => {
    //@ts-ignore
    [$root, root] = window.createDomElementForTest();
  });
  //@ts-ignore
  afterEach(window.destroyDomElementForTest);

  const systemNotifications = Stream(new SystemNotifications());

  beforeEach(() => {
    m.mount(root, {
      view() {
        return (<SystemNotificationsWidget systemNotifications={systemNotifications}/>);
      }
    });
    m.redraw();
  });

  beforeEach(() => {
    localStorage.clear();
    localStorage.setItem("system_notifications", JSON.stringify([]));
  });

  afterEach(() => {
    m.mount(root, null);
    m.redraw();
  });

  it("should not display notification bell when there are no notifications to display", () => {
    systemNotifications(SystemNotifications.fromJSON([]));
    m.redraw();
    expect($root.find(".notifications").get(0)).not.toBeInDOM();
  });

  it("should display notification bell and the notifications", () => {
    const notifications = [
      {
        id: "id1",
        message: "message 1.",
        read: false,
        type: "UpdateCheck",
        link: "link_1",
        linkText: "read more"
      },
      {
        id: "id2",
        message: "message 2.",
        read: false,
        type: "SomethingOfImportance",
        link: "link_2",
        linkText: "read more"
      }
    ] as Notification[];

    systemNotifications(SystemNotifications.fromJSON(notifications));
    m.redraw();
    const allNotifications = find("notification-item");
    expect(allNotifications.get(0)).toBeInDOM();
    expect(allNotifications.length).toBe(2);
    expect(allNotifications.eq(0)).toContainText("message 1. read more");
    expect(allNotifications.eq(0).find("a")).toContainText("read more");
    expect(allNotifications.eq(0).find(`[data-test-id='notification-item_close']`)).toContainText("X");
    expect(allNotifications.eq(1)).toContainText("message 2. read more");
    expect(allNotifications.eq(1).find("a")).toContainText("read more");
    expect(allNotifications.eq(1).find(`[data-test-id='notification-item_close']`)).toContainText("X");
  });

  it("should mark a notification as read and stop displaying it when user marks a notification as read", () => {
    const notifications = [
      {
        id: "id1",
        message: "message 1.",
        read: false,
        type: "UpdateCheck",
        link: "link_1",
        linkText: "read more"
      },
      {
        id: "id2",
        message: "message 2.",
        read: false,
        type: "SomethingOfImportance",
        link: "link_2",
        linkText: "read more"
      }
    ] as Notification[];

    systemNotifications(SystemNotifications.fromJSON(notifications));
    m.redraw();
    let allNotifications = find("notification-item");
    expect(allNotifications.length).toBe(2);
    simulateEvent.simulate(allNotifications.eq(0).find(`[data-test-id='notification-item_close']`).get(0), "click");
    m.redraw();

    allNotifications = find("notification-item");
    expect(allNotifications.length).toBe(1);
    expect(allNotifications.eq(0)).toContainText("message 2. read more");

    expect(systemNotifications().find((m: Notification) => {
      return m.id === "id1";
    })).toBeUndefined();

    const remainingNotification = systemNotifications().find((notification: Notification) => {
      return notification.id === "id2";
    }) as Notification;

    expect(remainingNotification).not.toBeUndefined();
    expect(remainingNotification.message).toBe("message 2.");
    expect(remainingNotification.read).toBe(false);
  });

  function find(id: string) {
    return $root.find(`[data-test-id='${id}']`);
  }
});


text:
package org.hisp.dhis.dxf2.datavalueset;

import org.amplecode.staxwax.reader.XMLReader;
import org.amplecode.staxwax.writer.XMLWriter;
import org.hisp.dhis.dxf2.datavalue.DataValue;
import org.hisp.dhis.dxf2.datavalue.StreamingDataValue;

/**
 * @author Lars Helge Overland
 */
public class StreamingDataValueSet
    extends DataValueSet
{
    private static final String XMLNS = "xmlns";
    private static final String NS = "http://dhis2.org/schema/dxf/2.0";
    private static final String TRUE = "true";

    private XMLWriter writer;

    private XMLReader reader;

    //--------------------------------------------------------------------------
    // Constructor
    //--------------------------------------------------------------------------

    public StreamingDataValueSet( XMLWriter writer )
    {
        this.writer = writer;

        this.writer.openDocument();
        this.writer.openElement( FIELD_DATAVALUESET );
        this.writer.writeAttribute( XMLNS, NS );
    }

    public StreamingDataValueSet( XMLReader reader )
    {
        this.reader = reader;
        this.reader.moveToStartElement( FIELD_DATAVALUESET );
    }

    //--------------------------------------------------------------------------
    // Getters
    //--------------------------------------------------------------------------

    @Override
    public String getIdScheme()
    {
        return idScheme = idScheme == null ? reader.getAttributeValue( FIELD_IDSCHEME ) : idScheme;
    }

    @Override
    public String getDataElementIdScheme()
    {
        return dataElementIdScheme = dataElementIdScheme == null ? reader.getAttributeValue( FIELD_DATAELEMENTIDSCHEME ) : dataElementIdScheme;
    }

    @Override
    public String getOrgUnitIdScheme()
    {
        return orgUnitIdScheme = orgUnitIdScheme == null ? reader.getAttributeValue( FIELD_ORGUNITIDSCHEME ) : orgUnitIdScheme;
    }

    @Override
    public Boolean getDryRun()
    {
        return dryRun = dryRun == null ? ( TRUE.equals( reader.getAttributeValue( FIELD_DRYRUN ) ) ? Boolean.TRUE : null ) : dryRun;
    }

    @Override
    public String getStrategy()
    {
        return strategy = strategy == null ? reader.getAttributeValue( FIELD_IMPORTSTRATEGY ) : strategy;
    }

    @Override
    public String getDataSet()
    {
        return dataSet = dataSet == null ? reader.getAttributeValue( FIELD_DATASET ) : dataSet;
    }

    @Override
    public String getCompleteDate()
    {
        return completeDate = completeDate == null ? reader.getAttributeValue( FIELD_COMPLETEDATE ) : completeDate;
    }

    @Override
    public String getPeriod()
    {
        return period = period == null ? reader.getAttributeValue( FIELD_PERIOD ) : period;
    }

    @Override
    public String getOrgUnit()
    {
        return orgUnit = orgUnit == null ? reader.getAttributeValue( FIELD_ORGUNIT ) : orgUnit;
    }

    @Override
    public String getAttributeOptionCombo()
    {
        return attributeOptionCombo = attributeOptionCombo == null ? reader.getAttributeValue( FIELD_ATTRIBUTE_OPTION_COMBO ) : attributeOptionCombo;
    }

    @Override
    public boolean hasNextDataValue()
    {
        return reader.moveToStartElement( FIELD_DATAVALUE, FIELD_DATAVALUESET );
    }

    @Override
    public DataValue getNextDataValue()
    {
        return new StreamingDataValue( reader );
    }

    //--------------------------------------------------------------------------
    // Setters
    //--------------------------------------------------------------------------

    @Override
    public void setIdScheme( String idScheme )
    {
        writer.writeAttribute( FIELD_IDSCHEME, idScheme );
    }

    @Override
    public void setDataElementIdScheme( String dataElementIdScheme )
    {
        writer.writeAttribute( FIELD_DATAELEMENTIDSCHEME, dataElementIdScheme );
    }

    @Override
    public void setOrgUnitIdScheme( String orgUnitIdScheme )
    {
        writer.writeAttribute( FIELD_ORGUNITIDSCHEME, orgUnitIdScheme );
    }

    @Override
    public void setDataSet( String dataSet )
    {
        writer.writeAttribute( FIELD_DATASET, dataSet );
    }

    @Override
    public void setCompleteDate( String completeDate )
    {
        writer.writeAttribute( FIELD_COMPLETEDATE, completeDate );
    }

    @Override
    public void setPeriod( String period )
    {
        writer.writeAttribute( FIELD_PERIOD, period );
    }

    @Override
    public void setOrgUnit( String orgUnit )
    {
        writer.writeAttribute( FIELD_ORGUNIT, orgUnit );
    }

    @Override
    public DataValue getDataValueInstance()
    {
        return new StreamingDataValue( writer );
    }

    @Override
    public void close()
    {
        if ( writer != null )
        {
            writer.closeElement();
            writer.closeDocument();
        }
    }
}


text:
using System;

namespace RowScatter.Common
{
    public class OutputHandlerAttribute : Attribute
    {
        public string Name { get; set; }
        public OutputHandlerAttribute(string name)
        {
            this.Name = name;
        }
    }
}


text:
using namespace FabricServices;
using namespace FabricUI;
using namespace FabricUI::DFG;

DFGNotificationRouter::DFGNotificationRouter(
  DFGController *dfgController,
  const DFGConfig & config
  )
  : m_dfgController( dfgController )
  , m_config( config )
  , m_performChecks( true )
{
  onExecChanged();
}

void DFGNotificationRouter::onExecChanged()
{
  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if ( exec )
    m_coreDFGView = exec.createView( &Callback, this );
  else
    m_coreDFGView = FabricCore::DFGView();
}

void DFGNotificationRouter::callback( FTL::CStrRef jsonStr )
{
  try
  {
    // printf( "notif = %s\n", jsonStr.c_str() );

    // FabricCore::DFGStringResult desc = m_exec.getDesc();
    // printf( "exec = %s\n", desc.getCString() );

    onNotification(jsonStr);

    FTL::JSONStrWithLoc jsonStrWithLoc( jsonStr );
    FTL::OwnedPtr<FTL::JSONObject> jsonObject(
      FTL::JSONValue::Decode( jsonStrWithLoc )->cast<FTL::JSONObject>()
      );
    FTL::StrRef descStr = jsonObject->getString( FTL_STR("desc") );

    if(descStr == FTL_STR("nodeInserted"))
    {
      onNodeInserted(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->get( FTL_STR("nodeDesc") )->cast<FTL::JSONObject>()
        );
    }
    else if(descStr == FTL_STR("nodeRemoved"))
    {
      onNodeRemoved(
        jsonObject->getString( FTL_STR("nodeName") )
        );
    }
    else if(descStr == FTL_STR("nodePortInserted"))
    {
      onNodePortInserted(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->get( FTL_STR("nodePortDesc") )->cast<FTL::JSONObject>()
        );
    }
    else if(descStr == FTL_STR("nodePortRemoved"))
    {
      onNodePortRemoved(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("portName") )
        );
    }
    else if(descStr == FTL_STR("execPortInserted"))
    {
      onExecPortInserted(
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->get( FTL_STR("execPortDesc") )->cast<FTL::JSONObject>()
        );
    }
    else if(descStr == FTL_STR("execPortRemoved"))
    {
      onExecPortRemoved(
        jsonObject->getString( FTL_STR("portName") )
        );
    }
    else if(descStr == FTL_STR("portsConnected"))
    {
      onPortsConnected(
        jsonObject->getString( FTL_STR("srcPath") ),
        jsonObject->getString( FTL_STR("dstPath") )
        );
    }
    else if(descStr == FTL_STR("portsDisconnected"))
    {
      onPortsDisconnected(
        jsonObject->getString( FTL_STR("srcPath") ),
        jsonObject->getString( FTL_STR("dstPath") )
        );
    }
    else if(descStr == FTL_STR("nodeMetadataChanged"))
    {
      onNodeMetadataChanged(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("key") ),
        jsonObject->getString( FTL_STR("value") )
        );
    }
    else if(descStr == FTL_STR("instExecTitleChanged"))
    {
      onNodeTitleChanged(
        jsonObject->getString( FTL_STR("instName") ),
        jsonObject->getString( FTL_STR("execTitle") )
        );
    }
    else if(descStr == FTL_STR("nodeRenamed"))
    {
      onNodeRenamed(
        jsonObject->getString( FTL_STR("oldNodeName") ),
        jsonObject->getString( FTL_STR("newNodeName") )
        );
    }
    else if(descStr == FTL_STR("execPortRenamed"))
    {
      onExecPortRenamed(
        jsonObject->getString( FTL_STR("oldPortName") ),
        jsonObject->getString( FTL_STR("newPortName") ),
        jsonObject->get( FTL_STR("execPortDesc") )->cast<FTL::JSONObject>()
        );
    }
    else if(descStr == FTL_STR("nodePortRenamed"))
    {
      onNodePortRenamed(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("oldPortName") ),
        jsonObject->getString( FTL_STR("newPortName") )
        );
    }
    else if(descStr == FTL_STR("execMetadataChanged"))
    {
      onExecMetadataChanged(
        jsonObject->getString( FTL_STR("key") ),
        jsonObject->getString( FTL_STR("value") )
        );
    }
    else if(descStr == FTL_STR("extDepAdded"))
    {
      onExtDepAdded(
        jsonObject->getString( FTL_STR("name") ),
        jsonObject->getString( FTL_STR("versionRange") )
        );
    }
    else if(descStr == FTL_STR("extDepRemoved"))
    {
      onExtDepRemoved(
        jsonObject->getString( FTL_STR("name") ),
        jsonObject->getString( FTL_STR("versionRange") )
        );
    }
    else if(descStr == FTL_STR("nodeCacheRuleChanged"))
    {
      onNodeCacheRuleChanged(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("cacheRule") )
        );
    }
    else if(descStr == FTL_STR("execCacheRuleChanged"))
    {
      onExecCacheRuleChanged(
        jsonObject->getString( FTL_STR("cacheRule") )
        );
    }
    else if(descStr == FTL_STR("execPortResolvedTypeChanged"))
    {
      onExecPortResolvedTypeChanged(
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->getStringOrEmpty( FTL_STR("newResolvedType") )
        );
    }
    else if(descStr == FTL_STR("execPortTypeSpecChanged"))
    {
      onExecPortTypeSpecChanged(
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->getStringOrEmpty( FTL_STR("newTypeSpec") )
        );
    }
    else if(descStr == FTL_STR("nodePortResolvedTypeChanged"))
    {
      onNodePortResolvedTypeChanged(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->getStringOrEmpty( FTL_STR("newResolvedType") )
        );
    }
    else if(descStr == FTL_STR("nodePortMetadataChanged"))
    {
      onNodePortMetadataChanged(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->getString( FTL_STR("key") ),
        jsonObject->getString( FTL_STR("value") )
        );
    }
    else if(descStr == FTL_STR("execPortMetadataChanged"))
    {
      onExecPortMetadataChanged(
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->getString( FTL_STR("key") ),
        jsonObject->getString( FTL_STR("value") )
        );
    }
    else if(descStr == FTL_STR("execPortTypeChanged"))
    {
      onExecPortTypeChanged(
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->getString( FTL_STR("newExecPortType") )
        );
    }
    else if(descStr == FTL_STR("nodePortTypeChanged"))
    {
      onNodePortTypeChanged(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("portName") ),
        jsonObject->getString( FTL_STR("newNodePortType") )
        );
    }
    else if(descStr == FTL_STR("refVarPathChanged"))
    {
      onRefVarPathChanged(
        jsonObject->getString( FTL_STR("refName") ),
        jsonObject->getString( FTL_STR("newVarPath") )
        );
    }
    else if(descStr == FTL_STR("funcCodeChanged"))
    {
      onFuncCodeChanged(
        jsonObject->getString( FTL_STR("code") )
        );
    }
    else if(descStr == FTL_STR("execTitleChanged"))
    {
      onExecTitleChanged(
        jsonObject->getString( FTL_STR("title") )
        );
    }
    else if(descStr == FTL_STR("extDepsChanged"))
    {
      onExecExtDepsChanged(
        jsonObject->getString( FTL_STR("extDeps") )
        );
    }
    else if( descStr == FTL_STR("execPortDefaultValuesChanged") )
    {
      onExecPortDefaultValuesChanged(
        jsonObject->getString( FTL_STR("portName") )
        );
    }
    else if( descStr == FTL_STR("nodePortDefaultValuesChanged") )
    {
      onNodePortDefaultValuesChanged(
        jsonObject->getString( FTL_STR("nodeName") ),
        jsonObject->getString( FTL_STR("portName") )
        );
    }
    else if ( descStr == FTL_STR("removedFromOwner") )
    {
      onRemovedFromOwner();
    }
    else if ( descStr == FTL_STR("execPortsReordered") )
    {
      const FTL::JSONArray * newOrder = jsonObject->maybeGetArray( FTL_STR("newOrder") );
      if ( newOrder )
      {
        std::vector<unsigned int> indices;
        for( size_t i = 0; i < newOrder->size(); i++ )
        {
          const FTL::JSONValue * indexVal = newOrder->get( i );
          unsigned int index = indexVal->getSInt32Value();
          indices.push_back( index );
        }

        if( indices.size() > 0 )
          onExecPortsReordered( indices.size(), &indices[ 0 ] );
      }
    }
    else if (descStr == FTL_STR("nodePortsReordered") )
    {
      FTL::CStrRef nodeName = jsonObject->getString( FTL_STR("nodeName") );
      const FTL::JSONArray * newOrder = jsonObject->maybeGetArray( FTL_STR("newOrder") );
      if ( newOrder )
      {
        std::vector<unsigned int> indices;
        for( size_t i = 0; i < newOrder->size(); i++ )
        {
          const FTL::JSONValue * indexVal = newOrder->get( i );
          unsigned int index = indexVal->getSInt32Value();
          indices.push_back( index );
        }

        if( indices.size() > 0 )
          onNodePortsReordered( nodeName, indices.size(), &indices[ 0 ] );
      }
    }
    else if (descStr == FTL_STR("execDidAttachPreset") )
    {
      FTL::CStrRef presetFilePath = jsonObject->getString( FTL_STR("presetFilePath") );
      onExecDidAttachPreset( presetFilePath );
    }
    else if (descStr == FTL_STR("instExecDidAttachPreset") )
    {
      FTL::CStrRef nodeName = jsonObject->getString( FTL_STR("nodeName") );
      FTL::CStrRef presetFilePath = jsonObject->getString( FTL_STR("presetFilePath") );
      onInstExecDidAttachPreset( nodeName, presetFilePath );
    }
    else if (descStr == FTL_STR("execWillDetachPreset") )
    {
      FTL::CStrRef presetFilePath = jsonObject->getString( FTL_STR("presetFilePath") );
      onExecWillDetachPreset( presetFilePath );
    }
    else if (descStr == FTL_STR("instExecWillDetachPreset") )
    {
      FTL::CStrRef nodeName = jsonObject->getString( FTL_STR("nodeName") );
      FTL::CStrRef presetFilePath = jsonObject->getString( FTL_STR("presetFilePath") );
      onInstExecWillDetachPreset( nodeName, presetFilePath );
    }
    else if (descStr == FTL_STR("execEditWouldSplitFromPresetMayHaveChanged") )
    {
      onExecEditWouldSplitFromPresetMayHaveChanged();
    }
    else if (descStr == FTL_STR("instExecEditWouldSplitFromPresetMayHaveChanged") )
    {
      FTL::CStrRef instName = jsonObject->getString( FTL_STR("instName") );
      onInstExecEditWouldSplitFromPresetMayHaveChanged( instName );
    }
    else
    {
      printf(
        "NotificationRouter::callback: Unhandled notification:\n%s\n",
        jsonStr.data()
        );
    }
  }
  catch ( FabricCore::Exception e )
  {
    printf(
      "NotificationRouter::callback: caught Core exception: %s\n",
      e.getDesc_cstr()
      );
  }
  catch ( FTL::JSONException e )
  {
    printf(
      "NotificationRouter::callback: caught FTL::JSONException: %s\n",
      e.getDescCStr()
      );
  }
}

void DFGNotificationRouter::onGraphSet()
{
  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if ( !exec )
    return;

  FabricCore::DFGStringResult desc = exec.getDesc();
  char const *descData;
  uint32_t descSize;
  desc.getStringDataAndLength( descData, descSize );

  FTL::JSONStrWithLoc jsonSrcWithLoc( FTL::StrRef( descData, descSize ) );
  FTL::OwnedPtr<FTL::JSONValue const> rootValue(
    FTL::JSONValue::Decode( jsonSrcWithLoc )
    );

  try
  {
    FTL::JSONObject const *rootObject = rootValue->cast<FTL::JSONObject>();

    FTL::JSONArray const *portsArray =
      rootObject->get( FTL_STR("ports") )->cast<FTL::JSONArray>();
    for ( size_t i = 0; i < portsArray->size(); ++i )
    {
      FTL::JSONObject const *portObject =
        portsArray->get( i )->cast<FTL::JSONObject>();
      onExecPortInserted(
        portObject->getString( FTL_STR("name") ),
        portObject
        );
    }

    if ( rootObject->getString( FTL_STR("objectType") ) == FTL_STR("Graph") )
    {
      FTL::JSONArray const *nodesArray =
        rootObject->get( FTL_STR("nodes") )->cast<FTL::JSONArray>();
      for ( size_t i = 0; i < nodesArray->size(); ++i )
      {
        FTL::JSONObject const *nodeObject =
          nodesArray->get( i )->cast<FTL::JSONObject>();
        onNodeInserted(
          nodeObject->getString( FTL_STR("name") ),
          nodeObject
          );
      }

      FTL::JSONObject const *connectionsObject =
        rootObject->get( FTL_STR("connections") )->cast<FTL::JSONObject>();
      for ( FTL::JSONObject::const_iterator it = connectionsObject->begin();
        it != connectionsObject->end(); ++it )
      {
        FTL::CStrRef srcPath = it->first;
        FTL::JSONArray const *dstsArray = it->second->cast<FTL::JSONArray>();
        for ( FTL::JSONArray::const_iterator it = dstsArray->begin();
          it != dstsArray->end(); ++it )
        {
          FTL::JSONValue const *dstValue = *it;
          FTL::CStrRef dstPath = dstValue->getStringValue();
          onPortsConnected( srcPath, dstPath );
        }
      }
    }

    FTL::JSONValue const *metadatasValue =
      rootObject->maybeGet( FTL_STR("metadata") );
    if ( metadatasValue )
    {
      FTL::JSONObject const *metadatasObject =
        metadatasValue->cast<FTL::JSONObject>();
      for ( FTL::JSONObject::const_iterator it = metadatasObject->begin();
        it != metadatasObject->end(); ++it )
      {
        FTL::CStrRef key = it->first;
        FTL::CStrRef value = it->second->getStringValue();
        onExecMetadataChanged( key, value );
      }
    }
  }
  catch ( FTL::JSONException je )
  {
    printf( "Caught JSONException: %s\n", je.getDescCStr() );
  }
}

void DFGNotificationRouter::onNotification(FTL::CStrRef json)
{
}

void DFGNotificationRouter::onNodeInserted(
  FTL::CStrRef nodeName,
  FTL::JSONObject const *jsonObject
  )
{
  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if ( !exec )
    return;

  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  FabricCore::DFGNodeType nodeType = exec.getNodeType( nodeName.c_str() );
  GraphView::Node * uiNode;
  if ( nodeType == FabricCore::DFGNodeType_User )
    uiNode = uiGraph->addBackDropNode( nodeName );
  else
    uiNode = uiGraph->addNode( nodeName, FTL::CStrRef() );
  if(!uiNode)
    return;

  if(nodeType == FabricCore::DFGNodeType_Var ||
    nodeType == FabricCore::DFGNodeType_Get ||
    nodeType == FabricCore::DFGNodeType_Set)
  {
    uiNode->setColor(m_config.varNodeDefaultColor);
    uiNode->setTitleColor(m_config.varLabelDefaultColor);
  }

  if(nodeType == FabricCore::DFGNodeType_Inst)
  {
    if ( exec.instExecIsPreset( nodeName.c_str() ) )
    {
      FTL::CStrRef title;
      if ( jsonObject->maybeGetString( FTL_STR("execTitle"), title ) )
        uiNode->setTitle( title );
    }
    else
    {
      uiNode->setTitle( nodeName );
      uiNode->setTitleSuffixAsterisk();
    }
  }
  else if(nodeType == FabricCore::DFGNodeType_Var)
  {
    FTL::CStrRef name;
    if ( jsonObject->maybeGetString( FTL_STR("name"), name ) )
      uiNode->setTitle( name );
  }
  else if(nodeType == FabricCore::DFGNodeType_Get || nodeType == FabricCore::DFGNodeType_Set)
  {
    FTL::CStrRef varPath = exec.getRefVarPath( nodeName.c_str() );
    onRefVarPathChanged(nodeName, varPath);
  }

  FTL::JSONArray const *portsJSONArray =
    jsonObject->get( FTL_STR("ports") )->cast<FTL::JSONArray>();
  for ( size_t i = 0; i < portsJSONArray->size(); ++i )
  {
    FTL::JSONObject const *portJSONObject =
      portsJSONArray->get( i )->cast<FTL::JSONObject>();
    onNodePortInserted(
      nodeName,
      portJSONObject->getString( FTL_STR("name") ),
      portJSONObject
      );
  }

  if(exec.getNodeType(nodeName.c_str()) == FabricCore::DFGNodeType_Inst)
  {
    FabricCore::DFGExec subExec = exec.getSubExec(nodeName.c_str());
    FTL::CStrRef uiNodeColor = subExec.getMetadata("uiNodeColor");
    if(!uiNodeColor.empty())
      onNodeMetadataChanged(nodeName, "uiNodeColor", uiNodeColor);
    FTL::CStrRef uiHeaderColor = subExec.getMetadata("uiHeaderColor");
    if(!uiHeaderColor.empty())
      onNodeMetadataChanged(nodeName, "uiHeaderColor", uiHeaderColor);
    FTL::CStrRef uiTextColor = subExec.getMetadata("uiTextColor");
    if(!uiTextColor.empty())
      onNodeMetadataChanged(nodeName, "uiTextColor", uiTextColor);
    FTL::CStrRef uiTooltip = subExec.getMetadata("uiTooltip");
    if(!uiTooltip.empty())
      onNodeMetadataChanged(nodeName, "uiTooltip", uiTooltip);
    FTL::CStrRef uiAlwaysShowDaisyChainPorts = subExec.getMetadata("uiAlwaysShowDaisyChainPorts");
    if(!uiAlwaysShowDaisyChainPorts.empty())
      onNodeMetadataChanged(nodeName, "uiAlwaysShowDaisyChainPorts", uiAlwaysShowDaisyChainPorts);
    FTL::CStrRef uiCollapsedState = subExec.getMetadata("uiCollapsedState");
    if(!uiCollapsedState.empty())
      onNodeMetadataChanged(nodeName, "uiCollapsedState", uiCollapsedState);
  }

  if ( exec.getNodeType(nodeName.c_str()) == FabricCore::DFGNodeType_User )
  {
    FTL::CStrRef uiNodeColor =
      exec.getNodeMetadata( nodeName.c_str(), "uiNodeColor" );
    if ( !uiNodeColor.empty() )
      onNodeMetadataChanged( nodeName, "uiNodeColor", uiNodeColor );
    FTL::CStrRef uiHeaderColor =
      exec.getNodeMetadata( nodeName.c_str(), "uiHeaderColor" );
    if ( !uiHeaderColor.empty() )
      onNodeMetadataChanged( nodeName, "uiHeaderColor", uiHeaderColor );
    FTL::CStrRef uiTextColor =
      exec.getNodeMetadata( nodeName.c_str(), "uiTextColor" );
    if ( !uiTextColor.empty() )
      onNodeMetadataChanged( nodeName, "uiTextColor", uiTextColor );
  }

  if ( FTL::JSONValue const *metadataJSONValue =
    jsonObject->maybeGet( FTL_STR("metadata") ) )
  {
    FTL::JSONObject const *metadataJSONObject =
      metadataJSONValue->cast<FTL::JSONObject>();

    for ( FTL::JSONObject::const_iterator it = metadataJSONObject->begin();
      it != metadataJSONObject->end(); ++it )
    {
      FTL::CStrRef key = it->first;
      FTL::CStrRef value = it->second->cast<FTL::JSONString>()->getValue();
      onNodeMetadataChanged(nodeName, key, value);
    }
  }

  if(m_performChecks)
  {
    ((DFGController*)m_dfgController)->checkErrors();
  }
}

void DFGNotificationRouter::onNodeRemoved(
  FTL::CStrRef nodeName
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;
  GraphView::Node * uiNode = uiGraph->node(nodeName);
  if(!uiNode)
    return;
  uiGraph->removeNode(uiNode);

  // todo - the notif should provide the node type
  // m_dfgController->updatePresetDB(true);

  if(m_performChecks)
  {
    ((DFGController*)m_dfgController)->checkErrors();
  }

  m_dfgController->emitNodeRemoved( nodeName );
}

void DFGNotificationRouter::onNodePortInserted(
  FTL::CStrRef nodeName,
  FTL::CStrRef portName,
  FTL::JSONObject const *jsonObject
  )
{
  GraphView::Graph * graph = m_dfgController->graph();
  if(!graph)
    return;
  GraphView::Node * uiNode = graph->node(nodeName);
  if(!uiNode)
    return;

  FTL::CStrRef dataType = jsonObject->getStringOrEmpty( FTL_STR("type") );

  FabricCore::DFGExec &exec = m_dfgController->getExec();

  QColor color;
  if(exec.getNodeType(nodeName.c_str()) == FabricCore::DFGNodeType_Inst)
  {
    FabricCore::DFGExec subExec = exec.getSubExec(nodeName.c_str());
    color = m_config.getColorForDataType(dataType, &subExec, portName.c_str());
  }
  else
    color = m_config.getColorForDataType(dataType);

  FTL::CStrRef nodePortType =
    jsonObject->getStringOrEmpty( FTL_STR("nodePortType") );
  GraphView::PortType pType = GraphView::PortType_Input;
  if(nodePortType == FTL_STR("Out"))
    pType = GraphView::PortType_Output;
  else if(nodePortType == FTL_STR("IO"))
    pType = GraphView::PortType_IO;

  GraphView::Pin * uiPin = new GraphView::Pin(uiNode, portName.c_str(), pType, color, portName.c_str());
  if ( !dataType.empty() )
    uiPin->setDataType(dataType);
  uiNode->addPin(uiPin, false);
}

void DFGNotificationRouter::onNodePortRemoved(
  FTL::CStrRef nodeName,
  FTL::CStrRef portName
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  GraphView::Node * uiNode = uiGraph->node(nodeName);
  if(!uiNode)
    return;
  GraphView::Pin * uiPin = uiNode->pin(portName);
  if(!uiPin)
    return;
  uiNode->removePin(uiPin, false);

  if(m_performChecks)
  {
    ((DFGController*)m_dfgController)->checkErrors();
  }
}

void DFGNotificationRouter::onExecPortInserted(
  FTL::CStrRef portName,
  FTL::JSONObject const *jsonObject
  )
{
  FTL::CStrRef dataType = jsonObject->getStringOrEmpty( FTL_STR("type") );

  FabricCore::DFGExec &exec = m_dfgController->getExec();

  if(exec.getType() == FabricCore::DFGExecType_Graph)
  {
    GraphView::Graph * uiGraph = m_dfgController->graph();
    if(!uiGraph)
      return;

    QColor color = m_config.getColorForDataType(dataType, &exec, portName.c_str());

    GraphView::Port * uiOutPort = NULL;
    GraphView::Port * uiInPort = NULL;

    FTL::CStrRef execPortType =
      jsonObject->getStringOrEmpty( FTL_STR("execPortType") );
    if(execPortType != FTL_STR("In"))
    {
      GraphView::SidePanel * uiPanel = uiGraph->sidePanel(GraphView::PortType_Input);
      if(!uiPanel)
        return;

      uiInPort = new GraphView::Port(
        uiPanel, portName, GraphView::PortType_Input, dataType, color, portName
        );
      uiPanel->addPort(uiInPort);
    }
    if(execPortType != FTL_STR("Out"))
    {
      GraphView::SidePanel * uiPanel = uiGraph->sidePanel(GraphView::PortType_Output);
      if(!uiPanel)
        return;

      uiOutPort = new GraphView::Port(
        uiPanel, portName, GraphView::PortType_Output, dataType, color, portName
        );
      uiPanel->addPort(uiOutPort);
    }
    if(uiOutPort && uiInPort)
    {
      uiGraph->addConnection(uiOutPort, uiInPort, false);
    }
  }
  else if(exec.getType() == FabricCore::DFGExecType_Func)
  {
    DFGKLEditorWidget * uiKlEditor = m_dfgController->getDFGWidget()->getKLEditor();
    if(!uiKlEditor)
      return;
    uiKlEditor->onExecChanged();
  }
}

void DFGNotificationRouter::onExecPortRemoved(
  FTL::CStrRef portName
  )
{
  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if(exec.getType() == FabricCore::DFGExecType_Graph)
  {
    GraphView::Graph * uiGraph = m_dfgController->graph();
    if(!uiGraph)
      return;

    GraphView::SidePanel * uiOutPanel = uiGraph->sidePanel(GraphView::PortType_Output);
    if(!uiOutPanel)
      return;
    GraphView::SidePanel * uiInPanel = uiGraph->sidePanel(GraphView::PortType_Input);
    if(!uiInPanel)
      return;
    GraphView::Port * uiOutPort = uiOutPanel->port(portName);
    GraphView::Port * uiInPort = uiInPanel->port(portName);

    if(uiOutPort && uiInPort)
    {
      uiGraph->removeConnection(uiOutPort, uiInPort);
    }
    if(uiInPort)
    {
      uiInPanel->removePort(uiInPort);
    }
    if(uiOutPort)
    {
      uiOutPanel->removePort(uiOutPort);
    }

    if(m_performChecks)
    {
      ((DFGController*)m_dfgController)->checkErrors();
    }
  }
  else if(exec.getType() == FabricCore::DFGExecType_Func)
  {
    DFGKLEditorWidget * uiKlEditor = m_dfgController->getDFGWidget()->getKLEditor();
    if(!uiKlEditor)
      return;
    uiKlEditor->onExecChanged();
  }
}

void DFGNotificationRouter::onPortsConnected(
  FTL::CStrRef srcPath,
  FTL::CStrRef dstPath
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  GraphView::ConnectionTarget * uiSrcTarget = NULL;
  GraphView::ConnectionTarget * uiDstTarget = NULL;

  std::pair<FTL::StrRef, FTL::CStrRef> srcSplit = srcPath.split('.');
  if(!srcSplit.second.empty())
  {
    GraphView::Node * uiSrcNode = uiGraph->node(srcSplit.first);
    if(!uiSrcNode)
      return;
    uiSrcTarget = uiSrcNode->pin(srcSplit.second);
  }
  else
  {
    GraphView::SidePanel * uiPanel = uiGraph->sidePanel(GraphView::PortType_Output);
    if(uiPanel)
      uiSrcTarget = uiPanel->port(srcSplit.first);
  }

  std::pair<FTL::StrRef, FTL::CStrRef> dstSplit = dstPath.split('.');
  if(!dstSplit.second.empty())
  {
    GraphView::Node * uiDstNode = uiGraph->node(dstSplit.first);
    if(!uiDstNode)
      return;
    uiDstTarget = uiDstNode->pin(dstSplit.second);
  }
  else
  {
    GraphView::SidePanel * uiPanel = uiGraph->sidePanel(GraphView::PortType_Input);
    if(uiPanel)
      uiDstTarget = uiPanel->port(dstSplit.first);
  }

  if(!uiSrcTarget || !uiDstTarget)
    return;

  uiGraph->addConnection(uiSrcTarget, uiDstTarget, false);

  if(m_performChecks)
  {
    ((DFGController*)m_dfgController)->checkErrors();
  }

  m_dfgController->bindUnboundRTVals();
}

void DFGNotificationRouter::onPortsDisconnected(
  FTL::CStrRef srcPath,
  FTL::CStrRef dstPath
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  GraphView::ConnectionTarget * uiSrcTarget = NULL;
  GraphView::ConnectionTarget * uiDstTarget = NULL;

  std::pair<FTL::StrRef, FTL::CStrRef> srcSplit = srcPath.split('.');
  if(!srcSplit.second.empty())
  {
    GraphView::Node * uiSrcNode = uiGraph->node(srcSplit.first);
    if(!uiSrcNode)
      return;
    uiSrcTarget = uiSrcNode->pin(srcSplit.second);
  }
  else
  {
    GraphView::SidePanel * uiPanel = uiGraph->sidePanel(GraphView::PortType_Output);
    if(uiPanel)
      uiSrcTarget = uiPanel->port(srcSplit.first);
  }

  std::pair<FTL::StrRef, FTL::CStrRef> dstSplit = dstPath.split('.');
  if(!dstSplit.second.empty())
  {
    GraphView::Node * uiDstNode = uiGraph->node(dstSplit.first);
    if(!uiDstNode)
      return;
    uiDstTarget = uiDstNode->pin(dstSplit.second);
  }
  else
  {
    GraphView::SidePanel * uiPanel = uiGraph->sidePanel(GraphView::PortType_Input);
    if(uiPanel)
      uiDstTarget = uiPanel->port(dstSplit.first);
  }

  if(!uiSrcTarget || !uiDstTarget)
    return;

  uiGraph->removeConnection(uiSrcTarget, uiDstTarget, false);

  if(m_performChecks)
  {
    ((DFGController*)m_dfgController)->checkErrors();
  }
}

void DFGNotificationRouter::onNodeMetadataChanged(
  FTL::CStrRef nodeName,
  FTL::CStrRef key,
  FTL::CStrRef value
  )
{
  if(m_dfgController->graph() == NULL)
    return;
  GraphView::Graph * uiGraph = m_dfgController->graph();
  GraphView::Node * uiNode = uiGraph->node(nodeName.data());
  if(!uiNode)
    return;

  // printf("'%s' metadata changed for '%s'\n", key, path.toUtf8().constData());

  if(key == FTL_STR("uiGraphPos"))
  {
    FTL::JSONStrWithLoc jsonStrWithLoc( value );
    FTL::OwnedPtr<FTL::JSONValue const> jsonValue(
      FTL::JSONValue::Decode( jsonStrWithLoc )
      );
    if ( jsonValue )
    {
      FTL::JSONObject const *jsonObject = jsonValue->cast<FTL::JSONObject>();
      float x = jsonObject->getFloat64( FTL_STR("x") );
      float y = jsonObject->getFloat64( FTL_STR("y") );
      uiNode->setTopLeftGraphPos(QPointF(x, y), false);
    }
  }
  else if(key == FTL_STR("uiGraphSize"))
  {
    FTL::JSONStrWithLoc jsonStrWithLoc( value );
    FTL::OwnedPtr<FTL::JSONValue const> jsonValue(
      FTL::JSONValue::Decode( jsonStrWithLoc )
      );
    if ( jsonValue )
    {
      FTL::JSONObject const *jsonObject = jsonValue->cast<FTL::JSONObject>();
      float w = jsonObject->getFloat64( FTL_STR("w") );
      float h = jsonObject->getFloat64( FTL_STR("h") );
      if ( uiNode->isBackDropNode() )
      {
        GraphView::BackDropNode *uiBackDropNode =
          static_cast<GraphView::BackDropNode *>( uiNode );
        uiBackDropNode->setSize( QSizeF( w, h ) );
      }
    }
  }
  else if(key == FTL_STR("uiTitle"))
  {
    if ( uiNode->isBackDropNode() )
    {
      GraphView::BackDropNode *uiBackDropNode =
        static_cast<GraphView::BackDropNode *>( uiNode );
      uiBackDropNode->setTitle( value );
    }
  }
  else if(key == FTL_STR("uiCollapsedState"))
  {
    FabricCore::Variant metadataVar = FabricCore::Variant::CreateFromJSON(value.c_str());
    GraphView::Node::CollapseState state = (GraphView::Node::CollapseState)metadataVar.getSInt32();
    uiNode->setCollapsedState(state);
  }
  else if(key == FTL_STR("uiNodeColor"))
  {
    FTL::JSONStrWithLoc jsonStrWithLoc( value );
    FTL::OwnedPtr<FTL::JSONValue const> jsonValue(
      FTL::JSONValue::Decode( jsonStrWithLoc )
      );
    if ( jsonValue )
    {
      FTL::JSONObject const *jsonObject = jsonValue->cast<FTL::JSONObject>();
      int r = int(jsonObject->getFloat64( FTL_STR("r") ));
      int g = int(jsonObject->getFloat64( FTL_STR("g") ));
      int b = int(jsonObject->getFloat64( FTL_STR("b") ));
      if ( uiNode->isBackDropNode() )
      {
        uiNode->setColor( QColor( r, g, b, 0xA0 ) );
        uiNode->setTitleColor( QColor( r, g, b, 0xB0 ) );
      }
      else
      {
        QColor color( r, g, b );
        uiNode->setColor(color);
        uiNode->setTitleColor(color.darker(130));
      }
    }
  }
  else if(key == FTL_STR("uiHeaderColor"))
  {
    FTL::JSONStrWithLoc jsonStrWithLoc( value );
    FTL::OwnedPtr<FTL::JSONValue const> jsonValue(
      FTL::JSONValue::Decode( jsonStrWithLoc )
      );
    if ( jsonValue )
    {
      FTL::JSONObject const *jsonObject = jsonValue->cast<FTL::JSONObject>();
      int r = int(jsonObject->getFloat64( FTL_STR("r") ));
      int g = int(jsonObject->getFloat64( FTL_STR("g") ));
      int b = int(jsonObject->getFloat64( FTL_STR("b") ));
      if ( uiNode->isBackDropNode() )
      {
        uiNode->setTitleColor( QColor( r, g, b, 0xB0 ) );
      }
      else
      {
        QColor color(r, g, b);
        uiNode->setTitleColor(color);
      }
    }
  }
  else if(key == FTL_STR("uiTextColor"))
  {
    FTL::JSONStrWithLoc jsonStrWithLoc( value );
    FTL::OwnedPtr<FTL::JSONValue const> jsonValue(
      FTL::JSONValue::Decode( jsonStrWithLoc )
      );
    if ( jsonValue )
    {
      FTL::JSONObject const *jsonObject = jsonValue->cast<FTL::JSONObject>();
      int r = int(jsonObject->getFloat64( FTL_STR("r") ));
      int g = int(jsonObject->getFloat64( FTL_STR("g") ));
      int b = int(jsonObject->getFloat64( FTL_STR("b") ));

      QColor color(r, g, b);
      uiNode->setFontColor(color);
    }
  }
  else if(key == FTL_STR("uiTooltip"))
  {
    QString tooltip = QSTRING_FROM_FTL_UTF8(value);
    uiNode->header()->setToolTip(tooltip.trimmed());
  }
  else if(key == FTL_STR("uiComment"))
  {
    QString text = QSTRING_FROM_FTL_UTF8(value);
    GraphView::NodeBubble *uiBubble = uiNode->bubble();
    if ( text.length() == 0 )
      uiBubble->hide();
    else
      uiBubble->show();
    uiBubble->setText(text);
  }
  else if(key == FTL_STR("uiCommentExpanded"))
  {
    GraphView::NodeBubble * uiBubble = uiNode->bubble();
    if ( value.empty() || value == FTL_STR("false") )
      uiBubble->collapse();
    else
      uiBubble->expand();
  }
  else if(key == FTL_STR("uiAlwaysShowDaisyChainPorts"))
  {
    if(value.size() == 0 || value == "false")
    {
      uiNode->setAlwaysShowDaisyChainPorts(false);
    }
    else
    {
      uiNode->setAlwaysShowDaisyChainPorts(true);
    }
  }
}

void DFGNotificationRouter::onNodeTitleChanged(
  FTL::CStrRef nodeName,
  FTL::CStrRef title
  )
{
  if(m_dfgController->graph() == NULL)
    return;
  GraphView::Graph * uiGraph = m_dfgController->graph();
  GraphView::Node * uiNode = uiGraph->node(nodeName);
  if(!uiNode)
    return;

  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if ( exec.getNodeType( nodeName.c_str() ) == FabricCore::DFGNodeType_Inst
    && exec.instExecIsPreset( nodeName.c_str() ) )
  {
    uiNode->setTitle( title );
    uiNode->update();
  }
}

void DFGNotificationRouter::onNodeRenamed(
  FTL::CStrRef oldNodeName,
  FTL::CStrRef newNodeName
  )
{
  GraphView::Graph *uiGraph = m_dfgController->graph();
  if ( !uiGraph )
    return;

  GraphView::Node *uiNode = uiGraph->renameNode( oldNodeName, newNodeName );

  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if ( exec.getNodeType( oldNodeName.c_str() ) == FabricCore::DFGNodeType_Inst
    && !exec.instExecIsPreset( newNodeName.c_str() ) )
  {
    assert( !!uiNode );
    uiNode->setTitle( newNodeName );
  }

  m_dfgController->emitNodeRenamed( oldNodeName, newNodeName );
}

void DFGNotificationRouter::onExecPortRenamed(
  FTL::CStrRef oldPortName,
  FTL::CStrRef newPortName,
  FTL::JSONObject const *execPortJSONObject
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  FTL::CStrRef execPortTypeStr =
    execPortJSONObject->getString( FTL_STR("execPortType") );

  if ( execPortTypeStr != FTL_STR("In") )
  {
    GraphView::SidePanel * uiPanel =
      uiGraph->sidePanel(GraphView::PortType_Input);
    if(!uiPanel)
      return;

    GraphView::Port * uiPort = uiPanel->port(oldPortName);
    if(!uiPort)
      return;
    uiPort->setName(newPortName);
  }

  if ( execPortTypeStr != FTL_STR("Out") )
  {
    GraphView::SidePanel * uiPanel =
      uiGraph->sidePanel(GraphView::PortType_Output);
    if(!uiPanel)
      return;

    GraphView::Port * uiPort = uiPanel->port(oldPortName);
    if(!uiPort)
      return;
    uiPort->setName(newPortName);
  }
}

void DFGNotificationRouter::onNodePortRenamed(
  FTL::CStrRef nodeName,
  FTL::CStrRef oldPortName,
  FTL::CStrRef newPortName
  )
{
  // this shouldn't happen for us for now
}

void DFGNotificationRouter::onExecMetadataChanged(
  FTL::CStrRef key,
  FTL::CStrRef value
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  // printf("'%s' metadata changed for '%s'\n", key, exec->getExecPath());

  if(key == "uiGraphPan")
  {
    FTL::JSONStrWithLoc jsonStrWithLoc( value );
    FTL::OwnedPtr<FTL::JSONValue const> jsonValue(
      FTL::JSONValue::Decode( jsonStrWithLoc )
      );
    if ( jsonValue )
    {
      FTL::JSONObject const *jsonObject = jsonValue->cast<FTL::JSONObject>();
      float x = jsonObject->getFloat64( FTL_STR("x") );
      float y = jsonObject->getFloat64( FTL_STR("y") );
      uiGraph->mainPanel()->setCanvasPan(QPointF(x, y), false);
    }
  }
  else if(key == "uiGraphZoom")
  {
    FTL::JSONStrWithLoc jsonStrWithLoc( value );
    FTL::OwnedPtr<FTL::JSONValue const> jsonValue(
      FTL::JSONValue::Decode( jsonStrWithLoc )
      );
    if ( jsonValue )
    {
      FTL::JSONObject const *jsonObject = jsonValue->cast<FTL::JSONObject>();
      float value = jsonObject->getFloat64( FTL_STR("value") );
      // float y = jsonObject->getFloat64( FTL_STR("y") );
      uiGraph->mainPanel()->setCanvasZoom(value, false);
    }
  }
}

void DFGNotificationRouter::onExtDepAdded(
  FTL::CStrRef extension,
  FTL::CStrRef version
  )
{
  if(m_dfgController->graph() == NULL)
    return;
  try
  {
    FabricCore::Client client = ((DFGController*)m_dfgController)->getClient();
    client.loadExtension(extension.data(), version.data(), false);
  }
  catch(FabricCore::Exception e)
  {
    ((DFGController*)m_dfgController)->logError(e.getDesc_cstr());
  }
}

void DFGNotificationRouter::onExtDepRemoved(
  FTL::CStrRef extension,
  FTL::CStrRef version
  )
{
  // todo: we don't do anything here...
}

void DFGNotificationRouter::onNodeCacheRuleChanged(
  FTL::CStrRef nodeName,
  FTL::CStrRef newCacheRule
  )
{
  // todo: we don't do anything here...
}

void DFGNotificationRouter::onExecCacheRuleChanged(
  FTL::CStrRef newCacheRule
  )
{
  // todo: we don't do anything here...
}

void DFGNotificationRouter::onExecPortResolvedTypeChanged(
  FTL::CStrRef portName,
  FTL::CStrRef newResolvedType
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  // we query for a vector because in case of an io port
  // we might actually have two
  std::vector<GraphView::Port *> uiPorts = uiGraph->ports(portName);
  if(uiPorts.size() == 0)
    return;

  if(newResolvedType != uiPorts[0]->dataType())
  {
    FabricCore::DFGExec &exec = m_dfgController->getExec();
    for(size_t i=0;i<uiPorts.size();i++)
    {
      uiPorts[i]->setDataType(newResolvedType);
      uiPorts[i]->setColor(m_config.getColorForDataType(newResolvedType, &exec, portName.c_str()));
    }
    uiGraph->updateColorForConnections(uiPorts[0]);
  }
}

void DFGNotificationRouter::onExecPortTypeSpecChanged(
  FTL::CStrRef portPath,
  FTL::CStrRef newTypeSpec
  )
{
  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if(exec.getType() == FabricCore::DFGExecType_Func)
  {
    DFGKLEditorWidget * uiKlEditor = m_dfgController->getDFGWidget()->getKLEditor();
    if(!uiKlEditor)
      return;
    uiKlEditor->onExecChanged();
  }
}

void DFGNotificationRouter::onNodePortResolvedTypeChanged(
  FTL::CStrRef nodeName,
  FTL::CStrRef portName,
  FTL::CStrRef newResolvedType
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  GraphView::Node * uiNode = uiGraph->node(nodeName);
  if(!uiNode)
    return;
  GraphView::Pin * uiPin = uiNode->pin(portName);
  if(!uiPin)
    return;

  if(newResolvedType != uiPin->dataType())
  {
    uiPin->setDataType(newResolvedType);
    FabricCore::DFGExec &exec = m_dfgController->getExec();
    if(exec.getNodeType(nodeName.c_str()) == FabricCore::DFGNodeType_Inst)
    {
      FabricCore::DFGExec subExec = exec.getSubExec( nodeName.c_str() );
      uiPin->setColor(m_config.getColorForDataType(newResolvedType, &subExec, portName.data()));
    }
    else
      uiPin->setColor(m_config.getColorForDataType(newResolvedType));
    uiGraph->updateColorForConnections(uiPin);
  }
}

void DFGNotificationRouter::onExecPortMetadataChanged(
  FTL::CStrRef portName,
  FTL::CStrRef key,
  FTL::CStrRef value)
{
  // todo: we don't do anything here...
}

void DFGNotificationRouter::onNodePortMetadataChanged(
  FTL::CStrRef nodeName,
  FTL::CStrRef portName,
  FTL::CStrRef key,
  FTL::CStrRef value)
{
  // todo: we don't do anything here...
}

void DFGNotificationRouter::onExecPortTypeChanged(
  FTL::CStrRef portName,
  FTL::CStrRef execPortType
  )
{
  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if(exec.getType() == FabricCore::DFGExecType_Func)
  {
    DFGKLEditorWidget * uiKlEditor = m_dfgController->getDFGWidget()->getKLEditor();
    if(!uiKlEditor)
      return;
    uiKlEditor->onExecChanged();
  }
}

void DFGNotificationRouter::onNodePortTypeChanged(
  FTL::CStrRef nodeName,
  FTL::CStrRef portName,
  FTL::CStrRef nodePortType
  )
{
  // todo: we don't do anything here...
}

void DFGNotificationRouter::onRefVarPathChanged(
  FTL::CStrRef refName,
  FTL::CStrRef newVarPath
  )
{
  FabricCore::DFGExec &exec = m_dfgController->getExec();
  if ( !exec )
    return;

  FabricCore::DFGNodeType nodeType = exec.getNodeType(refName.c_str());
  std::string title = newVarPath;
  if(nodeType == FabricCore::DFGNodeType_Get)
    title = "get "+title;
  else if(nodeType == FabricCore::DFGNodeType_Set)
    title = "set "+title;

  GraphView::Graph *uiGraph = m_dfgController->graph();
  if ( !uiGraph )
    return;
  GraphView::Node *uiNode = uiGraph->node( refName );
  if ( !uiNode )
    return;
  uiNode->setTitle( title );
}

void DFGNotificationRouter::onFuncCodeChanged(
  FTL::CStrRef code
  )
{
  // todo: we don't do anything here...
}

void DFGNotificationRouter::onExecTitleChanged(
  FTL::CStrRef title
  )
{
  DFGWidget *dfgWidget = m_dfgController->getDFGWidget();
  dfgWidget->refreshTitle( title );
}

void DFGNotificationRouter::onExecExtDepsChanged(
  FTL::CStrRef extDeps
  )
{
  DFGWidget *dfgWidget = m_dfgController->getDFGWidget();
  dfgWidget->refreshExtDeps( extDeps );
}

void DFGNotificationRouter::onNodePortDefaultValuesChanged(
  FTL::CStrRef nodeName,
  FTL::CStrRef portName
  )
{
  m_dfgController->emitDefaultValuesChanged();
}

void DFGNotificationRouter::onExecPortDefaultValuesChanged(
  FTL::CStrRef portName
  )
{
  m_dfgController->emitDefaultValuesChanged();
}

void DFGNotificationRouter::onRemovedFromOwner()
{
  FTL::StrRef execPath = m_dfgController->getExecPath();
  if ( execPath.empty() )
    return;

  // [FE-5435] we need to go up as high as required
  // the level above might not exist anymore either.
  while(true)
  {
    if(execPath.empty())
      break;

    FTL::StrRef::Split split = execPath.rsplit('.');

    std::string parentExecPath;
    if( split.first.empty() || split.second.empty() )
      parentExecPath = "";
    else
      parentExecPath = split.first;

    FabricCore::DFGExec parentExec;
    try
    {
      FabricCore::DFGBinding &binding = m_dfgController->getBinding();
      FabricCore::DFGExec rootExec = binding.getExec();
      if(parentExecPath.empty())
        parentExec = rootExec;
      else
        parentExec = rootExec.getSubExec( parentExecPath.c_str() );
    }
    catch ( FabricCore::Exception e )
    {
      // the sub exec does not exist... let's go up higher
      execPath = parentExecPath;
      continue;
    }

    m_dfgController->setExec( parentExecPath, parentExec );
    break;
  }
}

void DFGNotificationRouter::onExecPortsReordered(
  unsigned int indexCount,
  unsigned int * indices
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  GraphView::SidePanel * leftPanel = uiGraph->sidePanel(GraphView::PortType_Input);
  GraphView::SidePanel * rightPanel = uiGraph->sidePanel(GraphView::PortType_Output);

  FabricCore::DFGExec & exec = m_dfgController->getExec();
  QStringList inputs, outputs;
  for(unsigned int i=0;i<exec.getExecPortCount();i++)
  {
    QString name = exec.getExecPortName(i);
    if(exec.getExecPortType(i) != FabricCore::DFGPortType_Out)
      inputs.append(name);
    if(exec.getExecPortType(i) != FabricCore::DFGPortType_In)
      outputs.append(name);
  }

  leftPanel->reorderPorts(outputs);
  rightPanel->reorderPorts(inputs);
}

void DFGNotificationRouter::onNodePortsReordered(
  FTL::CStrRef nodeName,
  unsigned int indexCount,
  unsigned int * indices
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;

  GraphView::Node * uiNode = uiGraph->node(nodeName);
  if(!uiNode)
    return;

  FabricCore::DFGExec & exec = m_dfgController->getExec();
  FabricCore::DFGExec subExec = exec.getSubExec(nodeName.c_str());
  QStringList names;
  for(unsigned int i=0;i<subExec.getExecPortCount();i++)
  {
    QString name = subExec.getExecPortName(i);
    names.append(name);
  }

  uiNode->reorderPins(names);
}

void DFGNotificationRouter::onExecDidAttachPreset(
  FTL::CStrRef presetFilePath
  )
{
  // nothing to be done here for now.
}

void DFGNotificationRouter::onInstExecDidAttachPreset(
  FTL::CStrRef nodeName,
  FTL::CStrRef presetFilePath
  )
{
  // nothing to be done here for now.
}

void DFGNotificationRouter::onExecWillDetachPreset(
  FTL::CStrRef presetFilePath
  )
{
  // nothing to be done here for now.
}

void DFGNotificationRouter::onInstExecWillDetachPreset(
  FTL::CStrRef nodeName,
  FTL::CStrRef presetFilePath
  )
{
  // nothing to be done here for now.
}

void DFGNotificationRouter::onExecEditWouldSplitFromPresetMayHaveChanged()
{
  m_dfgController->emitExecSplitChanged();
}

void DFGNotificationRouter::onInstExecEditWouldSplitFromPresetMayHaveChanged(
  FTL::CStrRef instName
  )
{
  GraphView::Graph * uiGraph = m_dfgController->graph();
  if(!uiGraph)
    return;
  GraphView::Node * uiNode = uiGraph->node(instName);
  if(!uiNode)
    return;

  FabricCore::DFGExec & exec = m_dfgController->getExec();
  FabricCore::DFGExec subExec = exec.getSubExec( instName.c_str() );
  if ( !subExec.isPreset() )
  {
    uiNode->setTitle( instName );
    uiNode->setTitleSuffixAsterisk();
  }
  else
  {
    uiNode->setTitle( subExec.getTitle() );
    uiNode->removeTitleSuffix();
  }
}


text:
package app

import (
	"errors"
	"fmt"
	"io"

	"github.com/tsuru/tsuru/db"
	"github.com/tsuru/tsuru/log"
	"github.com/tsuru/tsuru/provision"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type Platform struct {
	Name string `bson:"_id"`
}

// Platforms returns the list of available platforms.
func Platforms() ([]Platform, error) {
	var platforms []Platform
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	err = conn.Platforms().Find(nil).All(&platforms)
	return platforms, err
}

// PlatformAdd add a new platform to tsuru
func PlatformAdd(name string, args map[string]string, w io.Writer) error {
	var (
		provisioner provision.ExtensibleProvisioner
		ok          bool
	)
	if provisioner, ok = Provisioner.(provision.ExtensibleProvisioner); !ok {
		return errors.New("Provisioner is not extensible")
	}
	if name == "" {
		return errors.New("Platform name is required.")
	}
	p := Platform{Name: name}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	err = conn.Platforms().Insert(p)
	if err != nil {
		if mgo.IsDup(err) {
			return DuplicatePlatformError{}
		}
		return err
	}
	err = provisioner.PlatformAdd(name, args, w)
	if err != nil {
		dbErr := conn.Platforms().RemoveId(p.Name)
		if dbErr != nil {
			return fmt.Errorf("Caused by: %s and %s", err.Error(), dbErr.Error())
		}
		return err
	}
	return nil
}

type DuplicatePlatformError struct{}

func (DuplicatePlatformError) Error() string {
	return "Duplicate platform"
}

func PlatformUpdate(name string, args map[string]string, w io.Writer) error {
	var (
		provisioner provision.ExtensibleProvisioner
		platform    Platform
		ok          bool
	)
	if provisioner, ok = Provisioner.(provision.ExtensibleProvisioner); !ok {
		return errors.New("Provisioner is not extensible")
	}
	if name == "" {
		return errors.New("Platform name is required.")
	}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	err = conn.Platforms().Find(bson.M{"_id": name}).One(&platform)
	if err != nil {
		if err == mgo.ErrNotFound {
			return errors.New("Platform doesn't exist.")
		}
		return err
	}
	err = provisioner.PlatformUpdate(name, args, w)
	if err != nil {
		return err
	}
	var apps []App
	err = conn.Apps().Find(bson.M{"framework": name}).All(&apps)
	if err != nil {
		return err
	}
	for _, app := range apps {
		app.SetUpdatePlatform(true)
	}
	return nil
}

func PlatformRemove(name string) error {
	var (
		provisioner provision.ExtensibleProvisioner
		ok          bool
	)
	if provisioner, ok = Provisioner.(provision.ExtensibleProvisioner); !ok {
		return errors.New("Provisioner is not extensible")
	}
	if name == "" {
		return errors.New("Platform name is required!")
	}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	apps, _ := conn.Apps().Find(bson.M{"framework": name}).Count()
	if apps > 0 {
		return errors.New("Platform has apps. You should remove them before remove the platform.")
	}
	err = provisioner.PlatformRemove(name)
	if err != nil {
		log.Errorf("Failed to remove platform from provisioner: %s", err)
	}
	return conn.Platforms().Remove(bson.M{"_id": name})
}

func getPlatform(name string) (*Platform, error) {
	var p Platform
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	err = conn.Platforms().Find(bson.M{"_id": name}).One(&p)
	if err != nil {
		return nil, InvalidPlatformError{}
	}
	return &p, nil
}

type InvalidPlatformError struct{}

func (InvalidPlatformError) Error() string {
	return "Invalid platform"
}


text:
package org.netmelody.cieye.server.response.responder.test;

import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.jmock.Mockery;
import org.junit.Test;
import org.netmelody.cieye.server.response.CiEyeResponse;
import org.netmelody.cieye.server.response.responder.RedirectResponder;
import org.simpleframework.http.Request;
import org.simpleframework.http.Status;

import com.google.common.collect.ImmutableMap;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;

public final class RedirectResponderTest {

    private final Mockery context = new Mockery();
    private final Request request = context.mock(Request.class);

    private final RedirectResponder redirect = new RedirectResponder("myNewLocation");

    @Test public void
    createsAValidHttpMovedPermanentlyResponse() throws Exception {
        final CiEyeResponse response = redirect.respond(request);
        assertThat(response.status, is(Status.MOVED_PERMANENTLY));
        assertThat(response.additionalStringHeaders, includesHeader("Location", "myNewLocation"));
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private Matcher<ImmutableMap<String, String>> includesHeader(String key, String value) {
        return (Matcher)Matchers.hasEntry(key, value);
    }
}