private static void PatchForObject(JsonElement orig, JsonElement mod, List <PatchOperation> patch, JsonPointer path)
        {
            var origNames = orig.EnumerateObject().Select(x => x.Name).ToArray();
            var modNames  = mod.EnumerateObject().Select(x => x.Name).ToArray();

            foreach (var k in origNames.Except(modNames))
            {
                patch.Add(PatchOperation.Remove(path.Combine(k)));
            }

            foreach (var k in modNames.Except(origNames))
            {
                var prop = mod.EnumerateObject().First(p => p.NameEquals(k));
                patch.Add(PatchOperation.Add(path.Combine(k), prop.Value));
            }

            foreach (var k in origNames.Intersect(modNames))
            {
                var origProp = orig.EnumerateObject().First(p => p.NameEquals(k));
                var modProp  = mod.EnumerateObject().First(p => p.NameEquals(k));

                if (origProp.Value.ValueKind != modProp.Value.ValueKind)
                {
                    patch.Add(PatchOperation.Replace(JsonPointer.Parse(path + modProp.Name), modProp.Value));
                }
                else if (!string.Equals(origProp.Value.ToString(), modProp.Value.ToString()))                 // TODO
                {
                    if (origProp.Value.ValueKind == JsonValueKind.Object)
                    {
                        PatchForObject(origProp.Value, modProp.Value, patch, path.Combine(modProp.Name));
                    }
                    else if (origProp.Value.ValueKind == JsonValueKind.Array)
                    {
                        PatchForArray(origProp.Value, modProp.Value, patch, path.Combine(modProp.Name));
                    }
                    else
                    {
                        patch.Add(PatchOperation.Replace(path.Combine(modProp.Name), modProp.Value));
                    }
                }
            }
        }
        private static void PatchForArray(JsonElement orig, JsonElement mod, List <PatchOperation> patch, JsonPointer path)
        {
            for (int i = 0; i < Math.Max(orig.GetArrayLength(), mod.GetArrayLength()); i++)
            {
                var ui = (uint)i;
                if (i >= orig.GetArrayLength())
                {
                    patch.Add(PatchOperation.Add(path.Combine(ui), mod[i]));
                    continue;
                }

                if (i >= mod.GetArrayLength())
                {
                    patch.Add(PatchOperation.Remove(path.Combine(ui)));
                    continue;
                }

                var origObject = orig[i];
                var modObject  = mod[i];

                if (origObject.ValueKind != modObject.ValueKind)
                {
                    patch.Add(PatchOperation.Replace(path.Combine("/" + i), modObject));
                }
                else if (!string.Equals(origObject.ToString(), modObject.ToString()))                 // TODO
                {
                    if (origObject.ValueKind == JsonValueKind.Object)
                    {
                        PatchForObject(origObject, modObject, patch, path.Combine(ui));
                    }
                    else if (origObject.ValueKind == JsonValueKind.Array)
                    {
                        PatchForArray(origObject, modObject, patch, path.Combine(ui));
                    }
                    else
                    {
                        patch.Add(PatchOperation.Replace(path.Combine(ui), modObject));
                    }
                }
            }
        }