İçeriğe geç
academia.sh

Ders 07 / 10

Ekip Topolojileri

Akış odaklı ekip düzenlerinin ölçülmesi: aynı modül grafiği ve aynı iş kalemi kümesi bileşen odaklı, akış odaklı ve karma üç ekip düzeninde koşturulur; el değiştirme, bekleme ve yeniden iş sayılarının yanına ekip başına bilişsel yük, dış talep, yinelenen uzmanlık ve ortak bileşenin darboğaza dönüşmesi eklenir.

İçindekiler

Önceki ders iki ekip bölünmesini aynı modül grafiği üzerinde karşılaştırdı ve akış odaklı bölünmenin akış süresini iki kattan fazla kısalttığını saydı. O tabloda bir sütun yoktu: ekiplerin taşıdığı yük. Akış odaklı bir ekip kalemini uçtan uca bitirebilmek için sahip olduğu modüllerin yanında bağımlı olduğu dış arayüzleri de bilmek zorundadır.

Bilişsel yük, bir ekibin işini yapabilmek için aynı anda zihninde tutmak zorunda olduğu şeyin büyüklüğüdür; burada iki sayıyla kurulur: ekibin sahip olduğu modül sayısı ve modüllerinin dışarıdan ithal ettiği modül sayısı. Aynı on iki iş kalemi üç düzende koşturulur — bileşen odaklı, akış odaklı ve karma. Through-line bölgesel kütüphane ağıdır ve kurgudur.

Üçüncü Düzen ve Yük Ölçüsü

ET8 — önceki dersin on yedi modüllü grafiği, iki bölünmesi ve on iki iş kalemi değişmeden kullanılır. Gerekçe: üç düzen ancak aynı grafik ve aynı iş yükü üzerinde karşılaştırılabilir.

ET9 — karma düzende yedi ekip vardır: üç akış ekibi, bir arayüz, bir kural, bir köprü ve bir platform ekibi; on iki kanal bulunur. Gerekçe: karma düzen alan bilgisini akışa, teknik bilgiyi ortak ekibe verme girişimidir; ekip sayısı arttığı için kanal sayısı da artar.

ET10 — bir ekibin bilişsel yükü, sahip olduğu modül sayısı ile modüllerinin dışarıdan ithal ettiği ayrık modül sayısının toplamıdır. ET11 — bir ekibin dış talebi, başka bir ekibin başlattığı ve o ekibin modüllerine dokunan kalem sayısıdır. Gerekçe: yük ekibin bildiği şeyi, dış talep ise ekibe başkasından gelen işi ölçer; bir ekipte biri düşükken diğeri yüksek olabilir.

// duzen.mjs — ayni modul grafigi ve ayni is kalemleri uc ekip duzeninde kosturulur (model)
import { writeFileSync } from "node:fs";

// ET8 — onceki dersin 17 modullu grafigi ve 12 is kalemi degismeden kullanilir
const ITHAL = {
  subeUcu: "oduncAkisi ucretAkisi rezervasyonAkisi ortakBicim",
  personelUcu: "uyelikAkisi oduncAkisi ucretAkisi ortakBicim",
  ceptenErisim: "oduncAkisi rezervasyonAkisi katalogKoprusu ortakBicim",
  oduncAkisi: "oduncKurali katalogKurali depoErisimi bildirimKuyrugu ortakBicim",
  ucretAkisi: "ucretKurali depoErisimi bildirimKuyrugu ortakBicim",
  uyelikAkisi: "uyelikKurali kimlikKoprusu depoErisimi ortakBicim",
  rezervasyonAkisi: "oduncKurali katalogKoprusu depoErisimi bildirimKuyrugu ortakBicim",
  oduncKurali: "ortakBicim", ucretKurali: "oduncKurali ortakBicim",
  katalogKurali: "ortakBicim", uyelikKurali: "ortakBicim",
  depoErisimi: "olayGunlugu ortakBicim", katalogKoprusu: "katalogKurali ortakBicim",
  kimlikKoprusu: "ortakBicim", bildirimKuyrugu: "olayGunlugu ortakBicim",
  olayGunlugu: "ortakBicim", ortakBicim: "",
};
const M = Object.keys(ITHAL);
const KENAR = Object.entries(ITHAL)
  .flatMap(([a, s]) => (s ? s.split(" ").map((b) => [a, b]) : []));
