diff --git a/source/ProtocolGenerator/CollectionExtensions.cs b/source/ProtocolGenerator/CollectionExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d901618c06777480ee25a90aa6769dd0a0a2615d
--- /dev/null
+++ b/source/ProtocolGenerator/CollectionExtensions.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+{
+    static class CollectionExtensions
+    {
+        public static bool CollectionEqual<T>(this ICollection<T> x, ICollection<T> y)
+        {
+            if (x == null || y == null)
+            {
+                return false;
+            }
+
+            if(x.Count != y.Count)
+            {
+                return false;
+            }
+
+            return x.All(e => y.Contains(e));
+        }
+
+        public static int GetCollectionHashCode<T>(this ICollection<T> x)
+        {
+            int hash = 17;
+
+            unchecked
+            {
+                foreach (var e in x)
+                {
+                    hash = hash * 23 + e.GetHashCode();
+                }
+            }
+
+            return hash;
+        }
+    }
+}
diff --git a/source/ProtocolGenerator/Command.cs b/source/ProtocolGenerator/Command.cs
index df3886ee795152cf0bfcc4c1d117f46b4f22b3ae..1707578d80217963d58d8b46ff13b1fd92c1fec0 100644
--- a/source/ProtocolGenerator/Command.cs
+++ b/source/ProtocolGenerator/Command.cs
@@ -1,4 +1,7 @@
-using System.Collections.ObjectModel;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text;
+using System.Linq;
 
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
@@ -46,5 +49,98 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             get;
             set;
         }
+
+        public override bool Equals(object obj)
+        {
+            var other = obj as Command;
+
+            if (other == null)
+            {
+                return false;
+            }
+
+            bool equals = base.Equals(obj);
+            equals &= this.Returns.SequenceEqual(other.Returns);
+            equals &= Property.Equals(this.Error, other.Error);
+            equals &= this.Handlers.CollectionEqual(other.Handlers);
+            equals &= this.Parameters.SequenceEqual(other.Parameters);
+            return equals;
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = base.GetHashCode();
+                hash = hash * 23 + this.Redirect.GetHashCode();
+
+                if (this.Error != null)
+                {
+                    hash = hash * 23 + this.Error.GetHashCode();
+                }
+
+                hash = hash * 23 + this.Handlers.GetCollectionHashCode();
+                hash = hash * 23 + this.Parameters.GetCollectionHashCode();
+                return hash;
+            }
+        }
+
+        public override string ToString()
+        {
+            StringBuilder name = new StringBuilder();
+
+            if (this.Returns.Count > 0)
+            {
+                name.Append("(");
+                bool isFirst = true;
+
+                foreach (var p in this.Returns)
+                {
+                    if (isFirst)
+                    {
+                        isFirst = false;
+                    }
+                    else
+                    {
+                        name.Append(", ");
+                    }
+
+                    name.Append(p.TypeName);
+                    name.Append(" ");
+                    name.Append(p.Name);
+                }
+
+                name.Append(") ");
+            }
+            else
+            {
+                name.Append("void ");
+            }
+
+            name.Append(this.Name);
+
+            name.Append("(");
+
+            bool isFirstParam = true;
+            foreach (var p in this.Parameters)
+            {
+                if (isFirstParam)
+                {
+                    isFirstParam = false;
+                }
+                else
+                {
+                    name.Append(", ");
+                }
+
+                name.Append(p.TypeName);
+                name.Append(" ");
+                name.Append(p.Name);
+            }
+
+            name.Append(")");
+
+            return name.ToString();
+        }
     }
 }
diff --git a/source/ProtocolGenerator/MasterDevs.ChromeDevTools.ProtocolGenerator.csproj b/source/ProtocolGenerator/MasterDevs.ChromeDevTools.ProtocolGenerator.csproj
index 4a58f80391dbf58d9e10dd4e977a50dc697846f2..a7206bdc45c6164a151ef9951dd4acead84a621f 100644
--- a/source/ProtocolGenerator/MasterDevs.ChromeDevTools.ProtocolGenerator.csproj
+++ b/source/ProtocolGenerator/MasterDevs.ChromeDevTools.ProtocolGenerator.csproj
@@ -50,14 +50,17 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="CollectionExtensions.cs" />
     <Compile Include="Command.cs" />
     <Compile Include="Domain.cs" />
     <Compile Include="Event.cs" />
