{"action":"created","comment":{"url":"https://api.github.com/repos/ppy/osu-framework/pulls/comments/281906331","pull_request_review_id":234842643,"id":281906331,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDI4MTkwNjMzMQ==","diff_hunk":"@@ -0,0 +1,326 @@\n+// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.\n+// See the LICENCE file in the repository root for full licence text.\n+\n+using System;\n+using System.Collections.Generic;\n+using System.Linq;\n+using osu.Framework.Input;\n+using osu.Framework.Input.Events;\n+using osuTK;\n+\n+namespace osu.Framework.Graphics.Containers\n+{\n+    /// <summary>\n+    /// A list container that enables its children to be rearranged via dragging.\n+    /// </summary>\n+    /// <typeparam name=\"T\">The type of <see cref=\"RearrangeableListItem\"/>.</typeparam>\n+    public abstract class RearrangeableListContainer<T> : CompositeDrawable where T : RearrangeableListItem\n+    {\n+        /// <summary>\n+        /// The spacing between individual elements. Default is <see cref=\"Vector2.Zero\"/>.\n+        /// </summary>\n+        public Vector2 Spacing\n+        {\n+            get => ListContainer.Spacing;\n+            set => ListContainer.Spacing = value;\n+        }\n+\n+        /// <summary>\n+        /// This event is fired after a rearrangement has occurred via dragging.\n+        /// </summary>\n+        public event Action Rearranged;\n+\n+        /// <summary>\n+        /// Children as they are currently arranged.\n+        /// </summary>\n+        public IEnumerable<T> ArrangedItems => ListContainer.FlowingChildren.Cast<DrawableRearrangeableListItem>().Select(i => i.Model);\n+\n+        private int maxLayoutPosition;\n+        protected readonly ListScrollContainer ScrollContainer;\n+        protected readonly ListFillFlowContainer ListContainer;\n+\n+        /// <summary>\n+        /// Creates a rearrangeable list container.\n+        /// </summary>\n+        protected RearrangeableListContainer()\n+        {\n+            RelativeSizeAxes = Axes.Both;\n+            InternalChild = ScrollContainer = CreateListScrollContainer(ListContainer = CreateListFillFlowContainer());\n+            ListContainer.Rearranged += OnRearrange;\n+        }\n+\n+        /// <summary>\n+        /// Adds a child to the end of this list.\n+        /// </summary>\n+        public void AddItem(T item)\n+        {\n+            var drawable = CreateDrawable(item);\n+            drawable.RemovalRequested += RemoveItem;\n+            ListContainer.Add(drawable);\n+            ListContainer.SetLayoutPosition(drawable, maxLayoutPosition++);\n+        }\n+\n+        /// <summary>\n+        /// Removes a child from this container.\n+        /// </summary>\n+        public void RemoveItem(DrawableRearrangeableListItem item) => ListContainer.Remove(item);\n+\n+        /// <summary>\n+        /// Removes all <see cref=\"Container{T}.Children\"/> from this container.\n+        /// </summary>\n+        public void Clear()\n+        {\n+            ListContainer.Clear();\n+            // Explicitly reset scroll position here so that ScrollContainer doesn't retain our\n+            // scroll position if we quickly add new items after calling a Clear().\n+            ScrollContainer.ScrollToStart();\n+        }\n+\n+        protected virtual void OnRearrange() => Rearranged?.Invoke();\n+\n+        /// <summary>\n+        /// Allows subclasses to customise the <see cref=\"ListFillFlowContainer\"/>.\n+        /// </summary>\n+        protected virtual ListFillFlowContainer CreateListFillFlowContainer() =>\n+            new ListFillFlowContainer\n+            {\n+                RelativeSizeAxes = Axes.X,\n+                AutoSizeAxes = Axes.Y,\n+                LayoutDuration = 160,\n+                LayoutEasing = Easing.OutQuint,\n+                Direction = FillDirection.Vertical,\n+                Spacing = new Vector2(1),\n+            };\n+\n+        /// <summary>\n+        /// Allows subclasses to customise the <see cref=\"ListScrollContainer\"/>.\n+        /// </summary>\n+        protected virtual ListScrollContainer CreateListScrollContainer(ListFillFlowContainer flowContainer) => new ListScrollContainer(flowContainer);\n+\n+        protected abstract DrawableRearrangeableListItem CreateDrawable(T item);\n+\n+        #region ListScrollContainer\n+\n+        protected class ListScrollContainer : ScrollContainer<ListFillFlowContainer>\n+        {\n+            private const float scroll_trigger_distance = 10;\n+            private const double max_power = 50;\n+            private const double exp_base = 1.05;\n+            private bool autoScrolling;\n+            private double scrollSpeed;\n+\n+            public ListScrollContainer(ListFillFlowContainer flowContainer)\n+            {\n+                RelativeSizeAxes = Axes.Both;\n+                ScrollbarOverlapsContent = false;\n+                Padding = new MarginPadding(5);\n+\n+                Child = flowContainer;\n+\n+                flowContainer.DragStart += _ => autoScrolling = true;\n+                flowContainer.Drag += updateDragPosition;\n+                flowContainer.DragEnd += _ =>\n+                {\n+                    autoScrolling = false;\n+                    scrollSpeed = 0;\n+                };\n+            }\n+\n+            protected override void Update()\n+            {\n+                base.Update();\n+\n+                if (autoScrolling)\n+                    updateScrollPosition();\n+            }\n+\n+            private void updateDragPosition(DragEvent dragEvent)\n+            {\n+                var localPos = ToLocalSpace(dragEvent.ScreenSpaceMousePosition);\n+\n+                if (localPos.Y < scroll_trigger_distance)\n+                {\n+                    var power = Math.Min(max_power, Math.Abs(scroll_trigger_distance - localPos.Y));\n+                    scrollSpeed = -(float)Math.Pow(exp_base, power);\n+                }\n+                else if (localPos.Y > DrawHeight - scroll_trigger_distance)\n+                {\n+                    var power = Math.Min(max_power, Math.Abs(DrawHeight - scroll_trigger_distance - localPos.Y));\n+                    scrollSpeed = (float)Math.Pow(exp_base, power);\n+                }\n+                else\n+                {\n+                    scrollSpeed = 0;\n+                }\n+            }\n+\n+            private void updateScrollPosition()\n+            {\n+                if ((scrollSpeed < 0 && Current > 0) || (scrollSpeed > 0 && !IsScrolledToEnd()))\n+                    ScrollBy((float)scrollSpeed);\n+            }\n+        }\n+\n+        #endregion\n+\n+        #region ListFillFlowContainer\n+\n+        protected class ListFillFlowContainer : FillFlowContainer<DrawableRearrangeableListItem>, IRequireHighFrequencyMousePosition\n+        {\n+            /// <summary>\n+            /// This event is fired after a rearrangement has occurred via dragging.\n+            /// </summary>\n+            public event Action Rearranged;\n+\n+            /// <summary>\n+            /// This event is fired when a drag start occurs.\n+            /// </summary>\n+            public event Action<DragStartEvent> DragStart;\n+\n+            /// <summary>\n+            /// This event is fired when a drag occurs.\n+            /// </summary>\n+            public event Action<DragEvent> Drag;\n+\n+            /// <summary>\n+            /// This event is fired when a drag end occurs.\n+            /// </summary>\n+            public event Action<DragEndEvent> DragEnd;\n+\n+            private DrawableRearrangeableListItem currentlyDraggedItem;\n+            private Vector2 nativeDragPosition;\n+            private readonly List<Drawable> cachedFlowingChildren = new List<Drawable>();\n+\n+            protected override bool OnDragStart(DragStartEvent e)\n+            {\n+                nativeDragPosition = e.ScreenSpaceMousePosition;\n+                currentlyDraggedItem = this.FirstOrDefault(d => d.IsBeingDragged);\n+\n+                cachedFlowingChildren.AddRange(FlowingChildren);\n+\n+                if (currentlyDraggedItem != null)\n+                    DragStart?.Invoke(e);\n+\n+                return currentlyDraggedItem != null || base.OnDragStart(e);\n+            }\n+\n+            protected override bool OnDrag(DragEvent e)\n+            {\n+                nativeDragPosition = e.ScreenSpaceMousePosition;\n+\n+                if (currentlyDraggedItem != null)\n+                    Drag?.Invoke(e);\n+\n+                return currentlyDraggedItem != null || base.OnDrag(e);\n+            }\n+\n+            protected override bool OnDragEnd(DragEndEvent e)\n+            {\n+                nativeDragPosition = e.ScreenSpaceMousePosition;\n+\n+                cachedFlowingChildren.Clear();\n+\n+                if (currentlyDraggedItem != null)\n+                    DragEnd?.Invoke(e);\n+\n+                var handled = currentlyDraggedItem != null || base.OnDragEnd(e);\n+                currentlyDraggedItem = null;\n+\n+                return handled;\n+            }\n+\n+            protected override void Update()\n+            {\n+                base.Update();\n+\n+                if (currentlyDraggedItem != null)\n+                    updateDragPosition();\n+            }\n+\n+            private void updateDragPosition()\n+            {\n+                var itemsPos = ToLocalSpace(nativeDragPosition);\n+                int srcIndex = (int)GetLayoutPosition(currentlyDraggedItem);\n+\n+                // Find the last item with position < mouse position. Note we can't directly use\n+                // the item positions as they are being transformed\n+                float heightAccumulator = 0;\n+                int dstIndex = 0;\n+                for (; dstIndex < Count; dstIndex++)\n+                {\n+                    // Using BoundingBox here takes care of scale, paddings, etc...\n+                    heightAccumulator += this[dstIndex].BoundingBox.Height + Spacing.Y;\n+                    if (heightAccumulator - Spacing.Y / 2 > itemsPos.Y)\n+                        break;\n+                }\n+\n+                dstIndex = MathHelper.Clamp(dstIndex, 0, Count - 1);\n+\n+                if (srcIndex == dstIndex)\n+                    return;\n+\n+                cachedFlowingChildren.Remove(currentlyDraggedItem);\n+\n+                if (srcIndex < dstIndex - 1)\n+                    dstIndex--;\n+\n+                cachedFlowingChildren.Insert(dstIndex, currentlyDraggedItem);\n+\n+                for (int i = 0; i < cachedFlowingChildren.Count; i++)\n+                    SetLayoutPosition(cachedFlowingChildren[i], i);\n+\n+                Rearranged?.Invoke();\n+            }\n+        }\n+\n+        #endregion\n+\n+        #region DrawableRearrangeableListItem\n+\n+        public abstract class DrawableRearrangeableListItem : CompositeDrawable\n+        {\n+            /// <summary>\n+            /// This event is fired when a removal is requested. e.g. on item removal.\n+            /// </summary>\n+            public event Action<DrawableRearrangeableListItem> RemovalRequested;\n+\n+            /// <summary>\n+            /// Returns whether the item is currently being dragged.\n+            /// </summary>\n+            public bool IsBeingDragged { get; private set; }\n+\n+            /// <summary>\n+            /// Returns whether the item is currently able to be dragged.\n+            /// </summary>\n+            protected virtual bool IsDraggableAt(Vector2 screenSpacePos) => true;","path":"osu.Framework/Graphics/Containers/RearrangeableListContainer.cs","position":295,"original_position":295,"commit_id":"ce963dad83256802736bccd7b13f41873b4841c9","original_commit_id":"ce963dad83256802736bccd7b13f41873b4841c9","user":{"login":"smoogipoo","id":1329837,"node_id":"MDQ6VXNlcjEzMjk4Mzc=","avatar_url":"https://avatars0.githubusercontent.com/u/1329837?v=4","gravatar_id":"","url":"https://api.github.com/users/smoogipoo","html_url":"https://github.com/smoogipoo","followers_url":"https://api.github.com/users/smoogipoo/followers","following_url":"https://api.github.com/users/smoogipoo/following{/other_user}","gists_url":"https://api.github.com/users/smoogipoo/gists{/gist_id}","starred_url":"https://api.github.com/users/smoogipoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smoogipoo/subscriptions","organizations_url":"https://api.github.com/users/smoogipoo/orgs","repos_url":"https://api.github.com/users/smoogipoo/repos","events_url":"https://api.github.com/users/smoogipoo/events{/privacy}","received_events_url":"https://api.github.com/users/smoogipoo/received_events","type":"User","site_admin":false},"body":"Methods should be below ctor at all times (incl. the one below this).","created_at":"2019-05-08T04:02:45Z","updated_at":"2019-05-08T04:06:59Z","html_url":"https://github.com/ppy/osu-framework/pull/2372#discussion_r281906331","pull_request_url":"https://api.github.com/repos/ppy/osu-framework/pulls/2372","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/ppy/osu-framework/pulls/comments/281906331"},"html":{"href":"https://github.com/ppy/osu-framework/pull/2372#discussion_r281906331"},"pull_request":{"href":"https://api.github.com/repos/ppy/osu-framework/pulls/2372"}}},"pull_request":{"url":"https://api.github.com/repos/ppy/osu-framework/pulls/2372","id":273071286,"node_id":"MDExOlB1bGxSZXF1ZXN0MjczMDcxMjg2","html_url":"https://github.com/ppy/osu-framework/pull/2372","diff_url":"https://github.com/ppy/osu-framework/pull/2372.diff","patch_url":"https://github.com/ppy/osu-framework/pull/2372.patch","issue_url":"https://api.github.com/repos/ppy/osu-framework/issues/2372","number":2372,"state":"open","locked":false,"title":"Implement a RearrangeableListContainer component","user":{"login":"nekodex","id":272140,"node_id":"MDQ6VXNlcjI3MjE0MA==","avatar_url":"https://avatars0.githubusercontent.com/u/272140?v=4","gravatar_id":"","url":"https://api.github.com/users/nekodex","html_url":"https://github.com/nekodex","followers_url":"https://api.github.com/users/nekodex/followers","following_url":"https://api.github.com/users/nekodex/following{/other_user}","gists_url":"https://api.github.com/users/nekodex/gists{/gist_id}","starred_url":"https://api.github.com/users/nekodex/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nekodex/subscriptions","organizations_url":"https://api.github.com/users/nekodex/orgs","repos_url":"https://api.github.com/users/nekodex/repos","events_url":"https://api.github.com/users/nekodex/events{/privacy}","received_events_url":"https://api.github.com/users/nekodex/received_events","type":"User","site_admin":false},"body":"Adds a new abstract component plus basic implementation of a 'rearrangeable list' that will be serve as the base class for sortable lists.\r\n\r\nThe intention is to use this to fix the music playlist component in lazer and for the implementation of the multiplayer beatmap playlist UI.\r\n\r\nSupports drag handles...\r\n![](https://puu.sh/Dj8Jq/6ca7752770.png)\r\nor without...\r\n![](https://puu.sh/Dj8JH/536fa667f7.png)\r\n\r\nIncluding a basic text list implementation:\r\n![textlist](https://user-images.githubusercontent.com/272140/56653062-ce77e600-66c7-11e9-9c76-b3f0fbc25d50.gif)","created_at":"2019-04-24T10:35:11Z","updated_at":"2019-05-08T04:06:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dd955aec6df571cc3930339a2f7c17e7de22fd49","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/ppy/osu-framework/pulls/2372/commits","review_comments_url":"https://api.github.com/repos/ppy/osu-framework/pulls/2372/comments","review_comment_url":"https://api.github.com/repos/ppy/osu-framework/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ppy/osu-framework/issues/2372/comments","statuses_url":"https://api.github.com/repos/ppy/osu-framework/statuses/ce963dad83256802736bccd7b13f41873b4841c9","head":{"label":"nekodex:rearrangeable-list-container-new","ref":"rearrangeable-list-container-new","sha":"ce963dad83256802736bccd7b13f41873b4841c9","user":{"login":"nekodex","id":272140,"node_id":"MDQ6VXNlcjI3MjE0MA==","avatar_url":"https://avatars0.githubusercontent.com/u/272140?v=4","gravatar_id":"","url":"https://api.github.com/users/nekodex","html_url":"https://github.com/nekodex","followers_url":"https://api.github.com/users/nekodex/followers","following_url":"https://api.github.com/users/nekodex/following{/other_user}","gists_url":"https://api.github.com/users/nekodex/gists{/gist_id}","starred_url":"https://api.github.com/users/nekodex/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nekodex/subscriptions","organizations_url":"https://api.github.com/users/nekodex/orgs","repos_url":"https://api.github.com/users/nekodex/repos","events_url":"https://api.github.com/users/nekodex/events{/privacy}","received_events_url":"https://api.github.com/users/nekodex/received_events","type":"User","site_admin":false},"repo":{"id":171820139,"node_id":"MDEwOlJlcG9zaXRvcnkxNzE4MjAxMzk=","name":"osu-framework","full_name":"nekodex/osu-framework","private":false,"owner":{"login":"nekodex","id":272140,"node_id":"MDQ6VXNlcjI3MjE0MA==","avatar_url":"https://avatars0.githubusercontent.com/u/272140?v=4","gravatar_id":"","url":"https://api.github.com/users/nekodex","html_url":"https://github.com/nekodex","followers_url":"https://api.github.com/users/nekodex/followers","following_url":"https://api.github.com/users/nekodex/following{/other_user}","gists_url":"https://api.github.com/users/nekodex/gists{/gist_id}","starred_url":"https://api.github.com/users/nekodex/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nekodex/subscriptions","organizations_url":"https://api.github.com/users/nekodex/orgs","repos_url":"https://api.github.com/users/nekodex/repos","events_url":"https://api.github.com/users/nekodex/events{/privacy}","received_events_url":"https://api.github.com/users/nekodex/received_events","type":"User","site_admin":false},"html_url":"https://github.com/nekodex/osu-framework","description":"A game framework written with osu! in mind.","fork":true,"url":"https://api.github.com/repos/nekodex/osu-framework","forks_url":"https://api.github.com/repos/nekodex/osu-framework/forks","keys_url":"https://api.github.com/repos/nekodex/osu-framework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nekodex/osu-framework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nekodex/osu-framework/teams","hooks_url":"https://api.github.com/repos/nekodex/osu-framework/hooks","issue_events_url":"https://api.github.com/repos/nekodex/osu-framework/issues/events{/number}","events_url":"https://api.github.com/repos/nekodex/osu-framework/events","assignees_url":"https://api.github.com/repos/nekodex/osu-framework/assignees{/user}","branches_url":"https://api.github.com/repos/nekodex/osu-framework/branches{/branch}","tags_url":"https://api.github.com/repos/nekodex/osu-framework/tags","blobs_url":"https://api.github.com/repos/nekodex/osu-framework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nekodex/osu-framework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nekodex/osu-framework/git/refs{/sha}","trees_url":"https://api.github.com/repos/nekodex/osu-framework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nekodex/osu-framework/statuses/{sha}","languages_url":"https://api.github.com/repos/nekodex/osu-framework/languages","stargazers_url":"https://api.github.com/repos/nekodex/osu-framework/stargazers","contributors_url":"https://api.github.com/repos/nekodex/osu-framework/contributors","subscribers_url":"https://api.github.com/repos/nekodex/osu-framework/subscribers","subscription_url":"https://api.github.com/repos/nekodex/osu-framework/subscription","commits_url":"https://api.github.com/repos/nekodex/osu-framework/commits{/sha}","git_commits_url":"https://api.github.com/repos/nekodex/osu-framework/git/commits{/sha}","comments_url":"https://api.github.com/repos/nekodex/osu-framework/comments{/number}","issue_comment_url":"https://api.github.com/repos/nekodex/osu-framework/issues/comments{/number}","contents_url":"https://api.github.com/repos/nekodex/osu-framework/contents/{+path}","compare_url":"https://api.github.com/repos/nekodex/osu-framework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nekodex/osu-framework/merges","archive_url":"https://api.github.com/repos/nekodex/osu-framework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nekodex/osu-framework/downloads","issues_url":"https://api.github.com/repos/nekodex/osu-framework/issues{/number}","pulls_url":"https://api.github.com/repos/nekodex/osu-framework/pulls{/number}","milestones_url":"https://api.github.com/repos/nekodex/osu-framework/milestones{/number}","notifications_url":"https://api.github.com/repos/nekodex/osu-framework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nekodex/osu-framework/labels{/name}","releases_url":"https://api.github.com/repos/nekodex/osu-framework/releases{/id}","deployments_url":"https://api.github.com/repos/nekodex/osu-framework/deployments","created_at":"2019-02-21T07:15:05Z","updated_at":"2019-04-18T08:56:01Z","pushed_at":"2019-04-30T10:58:16Z","git_url":"git://github.com/nekodex/osu-framework.git","ssh_url":"git@github.com:nekodex/osu-framework.git","clone_url":"https://github.com/nekodex/osu-framework.git","svn_url":"https://github.com/nekodex/osu-framework","homepage":"","size":78457,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"ppy:master","ref":"master","sha":"45deecbb7a706654319aba98059ee5169f34c3ab","user":{"login":"ppy","id":995763,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5NTc2Mw==","avatar_url":"https://avatars1.githubusercontent.com/u/995763?v=4","gravatar_id":"","url":"https://api.github.com/users/ppy","html_url":"https://github.com/ppy","followers_url":"https://api.github.com/users/ppy/followers","following_url":"https://api.github.com/users/ppy/following{/other_user}","gists_url":"https://api.github.com/users/ppy/gists{/gist_id}","starred_url":"https://api.github.com/users/ppy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ppy/subscriptions","organizations_url":"https://api.github.com/users/ppy/orgs","repos_url":"https://api.github.com/users/ppy/repos","events_url":"https://api.github.com/users/ppy/events{/privacy}","received_events_url":"https://api.github.com/users/ppy/received_events","type":"Organization","site_admin":false},"repo":{"id":66614524,"node_id":"MDEwOlJlcG9zaXRvcnk2NjYxNDUyNA==","name":"osu-framework","full_name":"ppy/osu-framework","private":false,"owner":{"login":"ppy","id":995763,"node_id":"MDEyOk9yZ2FuaXphdGlvbjk5NTc2Mw==","avatar_url":"https://avatars1.githubusercontent.com/u/995763?v=4","gravatar_id":"","url":"https://api.github.com/users/ppy","html_url":"https://github.com/ppy","followers_url":"https://api.github.com/users/ppy/followers","following_url":"https://api.github.com/users/ppy/following{/other_user}","gists_url":"https://api.github.com/users/ppy/gists{/gist_id}","starred_url":"https://api.github.com/users/ppy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ppy/subscriptions","organizations_url":"https://api.github.com/users/ppy/orgs","repos_url":"https://api.github.com/users/ppy/repos","events_url":"https://api.github.com/users/ppy/events{/privacy}","received_events_url":"https://api.github.com/users/ppy/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/ppy/osu-framework","description":"A game framework written with osu! in mind.","fork":false,"url":"https://api.github.com/repos/ppy/osu-framework","forks_url":"https://api.github.com/repos/ppy/osu-framework/forks","keys_url":"https://api.github.com/repos/ppy/osu-framework/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ppy/osu-framework/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ppy/osu-framework/teams","hooks_url":"https://api.github.com/repos/ppy/osu-framework/hooks","issue_events_url":"https://api.github.com/repos/ppy/osu-framework/issues/events{/number}","events_url":"https://api.github.com/repos/ppy/osu-framework/events","assignees_url":"https://api.github.com/repos/ppy/osu-framework/assignees{/user}","branches_url":"https://api.github.com/repos/ppy/osu-framework/branches{/branch}","tags_url":"https://api.github.com/repos/ppy/osu-framework/tags","blobs_url":"https://api.github.com/repos/ppy/osu-framework/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ppy/osu-framework/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ppy/osu-framework/git/refs{/sha}","trees_url":"https://api.github.com/repos/ppy/osu-framework/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ppy/osu-framework/statuses/{sha}","languages_url":"https://api.github.com/repos/ppy/osu-framework/languages","stargazers_url":"https://api.github.com/repos/ppy/osu-framework/stargazers","contributors_url":"https://api.github.com/repos/ppy/osu-framework/contributors","subscribers_url":"https://api.github.com/repos/ppy/osu-framework/subscribers","subscription_url":"https://api.github.com/repos/ppy/osu-framework/subscription","commits_url":"https://api.github.com/repos/ppy/osu-framework/commits{/sha}","git_commits_url":"https://api.github.com/repos/ppy/osu-framework/git/commits{/sha}","comments_url":"https://api.github.com/repos/ppy/osu-framework/comments{/number}","issue_comment_url":"https://api.github.com/repos/ppy/osu-framework/issues/comments{/number}","contents_url":"https://api.github.com/repos/ppy/osu-framework/contents/{+path}","compare_url":"https://api.github.com/repos/ppy/osu-framework/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ppy/osu-framework/merges","archive_url":"https://api.github.com/repos/ppy/osu-framework/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ppy/osu-framework/downloads","issues_url":"https://api.github.com/repos/ppy/osu-framework/issues{/number}","pulls_url":"https://api.github.com/repos/ppy/osu-framework/pulls{/number}","milestones_url":"https://api.github.com/repos/ppy/osu-framework/milestones{/number}","notifications_url":"https://api.github.com/repos/ppy/osu-framework/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ppy/osu-framework/labels{/name}","releases_url":"https://api.github.com/repos/ppy/osu-framework/releases{/id}","deployments_url":"https://api.github.com/repos/ppy/osu-framework/deployments","created_at":"2016-08-26T03:45:35Z","updated_at":"2019-05-08T02:24:00Z","pushed_at":"2019-05-07T19:15:23Z","git_url":"git://github.com/ppy/osu-framework.git","ssh_url":"git@github.com:ppy/osu-framework.git","clone_url":"https://github.com/ppy/osu-framework.git","svn_url":"https://github.com/ppy/osu-framework","homepage":"","size":78350,"stargazers_count":368,"watchers_count":368,"language":"C#","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":163,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":148,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":163,"open_issues":148,"watchers":368,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ppy/osu-framework/pulls/2372"},"html":{"href":"https://github.com/ppy/osu-framework/pull/2372"},"issue":{"href":"https://api.github.com/repos/ppy/osu-framework/issues/2372"},"comments":{"href":"https://api.github.com/repos/ppy/osu-framework/issues/2372/comments"},"review_comments":{"href":"https://api.github.com/repos/ppy/osu-framework/pulls/2372/comments"},"review_comment":{"href":"https://api.github.com/repos/ppy/osu-framework/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ppy/osu-framework/pulls/2372/commits"},"statuses":{"href":"https://api.github.com/repos/ppy/osu-framework/statuses/ce963dad83256802736bccd7b13f41873b4841c9"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"smoogipoo"}}