const KALEM = [
  ["gecikme ucreti orani", "ucretAkisi ucretKurali subeUcu ortakBicim"],
  ["rezervasyon iptali", "ceptenErisim rezervasyonAkisi oduncKurali bildirimKuyrugu"],
  ["uyelik hatirlatmasi", "uyelikAkisi uyelikKurali bildirimKuyrugu personelUcu"],
  ["katalog kaydinda alan", "katalogKoprusu katalogKurali ortakBicim ceptenErisim"],
  ["odunc suresi uzatma", "oduncAkisi oduncKurali subeUcu"],
  ["kimlikte ikinci adim", "kimlikKoprusu uyelikAkisi personelUcu ortakBicim"],
  ["ucret iadesi kaydi", "ucretAkisi depoErisimi olayGunlugu"],
  ["sube gecikme raporu", "personelUcu depoErisimi oduncAkisi"],
  ["bildirim metni bicimi", "bildirimKuyrugu ortakBicim"],
  ["rezervasyon sirasi", "ceptenErisim rezervasyonAkisi subeUcu"],
  ["odunc kurali istisnasi", "oduncKurali ucretKurali oduncAkisi ucretAkisi"],
  ["olay gunlugune alan", "olayGunlugu ortakBicim depoErisimi"],
];

const DUZEN = [
  { ad: "bilesen odakli", bolunme: {                        // ET8: onceki dersin bolunme A'si
    arayuz: "subeUcu personelUcu ceptenErisim",
    akis: "oduncAkisi ucretAkisi uyelikAkisi rezervasyonAkisi",
    kural: "oduncKurali ucretKurali katalogKurali uyelikKurali",
    altyapi: "depoErisimi katalogKoprusu kimlikKoprusu bildirimKuyrugu olayGunlugu",
    ortak: "ortakBicim" },
    kanal: "arayuz-akis akis-kural akis-altyapi kural-altyapi" },
  { ad: "akis odakli", bolunme: {                           // ET8: onceki dersin bolunme B'si
    deneyim: "subeUcu personelUcu ceptenErisim",
    odunc: "oduncAkisi oduncKurali rezervasyonAkisi depoErisimi",
    ucret: "ucretAkisi ucretKurali",
    uyelik: "uyelikAkisi uyelikKurali kimlikKoprusu",
    katalog: "katalogKurali katalogKoprusu",
    platform: "ortakBicim olayGunlugu bildirimKuyrugu" },
    kanal: "deneyim-odunc deneyim-ucret deneyim-uyelik odunc-ucret odunc-katalog " +
      "odunc-platform ucret-platform uyelik-platform katalog-platform" },
  { ad: "karma", bolunme: {                                 // ET9: akis ekipleri + ortak bilesen
    deneyim: "subeUcu personelUcu ceptenErisim",
    odunc: "oduncAkisi rezervasyonAkisi",
    ucret: "ucretAkisi", uyelik: "uyelikAkisi",
    kural: "oduncKurali ucretKurali katalogKurali uyelikKurali",
    kopru: "depoErisimi katalogKoprusu kimlikKoprusu",
    platform: "ortakBicim olayGunlugu bildirimKuyrugu" },
    kanal: "deneyim-odunc deneyim-ucret deneyim-uyelik odunc-kural ucret-kural uyelik-kural " +
      "odunc-kopru uyelik-kopru kural-kopru kural-platform kopru-platform deneyim-platform" },
];

