{"action":"created","comment":{"url":"https://api.github.com/repos/wso2/carbon-kernel/pulls/comments/209159795","pull_request_review_id":145120734,"id":209159795,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwOTE1OTc5NQ==","diff_hunk":"@@ -2639,6 +2650,458 @@ public int getTenantId() throws UserStoreException {\n         return values.toArray(new String[values.size()]);\n     }\n \n+    /**\n+     * This method support multi-attribute search filters for user(s).\n+     *\n+     * @param condition   Validated Condiction tree\n+     * @param profileName Default profile name\n+     * @param limit       The number of entries to return in a page.\n+     * @param offset      Start index.\n+     * @param sortBy      Sort according to the given attribute name.\n+     * @param sortOrder   Sorting order.\n+     * @return A non-null PaginatedSearchResult instance. Typically contains user names with pagination.\n+     * @throws UserStoreException If an UserStoreException is encountered\n+     *                            while searching for users in a given condition.\n+     */\n+    protected PaginatedSearchResult doGetUserList(Condition condition, String profileName, int limit, int offset,\n+                                                  String sortBy, String sortOrder) throws UserStoreException {\n+\n+        boolean isGroupFiltering = false;\n+        boolean isMultiGroupFiltering = false;\n+        boolean isUsernameFiltering = false;\n+        boolean isClaimFiltering = false;\n+        PaginatedSearchResult result = new PaginatedSearchResult();\n+        // Since we support only AND operation get expressions as a list.\n+        List<ExpressionCondition> expressionConditions = getExpressionConditions(condition);\n+\n+        for (ExpressionCondition expressionCondition : expressionConditions) {\n+            if (ExpressionAttribute.ROLE.toString().equals(expressionCondition.getAttributeName())\n+                    && isGroupFiltering) {\n+                isMultiGroupFiltering = true;\n+            } else if (ExpressionAttribute.ROLE.toString().equals(expressionCondition.getAttributeName())) {\n+                isGroupFiltering = true;\n+            } else if (ExpressionAttribute.USERNAME.toString().equals(expressionCondition.getAttributeName())) {\n+                isUsernameFiltering = true;\n+            } else {\n+                isClaimFiltering = true;\n+            }\n+            expressionCondition.setAttributeValue(\n+                    escapeSpecialCharactersForFilterWithStarAsRegex(expressionCondition.getAttributeValue()));\n+        }\n+\n+        LDAPSearchSpecification ldapSearchSpecification = new LDAPSearchSpecification(realmConfig);\n+        ldapSearchSpecification.setLDAPSearchParamters(isGroupFiltering, isMultiGroupFiltering,\n+                expressionConditions, SearchControls.SUBTREE_SCOPE);\n+        boolean isMemberShipPropertyFound = ldapSearchSpecification.isMemberShipPropertyFound();\n+        String searchBases = ldapSearchSpecification.getSearchBases();\n+        SearchControls searchControls = ldapSearchSpecification.getSearchControls();\n+        List<String> returnedAttributes = Arrays.asList(searchControls.getReturningAttributes());\n+        String searchFilter = ldapSearchSpecification.getSearchFilterQuery();\n+        int givenMax;\n+\n+        try {\n+            givenMax = Integer.parseInt(realmConfig.getUserStoreProperty(UserCoreConstants.RealmConfig\n+                    .PROPERTY_MAX_USER_LIST));\n+        } catch (Exception e) {\n+            givenMax = UserCoreConstants.MAX_USER_ROLE_LIST;\n+        }\n+        // For group filtering can't apply pagination. We don't know how many group details will be return.\n+        // so set to max value.\n+        if (isMemberShipPropertyFound || limit > givenMax) {\n+            limit = givenMax;\n+        }\n+\n+        if (limit == 0) {\n+            return result;\n+        }\n+\n+        if (offset <= 0) {\n+            offset = 0;\n+        } else {\n+            offset = offset - 1;\n+        }\n+\n+        int pageSize = limit;\n+        byte[] cookie;\n+        int pageIndex = -1;\n+        DirContext dirContext = this.connectionSource.getContext();\n+        LdapContext ldapContext = (LdapContext) dirContext;\n+        String[] searchBaseAraay = searchBases.split(\"#\");\n+        NamingEnumeration<SearchResult> answer = null;\n+        List<String> tempUserList = new ArrayList<>();\n+        List<String> users = new ArrayList<>();\n+\n+        if (log.isDebugEnabled()) {\n+            log.debug(\"Searching for user(s) with SearchFilter: \" + searchFilter);\n+            if (returnedAttributes == null) {\n+                log.debug(\"No attributes requested\");\n+            } else {\n+                for (String attribute : returnedAttributes) {\n+                    log.debug(\"Requesting attribute :\" + attribute);\n+                }\n+            }\n+        }\n+\n+        try {\n+            ldapContext.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.CRITICAL)});\n+            for (String searchBase : searchBaseAraay) {\n+                int needMore = -1;\n+                do {\n+                    answer = ldapContext.search(escapeDNForSearch(searchBase), searchFilter, searchControls);\n+                    if (answer.hasMore() && isGroupFiltering) {\n+                        tempUserList = getUserListFromGroupFilteringResult(answer, returnedAttributes);\n+                        pageIndex++;\n+                    } else if (answer.hasMore()) {\n+                        tempUserList = getUserListFromNonGroupFilterResult(answer, returnedAttributes);\n+                        pageIndex++;\n+                    }\n+\n+                    if (!tempUserList.isEmpty()) {\n+                        if (isMemberShipPropertyFound) {\n+                            List<String> userList2 = new ArrayList<>();\n+                            // When found group filtering with 'member' attribute, pagination is not supported also\n+                            // we need do post processing if we found username filtering or claim filtering.\n+                            // Because can't apply claim filtering with memberShip group filtering.\n+                            // Also can't apply username filtering with 'CO', 'EW' filter operations.\n+                            if (isUsernameFiltering) {\n+                                users = getMatchUsersFromMemberList(expressionConditions, tempUserList);\n+                            } else if (isClaimFiltering) {\n+                                List<ExpressionCondition> derivedConditionList = expressionConditions;\n+                                Iterator<ExpressionCondition> iterator = derivedConditionList.iterator();\n+                                while (iterator.hasNext()) {\n+                                    ExpressionCondition expressionCondition = iterator.next();\n+                                    if (ExpressionAttribute.ROLE.toString().equals(\n+                                            expressionCondition.getAttributeName())) {\n+                                        iterator.remove();\n+                                    }\n+                                }\n+                                LDAPSearchSpecification searchSpecification = new LDAPSearchSpecification(realmConfig);\n+                                searchSpecification.setLDAPSearchParamters(false,\n+                                        false, derivedConditionList, SearchControls.SUBTREE_SCOPE);\n+                                SearchControls searchControls1 = searchSpecification.getSearchControls();\n+                                DirContext dirContext1 = this.connectionSource.getContext();\n+                                NamingEnumeration<SearchResult> tempAnswer;\n+\n+                                tempAnswer = dirContext1.search(searchSpecification.getSearchBases(),\n+                                        searchSpecification.getSearchFilterQuery(), searchControls1);\n+                                if (tempAnswer.hasMore()) {\n+                                    userList2 = getUserListFromNonGroupFilterResult(answer,\n+                                            Arrays.asList(searchControls1.getReturningAttributes()));\n+                                }\n+                                tempUserList.retainAll(userList2);\n+                                users = tempUserList;\n+                                JNDIUtil.closeContext(dirContext1);\n+                                JNDIUtil.closeNamingEnumeration(tempAnswer);\n+                            } else {\n+                                users = tempUserList;\n+                            }\n+                            break;\n+                        } else {\n+                            //Handle pagination depends on given offset, i.e. start index.\n+                            if (pageIndex == (offset / pageSize)) {\n+                                int startPosition = (offset % pageSize);\n+                                if (startPosition < tempUserList.size() - 1 && 0 < startPosition) {\n+                                    users.addAll(tempUserList.subList(startPosition, tempUserList.size()));\n+                                } else if (startPosition == tempUserList.size() - 1) {\n+                                    users.add(tempUserList.get(tempUserList.size() - 1));\n+                                } else {\n+                                    users = tempUserList;\n+                                }\n+                                needMore = pageSize - users.size();\n+                                if (needMore == 0) {\n+                                    break;\n+                                }\n+                            } else if (pageIndex == (offset / pageSize) + 1) {\n+                                if (needMore - 1 == 0) {\n+                                    users.add(tempUserList.get(0));\n+                                } else if (tempUserList.size() > needMore) {\n+                                    users.addAll(tempUserList.subList(0, (needMore - 1)));\n+                                } else {\n+                                    users.addAll(tempUserList);\n+                                }\n+                                break;\n+                            }\n+                        }\n+                    }\n+                    cookie = parseControls(ldapContext.getResponseControls());\n+                    ldapContext.setRequestControls(new Control[]{new PagedResultsControl(pageSize, cookie,\n+                            Control.CRITICAL)});\n+                } while ((cookie != null) && (cookie.length != 0));\n+            }\n+        } catch (PartialResultException e) {\n+            // can be due to referrals in AD. so just ignore error\n+            String errorMessage = \"Error occurred while searching for user(s) for filter: \" + searchFilter;\n+            if (isIgnorePartialResultException()) {\n+                if (log.isDebugEnabled()) {\n+                    log.debug(errorMessage, e);\n+                }\n+            } else {\n+                throw new UserStoreException(errorMessage, e);\n+            }\n+        } catch (NamingException e) {\n+            String errorMessage = \"Error occurred while searching for user(s) for filter: \" + searchFilter;\n+            if (log.isDebugEnabled()) {\n+                log.debug(errorMessage, e);\n+            }\n+            throw new UserStoreException(errorMessage, e);\n+        } catch (IOException e) {\n+            e.printStackTrace();\n+        } finally {\n+            // close ldap context, directory context, close naming enumeration and free up the resources.\n+            JNDIUtil.closeContext(dirContext);\n+            JNDIUtil.closeContext(ldapContext);\n+            JNDIUtil.closeNamingEnumeration(answer);\n+        }\n+        result.setUsers(users.toArray(new String[0]));\n+        return result;\n+    }\n+\n+    private static byte[] parseControls(Control[] controls) {\n+\n+        byte[] cookie = null;\n+        // Handle the paged results control response\n+        if (controls != null) {\n+            for (int i = 0; i < controls.length; i++) {\n+                if (controls[i] instanceof PagedResultsResponseControl) {\n+                    PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];\n+                    cookie = prrc.getCookie();\n+                }\n+            }\n+        }\n+        return cookie;\n+    }\n+\n+    private List<ExpressionCondition> getExpressionConditions(Condition condition) {\n+\n+        List<ExpressionCondition> expressionConditions = new ArrayList<>();\n+        getExpressionConditionsAsList(condition, expressionConditions);\n+        return expressionConditions;\n+    }\n+\n+    private void getExpressionConditionsAsList(Condition condition, List<ExpressionCondition> expressionConditions) {\n+\n+        if (condition instanceof ExpressionCondition) {\n+            expressionConditions.add((ExpressionCondition) condition);\n+        } else if (condition instanceof OperationalCondition) {\n+            Condition leftCondition = ((OperationalCondition) condition).getLeftCondition();\n+            getExpressionConditionsAsList(leftCondition, expressionConditions);\n+            Condition rightCondition = ((OperationalCondition) condition).getRightCondition();\n+            getExpressionConditionsAsList(rightCondition, expressionConditions);\n+        }\n+    }\n+\n+    private List<String> getUserListFromGroupFilteringResult(NamingEnumeration<SearchResult> answer,\n+                                                             List<String> returnedAttributes)\n+            throws UserStoreException {\n+\n+        List<String> users = new ArrayList<>();\n+        //Can be user DN list or username list\n+        List<String> userListFromSearch = new ArrayList<>();\n+        int count = 0; //multi group reterival\n+        NamingEnumeration<?> attrs = null;\n+\n+        try {\n+            while (answer.hasMoreElements()) {\n+                count++;\n+                List<String> tempUserList = new ArrayList<>();\n+                SearchResult searchResult = answer.next();\n+                Attributes attributes = searchResult.getAttributes();\n+                if (attributes != null) {\n+                    NamingEnumeration attributeEntry;\n+                    for (attributeEntry = attributes.getAll(); attributeEntry.hasMore(); ) {\n+                        Attribute valAttribute = (Attribute) attributeEntry.next();\n+                        if (isAttributeEqualsProperty(returnedAttributes.get(0), valAttribute.getID())) {\n+                            NamingEnumeration values;\n+                            for (values = valAttribute.getAll(); values.hasMore(); ) {\n+                                String value = values.next().toString();\n+                                tempUserList.add(value);\n+                            }\n+                        }\n+                    }\n+                }\n+                /*\n+                 * To get the mutual users from multi group filtering with member attribute, need to get the all\n+                 * the members from each group and then get the mutual users. When we use memberOf group filtering\n+                 * we can able to get mutual users directly.\n+                 * If returnedAttributes does not contain 'member' attribute, then it's memberOf group filter. If so we\n+                 * don't need to do post processing.\n+                 */\n+                if (!returnedAttributes.contains(realmConfig.getUserStoreProperty(LDAPConstants.MEMBERSHIP_ATTRIBUTE))\n+                        || count == 1) {\n+                    userListFromSearch.addAll(tempUserList);\n+                } else {\n+                    userListFromSearch.retainAll(tempUserList);\n+                }\n+            }\n+        } catch (NamingException e) {\n+            if (log.isDebugEnabled()) {\n+                log.debug(e.getMessage(), e);\n+            }\n+        } finally {\n+            // close the naming enumeration and free up resources\n+            JNDIUtil.closeNamingEnumeration(attrs);\n+            JNDIUtil.closeNamingEnumeration(answer);\n+        }\n+\n+        // if 'member' attribute found, we need iterate over users' DN list and get userName\n+        if (returnedAttributes.contains(realmConfig.getUserStoreProperty(LDAPConstants.MEMBERSHIP_ATTRIBUTE))) {\n+            DirContext dirContext = this.connectionSource.getContext();\n+            String userNameProperty = realmConfig.getUserStoreProperty(LDAPConstants.USER_NAME_ATTRIBUTE);\n+            String displayNameAttribute = realmConfig\n+                    .getUserStoreProperty(LDAPConstants.DISPLAY_NAME_ATTRIBUTE);\n+            String[] requiredAttributes = {userNameProperty, displayNameAttribute};\n+\n+            for (String user : userListFromSearch) {\n+                try {\n+                    Attributes userAttributes = dirContext.getAttributes(new CompositeName().add(user),\n+                            requiredAttributes);\n+\n+                    String displayName = null;\n+                    String userName = null;\n+                    if (userAttributes != null) {\n+                        Attribute userNameAttribute = userAttributes.get(userNameProperty);\n+                        if (userNameAttribute != null) {\n+                            userName = (String) userNameAttribute.get();\n+                            if (log.isDebugEnabled()) {\n+                                log.debug(\"UserName: \" + userName);\n+                            }\n+                        }\n+                        if (StringUtils.isNotEmpty(displayNameAttribute)) {\n+                            Attribute displayAttribute = userAttributes.get(displayNameAttribute);\n+                            if (displayAttribute != null) {\n+                                displayName = (String) displayAttribute.get();\n+                            }\n+                        }\n+                    }\n+                    String domainName =\n+                            realmConfig.getUserStoreProperty(UserCoreConstants.RealmConfig.PROPERTY_DOMAIN_NAME);\n+                    // Username will be null in the special case where the username attribute has changed to another\n+                    // and having different userNameProperty than the current user-mgt.xml\n+                    if (userName != null) {\n+                        user = UserCoreUtil.getCombinedName(domainName, userName, displayName);\n+                        users.add(user);\n+                        if (log.isDebugEnabled()) {\n+                            log.debug(user + \" is added to the result list\");\n+                        }\n+                    } else {\n+                        // Skip listing users which are not applicable to current user-mgt.xml\n+                        if (log.isDebugEnabled()) {\n+                            log.debug(\"User \" + user + \" doesn't have the user name property : \" +\n+                                    userNameProperty);\n+                        }\n+                    }\n+                } catch (NamingException e) {\n+                    if (log.isDebugEnabled()) {\n+                        log.debug(\"Error in reading user information in the user store for the user \" +","path":"core/org.wso2.carbon.user.core/src/main/java/org/wso2/carbon/user/core/ldap/ReadOnlyLDAPUserStoreManager.java","position":null,"original_position":402,"commit_id":"479835db7ddac9ba57a3653f5f30948f7a80a54b","original_commit_id":"3c589e1cfdb4bf8478c7af7fac6498f83107bd1c","user":{"login":"sarubi","id":20983809,"node_id":"MDQ6VXNlcjIwOTgzODA5","avatar_url":"https://avatars0.githubusercontent.com/u/20983809?v=4","gravatar_id":"","url":"https://api.github.com/users/sarubi","html_url":"https://github.com/sarubi","followers_url":"https://api.github.com/users/sarubi/followers","following_url":"https://api.github.com/users/sarubi/following{/other_user}","gists_url":"https://api.github.com/users/sarubi/gists{/gist_id}","starred_url":"https://api.github.com/users/sarubi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sarubi/subscriptions","organizations_url":"https://api.github.com/users/sarubi/orgs","repos_url":"https://api.github.com/users/sarubi/repos","events_url":"https://api.github.com/users/sarubi/events{/privacy}","received_events_url":"https://api.github.com/users/sarubi/received_events","type":"User","site_admin":false},"body":"fixed","created_at":"2018-08-10T06:51:10Z","updated_at":"2018-08-10T06:51:10Z","html_url":"https://github.com/wso2/carbon-kernel/pull/1817#discussion_r209159795","pull_request_url":"https://api.github.com/repos/wso2/carbon-kernel/pulls/1817","author_association":"NONE","_links":{"self":{"href":"https://api.github.com/repos/wso2/carbon-kernel/pulls/comments/209159795"},"html":{"href":"https://github.com/wso2/carbon-kernel/pull/1817#discussion_r209159795"},"pull_request":{"href":"https://api.github.com/repos/wso2/carbon-kernel/pulls/1817"}},"in_reply_to_id":208451050},"pull_request":{"url":"https://api.github.com/repos/wso2/carbon-kernel/pulls/1817","id":201459043,"node_id":"MDExOlB1bGxSZXF1ZXN0MjAxNDU5MDQz","html_url":"https://github.com/wso2/carbon-kernel/pull/1817","diff_url":"https://github.com/wso2/carbon-kernel/pull/1817.diff","patch_url":"https://github.com/wso2/carbon-kernel/pull/1817.patch","issue_url":"https://api.github.com/repos/wso2/carbon-kernel/issues/1817","number":1817,"state":"open","locked":false,"title":"Introducing Logical Operator for SCIM2 Filters with Pagination in WSO2 Identity Server","user":{"login":"sarubi","id":20983809,"node_id":"MDQ6VXNlcjIwOTgzODA5","avatar_url":"https://avatars0.githubusercontent.com/u/20983809?v=4","gravatar_id":"","url":"https://api.github.com/users/sarubi","html_url":"https://github.com/sarubi","followers_url":"https://api.github.com/users/sarubi/followers","following_url":"https://api.github.com/users/sarubi/following{/other_user}","gists_url":"https://api.github.com/users/sarubi/gists{/gist_id}","starred_url":"https://api.github.com/users/sarubi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sarubi/subscriptions","organizations_url":"https://api.github.com/users/sarubi/orgs","repos_url":"https://api.github.com/users/sarubi/repos","events_url":"https://api.github.com/users/sarubi/events{/privacy}","received_events_url":"https://api.github.com/users/sarubi/received_events","type":"User","site_admin":false},"body":"## Purpose\r\nImprove the WSO2 Identity Server SCIM2 filters to support multi-attribute paginated search with 'AND' logical operation. \r\n\r\n## Goals\r\nIntroducing logical operators for SCIM2 filters in WSO2 Identity Server. Here we going to support 'AND' logical operator for following SCIM2 filters such as eq, sw, ew, co. The user can query user details using multi-attribute search filters.  \r\nAlso, support pagination for multi-attribute filtering except when using the 'member' attribute for group filtering. \r\nIf the end user didn't specify pagination, then perform filtering on all available user stores and retrieve.\r\n\r\n## Approach\r\n> Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.\r\n\r\n## User stories\r\n> Summary of user stories addressed by this change>\r\n\r\n## Release note\r\n> Brief description of the new feature or bug fix as it will appear in the release notes\r\n\r\n## Documentation\r\n[https://docs.google.com/document/d/1rsJgQ7g8dAJL0pW1biLe6iRXHbZKmJsTCEJncVHJ5hQ/edit?usp=sharing](url)\r\n\r\n## Training\r\n> Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable\r\n\r\n## Certification\r\n> Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why.\r\n\r\n## Marketing\r\n> Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable\r\n\r\n## Automation tests\r\n - Unit tests \r\n   > Code coverage information\r\n - Integration tests\r\n   > Details about the test cases and coverage\r\n\r\n## Security checks\r\n - Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes/no\r\n - Ran FindSecurityBugs plugin and verified report? yes/no\r\n - Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes/no\r\n\r\n## Samples\r\n> Provide high-level details about the samples related to this feature\r\n\r\n## Related PRs\r\n> List any other related PRs\r\n\r\n## Migrations (if applicable)\r\n> Describe migration steps and platforms on which migration has been tested\r\n\r\n## Test environment\r\n> List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested\r\n \r\n## Learning\r\n> Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.","created_at":"2018-07-14T16:36:38Z","updated_at":"2018-08-10T06:51:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"943bc9c3255b65410becd92ff36197e08e8d77cd","assignee":null,"assignees":[],"requested_reviewers":[{"login":"emswbandara","id":8380730,"node_id":"MDQ6VXNlcjgzODA3MzA=","avatar_url":"https://avatars1.githubusercontent.com/u/8380730?v=4","gravatar_id":"","url":"https://api.github.com/users/emswbandara","html_url":"https://github.com/emswbandara","followers_url":"https://api.github.com/users/emswbandara/followers","following_url":"https://api.github.com/users/emswbandara/following{/other_user}","gists_url":"https://api.github.com/users/emswbandara/gists{/gist_id}","starred_url":"https://api.github.com/users/emswbandara/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emswbandara/subscriptions","organizations_url":"https://api.github.com/users/emswbandara/orgs","repos_url":"https://api.github.com/users/emswbandara/repos","events_url":"https://api.github.com/users/emswbandara/events{/privacy}","received_events_url":"https://api.github.com/users/emswbandara/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/wso2/carbon-kernel/pulls/1817/commits","review_comments_url":"https://api.github.com/repos/wso2/carbon-kernel/pulls/1817/comments","review_comment_url":"https://api.github.com/repos/wso2/carbon-kernel/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wso2/carbon-kernel/issues/1817/comments","statuses_url":"https://api.github.com/repos/wso2/carbon-kernel/statuses/479835db7ddac9ba57a3653f5f30948f7a80a54b","head":{"label":"sarubi:4.4.x","ref":"4.4.x","sha":"479835db7ddac9ba57a3653f5f30948f7a80a54b","user":{"login":"sarubi","id":20983809,"node_id":"MDQ6VXNlcjIwOTgzODA5","avatar_url":"https://avatars0.githubusercontent.com/u/20983809?v=4","gravatar_id":"","url":"https://api.github.com/users/sarubi","html_url":"https://github.com/sarubi","followers_url":"https://api.github.com/users/sarubi/followers","following_url":"https://api.github.com/users/sarubi/following{/other_user}","gists_url":"https://api.github.com/users/sarubi/gists{/gist_id}","starred_url":"https://api.github.com/users/sarubi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sarubi/subscriptions","organizations_url":"https://api.github.com/users/sarubi/orgs","repos_url":"https://api.github.com/users/sarubi/repos","events_url":"https://api.github.com/users/sarubi/events{/privacy}","received_events_url":"https://api.github.com/users/sarubi/received_events","type":"User","site_admin":false},"repo":{"id":139711019,"node_id":"MDEwOlJlcG9zaXRvcnkxMzk3MTEwMTk=","name":"carbon-kernel","full_name":"sarubi/carbon-kernel","owner":{"login":"sarubi","id":20983809,"node_id":"MDQ6VXNlcjIwOTgzODA5","avatar_url":"https://avatars0.githubusercontent.com/u/20983809?v=4","gravatar_id":"","url":"https://api.github.com/users/sarubi","html_url":"https://github.com/sarubi","followers_url":"https://api.github.com/users/sarubi/followers","following_url":"https://api.github.com/users/sarubi/following{/other_user}","gists_url":"https://api.github.com/users/sarubi/gists{/gist_id}","starred_url":"https://api.github.com/users/sarubi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sarubi/subscriptions","organizations_url":"https://api.github.com/users/sarubi/orgs","repos_url":"https://api.github.com/users/sarubi/repos","events_url":"https://api.github.com/users/sarubi/events{/privacy}","received_events_url":"https://api.github.com/users/sarubi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sarubi/carbon-kernel","description":null,"fork":true,"url":"https://api.github.com/repos/sarubi/carbon-kernel","forks_url":"https://api.github.com/repos/sarubi/carbon-kernel/forks","keys_url":"https://api.github.com/repos/sarubi/carbon-kernel/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sarubi/carbon-kernel/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sarubi/carbon-kernel/teams","hooks_url":"https://api.github.com/repos/sarubi/carbon-kernel/hooks","issue_events_url":"https://api.github.com/repos/sarubi/carbon-kernel/issues/events{/number}","events_url":"https://api.github.com/repos/sarubi/carbon-kernel/events","assignees_url":"https://api.github.com/repos/sarubi/carbon-kernel/assignees{/user}","branches_url":"https://api.github.com/repos/sarubi/carbon-kernel/branches{/branch}","tags_url":"https://api.github.com/repos/sarubi/carbon-kernel/tags","blobs_url":"https://api.github.com/repos/sarubi/carbon-kernel/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sarubi/carbon-kernel/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sarubi/carbon-kernel/git/refs{/sha}","trees_url":"https://api.github.com/repos/sarubi/carbon-kernel/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sarubi/carbon-kernel/statuses/{sha}","languages_url":"https://api.github.com/repos/sarubi/carbon-kernel/languages","stargazers_url":"https://api.github.com/repos/sarubi/carbon-kernel/stargazers","contributors_url":"https://api.github.com/repos/sarubi/carbon-kernel/contributors","subscribers_url":"https://api.github.com/repos/sarubi/carbon-kernel/subscribers","subscription_url":"https://api.github.com/repos/sarubi/carbon-kernel/subscription","commits_url":"https://api.github.com/repos/sarubi/carbon-kernel/commits{/sha}","git_commits_url":"https://api.github.com/repos/sarubi/carbon-kernel/git/commits{/sha}","comments_url":"https://api.github.com/repos/sarubi/carbon-kernel/comments{/number}","issue_comment_url":"https://api.github.com/repos/sarubi/carbon-kernel/issues/comments{/number}","contents_url":"https://api.github.com/repos/sarubi/carbon-kernel/contents/{+path}","compare_url":"https://api.github.com/repos/sarubi/carbon-kernel/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sarubi/carbon-kernel/merges","archive_url":"https://api.github.com/repos/sarubi/carbon-kernel/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sarubi/carbon-kernel/downloads","issues_url":"https://api.github.com/repos/sarubi/carbon-kernel/issues{/number}","pulls_url":"https://api.github.com/repos/sarubi/carbon-kernel/pulls{/number}","milestones_url":"https://api.github.com/repos/sarubi/carbon-kernel/milestones{/number}","notifications_url":"https://api.github.com/repos/sarubi/carbon-kernel/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sarubi/carbon-kernel/labels{/name}","releases_url":"https://api.github.com/repos/sarubi/carbon-kernel/releases{/id}","deployments_url":"https://api.github.com/repos/sarubi/carbon-kernel/deployments","created_at":"2018-07-04T11:08:32Z","updated_at":"2018-07-04T11:08:36Z","pushed_at":"2018-08-10T06:21:03Z","git_url":"git://github.com/sarubi/carbon-kernel.git","ssh_url":"git@github.com:sarubi/carbon-kernel.git","clone_url":"https://github.com/sarubi/carbon-kernel.git","svn_url":"https://github.com/sarubi/carbon-kernel","homepage":null,"size":48861,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"wso2:4.4.x","ref":"4.4.x","sha":"a0f24a1994773fa46b7314b7dd8926104a2c4924","user":{"login":"wso2","id":533043,"node_id":"MDEyOk9yZ2FuaXphdGlvbjUzMzA0Mw==","avatar_url":"https://avatars3.githubusercontent.com/u/533043?v=4","gravatar_id":"","url":"https://api.github.com/users/wso2","html_url":"https://github.com/wso2","followers_url":"https://api.github.com/users/wso2/followers","following_url":"https://api.github.com/users/wso2/following{/other_user}","gists_url":"https://api.github.com/users/wso2/gists{/gist_id}","starred_url":"https://api.github.com/users/wso2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wso2/subscriptions","organizations_url":"https://api.github.com/users/wso2/orgs","repos_url":"https://api.github.com/users/wso2/repos","events_url":"https://api.github.com/users/wso2/events{/privacy}","received_events_url":"https://api.github.com/users/wso2/received_events","type":"Organization","site_admin":false},"repo":{"id":16162184,"node_id":"MDEwOlJlcG9zaXRvcnkxNjE2MjE4NA==","name":"carbon-kernel","full_name":"wso2/carbon-kernel","owner":{"login":"wso2","id":533043,"node_id":"MDEyOk9yZ2FuaXphdGlvbjUzMzA0Mw==","avatar_url":"https://avatars3.githubusercontent.com/u/533043?v=4","gravatar_id":"","url":"https://api.github.com/users/wso2","html_url":"https://github.com/wso2","followers_url":"https://api.github.com/users/wso2/followers","following_url":"https://api.github.com/users/wso2/following{/other_user}","gists_url":"https://api.github.com/users/wso2/gists{/gist_id}","starred_url":"https://api.github.com/users/wso2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wso2/subscriptions","organizations_url":"https://api.github.com/users/wso2/orgs","repos_url":"https://api.github.com/users/wso2/repos","events_url":"https://api.github.com/users/wso2/events{/privacy}","received_events_url":"https://api.github.com/users/wso2/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wso2/carbon-kernel","description":null,"fork":false,"url":"https://api.github.com/repos/wso2/carbon-kernel","forks_url":"https://api.github.com/repos/wso2/carbon-kernel/forks","keys_url":"https://api.github.com/repos/wso2/carbon-kernel/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wso2/carbon-kernel/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wso2/carbon-kernel/teams","hooks_url":"https://api.github.com/repos/wso2/carbon-kernel/hooks","issue_events_url":"https://api.github.com/repos/wso2/carbon-kernel/issues/events{/number}","events_url":"https://api.github.com/repos/wso2/carbon-kernel/events","assignees_url":"https://api.github.com/repos/wso2/carbon-kernel/assignees{/user}","branches_url":"https://api.github.com/repos/wso2/carbon-kernel/branches{/branch}","tags_url":"https://api.github.com/repos/wso2/carbon-kernel/tags","blobs_url":"https://api.github.com/repos/wso2/carbon-kernel/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wso2/carbon-kernel/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wso2/carbon-kernel/git/refs{/sha}","trees_url":"https://api.github.com/repos/wso2/carbon-kernel/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wso2/carbon-kernel/statuses/{sha}","languages_url":"https://api.github.com/repos/wso2/carbon-kernel/languages","stargazers_url":"https://api.github.com/repos/wso2/carbon-kernel/stargazers","contributors_url":"https://api.github.com/repos/wso2/carbon-kernel/contributors","subscribers_url":"https://api.github.com/repos/wso2/carbon-kernel/subscribers","subscription_url":"https://api.github.com/repos/wso2/carbon-kernel/subscription","commits_url":"https://api.github.com/repos/wso2/carbon-kernel/commits{/sha}","git_commits_url":"https://api.github.com/repos/wso2/carbon-kernel/git/commits{/sha}","comments_url":"https://api.github.com/repos/wso2/carbon-kernel/comments{/number}","issue_comment_url":"https://api.github.com/repos/wso2/carbon-kernel/issues/comments{/number}","contents_url":"https://api.github.com/repos/wso2/carbon-kernel/contents/{+path}","compare_url":"https://api.github.com/repos/wso2/carbon-kernel/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wso2/carbon-kernel/merges","archive_url":"https://api.github.com/repos/wso2/carbon-kernel/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wso2/carbon-kernel/downloads","issues_url":"https://api.github.com/repos/wso2/carbon-kernel/issues{/number}","pulls_url":"https://api.github.com/repos/wso2/carbon-kernel/pulls{/number}","milestones_url":"https://api.github.com/repos/wso2/carbon-kernel/milestones{/number}","notifications_url":"https://api.github.com/repos/wso2/carbon-kernel/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wso2/carbon-kernel/labels{/name}","releases_url":"https://api.github.com/repos/wso2/carbon-kernel/releases{/id}","deployments_url":"https://api.github.com/repos/wso2/carbon-kernel/deployments","created_at":"2014-01-23T04:23:41Z","updated_at":"2018-08-01T02:30:29Z","pushed_at":"2018-08-10T06:21:06Z","git_url":"git://github.com/wso2/carbon-kernel.git","ssh_url":"git@github.com:wso2/carbon-kernel.git","clone_url":"https://github.com/wso2/carbon-kernel.git","svn_url":"https://github.com/wso2/carbon-kernel","homepage":null,"size":48787,"stargazers_count":52,"watchers_count":52,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":398,"mirror_url":null,"archived":false,"open_issues_count":79,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":398,"open_issues":79,"watchers":52,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wso2/carbon-kernel/pulls/1817"},"html":{"href":"https://github.com/wso2/carbon-kernel/pull/1817"},"issue":{"href":"https://api.github.com/repos/wso2/carbon-kernel/issues/1817"},"comments":{"href":"https://api.github.com/repos/wso2/carbon-kernel/issues/1817/comments"},"review_comments":{"href":"https://api.github.com/repos/wso2/carbon-kernel/pulls/1817/comments"},"review_comment":{"href":"https://api.github.com/repos/wso2/carbon-kernel/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wso2/carbon-kernel/pulls/1817/commits"},"statuses":{"href":"https://api.github.com/repos/wso2/carbon-kernel/statuses/479835db7ddac9ba57a3653f5f30948f7a80a54b"}},"author_association":"NONE"}}
{"actor":{"display_login":"sarubi"}}