/// <summary>
        /// Exports the data.
        /// </summary>
        /// <param name="source">The source output to export.</param>
        /// <param name="destination">The output destination.</param>
        public override void Export(EventOutput source, StreamWriter destination)
        {
            var threads = source.Select(e => e.Tid).Distinct().ToArray();
            var types = source.Select(e => e.Type)
                .Distinct()
                .Where(t => t.EndsWith("perf") || t == "ipc" || t == "time")
                .ToArray();
            var min = new DateTime(source.Select(e => e.Time).Min());
            var max = new DateTime(source.Select(e => e.Time).Max());

            // The output and global values
            var output = new JsonOutput();
            output.Name = source.ProcessName;

            foreach(var tid in threads)
            {
                var thread = new JsonThread(tid);
                var runtime = new List<double>();
                foreach(var type in types)
                {
                    var measure = new JsonMeasure(type.Replace("perf", String.Empty).ToUpper());
                    foreach (var timeGroup in source.GroupBy(e => e.Time))
                    {
                        // Get the values
                        var values = timeGroup
                            .Where(t => t.Tid == tid && t.Type == type)
                            .Select(e => e.Value)
                            .ToArray();

                        var average = values.Length == 0 ? 0 : values.Average();
                        if (type.EndsWith("perf") || type == "ipc")
                            average *= 100;

                        if (type == "time")
                            runtime.Add(average);
                        else
                            measure.Data.Add(Math.Min(Math.Round(average, 2), 100));
                    }

                    // Add the thread to the output
                    if(measure.Data.Count > 0)
                        thread.Measures.Add(measure);
                }

                // Calculate the lifetime
                thread.RuntimeAvg = runtime.Average() * 100;

                // Add the thread to the output
                output.Threads.Add(thread);
            }

            // Only threads of the process we monitor
            var ownThreads = source.Where(t => t.Pid != 0).ToArray();
            var summableTypes = source
                .Select(e => e.Type)
                .Distinct()
                .Where(t => !t.EndsWith("perf") && !t.EndsWith("ipc") && !t.EndsWith("time"))
                .ToArray();

            // Various variables
            output.Info["duration"] = (max - min).TotalMilliseconds;
            output.Info["frames"] = output.Threads.First().Measures.First().Data.Count;

            foreach (var type in summableTypes)
            {
                output.Info[type] = ownThreads
                    .Where(t => t.Type == type)
                    .Select(t => t.Value)
                    .Sum();
            }

            // Sort by runtime and remove the '0' thread
            output.Threads = output.Threads
                .Where(t => t.Id != "0")
                .OrderBy(t => t.RuntimeAvg)
                .ToList();

            // Write
            destination.WriteLine(JsonConvert.SerializeObject(output));
        }