{"action":"created","comment":{"url":"https://api.github.com/repos/dimagi/commcare-core/pulls/comments/126543558","pull_request_review_id":49038181,"id":126543558,"diff_hunk":"@@ -0,0 +1,146 @@\n+package org.javarosa.xpath.expr;\n+\n+import org.javarosa.core.model.condition.EvaluationContext;\n+import org.javarosa.core.model.instance.DataInstance;\n+import org.javarosa.xpath.XPathArityException;\n+import org.javarosa.xpath.XPathTypeMismatchException;\n+import org.javarosa.xpath.parser.XPathSyntaxException;\n+\n+import java.util.ArrayList;\n+import java.util.Arrays;\n+import java.util.Collections;\n+import java.util.Comparator;\n+import java.util.HashMap;\n+import java.util.List;\n+import java.util.Map;\n+\n+import javax.xml.crypto.dsig.spec.XPathType;\n+\n+/**\n+ * Created by amstone326 on 6/28/17.\n+ */\n+\n+public class XPathSortFunc extends XPathFuncExpr {\n+\n+    public static final String NAME = \"sort\";\n+\n+    // since we accept 1-3 arguments\n+    private static final int EXPECTED_ARG_COUNT = -1;\n+\n+    public XPathSortFunc() {\n+        name = NAME;\n+        expectedArgCount = EXPECTED_ARG_COUNT;\n+    }\n+\n+    public XPathSortFunc(XPathExpression[] args) throws XPathSyntaxException {\n+        super(NAME, args, EXPECTED_ARG_COUNT, true);\n+    }\n+\n+    @Override\n+    protected void validateArgCount() throws XPathSyntaxException {\n+        if (args.length < 1 || args.length > 3) {\n+            throw new XPathArityException(name, \"between 1 and 3 arguments\", args.length);\n+        }\n+    }\n+\n+    @Override\n+    protected Object evalBody(DataInstance model, EvaluationContext evalContext, Object[] evaluatedArgs) {\n+        List<String> sortedList;\n+        if (evaluatedArgs.length == 1) {\n+            sortedList = sortSingleList(FunctionUtils.toString(evaluatedArgs[0]), true);\n+        } else if (evaluatedArgs.length == 2) {\n+            Object lastArg = evaluatedArgs[1];\n+            if (lastArg instanceof Boolean) {\n+                sortedList =\n+                        sortSingleList(FunctionUtils.toString(evaluatedArgs[0]),\n+                                FunctionUtils.toBoolean(evaluatedArgs[1]));\n+            } else {\n+                sortedList = sortListByOtherList(FunctionUtils.toString(evaluatedArgs[0]),\n+                        FunctionUtils.toString(evaluatedArgs[1]), true);\n+            }\n+        } else {\n+            sortedList =\n+                    sortListByOtherList(FunctionUtils.toString(evaluatedArgs[0]),\n+                            FunctionUtils.toString(evaluatedArgs[1]),\n+                            FunctionUtils.toBoolean(evaluatedArgs[2]));\n+        }\n+        return listToString(sortedList);\n+    }\n+\n+    private List<String> sortSingleList(String spaceSeparatedString, boolean ascending) {\n+        List<String> items = stringToList(spaceSeparatedString);\n+        sortSingleList(items, ascending);\n+        return items;\n+    }\n+\n+    private void sortSingleList(List<String> items, final boolean ascending) {\n+        Collections.sort(items, new Comparator<String>() {\n+            @Override\n+            public int compare(String s1, String s2) {\n+                return (ascending ? 1 : -1) * s1.compareTo(s2);\n+            }\n+        });\n+    }\n+\n+    private List<String> sortListByOtherList(String s1, String s2, boolean ascending) {\n+        List<String> targetListItems = stringToList(s1);\n+        List<String> comparisonListItems = stringToList(s2);\n+\n+        if (targetListItems.size() != comparisonListItems.size()) {\n+            throw new XPathTypeMismatchException(\"Length of lists passed to sort() must match\");","path":"src/main/java/org/javarosa/xpath/expr/XPathSortFunc.java","position":90,"original_position":90,"commit_id":"1685998e140be6124a6f13672e1516d69f707d70","original_commit_id":"1685998e140be6124a6f13672e1516d69f707d70","user":{"login":"ctsims","id":155066,"avatar_url":"https://avatars0.githubusercontent.com/u/155066?v=3","gravatar_id":"","url":"https://api.github.com/users/ctsims","html_url":"https://github.com/ctsims","followers_url":"https://api.github.com/users/ctsims/followers","following_url":"https://api.github.com/users/ctsims/following{/other_user}","gists_url":"https://api.github.com/users/ctsims/gists{/gist_id}","starred_url":"https://api.github.com/users/ctsims/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ctsims/subscriptions","organizations_url":"https://api.github.com/users/ctsims/orgs","repos_url":"https://api.github.com/users/ctsims/repos","events_url":"https://api.github.com/users/ctsims/events{/privacy}","received_events_url":"https://api.github.com/users/ctsims/received_events","type":"User","site_admin":false},"body":"It would possibly be worth including the list contents here, since we already have the strings. Or describing the lengths. Generally providing any cue that would let someone track why things did/didn't map.","created_at":"2017-07-10T21:36:32Z","updated_at":"2017-07-10T21:51:29Z","html_url":"https://github.com/dimagi/commcare-core/pull/594#discussion_r126543558","pull_request_url":"https://api.github.com/repos/dimagi/commcare-core/pulls/594","_links":{"self":{"href":"https://api.github.com/repos/dimagi/commcare-core/pulls/comments/126543558"},"html":{"href":"https://github.com/dimagi/commcare-core/pull/594#discussion_r126543558"},"pull_request":{"href":"https://api.github.com/repos/dimagi/commcare-core/pulls/594"}}},"pull_request":{"url":"https://api.github.com/repos/dimagi/commcare-core/pulls/594","id":126755324,"html_url":"https://github.com/dimagi/commcare-core/pull/594","diff_url":"https://github.com/dimagi/commcare-core/pull/594.diff","patch_url":"https://github.com/dimagi/commcare-core/pull/594.patch","issue_url":"https://api.github.com/repos/dimagi/commcare-core/issues/594","number":594,"state":"open","locked":false,"title":"Dev work for INDDEX","user":{"login":"amstone326","id":3723143,"avatar_url":"https://avatars3.githubusercontent.com/u/3723143?v=3","gravatar_id":"","url":"https://api.github.com/users/amstone326","html_url":"https://github.com/amstone326","followers_url":"https://api.github.com/users/amstone326/followers","following_url":"https://api.github.com/users/amstone326/following{/other_user}","gists_url":"https://api.github.com/users/amstone326/gists{/gist_id}","starred_url":"https://api.github.com/users/amstone326/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/amstone326/subscriptions","organizations_url":"https://api.github.com/users/amstone326/orgs","repos_url":"https://api.github.com/users/amstone326/repos","events_url":"https://api.github.com/users/amstone326/events{/privacy}","received_events_url":"https://api.github.com/users/amstone326/received_events","type":"User","site_admin":false},"body":"Changes implemented:\r\n- Sorting of answer choices in itemset select questions\r\n- Add a `sort()` function in XPath (documentation with detailed specifications added [here](https://confluence.dimagi.com/display/commcarepublic/CommCare+Functions#CommCareFunctions-sort))\r\n- Make it possible to index the same column name in multiple fixtures","created_at":"2017-06-21T12:50:33Z","updated_at":"2017-07-10T21:51:29Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d86d62e07841105135f7ff499123e9403523cbb4","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":{"url":"https://api.github.com/repos/dimagi/commcare-core/milestones/16","html_url":"https://github.com/dimagi/commcare-core/milestone/16","labels_url":"https://api.github.com/repos/dimagi/commcare-core/milestones/16/labels","id":2595880,"number":16,"title":"commcare_2.38","description":null,"creator":{"login":"amstone326","id":3723143,"avatar_url":"https://avatars3.githubusercontent.com/u/3723143?v=3","gravatar_id":"","url":"https://api.github.com/users/amstone326","html_url":"https://github.com/amstone326","followers_url":"https://api.github.com/users/amstone326/followers","following_url":"https://api.github.com/users/amstone326/following{/other_user}","gists_url":"https://api.github.com/users/amstone326/gists{/gist_id}","starred_url":"https://api.github.com/users/amstone326/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/amstone326/subscriptions","organizations_url":"https://api.github.com/users/amstone326/orgs","repos_url":"https://api.github.com/users/amstone326/repos","events_url":"https://api.github.com/users/amstone326/events{/privacy}","received_events_url":"https://api.github.com/users/amstone326/received_events","type":"User","site_admin":false},"open_issues":2,"closed_issues":0,"state":"open","created_at":"2017-06-21T12:50:17Z","updated_at":"2017-06-27T22:12:32Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/dimagi/commcare-core/pulls/594/commits","review_comments_url":"https://api.github.com/repos/dimagi/commcare-core/pulls/594/comments","review_comment_url":"https://api.github.com/repos/dimagi/commcare-core/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dimagi/commcare-core/issues/594/comments","statuses_url":"https://api.github.com/repos/dimagi/commcare-core/statuses/1685998e140be6124a6f13672e1516d69f707d70","head":{"label":"dimagi:inddex-work","ref":"inddex-work","sha":"1685998e140be6124a6f13672e1516d69f707d70","user":{"login":"dimagi","id":94514,"avatar_url":"https://avatars2.githubusercontent.com/u/94514?v=3","gravatar_id":"","url":"https://api.github.com/users/dimagi","html_url":"https://github.com/dimagi","followers_url":"https://api.github.com/users/dimagi/followers","following_url":"https://api.github.com/users/dimagi/following{/other_user}","gists_url":"https://api.github.com/users/dimagi/gists{/gist_id}","starred_url":"https://api.github.com/users/dimagi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dimagi/subscriptions","organizations_url":"https://api.github.com/users/dimagi/orgs","repos_url":"https://api.github.com/users/dimagi/repos","events_url":"https://api.github.com/users/dimagi/events{/privacy}","received_events_url":"https://api.github.com/users/dimagi/received_events","type":"Organization","site_admin":false},"repo":{"id":20939782,"name":"commcare-core","full_name":"dimagi/commcare-core","owner":{"login":"dimagi","id":94514,"avatar_url":"https://avatars2.githubusercontent.com/u/94514?v=3","gravatar_id":"","url":"https://api.github.com/users/dimagi","html_url":"https://github.com/dimagi","followers_url":"https://api.github.com/users/dimagi/followers","following_url":"https://api.github.com/users/dimagi/following{/other_user}","gists_url":"https://api.github.com/users/dimagi/gists{/gist_id}","starred_url":"https://api.github.com/users/dimagi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dimagi/subscriptions","organizations_url":"https://api.github.com/users/dimagi/orgs","repos_url":"https://api.github.com/users/dimagi/repos","events_url":"https://api.github.com/users/dimagi/events{/privacy}","received_events_url":"https://api.github.com/users/dimagi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dimagi/commcare-core","description":"Last-mile mobile app platform utilized across sectors, from healthcare to supply and logistics","fork":false,"url":"https://api.github.com/repos/dimagi/commcare-core","forks_url":"https://api.github.com/repos/dimagi/commcare-core/forks","keys_url":"https://api.github.com/repos/dimagi/commcare-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dimagi/commcare-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dimagi/commcare-core/teams","hooks_url":"https://api.github.com/repos/dimagi/commcare-core/hooks","issue_events_url":"https://api.github.com/repos/dimagi/commcare-core/issues/events{/number}","events_url":"https://api.github.com/repos/dimagi/commcare-core/events","assignees_url":"https://api.github.com/repos/dimagi/commcare-core/assignees{/user}","branches_url":"https://api.github.com/repos/dimagi/commcare-core/branches{/branch}","tags_url":"https://api.github.com/repos/dimagi/commcare-core/tags","blobs_url":"https://api.github.com/repos/dimagi/commcare-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dimagi/commcare-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dimagi/commcare-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/dimagi/commcare-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dimagi/commcare-core/statuses/{sha}","languages_url":"https://api.github.com/repos/dimagi/commcare-core/languages","stargazers_url":"https://api.github.com/repos/dimagi/commcare-core/stargazers","contributors_url":"https://api.github.com/repos/dimagi/commcare-core/contributors","subscribers_url":"https://api.github.com/repos/dimagi/commcare-core/subscribers","subscription_url":"https://api.github.com/repos/dimagi/commcare-core/subscription","commits_url":"https://api.github.com/repos/dimagi/commcare-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/dimagi/commcare-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/dimagi/commcare-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/dimagi/commcare-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/dimagi/commcare-core/contents/{+path}","compare_url":"https://api.github.com/repos/dimagi/commcare-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dimagi/commcare-core/merges","archive_url":"https://api.github.com/repos/dimagi/commcare-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dimagi/commcare-core/downloads","issues_url":"https://api.github.com/repos/dimagi/commcare-core/issues{/number}","pulls_url":"https://api.github.com/repos/dimagi/commcare-core/pulls{/number}","milestones_url":"https://api.github.com/repos/dimagi/commcare-core/milestones{/number}","notifications_url":"https://api.github.com/repos/dimagi/commcare-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dimagi/commcare-core/labels{/name}","releases_url":"https://api.github.com/repos/dimagi/commcare-core/releases{/id}","deployments_url":"https://api.github.com/repos/dimagi/commcare-core/deployments","created_at":"2014-06-17T21:13:25Z","updated_at":"2017-04-12T14:38:32Z","pushed_at":"2017-07-10T20:07:26Z","git_url":"git://github.com/dimagi/commcare-core.git","ssh_url":"git@github.com:dimagi/commcare-core.git","clone_url":"https://github.com/dimagi/commcare-core.git","svn_url":"https://github.com/dimagi/commcare-core","homepage":"http://www.dimagi.com/products/","size":22366,"stargazers_count":4,"watchers_count":4,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":9,"mirror_url":null,"open_issues_count":7,"forks":9,"open_issues":7,"watchers":4,"default_branch":"master"}},"base":{"label":"dimagi:master","ref":"master","sha":"33f9cbe33d0083193375c82ea18d1600b0e4e857","user":{"login":"dimagi","id":94514,"avatar_url":"https://avatars2.githubusercontent.com/u/94514?v=3","gravatar_id":"","url":"https://api.github.com/users/dimagi","html_url":"https://github.com/dimagi","followers_url":"https://api.github.com/users/dimagi/followers","following_url":"https://api.github.com/users/dimagi/following{/other_user}","gists_url":"https://api.github.com/users/dimagi/gists{/gist_id}","starred_url":"https://api.github.com/users/dimagi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dimagi/subscriptions","organizations_url":"https://api.github.com/users/dimagi/orgs","repos_url":"https://api.github.com/users/dimagi/repos","events_url":"https://api.github.com/users/dimagi/events{/privacy}","received_events_url":"https://api.github.com/users/dimagi/received_events","type":"Organization","site_admin":false},"repo":{"id":20939782,"name":"commcare-core","full_name":"dimagi/commcare-core","owner":{"login":"dimagi","id":94514,"avatar_url":"https://avatars2.githubusercontent.com/u/94514?v=3","gravatar_id":"","url":"https://api.github.com/users/dimagi","html_url":"https://github.com/dimagi","followers_url":"https://api.github.com/users/dimagi/followers","following_url":"https://api.github.com/users/dimagi/following{/other_user}","gists_url":"https://api.github.com/users/dimagi/gists{/gist_id}","starred_url":"https://api.github.com/users/dimagi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dimagi/subscriptions","organizations_url":"https://api.github.com/users/dimagi/orgs","repos_url":"https://api.github.com/users/dimagi/repos","events_url":"https://api.github.com/users/dimagi/events{/privacy}","received_events_url":"https://api.github.com/users/dimagi/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dimagi/commcare-core","description":"Last-mile mobile app platform utilized across sectors, from healthcare to supply and logistics","fork":false,"url":"https://api.github.com/repos/dimagi/commcare-core","forks_url":"https://api.github.com/repos/dimagi/commcare-core/forks","keys_url":"https://api.github.com/repos/dimagi/commcare-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dimagi/commcare-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dimagi/commcare-core/teams","hooks_url":"https://api.github.com/repos/dimagi/commcare-core/hooks","issue_events_url":"https://api.github.com/repos/dimagi/commcare-core/issues/events{/number}","events_url":"https://api.github.com/repos/dimagi/commcare-core/events","assignees_url":"https://api.github.com/repos/dimagi/commcare-core/assignees{/user}","branches_url":"https://api.github.com/repos/dimagi/commcare-core/branches{/branch}","tags_url":"https://api.github.com/repos/dimagi/commcare-core/tags","blobs_url":"https://api.github.com/repos/dimagi/commcare-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dimagi/commcare-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dimagi/commcare-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/dimagi/commcare-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dimagi/commcare-core/statuses/{sha}","languages_url":"https://api.github.com/repos/dimagi/commcare-core/languages","stargazers_url":"https://api.github.com/repos/dimagi/commcare-core/stargazers","contributors_url":"https://api.github.com/repos/dimagi/commcare-core/contributors","subscribers_url":"https://api.github.com/repos/dimagi/commcare-core/subscribers","subscription_url":"https://api.github.com/repos/dimagi/commcare-core/subscription","commits_url":"https://api.github.com/repos/dimagi/commcare-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/dimagi/commcare-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/dimagi/commcare-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/dimagi/commcare-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/dimagi/commcare-core/contents/{+path}","compare_url":"https://api.github.com/repos/dimagi/commcare-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dimagi/commcare-core/merges","archive_url":"https://api.github.com/repos/dimagi/commcare-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dimagi/commcare-core/downloads","issues_url":"https://api.github.com/repos/dimagi/commcare-core/issues{/number}","pulls_url":"https://api.github.com/repos/dimagi/commcare-core/pulls{/number}","milestones_url":"https://api.github.com/repos/dimagi/commcare-core/milestones{/number}","notifications_url":"https://api.github.com/repos/dimagi/commcare-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dimagi/commcare-core/labels{/name}","releases_url":"https://api.github.com/repos/dimagi/commcare-core/releases{/id}","deployments_url":"https://api.github.com/repos/dimagi/commcare-core/deployments","created_at":"2014-06-17T21:13:25Z","updated_at":"2017-04-12T14:38:32Z","pushed_at":"2017-07-10T20:07:26Z","git_url":"git://github.com/dimagi/commcare-core.git","ssh_url":"git@github.com:dimagi/commcare-core.git","clone_url":"https://github.com/dimagi/commcare-core.git","svn_url":"https://github.com/dimagi/commcare-core","homepage":"http://www.dimagi.com/products/","size":22366,"stargazers_count":4,"watchers_count":4,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":9,"mirror_url":null,"open_issues_count":7,"forks":9,"open_issues":7,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dimagi/commcare-core/pulls/594"},"html":{"href":"https://github.com/dimagi/commcare-core/pull/594"},"issue":{"href":"https://api.github.com/repos/dimagi/commcare-core/issues/594"},"comments":{"href":"https://api.github.com/repos/dimagi/commcare-core/issues/594/comments"},"review_comments":{"href":"https://api.github.com/repos/dimagi/commcare-core/pulls/594/comments"},"review_comment":{"href":"https://api.github.com/repos/dimagi/commcare-core/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dimagi/commcare-core/pulls/594/commits"},"statuses":{"href":"https://api.github.com/repos/dimagi/commcare-core/statuses/1685998e140be6124a6f13672e1516d69f707d70"}}}}
{"actor":{"display_login":"ctsims"}}