function kur({ ad, bolunme, kanal }) {
  const sahip = {}, E = Object.keys(bolunme), kom = Object.fromEntries(E.map((e) => [e, []]));
  for (const [e, ms] of Object.entries(bolunme)) for (const m of ms.split(" ")) sahip[m] = e;
  for (const k of kanal.split(" ")) {
    const [x, y] = k.split("-");
    kom[x].push(y); kom[y].push(x);
  }
  const d = {};
  for (const s of E) {
    d[s] = Object.fromEntries(E.map((e) => [e, -1]));
    d[s][s] = 0;
    for (let q = [s]; q.length; ) {
      const u = q.shift();
      for (const v of kom[u]) if (d[s][v] < 0) { d[s][v] = d[s][u] + 1; q.push(v); }
    }
  }
  const deg = Object.fromEntries(M.map((m) => [m, new Set([sahip[m]])]));
  for (const [, ms] of KALEM) for (const m of ms.split(" ")) deg[m].add(sahip[ms.split(" ")[0]]);
  // ET10 — bilissel yuk: sahip olunan modul + disaridan ithal edilen modul (dis arayuz)
  const yuk = Object.fromEntries(E.map((e) => [e, { sahip: bolunme[e].split(" ").length,
    disArayuz: new Set(), disEkip: new Set(), disTalep: 0 }]));
  for (const [a, b] of KENAR) if (sahip[a] !== sahip[b]) {
    yuk[sahip[a]].disArayuz.add(b);
    yuk[sahip[a]].disEkip.add(sahip[b]);
  }
  // ET11 — dis talep: baska ekibin baslattigi ve bu ekibin modulune dokunan kalem
  for (const [, ms] of KALEM) {
    const dizi = ms.split(" "), bas = sahip[dizi[0]];
    for (const e of new Set(dizi.map((m) => sahip[m]))) if (e !== bas) yuk[e].disTalep += 1;
  }
  return { ad, kanalSayisi: kanal.split(" ").length, bolunme, sahip, d, deg, yuk, E };
}

const D = DUZEN.map(kur);
writeFileSync("duzen.json", JSON.stringify({ M, KENAR, KALEM, D: D.map((x) =>
  ({ ...x, deg: Object.fromEntries(M.map((m) => [m, [...x.deg[m]]])) })) }));

const orta = (v) => `${v[0]} / ${v[(v.length - 1) >> 1]} / ${v[v.length - 1]}`;
console.log(`${"duzen".padEnd(16)}${"ekip".padStart(6)}${"kanal".padStart(7)}` +
  `${"sahip olunan modul".padStart(22)}${"bilissel yuk".padStart(22)}`);
console.log(`${"".padEnd(29)}${"en az/ortanca/en cok".padStart(22)}${"en az/ortanca/en cok".padStart(22)}`);
for (const x of D) {
  const mod = x.E.map((e) => x.yuk[e].sahip).sort((a, b) => a - b);
  const yk = x.E.map((e) => x.yuk[e].sahip + x.yuk[e].disArayuz.size).sort((a, b) => a - b);
  console.log(`${x.ad.padEnd(16)}${String(x.E.length).padStart(6)}` +
    `${String(x.kanalSayisi).padStart(7)}${orta(mod).padStart(22)}${orta(yk).padStart(22)}`);
}

for (const x of D) {
  console.log(`\n${x.ad} — ekip basina bilissel yuk`);
  console.log(`${"ekip".padEnd(12)}${"sahip".padStart(7)}${"dis arayuz".padStart(12)}` +
    `${"dis ekip".padStart(10)}${"yuk".padStart(6)}${"dis talep".padStart(11)}`);
  for (const e of x.E)
    console.log(`${e.padEnd(12)}${String(x.yuk[e].sahip).padStart(7)}` +
      `${String(x.yuk[e].disArayuz.size).padStart(12)}${String(x.yuk[e].disEkip.size).padStart(10)}` +
      `${String(x.yuk[e].sahip + x.yuk[e].disArayuz.size).padStart(6)}` +
      `${String(x.yuk[e].disTalep).padStart(11)}`);
}
duzen             ekip  kanal    sahip olunan modul          bilissel yuk
                               en az/ortanca/en cok  en az/ortanca/en cok
bilesen odakli       5      4             1 / 4 / 5            1 / 7 / 13
akis odakli          6      9             2 / 3 / 4             3 / 5 / 9
karma                7     12             1 / 3 / 4             3 / 5 / 9

bilesen odakli — ekip basina bilissel yuk
ekip          sahip  dis arayuz  dis ekip   yuk  dis talep
arayuz            3           6         3     9          5
akis              4           9         3    13          5
kural             4           1         1     5          5
altyapi           5           2         2     7          4
ortak             1           0         0     1          5

akis odakli — ekip basina bilissel yuk
ekip          sahip  dis arayuz  dis ekip   yuk  dis talep
deneyim           3           6         5     9          5
odunc             4           5         2     9          5
ucret             2           4         2     6          1
uyelik            3           2         2     5          0
katalog           2           1         1     3          0
platform          3           0         0     3          6