+    <Compile Include="NameEqualityComparer.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Property.cs" />
     <Compile Include="Protocol.cs" />
     <Compile Include="ProtocolItem.cs" />
+    <Compile Include="ProtocolMerger.cs" />
     <Compile Include="Type.cs" />
     <Compile Include="Version.cs" />
   </ItemGroup>
diff --git a/source/ProtocolGenerator/NameEqualityComparer.cs b/source/ProtocolGenerator/NameEqualityComparer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..75287f9b470f9188e6efe7a6baeb0d8e4caa38d6
--- /dev/null
+++ b/source/ProtocolGenerator/NameEqualityComparer.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+{
+    class NameEqualityComparer : EqualityComparer<ProtocolItem>
+    {
+        public static NameEqualityComparer Instance
+        { get; } = new NameEqualityComparer();
+
+        public override bool Equals(ProtocolItem x, ProtocolItem y)
+        {
+            if (x == null || y == null)
+            {
+                return false;
+            }
+
+            return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
+        }
+
+        public override int GetHashCode(ProtocolItem obj)
+        {
+            if (obj == null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
+
+            return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name);
+        }
+    }
+}
diff --git a/source/ProtocolGenerator/Program.cs b/source/ProtocolGenerator/Program.cs
index 0b16d5fe7e0267808d66d16d60ea191d355ff2fb..4315bbb2f286f3313e16e0410e3b50eb6d095e1e 100644
--- a/source/ProtocolGenerator/Program.cs
+++ b/source/ProtocolGenerator/Program.cs
@@ -2,6 +2,7 @@
 using Newtonsoft.Json.Linq;
 using System;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.IO;
 using System.Linq;
 using System.Text;
@@ -23,20 +24,61 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
         private static Dictionary<string, List<string>> _DomainEvents = new Dictionary<string, List<string>>();
         private static Dictionary<string, string> _SimpleTypes = new Dictionary<string, string>();
 
-        private static Protocol LoadProtocol(string path)
+        private static Protocol LoadProtocol(string path, string alias)
         {
             string json = File.ReadAllText(path);
             JsonSerializerSettings settings = new JsonSerializerSettings();
             settings.MissingMemberHandling = MissingMemberHandling.Error;
             settings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
             Protocol p = JsonConvert.DeserializeObject<Protocol>(json, settings);
+            p.SourceFile = path;
+            p.Alias = alias;
+
+            foreach(var domain in p.Domains)
+            {
+                foreach(var command in domain.Commands)
+                {
+                    command.SupportedBy.Add(alias);
+                }
+
+                foreach(var @event in domain.Events)
+                {
+                    @event.SupportedBy.Add(alias);
+                }
+
+                foreach(var type in domain.Types)
+                {
+                    type.SupportedBy.Add(alias);
+                }
+            }
+
             return p;
         }
 
         private static void Main(string[] args)
         {
-            var filePath = "protocol.json";
-            var protocolObject = LoadProtocol(filePath);
+            Dictionary<string, string> protocolFiles = new Dictionary<string, string>();
+            protocolFiles.Add("Chrome-0.1", "Inspector-0.1.json");
+            protocolFiles.Add("Chrome-1.0", "Inspector-1.0.json");
+            protocolFiles.Add("Chrome-1.1", "Inspector-1.1.json");
+            protocolFiles.Add("Chrome-Tip", "protocol.json");
+            protocolFiles.Add("iOS-7.0", "Inspector-iOS-7.0.json");
+            protocolFiles.Add("iOS-8.0", "Inspector-iOS-8.0.json");
+            protocolFiles.Add("iOS-9.0", "Inspector-iOS-9.0.json");
+            protocolFiles.Add("iOS-9.3", "Inspector-iOS-9.3.json");
+
+            Collection<Protocol> protocols = new Collection<Protocol>();
+            
+            foreach(var protocolFile in protocolFiles)
+            {
+                protocols.Add(LoadProtocol(protocolFile.Value, protocolFile.Key));
+            }
+
+            Protocol protocolObject = new Protocol();
+            foreach(var protocol in protocols)
+            {
+                ProtocolMerger.Merge(protocol, protocolObject);
+            }
 
             var outputFolder = "OutputProtocol";
             if (args.Length > 0)
diff --git a/source/ProtocolGenerator/Protocol.cs b/source/ProtocolGenerator/Protocol.cs
index ae206ed86f9019041adf5f86c381dc4faa1895e3..f4d70de17c9fe68d1346230c90eae1bc68290e16 100644
--- a/source/ProtocolGenerator/Protocol.cs
+++ b/source/ProtocolGenerator/Protocol.cs
@@ -4,6 +4,12 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
     class Protocol
     {
+        public Protocol()
+        {
+            this.Compatible = new Collection<string>();
+            this.Domains = new Collection<Domain>();
+        }
+
         public Collection<string> Compatible
         {
             get;
@@ -21,5 +27,17 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             get;
             set;
         }
+
+        public string SourceFile
+        {
+            get;
+            set;
+        }
+
+        public string Alias
+        {
+            get;
+            set;
+        }
     }
 }
