diff --git a/src/contributors/GitHubService.kt b/src/contributors/GitHubService.kt
index 3dc8b7c..8157082 100644
--- a/src/contributors/GitHubService.kt
+++ b/src/contributors/GitHubService.kt
@@ -25,6 +25,17 @@ interface GitHubService {
         @Path("owner") owner: String,
         @Path("repo") repo: String
     ): Call<List<User>>
+
+    @GET("orgs/{org}/repos?per_page=100")
+    suspend fun getOrgRepos(
+        @Path("org") org: String
+    ): Response<List<Repo>>
+
+    @GET("repos/{owner}/{repo}/contributors?per_page=100")
+    suspend fun getRepoContributors(
+        @Path("owner") owner: String,
+        @Path("repo") repo: String
+    ): Response<List<User>>
 }
 
 @Serializable
diff --git a/src/tasks/Aggregation.kt b/src/tasks/Aggregation.kt
index f2d6fa7..145b344 100644
--- a/src/tasks/Aggregation.kt
+++ b/src/tasks/Aggregation.kt
@@ -15,4 +15,6 @@ TODO: Write aggregation code.
  You can use 'Navigate | Test' menu action (note the shortcut) to navigate to the test.
 */
 fun List<User>.aggregate(): List<User> =
-    this
\ No newline at end of file
+    groupBy { it.login }
+        .map { (login, group) -> User(login, group.sumBy { it.contributions }) }
+        .sortedByDescending { it.contributions }
\ No newline at end of file
diff --git a/src/tasks/Request2Background.kt b/src/tasks/Request2Background.kt
index 0ccfaf4..1ff509b 100644
--- a/src/tasks/Request2Background.kt
+++ b/src/tasks/Request2Background.kt
@@ -7,6 +7,6 @@ import kotlin.concurrent.thread
 
 fun loadContributorsBackground(service: GitHubService, req: RequestData, updateResults: (List<User>) -> Unit) {
     thread {
-        loadContributorsBlocking(service, req)
+        updateResults(loadContributorsBlocking(service, req))
     }
 }
\ No newline at end of file
diff --git a/src/tasks/Request3Callbacks.kt b/src/tasks/Request3Callbacks.kt
index 392c57a..507a2b4 100644
--- a/src/tasks/Request3Callbacks.kt
+++ b/src/tasks/Request3Callbacks.kt
@@ -11,16 +11,18 @@ fun loadContributorsCallbacks(service: GitHubService, req: RequestData, updateRe
     service.getOrgReposCall(req.org).onResponse { responseRepos ->
         logRepos(req, responseRepos)
         val repos = responseRepos.bodyList()
-        val allUsers = mutableListOf<User>()
+        val allUsers = Collections.synchronizedList(mutableListOf<User>())
+        val numberOfProcessed = AtomicInteger(0)
         for (repo in repos) {
             service.getRepoContributorsCall(req.org, repo.name).onResponse { responseUsers ->
                 logUsers(repo, responseUsers)
                 val users = responseUsers.bodyList()
                 allUsers += users
+                if (numberOfProcessed.incrementAndGet() == repos.size) {
+                    updateResults(allUsers.aggregate())
+                }
             }
         }
-        // TODO: Why this code doesn't work? How to fix that?
-        updateResults(allUsers.aggregate())
     }
 }
 
diff --git a/src/tasks/Request4Suspend.kt b/src/tasks/Request4Suspend.kt
index 37949e7..4ce00dc 100644
--- a/src/tasks/Request4Suspend.kt
+++ b/src/tasks/Request4Suspend.kt
@@ -3,5 +3,14 @@ package tasks
 import contributors.*
 
 suspend fun loadContributorsSuspend(service: GitHubService, req: RequestData): List<User> {
-    TODO()
+    val repos = service
+        .getOrgRepos(req.org)
+        .also { logRepos(req, it) }
+        .bodyList()
+
+    return repos.flatMap { repo ->
+        service.getRepoContributors(req.org, repo.name)
+            .also { logUsers(repo, it) }
+            .bodyList()
+    }.aggregate()
 }
\ No newline at end of file
diff --git a/src/tasks/Request5Concurrent.kt b/src/tasks/Request5Concurrent.kt
index 03ab317..971db97 100644
--- a/src/tasks/Request5Concurrent.kt
+++ b/src/tasks/Request5Concurrent.kt
@@ -4,5 +4,17 @@ import contributors.*
 import kotlinx.coroutines.*
 
 suspend fun loadContributorsConcurrent(service: GitHubService, req: RequestData): List<User> = coroutineScope {
-    TODO()
+    val repos = service
+        .getOrgRepos(req.org)
+        .also { logRepos(req, it) }
+        .bodyList()
+
+    val deferreds: List<Deferred<List<User>>> = repos.map { repo ->
+        async {
+            service.getRepoContributors(req.org, repo.name)
+                .also { logUsers(repo, it) }
+                .bodyList()
+        }
+    }
+    deferreds.awaitAll().flatten().aggregate()
 }
\ No newline at end of file
diff --git a/src/tasks/Request5NotCancellable.kt b/src/tasks/Request5NotCancellable.kt
index eb41acd..87bac9a 100644
--- a/src/tasks/Request5NotCancellable.kt
+++ b/src/tasks/Request5NotCancellable.kt
@@ -5,5 +5,19 @@ import kotlinx.coroutines.*
 import kotlin.coroutines.coroutineContext
 
 suspend fun loadContributorsNotCancellable(service: GitHubService, req: RequestData): List<User> {
-    TODO()
+    val repos = service
+        .getOrgRepos(req.org)
+        .also { logRepos(req, it) }
+        .bodyList()
+
+    val deferreds: List<Deferred<List<User>>> = repos.map { repo ->
+        GlobalScope.async(Dispatchers.Default) {
+            log("starting loading for ${repo.name}")
+            delay(3000)
+            service.getRepoContributors(req.org, repo.name)
+                .also { logUsers(repo, it) }
+                .bodyList()
+        }
+    }
+    return deferreds.awaitAll().flatten().aggregate()
 }
\ No newline at end of file
diff --git a/src/tasks/Request6Progress.kt b/src/tasks/Request6Progress.kt
index 2d484db..bd6b7e3 100644
--- a/src/tasks/Request6Progress.kt
+++ b/src/tasks/Request6Progress.kt
@@ -7,5 +7,18 @@ suspend fun loadContributorsProgress(
     req: RequestData,
     updateResults: suspend (List<User>, completed: Boolean) -> Unit
 ) {
-    TODO()
+    val repos = service
+        .getOrgRepos(req.org)
+        .also { logRepos(req, it) }
+        .bodyList()
+
+    var allUsers = emptyList<User>()
+    for ((index, repo) in repos.withIndex()) {
+        val users = service.getRepoContributors(req.org, repo.name)
+            .also { logUsers(repo, it) }
+            .bodyList()
+
+        allUsers = (allUsers + users).aggregate()
+        updateResults(allUsers, index == repos.lastIndex)
+    }
 }
diff --git a/src/tasks/Request7Channels.kt b/src/tasks/Request7Channels.kt
index be93b16..f89b734 100644
--- a/src/tasks/Request7Channels.kt
+++ b/src/tasks/Request7Channels.kt
@@ -9,8 +9,25 @@ suspend fun loadContributorsChannels(
     service: GitHubService,
     req: RequestData,
     updateResults: suspend (List<User>, completed: Boolean) -> Unit
-) {
-    coroutineScope {
-        TODO()
+) = coroutineScope {
+    val repos = service
+        .getOrgRepos(req.org)
+        .also { logRepos(req, it) }
+        .bodyList()
+
+    val channel = Channel<List<User>>()
+    for (repo in repos) {
+        launch {
+            val users = service.getRepoContributors(req.org, repo.name)
+                .also { logUsers(repo, it) }
+                .bodyList()
+            channel.send(users)
+        }
+    }
+    var allUsers = emptyList<User>()
+    repeat(repos.size) {
+        val users = channel.receive()
+        allUsers = (allUsers + users).aggregate()
+        updateResults(allUsers, it == repos.lastIndex)
     }
 }
diff --git a/test/contributors/MockGithubService.kt b/test/contributors/MockGithubService.kt
index 7542eab..43a3199 100644
--- a/test/contributors/MockGithubService.kt
+++ b/test/contributors/MockGithubService.kt
@@ -14,9 +14,6 @@ object MockGithubService : GitHubService {
         return Calls.response(reposMap.getValue(repo).users)
     }
 
-/*
-    // Uncomment the following implementations after adding these methods to GitHubService:
-
     override suspend fun getOrgRepos(org: String): Response<List<Repo>> {
         delay(reposDelay)
         return Response.success(repos)
@@ -27,5 +24,4 @@ object MockGithubService : GitHubService {
         delay(testRepo.delay)
         return Response.success(testRepo.users)
     }
-*/
 }