karma — ekip basina bilissel yuk
ekip          sahip  dis arayuz  dis ekip   yuk  dis talep
deneyim           3           6         5     9          5
odunc             2           6         3     8          4
ucret             1           4         3     5          1
uyelik            1           4         3     5          1
kural             4           1         1     5          5
kopru             3           3         2     6          3
platform          3           0         0     3          6

Yükün Dağılımı

İlk tablo bileşen odaklı düzenin sorununu ortaya koyar: yük en az 1, en çok 13’tür. akis ekibi dört modüle sahiptir ama dokuz dış arayüze bağımlıdır; ortak ekibi tek modüle sahiptir ve hiçbir dış arayüze bağımlı değildir. Aynı kuruluşta bir ekip on üç şeyi, başka bir ekip bir şeyi bilmek zorundadır. Akış odaklı ve karma düzenlerde aralık 3–9’a iner.

Dengelenmenin nasıl olduğu ikinci tabloda görünür. akis ekibinin dokuz dış arayüzü üç ekibe bölünür: odunc beş, ucret dört, uyelik iki dış arayüze bağımlıdır. Yük yok olmadı, bölündü — ve bölünme işe yarar, çünkü her akış ekibi kendi alanının kuralını da sahiplenir: odunc ekibi oduncKurali modülünü içeride tutar ve o modül artık dış arayüz sayılmaz.

Dış talep sütunu ters yönde okunur. Akış odaklı düzende platform ekibinin bilişsel yükü üçtür — en düşük değerlerden biri — ama dış talebi altıdır. Yükü en hafif olan ekip, işin en çok geçtiği ekiptir.

Akış Sayıları ve Yinelenen Uzmanlık

İkinci koşum üç düzeni akış cinsinden karşılaştırır ve iki yeni sayı ekler.

ET12 — bir modülün yinelenen uzmanlığı, o modülü sahibi olmadığı halde ithal eden ekip sayısıdır. Gerekçe: bir modülü ithal eden her ekip onun arayüzünü öğrenmek zorundadır; aynı bilgi kaç ekipte tekrarlanıyorsa uzmanlık o kadar yinelenmiştir.

ET13 — darboğaz, en çok dış talep alan ekiptir; o ekibin modüllerine dokunan yeniden iş kalemleri ayrıca sayılır. Gerekçe: bedelin nerede toplandığı ancak bu iki sayı birlikte okunarak görülür.

// akis2.mjs — uc duzende akis sayilari ve yinelenen uzmanlik
import { readFileSync } from "node:fs";
const { M, KENAR, KALEM, D } = JSON.parse(readFileSync("duzen.json", "utf8"));

const BEKLE = [0, 1, 3, 5], YOK = 8;      // ET6'nin bekleme cetveli degismeden kullanilir
const kosum = (x) => KALEM.map(([ad, dizi]) => {
  const ms = dizi.split(" "), sira = [...new Set(ms.map((m) => x.sahip[m]))];
  let bek = 0, enUzun = 0, kopuk = 0;
  for (let j = 1; j < sira.length; j++) {
    const u = x.d[sira[j - 1]][sira[j]], b = u < 0 ? YOK : BEKLE[u];
    bek += b; enUzun = Math.max(enUzun, b);
    if (u < 0 || u >= 2) kopuk += 1;
  }
  const neden = [];
  if (kopuk) neden.push("kisit");
  if (ms.some((m) => x.deg[m].length >= 3)) neden.push("sinir");
  if (sira.length >= 4) neden.push("bilgi");
  const cal = ms.length + neden.length * 2, bekT = bek + neden.length * enUzun;
  return { ad, ekip: sira.length, eld: sira.length - 1, cal, bek: bekT, akis: cal + bekT, neden };
});

const R = D.map((x) => ({ ad: x.ad, k: kosum(x) }));
const T = (r, f) => r.k.reduce((t, y) => t + f(y), 0);
const n = (r, c) => r.k.filter((y) => y.neden.includes(c)).length;
console.log(`${"duzen".padEnd(16)}${"el deg.".padStart(9)}${"bekleme".padStart(9)}` +
  `${"akis".padStart(7)}${"bekleme payi".padStart(14)}${"yen. is".padStart(9)}` +
  `${"kisit".padStart(7)}${"sinir".padStart(7)}${"bilgi".padStart(7)}${"tek ekip".padStart(10)}`);