diff --git a/source/ProtocolGenerator/ProtocolItem.cs b/source/ProtocolGenerator/ProtocolItem.cs
index 61bae95f698cfcfecdfb486507599265f205e729..984fcda35bccb19566c2a63c7bbaed12d27a5a31 100644
--- a/source/ProtocolGenerator/ProtocolItem.cs
+++ b/source/ProtocolGenerator/ProtocolItem.cs
@@ -1,7 +1,16 @@
-namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
     abstract class ProtocolItem
     {
+        public ProtocolItem()
+        {
+            this.SupportedBy = new Collection<string>();
+        }
+
         public virtual string Description
         {
             get;
@@ -20,9 +29,64 @@
             set;
         }
 
+        public Collection<string> SupportedBy
+        {
+            get;
+        }
+
         public override string ToString()
         {
             return this.Name;
         }
+
+        public static bool Equals(ProtocolItem a, ProtocolItem b)
+        {
+            if (a == null && b == null)
+            {
+                return true;
+            }
+
+            if (a == null || b == null)
+            {
+                return false;
+            }
+
+            if (a.GetType() != b.GetType())
+            {
+                return false;
+            }
+
+            return a.Equals(b);
+        }
+
+        public override bool Equals(object obj)
+        {
+            // In the Equals method, we only include properties which would impact how 
+            // messages are serialized over the wire. E.g.: because the description does not
+            // impact this, but the name does, the description is ignored but the name is included.
+            var other = obj as ProtocolItem;
+
+            if (other == null)
+            {
+                return false;
+            }
+
+            return string.Equals(other.Name, this.Name, StringComparison.OrdinalIgnoreCase);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = 17;
+
+                if (this.Name != null)
+                {
+                    hash = hash * 23 + StringComparer.OrdinalIgnoreCase.GetHashCode(this.Name);
+                }
+
+                return hash;
+            }
+        }
     }
 }