\ No newline at end of file
diff --git a/test/tasks/AggregationKtTest.kt b/test/tasks/AggregationKtTest.kt
index d9759e3..ea3baeb 100644
--- a/test/tasks/AggregationKtTest.kt
+++ b/test/tasks/AggregationKtTest.kt
@@ -10,9 +10,11 @@ class AggregationKtTest {
         val actual = listOf(
             User("Alice", 1), User("Bob", 3),
             User("Alice", 2), User("Bob", 7),
+            User("Beth", 3), User("Beth", 7),
             User("Charlie", 3), User("Alice", 5)
         ).aggregate()
         val expected = listOf(
+            User("Beth", 10),
             User("Bob", 10),
             User("Alice", 8),
             User("Charlie", 3)
diff --git a/test/tasks/Request4SuspendKtTest.kt b/test/tasks/Request4SuspendKtTest.kt
index af92edb..47515ad 100644
--- a/test/tasks/Request4SuspendKtTest.kt
+++ b/test/tasks/Request4SuspendKtTest.kt
@@ -3,29 +3,23 @@ package tasks
 import contributors.MockGithubService
 import contributors.expectedResults
 import contributors.testRequestData
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runBlockingTest
 import org.junit.Assert
 import org.junit.Test
 
+@OptIn(ExperimentalCoroutinesApi::class)
 class Request4SuspendKtTest {
     @Test
-    fun testSuspend() = runBlocking {
-        val startTime = System.currentTimeMillis()
+    fun testSuspend() = runBlockingTest {
+        val startTime = currentTime
         val result = loadContributorsSuspend(MockGithubService, testRequestData)
         Assert.assertEquals("Wrong result for 'loadContributorsSuspend'", expectedResults.users, result)
-        val totalTime = System.currentTimeMillis() - startTime
-        /*
-        // TODO: uncomment this assertion
+        val totalTime = currentTime - startTime
         Assert.assertEquals(
-            "The calls run consequently, so the total virtual time should be 4000 ms: " +
-                    "1000 for repos request plus (1000 + 1200 + 800) = 3000 for sequential contributors requests)",
+            "The calls run consequently," +
+                    "so the total virtual time should be 4000 ms: ",
             expectedResults.timeFromStart, totalTime
         )
-        */
-        Assert.assertTrue(
-            "The calls run consequently, so the total time should be around 4000 ms: " +
-                    "1000 for repos request plus (1000 + 1200 + 800) = 3000 for sequential contributors requests)",
-            totalTime in expectedResults.timeFromStart..(expectedResults.timeFromStart + 500)
-        )
     }
 }
\ No newline at end of file
diff --git a/test/tasks/Request5ConcurrentKtTest.kt b/test/tasks/Request5ConcurrentKtTest.kt
index 24c7e94..6f1933b 100644
--- a/test/tasks/Request5ConcurrentKtTest.kt
+++ b/test/tasks/Request5ConcurrentKtTest.kt
@@ -3,29 +3,23 @@ package tasks
 import contributors.MockGithubService
 import contributors.expectedConcurrentResults
 import contributors.testRequestData
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runBlockingTest
 import org.junit.Assert
 import org.junit.Test
 
+@OptIn(ExperimentalCoroutinesApi::class)
 class Request5ConcurrentKtTest {
     @Test
-    fun testConcurrent() = runBlocking {
-        val startTime = System.currentTimeMillis()
+    fun testConcurrent() = runBlockingTest {
+        val startTime = currentTime
         val result = loadContributorsConcurrent(MockGithubService, testRequestData)
         Assert.assertEquals("Wrong result for 'loadContributorsConcurrent'", expectedConcurrentResults.users, result)
-        val totalTime = System.currentTimeMillis() - startTime
-        /*
-        // TODO: uncomment this assertion
+        val totalTime = currentTime - startTime
         Assert.assertEquals(
             "The calls run concurrently, so the total virtual time should be 2200 ms: " +
                     "1000 ms for repos request plus max(1000, 1200, 800) = 1200 ms for concurrent contributors requests)",
             expectedConcurrentResults.timeFromStart, totalTime
         )
-        */
-        Assert.assertTrue(
-            "The calls run concurrently, so the total virtual time should be 2200 ms: " +
-                    "1000 ms for repos request plus max(1000, 1200, 800) = 1200 ms for concurrent contributors requests)",
-            totalTime in expectedConcurrentResults.timeFromStart..(expectedConcurrentResults.timeFromStart + 500)
-        )
     }
 }
\ No newline at end of file
diff --git a/test/tasks/Request6ProgressKtTest.kt b/test/tasks/Request6ProgressKtTest.kt
index 4c9e441..4d9f446 100644
--- a/test/tasks/Request6ProgressKtTest.kt
+++ b/test/tasks/Request6ProgressKtTest.kt
@@ -3,24 +3,23 @@ package tasks
 import contributors.MockGithubService
 import contributors.progressResults
 import contributors.testRequestData
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runBlockingTest
 import org.junit.Assert
 import org.junit.Test
 
+@OptIn(ExperimentalCoroutinesApi::class)
 class Request6ProgressKtTest {
     @Test
-    fun testProgress() = runBlocking {
-        val startTime = System.currentTimeMillis()
+    fun testProgress() = runBlockingTest {
+        val startTime = currentTime
         var index = 0
         loadContributorsProgress(MockGithubService, testRequestData) {
             users, _ ->
             val expected = progressResults[index++]
-            val time = System.currentTimeMillis() - startTime
-            /*
-            // TODO: uncomment this assertion
+            val time = currentTime - startTime
             Assert.assertEquals("Expected intermediate result after virtual ${expected.timeFromStart} ms:",
                 expected.timeFromStart, time)
-            */
             Assert.assertEquals("Wrong intermediate result after $time:", expected.users, users)
         }
     }
diff --git a/test/tasks/Request7ChannelsKtTest.kt b/test/tasks/Request7ChannelsKtTest.kt
index f377e85..d054f7f 100644
--- a/test/tasks/Request7ChannelsKtTest.kt
+++ b/test/tasks/Request7ChannelsKtTest.kt
@@ -3,24 +3,23 @@ package tasks
 import contributors.MockGithubService
 import contributors.concurrentProgressResults
 import contributors.testRequestData
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runBlockingTest
 import org.junit.Assert
 import org.junit.Test
 
+@OptIn(ExperimentalCoroutinesApi::class)
 class Request7ChannelsKtTest {
     @Test
-    fun testChannels() = runBlocking {
-        val startTime = System.currentTimeMillis()
+    fun testChannels() = runBlockingTest {
+        val startTime = currentTime
         var index = 0
         loadContributorsChannels(MockGithubService, testRequestData) {
                 users, _ ->
             val expected = concurrentProgressResults[index++]
-            val time = System.currentTimeMillis() - startTime
-            /*
-            // TODO: uncomment this assertion
+            val time = currentTime - startTime
             Assert.assertEquals("Expected intermediate result after virtual ${expected.timeFromStart} ms:",
                 expected.timeFromStart, time)
-            */
             Assert.assertEquals("Wrong intermediate result after $time:", expected.users, users)
         }
     }