for (const r of R)
  console.log(`${r.ad.padEnd(16)}${String(T(r, (y) => y.eld)).padStart(9)}` +
    `${String(T(r, (y) => y.bek)).padStart(9)}${String(T(r, (y) => y.akis)).padStart(7)}` +
    `${`%${(100 * T(r, (y) => y.bek) / T(r, (y) => y.akis)).toFixed(1)}`.padStart(14)}` +
    `${String(T(r, (y) => y.neden.length)).padStart(9)}${String(n(r, "kisit")).padStart(7)}` +
    `${String(n(r, "sinir")).padStart(7)}${String(n(r, "bilgi")).padStart(7)}` +
    `${String(r.k.filter((y) => y.ekip === 1).length).padStart(10)}`);

// ET12 — yinelenen uzmanlik: bir modulu sahibi olmadigi halde ithal eden ekip sayisi
const bagimli = (x, m) => new Set(KENAR.filter(([a, b]) => b === m && x.sahip[a] !== x.sahip[m])
  .map(([a]) => x.sahip[a])).size;
const ilgi = M.filter((m) => D.some((x) => bagimli(x, m) >= 2));
console.log(`\n${"modul".padEnd(18)}${D.map((x) => x.ad.padStart(16)).join("")}   sahibi (uc duzende)`);
for (const m of ilgi)
  console.log(`${m.padEnd(18)}${D.map((x) => String(bagimli(x, m)).padStart(16)).join("")}` +
    `   ${D.map((x) => x.sahip[m]).join(" / ")}`);
console.log(`${"TOPLAM ekip-modul".padEnd(18)}` +
  `${D.map((x) => String(M.reduce((t, m) => t + bagimli(x, m), 0)).padStart(16)).join("")}`);

// ET13 — darbogaz: en cok dis talep alan ekip ve o ekibin modullerine dokunan yeniden is
console.log(`\n${"duzen".padEnd(16)}${"en cok dis talep alan ekip".padStart(28)}` +
  `${"dis talep".padStart(11)}${"sahip".padStart(7)}${"o ekibin moduluyle gelen yen. is".padStart(34)}`);
D.forEach((x, i) => {
  const e = x.E.reduce((a, b) => (x.yuk[a].disTalep >= x.yuk[b].disTalep ? a : b));
  const ykl = R[i].k.filter((y, j) => y.neden.length &&
    KALEM[j][1].split(" ").some((m) => x.sahip[m] === e)).length;
  console.log(`${x.ad.padEnd(16)}${e.padStart(28)}${String(x.yuk[e].disTalep).padStart(11)}` +
    `${String(x.yuk[e].sahip).padStart(7)}${String(ykl).padStart(34)}`);
});
duzen             el deg.  bekleme   akis  bekleme payi  yen. is  kisit  sinir  bilgi  tek ekip
bilesen odakli         24      203    292         %69.5       24      8     11      5         0
akis odakli            17       55    126         %43.7       15      4     11      0         1
karma                  25       78    163         %47.9       22      5     12      5         1

modul               bilesen odakli     akis odakli           karma   sahibi (uc duzende)
katalogKurali                    2               1               2   kural / katalog / kural
depoErisimi                      1               2               3   altyapi / odunc / kopru
katalogKoprusu                   2               2               2   altyapi / katalog / kopru
bildirimKuyrugu                  1               2               2   altyapi / platform / platform
ortakBicim                       4               5               6   ortak / platform / platform
TOPLAM ekip-modul               18              18              24

duzen             en cok dis talep alan ekip  dis talep  sahip  o ekibin moduluyle gelen yen. is
bilesen odakli                        arayuz          5      3                                 7
akis odakli                         platform          6      3                                 8
karma                               platform          6      3                                 8

Akış Odaklı Düzenin Kaybettiği Yer

Akış sayılarında akış odaklı düzen üç düzenin de önündedir: en az el değiştirme (17), en az bekleme (55 tur), en kısa akış (126 tur), en az yeniden iş (15). Karma düzen beklenenin tersini yapar — yirmi beş el değiştirmeyle üç düzenin en yükseğidir, bileşen odaklının yirmi dördünü de aşar. Nedeni yapısaldır: karma düzen akışı böldüğü gibi kuralı, köprüyü ve platformu da ayrı ekiplere verir, yani bir kalem hem akış sınırını hem katman sınırını geçer. sinir nedeninde de en yüksektir (12).