diff --git a/source/ProtocolGenerator/ProtocolMerger.cs b/source/ProtocolGenerator/ProtocolMerger.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e823b6b552ef2ac1f2c11e654d99dc2e6c06d8d2
--- /dev/null
+++ b/source/ProtocolGenerator/ProtocolMerger.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+{
+    class ProtocolMerger
+    {
+        public static void Merge(Protocol source, Protocol target)
+        {
+            foreach (var domain in source.Domains)
+            {
+                if (!target.Domains.Contains(domain, NameEqualityComparer.Instance))
+                {
+                    target.Domains.Add(domain);
+                }
+                else
+                {
+                    Merge(domain, target.Domains.Single(t => NameEqualityComparer.Instance.Equals(domain, t)));
+                }
+            }
+        }
+
+        static void Merge(Domain source, Domain target)
+        {
+            foreach (var command in source.Commands)
+            {
+                if (!target.Commands.Contains(command, NameEqualityComparer.Instance))
+                {
+                    target.Commands.Add(command);
+                }
+                else
+                {
+                    var targetCommand = target.Commands.Single(t => NameEqualityComparer.Instance.Equals(command, t));
+
+                    if(!targetCommand.Equals(command))
+                    {
+                        Console.WriteLine($"{source.Name}:{command},{targetCommand}");
+                    }
+                    else
+                    {
+                        foreach (var v in command.SupportedBy)
+                        {
+                            targetCommand.SupportedBy.Add(v);
+                        }
+                    }
+                }
+            }
+
+            foreach (var @event in source.Events)
+            {
+                if (!target.Events.Contains(@event, NameEqualityComparer.Instance))
+                {
+                    target.Events.Add(@event);
+                }
+                else
+                {
+                }
+            }
+
+            foreach (var type in source.Types)
+            {
+                if (!target.Types.Contains(type, NameEqualityComparer.Instance))
+                {
+                    target.Types.Add(type);
+                }
+                else
+                {
+                }
+            }
+        }
+    }
+}
diff --git a/source/ProtocolGenerator/Type.cs b/source/ProtocolGenerator/Type.cs
index 79c70838ea69b7751fb0a745b6d40946404159a4..b10c7b9ba1bfd44b41a9151dead9e991a503f2eb 100644
--- a/source/ProtocolGenerator/Type.cs
+++ b/source/ProtocolGenerator/Type.cs
@@ -1,4 +1,6 @@
 using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
 
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
@@ -7,8 +9,8 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
     {
         public Type()
         {
-            this.Enum = new Collection<string>();
-            this.Properties = new Collection<Property>();
+            this.Enum = new HashSet<string>();
+            this.Properties = new HashSet<Property>();
         }
 
         [JsonProperty(PropertyName = "Id")]
@@ -18,20 +20,20 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             set;
         }
 
-        [JsonProperty(PropertyName ="type")]
+        [JsonProperty(PropertyName = "type")]
         public string Kind
         {
             get;
             set;
         }
 
-        public Collection<string> Enum
+        public HashSet<string> Enum
         {
             get;
             set;
         }
 
-        public Collection<Property> Properties
+        public HashSet<Property> Properties
         {
             get;
             set;
@@ -61,5 +63,77 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             get;
             set;
         }
+
+        public string TypeName
+        {
+            get
+            {
+                if (this.TypeReference != null)
+                {
+                    return this.TypeReference;
+                }
+                else if (this.Items != null)
+                {
+                    return this.Items.Name + "[]";
+                }
+                else if(this.Kind != null && this.Kind != "object")
+                {
+                    return this.Kind;
+                }
+                else
+                {
+                    return this.Name;
+                }
+            }
+        }
+        public override bool Equals(object obj)
+        {
+            var other = obj as Type;
+
+            if (other == null)
+            {
+                return false;
+            }
+
+            return base.Equals(obj)
+                && string.Equals(this.Kind, other.Kind, StringComparison.OrdinalIgnoreCase)
+                && this.Enum.SetEquals(other.Enum)
+                && this.Properties.SetEquals(other.Properties)
+                && Type.Equals(this.Items, other.Items)
+                && this.MinItems == other.MinItems
+                && this.MaxItems == other.MaxItems
+                && string.Equals(this.TypeReference, other.TypeReference, StringComparison.OrdinalIgnoreCase);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = base.GetHashCode();
+
+                if (this.Kind != null)
+                {
+                    hash = hash * 23 + StringComparer.OrdinalIgnoreCase.GetHashCode(this.Kind);
+                }
+
+                hash = hash * 23 + this.Enum.GetCollectionHashCode();
+                hash = hash * 23 + this.Properties.GetCollectionHashCode();
+
+                if (this.Items != null)
+                {
+                    hash = hash * 23 + this.Items.GetHashCode();
+                }
+
+                hash = hash * 23 + this.MinItems.GetHashCode();
+                hash = hash * 23 + this.MaxItems.GetHashCode();
+
+                if (this.TypeReference != null)
+                {
+                    hash = hash * 23 + StringComparer.OrdinalIgnoreCase.GetHashCode(this.TypeReference);
+                }
+
+                return hash;
+            }
+        }
     }
 }