diff --git a/.idea/artifacts/kemence_js_1_0.xml b/.idea/artifacts/kemence_js_1_0.xml
index 1fa591a46e0662352205c15d3d1df1bbee3eaaa3..5cfa20872d3eb89461e4fedb0647751d71073de4 100644
--- a/.idea/artifacts/kemence_js_1_0.xml
+++ b/.idea/artifacts/kemence_js_1_0.xml
@@ -1,8 +1,6 @@
 <component name="ArtifactManager">
   <artifact type="jar" name="kemence-js-1.0">
     <output-path>$PROJECT_DIR$/build/libs</output-path>
-    <root id="archive" name="kemence-js-1.0.jar">
-      <element id="module-output" name="kemence.jsMain" />
-    </root>
+    <root id="archive" name="kemence-js-1.0.jar" />
   </artifact>
 </component>
\ No newline at end of file
diff --git a/src/jsMain/kotlin/datasources/CSVTable.kt b/src/jsMain/kotlin/datasources/CSVTable.kt
index 39dc918852752856cdbc22155483c12488028060..985b6e15952b408f7adaca9f361d86cc7f7b37d2 100644
--- a/src/jsMain/kotlin/datasources/CSVTable.kt
+++ b/src/jsMain/kotlin/datasources/CSVTable.kt
@@ -3,7 +3,7 @@ package datasources
 import com.github.doyaaaaaken.kotlincsv.dsl.csvReader
 import pekstuff.trimAsPrinciple
 
-class CSVTable(data: String) {
+class CSVTable(data: String): DataSource {
     private val rows = csvReader().readAll(data)
     companion object {
         private val filterList = listOf(
@@ -20,7 +20,7 @@ class CSVTable(data: String) {
         }
         .toMap()
 
-    val principles get() = principleIndexes.keys
+    override val principles get() = principleIndexes.keys
 
     private val peopleIndexes = rows
         .mapIndexed { i, p -> p[0] to i }
@@ -28,16 +28,9 @@ class CSVTable(data: String) {
         .filter { it.first.isNotBlank() }
         .toMap()
 
-    val people: List<String>
-    get() {
-        val ret = mutableListOf<String>()
-        rows.drop(1)
-            .filter { it[0].isNotEmpty() }
-            .forEach { ret.add(it[0]) }
-        return ret
-    }
+    override val people get() = peopleIndexes.keys
 
-    operator fun get(person: String, principle: String): Int {
+    override operator fun get(person: String, principle: String): Int {
         val pers = peopleIndexes[person]!!
         val princ = principleIndexes[principle]!!
         return rows[pers][princ].toIntOrNull() ?: 0
diff --git a/src/jsMain/kotlin/datasources/DataSource.kt b/src/jsMain/kotlin/datasources/DataSource.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b5ebb9ee9cf0d354abf453864e9b110617d1a9dc
--- /dev/null
+++ b/src/jsMain/kotlin/datasources/DataSource.kt
@@ -0,0 +1,13 @@
+package datasources
+
+interface DataSource {
+    val principles: Set<String>
+    val people: Set<String>
+    operator fun get(person: String, principle: String): Int
+}
+
+interface NoteDataSource {
+    val principles: Set<String>
+    val people: Set<String>
+    fun getNote(person: String, principle: String): String
+}
\ No newline at end of file
diff --git a/src/jsMain/kotlin/datasources/GSheet.kt b/src/jsMain/kotlin/datasources/GSheet.kt
index cec5899f78a7b7a1a667cd636b857d8eb666b16f..2b7eb89ee6658d4b38e3231dd2c63e09e74c4735 100644
--- a/src/jsMain/kotlin/datasources/GSheet.kt
+++ b/src/jsMain/kotlin/datasources/GSheet.kt
@@ -1,48 +1,70 @@
 package datasources
 
+import androidx.compose.runtime.NoLiveLiterals
 import gapi.gapi
 import gapi.isSignedIn
 import gapi.sheets
+import kotlinx.browser.window
+import pekstuff.trimAsPrinciple
 import kotlin.coroutines.resume
 import kotlin.coroutines.resumeWithException
 import kotlin.coroutines.suspendCoroutine
 
-class GSheet private constructor() {
+class GSheet private constructor(private val sheet: sheets.Spreadsheet): DataSource, NoteDataSource {
     companion object {
+        private val filterList = listOf(
+            "szumma", "színes belépő"
+        )
+
         suspend fun new(url: String): GSheet {
             if (!isSignedIn()) throw Error("You must sign in to get gapi.sheets")
-
-            val sheet = GSheet()
-            sheet.setUrl(url)
-            return sheet
+            val sheet = getSheetFromUrl(url)
+            window.asDynamic().test = sheet
+            return GSheet(sheet)
         }
-    }
 
-    private var _url = ""
-    suspend fun setUrl(value: String){
-        _url = value
-        loadSheet()
-    }
-
-    val url: String get() = _url
-
-    private suspend fun getSheetFromUrl() = suspendCoroutine<sheets.Spreadsheet> { cont ->
-        gapi.client.sheets.spreadsheets.get(object: sheets.SpreadsheetGetType {
-            override var spreadsheetId = url
+        @NoLiveLiterals
+        private suspend fun getSheetFromUrl(url: String) = suspendCoroutine<sheets.Spreadsheet> { cont ->
+            val obj = js("{}")
+            obj["spreadsheetId"] = url
                 .removePrefix("https://docs.google.com/spreadsheets/d/")
                 .split("/")[0]
-        }).execute {
-            if (it.status != 200) {
-                cont.resumeWithException(Error("unable to load sheet: ${it.statusText}"))
-                return@execute Unit
+            obj["includeGridData"] = true
+
+            gapi.client.sheets.spreadsheets.get(obj).execute {
+                cont.resume(it.result)
             }
-            cont.resume(it.result)
         }
     }
 
-    private suspend fun loadSheet() {
-        sheet = getSheetFromUrl()
+    private val rows = sheet.sheets!![0].data!![0].rowData!!
+
+    private val principleIndexes = rows[0].values!!.mapIndexed { i, data ->
+        (data.formattedValue?.trimAsPrinciple() ?: "") to i
+    }.drop(1).filter {
+        filterList.all { filter -> !it.first.lowercase().contains(filter) } &&
+            it.first.isNotBlank()
+    }.toMap()
+
+    override val principles get() = principleIndexes.keys
+
+    private val peopleIndexes = rows
+        .mapIndexed { i, data -> (data.values!![0].formattedValue ?: "") to i }
+        .drop(1)
+        .filter { it.first.isNotBlank() }
+        .toMap()
+
+    override val people get() = peopleIndexes.keys
+
+    override operator fun get(person: String, principle: String): Int {
+        val pers = peopleIndexes[person]!!
+        val princ = principleIndexes[principle]!!
+        return rows[pers].values!![princ].formattedValue!!.toIntOrNull() ?: 0
     }
 
-    private lateinit var sheet: sheets.Spreadsheet
+    override fun getNote(person: String, principle: String): String {
+        val pers = peopleIndexes[person]!!
+        val princ = principleIndexes[principle]!!
+        return rows[pers].values!![princ].note ?: ""
+    }
 }
diff --git a/src/jsMain/kotlin/pekstuff/PekNote.kt b/src/jsMain/kotlin/pekstuff/PekNote.kt
new file mode 100644
index 0000000000000000000000000000000000000000..11077af44491a0524980eb8df80ba609b5587451
--- /dev/null
+++ b/src/jsMain/kotlin/pekstuff/PekNote.kt
@@ -0,0 +1,28 @@
+package pekstuff
+
+import kotlinx.browser.document
+import kotlinx.coroutines.delay
+import org.w3c.dom.HTMLInputElement
+import org.w3c.dom.HTMLTextAreaElement
+
+object PekNote {
+    val noteNameCnt get() = document.querySelector("#comment-container > div.uk-padding.uk-text-center")
+    val noteName get() = noteNameCnt?.textContent
+
+    val noteCnt get() = document.getElementById("comment-textarea") as? HTMLTextAreaElement
+    val btn get() = document.querySelector("#new_point_detail_comment > article > div.uk-clearfix > div.uk-float-right > input.uk-button") as? HTMLInputElement
+    var note
+        get() = noteCnt!!.value
+        set(value) {
+            noteCnt!!.value = value
+            btn!!.click()
+        }
+
+    suspend fun waitUntilLoaded(person: String, principle: String) {
+        val expected = "$person - $principle"
+        while (noteName != expected) {
+            println("$noteName != $expected")
+            delay(100)
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/jsMain/kotlin/pekstuff/PekTable.kt b/src/jsMain/kotlin/pekstuff/PekTable.kt
index 2da963e33372113179f2f44c4538350d40e759a4..c4511dac503ddfd88a2b54da79b0c2d6a9afb1a4 100644
--- a/src/jsMain/kotlin/pekstuff/PekTable.kt
+++ b/src/jsMain/kotlin/pekstuff/PekTable.kt
@@ -1,6 +1,7 @@
 package pekstuff
 
 import kotlinx.browser.document
+import kotlinx.browser.window
 import kotlinx.coroutines.*
 import org.w3c.dom.Element
 import org.w3c.dom.HTMLInputElement
@@ -59,13 +60,14 @@ object PekTable {
             elem.style.background = origBg
         }
 
+        elem.click()
+
         if (elem.value.toIntOrNull() == value) { // don't update if up-to-date
             // sort of ugly workaround, meh.
             PekDelay.skipNext()
             return
         }
 
-        elem.click()
         elem.value = value.toString()
         elem.trigger()
         tableElem.click()
diff --git a/src/jsMain/kotlin/processing/ProcessCSV.kt b/src/jsMain/kotlin/processing/Process.kt
similarity index 82%
rename from src/jsMain/kotlin/processing/ProcessCSV.kt
rename to src/jsMain/kotlin/processing/Process.kt
index 01c9a9d6e85468db4043ba01d4a5a58428955cb0..616f34418d79696ff22915acfe8cd7229ee94b8c 100644
--- a/src/jsMain/kotlin/processing/ProcessCSV.kt
+++ b/src/jsMain/kotlin/processing/Process.kt
@@ -1,7 +1,10 @@
 package processing
 
-import datasources.CSVTable
+import datasources.DataSource
+import datasources.NoteDataSource
+import kotlinx.coroutines.delay
 import pekstuff.PekDelay
+import pekstuff.PekNote
 import pekstuff.PekTable
 import kotlin.math.max
 
@@ -12,9 +15,11 @@ class ProcessingError(private val errors: List<String>): Exception(errors.toStri
     }
 }
 
-suspend fun CSVTable.process(
+suspend fun DataSource.process(
     progress: (Double) -> Unit = {}
 ) {
+    // todo show comment stuff
+
     progress(0.0)
     val principleMappings = principles.associateWith {
         PekTable.principles.findClosestMatch(it)
@@ -22,7 +27,7 @@ suspend fun CSVTable.process(
 
     val errors = mutableListOf<String>()
 
-    people.forEachIndexed { i, person ->
+    people.sorted().forEachIndexed { i, person ->
         val pekPerson = PekTable.people.findClosestMatch(person)
 
         if (pekPerson == null) {
@@ -35,6 +40,11 @@ suspend fun CSVTable.process(
 
             PekTable[pekPerson, pekPrinciple] = point
             PekDelay()
+            if (this is NoteDataSource) {
+                PekNote.waitUntilLoaded(pekPerson, pekPrinciple)
+                PekNote.note = getNote(person, principle)
+            }
+
             progress(calcProgress(i, j, people.size, principles.size))
 
             if (person != pekPerson) {
diff --git a/src/jsMain/kotlin/processing/ProcessGSheet.kt b/src/jsMain/kotlin/processing/ProcessGSheet.kt
deleted file mode 100644
index 1f5e19f81f3067b436f16a0943ff906288d622db..0000000000000000000000000000000000000000
--- a/src/jsMain/kotlin/processing/ProcessGSheet.kt
+++ /dev/null
@@ -1 +0,0 @@
-package processing
\ No newline at end of file
diff --git a/src/jsMain/kotlin/ui/SheetsModal.kt b/src/jsMain/kotlin/ui/SheetsModal.kt
index fe9f4c16403ee991112c07b7b649b7c6a5fbeaf5..684e49fe671eacdbb76b6cb9493a4eaaeb99054f 100644
--- a/src/jsMain/kotlin/ui/SheetsModal.kt
+++ b/src/jsMain/kotlin/ui/SheetsModal.kt
@@ -9,6 +9,7 @@ import org.jetbrains.compose.web.attributes.InputType
 import org.jetbrains.compose.web.attributes.disabled
 import org.jetbrains.compose.web.dom.*
 import org.w3c.dom.HTMLElement
+import processing.process
 
 private object SheetsModal: ModalType {
     override val title = "Google Sheets import"
@@ -18,7 +19,7 @@ private object SheetsModal: ModalType {
         closeId: String,
         setState: (State) -> Unit,
         hint: String,
-        setHint: (String) -> Unit
+        setHint: (String) -> Unit,
     ) {
         val scope = rememberCoroutineScope()
 
@@ -33,12 +34,15 @@ private object SheetsModal: ModalType {
             }
         }
 
+        var sheetUrl by remember { mutableStateOf("") }
         var sheet by remember { mutableStateOf<GSheet?>(null) }
 
         setHint(
-            if (!signedIn)  "Jelentkezz be"
-            else if (sheet == null) "Adj meg egy Google Sheet URL-t"
-            else ""
+            when {
+                !signedIn -> "Jelentkezz be"
+                sheetUrl.isBlank() || !sheetUrl.contains("https://docs.google.com/spreadsheets") -> "Adj meg egy Google Sheet URL-t"
+                else -> ""
+            }
         )
 
         withLabel(
@@ -72,12 +76,11 @@ private object SheetsModal: ModalType {
 
         Br {}
 
-        var sheetUrl by remember { mutableStateOf("") }
         withLabel("Google Sheet URL") { id ->
             Input(type = InputType.Text, attrs = {
                 id(id)
                 classes("uk-input")
-                onChange { sheetUrl = it.value }
+                onInput { sheetUrl = it.value }
                 value(sheetUrl)
             })
         }
@@ -87,7 +90,9 @@ private object SheetsModal: ModalType {
                 classes("uk-button", "uk-button-primary")
                 onClick {
                     scope.launch {
-                        println("zsa")
+                        sheet = GSheet.new(sheetUrl)
+                        sheet?.process { setState(ImportInProgress(it)) }
+                        setState(Ready)
                     }
                     (document.getElementById(closeId) as HTMLElement).click()
                 }