Akış odaklı düzenin kaybettiği yer ikinci tablodadır. Toplam ekip-modül bağımlılık çifti bileşen odaklı düzende 18, akış odaklı düzende de 18’dir — akış odaklı düzen yinelenen uzmanlığı hiç azaltmaz. Tek tek satırlarda ise dağılım kayar: depoErisimi bir ekip yerine iki, bildirimKuyrugu bir yerine iki, ortakBicim dört yerine beş ekip tarafından dışarıdan ithal edilir. Ortak biçim modülünü bilmek zorunda olan ekip sayısı artmıştır, çünkü her akış ekibi kendi kalemini uçtan uca bitirirken o modülün arayüzüne çarpar. Karma düzende toplam 24’e çıkar ve ortakBicim altı ekibe ulaşır: düzen ne kadar bölünürse yinelenen uzmanlık o kadar artar.

Üçüncü tablo ortak bileşenin ne olduğunu adlandırır. Akış odaklı ve karma düzenlerde darboğaz platform ekibidir: üç modüle sahiptir, altı dış talep alır ve yeniden işe giren kalemlerin sekizi onun bir modülüne dokunur. Ortak bileşen sahipsiz değildir — sahibi vardır, ama kendi akışına ait bir kalem üretmez, yalnız başkasının kalemini bekletir. Bileşen odaklı düzende aynı rolü arayuz ekibi oynar (beş dış talep, yedi yeniden iş kalemi), fakat orada darboğazın yükü de yüksektir (9); akış odaklı düzende üçtür. Düzen değiştikçe darboğazın yeri değişir, varlığı değişmez.

Akış odaklı düzen akış sayılarını ve yük dengesini birlikte iyileştirir; bunu yinelenen uzmanlığı azaltmadan, hatta ortak modüllerde artırarak yapar. Karma düzen yükü aynı ölçüde dengeler ama el değiştirmeyi ve yinelenen uzmanlığı en kötü noktaya çıkarır.

Özet

  • Aynı grafik ve aynı 12 kalem üç düzende koşturuldu: bileşen odaklı (5 ekip, 4 kanal), akış odaklı (6 ekip, 9 kanal) ve karma (7 ekip, 12 kanal).
  • Bileşen odaklı düzende bilişsel yük 1 ile 13 arasında dağılır; akis ekibi 4 modüle sahipken 9 dış arayüze bağımlıdır. Akış odaklı ve karma düzenlerde aralık 3–9’a iner.
  • Akış sayılarında akış odaklı düzen önde: el değiştirme 17, bekleme 55 tur, akış 126 tur, yeniden iş 15. Karma düzen 25 el değiştirmeyle üç düzenin en yükseğidir, bileşen odaklının 24’ünü de aşar.
  • Yinelenen uzmanlıkta akış odaklı düzenin kazancı yoktur: toplam ekip-modül bağımlılık çifti bileşen odaklıda da akış odaklıda da 18, karma düzende 24’tür.
  • ortakBicim modülünü dışarıdan ithal eden ekip sayısı üç düzende sırasıyla 4, 5 ve 6’dır; düzen bölündükçe ortak biçimi bilmek zorunda olan ekip sayısı artar.
  • Akış odaklı ve karma düzende darboğaz platform ekibidir: bilişsel yükü 3, dış talebi 6 ve yeniden işe giren kalemlerin 8’i onun modüllerine dokunur. Darboğazın yeri değişir, varlığı değişmez.

Sonraki Adım

Bu iki derste ekip sınırının nereden geçtiği ölçüldü ve bir çeyreklik iş yükü üç düzende koşturuldu. Her koşumda iş kaleminin dokunduğu modüller baştan biliniyordu. Gerçekte bu bilgi kalem başlarken yoktur: bir kalemin ne kadar süreceği ancak tahmin edilir ve tahmin ilerledikçe daralır. Sonraki ders tahmini ölçer — bir tahmin kümesi gerçekleşen sürelerle karşılaştırılır, hata payı ve belirsizliğin aşama aşama daralması sayılır, tek kalem tahmini ile toplam tahmininin neden farklı davrandığı gösterilir.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat