{
  "ad": "NotOrtalama",
  "slug": "not-ortalama",
  "surum": "1.2.0",
  "dil": "tr",
  "kategori": "egitim",
  "aciklama": "Ağırlıklı not ortalamasını ve hedef ortalama için finalden gereken notu hesaplar.",
  "deterministik": true,
  "offline": true,
  "motor": {
    "kaynak": "./index.html",
    "baslangic_isareti": "// ==MOTOR-BASLANGIC==",
    "bitis_isareti": "// ==MOTOR-BITIS==",
    "saf_fonksiyonlar": true
  },
  "girdi_alanlari": {
    "satir": {
      "tip": "nesne",
      "birim": null,
      "zorunlu": true,
      "alanlar": {
        "ad": {
          "tip": "metin",
          "birim": null,
          "zorunlu": true,
          "aralik": null,
          "aciklama": "Not bileşeninin adı; örneğin Vize, Final, Ödev veya Proje."
        },
        "not": {
          "tip": "sayi",
          "birim": "puan",
          "zorunlu": true,
          "aralik": {
            "min": 0,
            "max": 100,
            "dahil": true
          },
          "aciklama": "Bileşenden alınan not."
        },
        "agirlik": {
          "tip": "sayi",
          "birim": "yuzde",
          "zorunlu": true,
          "aralik": {
            "min": 0,
            "max": 100,
            "dahil": true
          },
          "aciklama": "Bileşenin toplam ortalamadaki yüzde ağırlığı."
        }
      }
    },
    "hedef": {
      "tip": "sayi",
      "birim": "puan",
      "zorunlu": true,
      "aralik": {
        "min": 0,
        "max": 100,
        "dahil": true
      }
    },
    "finalAgirligi": {
      "tip": "sayi",
      "birim": "yuzde",
      "zorunlu": true,
      "aralik": {
        "min_haric": 0,
        "max": 100,
        "dahil": true
      }
    },
    "baraj": {
      "tip": "sayi",
      "birim": "puan",
      "zorunlu": false,
      "varsayilan": 0,
      "aralik": {
        "min": 0,
        "max": 100,
        "dahil": true
      },
      "aciklama": "Yalnız kullanıcı kurumundaki final barajını biliyorsa girilir."
    },
    "orantila": {
      "tip": "boolean",
      "birim": null,
      "zorunlu": false,
      "varsayilan": false
    }
  },
  "fonksiyonlar": {
    "hesaplaOrtalama": {
      "imza": "hesaplaOrtalama({satirlar, orantila}) -> {ortalama, katkilar, agirlikToplami, uyarilar}",
      "formul": "ortalama = Σ(not × ağırlık) / Σ(ağırlık)",
      "girdi": {
        "satirlar": {
          "tip": "nesne[]",
          "birim": null,
          "zorunlu": true,
          "min_oge": 1,
          "oge": {
            "ad": {
              "tip": "metin",
              "birim": null
            },
            "not": {
              "tip": "sayi",
              "birim": "puan"
            },
            "agirlik": {
              "tip": "sayi",
              "birim": "yuzde"
            }
          }
        },
        "orantila": {
          "tip": "boolean",
          "birim": null,
          "zorunlu": false,
          "varsayilan": false
        }
      },
      "cikti": {
        "ortalama": {
          "tip": "sayi|null",
          "birim": "puan",
          "kesinlik": "iki_ondalik_yuvarlanmis",
          "yaklasik": false,
          "yuvarlama_yonu": "yari_yukari",
          "yuvarlama_modu": "ROUND_HALF_UP",
          "ondalik_hane": 2,
          "aciklama": "Geçerli sonuç 0–100 aralığında ölçek-duyarlı yarı-yukarı (ROUND_HALF_UP) iki ondalığa yuvarlanır; 10,075 → 10,08. Hesap engellendiyse null döner."
        },
        "katkilar": {
          "tip": "nesne[]",
          "birim": null,
          "oge": {
            "ad": {
              "tip": "metin",
              "birim": null
            },
            "not": {
              "tip": "sayi",
              "birim": "puan"
            },
            "agirlik": {
              "tip": "sayi",
              "birim": "yuzde"
            },
            "katki": {
              "tip": "sayi",
              "birim": "puan",
              "kesinlik": "ham_makine_degeri",
              "yaklasik": false,
              "yuvarlama_yonu": "yok",
              "aciklama": "not × ağırlık / 100 formülünün ham sonucudur; görünür sunumda iki ondalığa biçimlenir, kırpılmaz."
            },
            "katkiYuvarlanmis": {
              "tip": "sayi",
              "birim": "puan",
              "kesinlik": "iki_ondalik_yuvarlanmis",
              "yaklasik": false,
              "yuvarlama_yonu": "yari_yukari",
              "yuvarlama_modu": "ROUND_HALF_UP",
              "ondalik_hane": 2,
              "aciklama": "katki alanının ölçek-duyarlı yarı-yukarı iki ondalığa yuvarlanmış dönüşümü. Yuvarlanmış katkıların toplamı (0,33+0,33+0,33=0,99) kesin toplam değildir; toplam ham katkılardan kurulmalıdır."
            }
          },
          "formul": "katki = not × ağırlık / 100 (ham); katkiYuvarlanmis = ROUND_HALF_UP(katki, 2)"
        },
        "agirlikToplami": {
          "tip": "sayi",
          "birim": "yuzde"
        },
        "uyarilar": {
          "tip": "hata_kodu[]",
          "birim": null
        }
      },
      "davranis": [
        "Ağırlık toplamı 100 değil ve orantila false ise ortalama null döner.",
        "Ağırlık toplamı 100 değil ve orantila true ise sonuç mevcut ağırlık toplamına bölünür; AGIRLIK_TOPLAMI_100_DEGIL uyarısı korunur.",
        "Hiçbir ağırlık sessizce değiştirilmez."
      ]
    },
    "gerekenNot": {
      "imza": "gerekenNot({satirlar, hedef, finalAgirligi, baraj}) -> {gereken, gerekenIkiOndalik, tamNot, ulasilabilirMax, durum, uyarilar}",
      "formul": "gereken = (hedef − mevcutKatkı) / (finalAğırlığı / 100)",
      "yardimci_formul": "mevcutKatkı = Σ(not × ağırlık) / 100",
      "girdi": {
        "satirlar": {
          "tip": "nesne[]",
          "birim": null,
          "zorunlu": true,
          "oge": {
            "ad": {
              "tip": "metin",
              "birim": null
            },
            "not": {
              "tip": "sayi",
              "birim": "puan"
            },
            "agirlik": {
              "tip": "sayi",
              "birim": "yuzde"
            }
          },
          "aciklama": "Final dışındaki bileşenler. Final dâhil ağırlık toplamı 100 olmalıdır."
        },
        "hedef": {
          "tip": "sayi",
          "birim": "puan",
          "zorunlu": true,
          "aralik": "0..100"
        },
        "finalAgirligi": {
          "tip": "sayi",
          "birim": "yuzde",
          "zorunlu": true,
          "aralik": "0..100; 0 hesap için geçersizdir"
        },
        "baraj": {
          "tip": "sayi",
          "birim": "puan",
          "zorunlu": false,
          "varsayilan": 0,
          "aralik": "0..100"
        }
      },
      "cikti": {
        "gereken": {
          "tip": "sayi|null",
          "birim": "puan",
          "kesinlik": "ham_makine_degeri",
          "yaklasik": false,
          "yuvarlama_yonu": "yok",
          "aciklama": "Baraj ve sıfır alt sınırı uygulanmış gereken notun ham sayısal değeri. İmkânsız durumda 100'e kırpılmaz."
        },
        "gerekenIkiOndalik": {
          "tip": "sayi|null",
          "birim": "puan",
          "kesinlik": "guvenli_asgari",
          "yaklasik": false,
          "yuvarlama_yonu": "yukari",
          "yuvarlama_modu": "ROUND_CEILING",
          "ondalik_hane": 2,
          "aciklama": "gereken alanını kayan nokta toleransıyla iki ondalığa yukarı tamamlayan güvenli asgari sunum değeri."
        },
        "tamNot": {
          "tip": "tamsayi|null",
          "birim": "puan",
          "kesinlik": "guvenli_asgari",
          "yaklasik": false,
          "yuvarlama_yonu": "yukari",
          "yuvarlama_modu": "ROUND_CEILING",
          "ondalik_hane": 0,
          "aciklama": "Ham etkin gereken notun kayan nokta toleransıyla yukarı tamamlanmış tam sayısı; ulaşılamaz veya geçersiz hesapta null."
        },
        "ulasilabilirMax": {
          "tip": "sayi|null",
          "birim": "puan",
          "kesinlik": "ham_makine_degeri",
          "yaklasik": false,
          "yuvarlama_yonu": "yok",
          "formul": "mevcutKatkı + finalAgirligi",
          "aciklama": "Formülün ham sayısal sonucudur. Arayüz kısaltırsa yaklaşık işareti ve açıklaması gerekir."
        },
        "durum": {
          "tip": "enum",
          "birim": null,
          "degerler": [
            "ok",
            "imkansiz",
            "gerekmez"
          ]
        },
        "uyarilar": {
          "tip": "hata_kodu[]",
          "birim": null
        }
      },
      "davranis": [
        "Matematiksel gereken 100 ise durum ok olur. İkili kayan noktada 100,000…01 (örn. vize 11, %40, hedef 64,4, final %60) veya 99,999…9 çıkan tam 100 vakaları ölçek-duyarlı 1e-9 penceresiyle kanonik 100'e eşitlenir; gerçek 100,004 aşımı imkansiz kalır ve tolere edilmez.",
        "Matematiksel ham gereken 100'den büyükse durum imkansiz olur; gereken 100'e kırpılmadan, gerekenIkiOndalik ve ham ulasilabilirMax ile döner.",
        "Matematiksel gereken 0 veya daha küçükse durum gerekmez olur.",
        "Baraj matematiksel gerekenden yüksekse ham gereken baraja göre yükselir; gerekenIkiOndalik iki ondalığa ve tamNot tam sayıya yukarı tamamlanır; FINAL_BARAJI_UYGULANDI uyarısı döner.",
        "Durum kararı gereken veya ulasilabilirMax alanlarının yuvarlanmış sunumlarından değil ham formül değerlerinden verilir.",
        "Final ağırlığı 0 ise bölme yapılmaz."
      ]
    },
    "harfeCevir": {
      "imza": "harfeCevir(ortalama, tablo) -> harf|null",
      "girdi": {
        "ortalama": {
          "tip": "sayi",
          "birim": "puan",
          "aralik": "0..100"
        },
        "tablo": {
          "tip": "nesne[]",
          "birim": null,
          "oge": {
            "esik": {
              "tip": "sayi",
              "birim": "puan"
            },
            "harf": {
              "tip": "metin",
              "birim": null
            }
          },
          "aciklama": "Kullanıcının kendi kurumundan aldığı eşik-harf çiftleri."
        }
      },
      "cikti": {
        "tip": "metin|null",
        "birim": null
      },
      "davranis": "Tablo boş veya geçersizse null; aksi halde ortalamanın karşıladığı en yüksek alt eşiğin harfi döner. Yerleşik tablo yoktur."
    }
  },
  "hata_kodlari": {
    "AGIRLIK_TOPLAMI_100_DEGIL": "Ağırlık toplamı 100 değildir.",
    "NOT_ARALIK_DISI": "Bir not 0–100 aralığının dışındadır.",
    "FINAL_AGIRLIGI_SIFIR": "Final ağırlığı sıfırdır; ters hesapta bölme yapılamaz.",
    "HEDEF_ULASILAMAZ": "Gereken final notu 100'den büyüktür.",
    "BOS_SATIR_LISTESI": "İleri ortalama hesabında en az bir satır gerekir.",
    "SATIR_ADI_EKSIK": "Bir bileşenin adı boş bırakılmıştır.",
    "GECERSIZ_SAYI": "Bir sayı alanı boş veya geçersizdir.",
    "AGIRLIK_ARALIK_DISI": "Bir ağırlık 0–100 aralığının dışındadır.",
    "AGIRLIK_TOPLAMI_SIFIR": "Orantılanacak ağırlık toplamı sıfırdır.",
    "HEDEF_ARALIK_DISI": "Hedef 0–100 aralığının dışındadır.",
    "BARAJ_ARALIK_DISI": "Final barajı 0–100 aralığının dışındadır.",
    "FINAL_BARAJI_UYGULANDI": "Kurumsal final barajı matematiksel gereken nottan yüksektir."
  },
  "ornekler": [
    {
      "id": "ileri-iki-bilesen-52",
      "fonksiyon": "hesaplaOrtalama",
      "girdi": {
        "satirlar": [
          {
            "ad": "Vize",
            "not": 40,
            "agirlik": 40
          },
          {
            "ad": "Final",
            "not": 60,
            "agirlik": 60
          }
        ],
        "orantila": false
      },
      "beklenen": {
        "ortalama": 52,
        "katkilar": [
          {
            "ad": "Vize",
            "not": 40,
            "agirlik": 40,
            "katki": 16,
            "katkiYuvarlanmis": 16
          },
          {
            "ad": "Final",
            "not": 60,
            "agirlik": 60,
            "katki": 36,
            "katkiYuvarlanmis": 36
          }
        ],
        "agirlikToplami": 100,
        "uyarilar": []
      }
    },
    {
      "id": "ileri-uc-bilesen-66",
      "fonksiyon": "hesaplaOrtalama",
      "girdi": {
        "satirlar": [
          {
            "ad": "Ödev",
            "not": 80,
            "agirlik": 20
          },
          {
            "ad": "Vize",
            "not": 50,
            "agirlik": 30
          },
          {
            "ad": "Final",
            "not": 70,
            "agirlik": 50
          }
        ],
        "orantila": false
      },
      "beklenen": {
        "ortalama": 66,
        "katkilar": [
          {
            "ad": "Ödev",
            "not": 80,
            "agirlik": 20,
            "katki": 16,
            "katkiYuvarlanmis": 16
          },
          {
            "ad": "Vize",
            "not": 50,
            "agirlik": 30,
            "katki": 15,
            "katkiYuvarlanmis": 15
          },
          {
            "ad": "Final",
            "not": 70,
            "agirlik": 50,
            "katki": 35,
            "katkiYuvarlanmis": 35
          }
        ],
        "agirlikToplami": 100,
        "uyarilar": []
      }
    },
    {
      "id": "ters-hedef-60-gereken-70",
      "fonksiyon": "gerekenNot",
      "girdi": {
        "satirlar": [
          {
            "ad": "Vize",
            "not": 45,
            "agirlik": 40
          }
        ],
        "hedef": 60,
        "finalAgirligi": 60,
        "baraj": 0
      },
      "beklenen": {
        "gereken": 70,
        "gerekenIkiOndalik": 70,
        "tamNot": 70,
        "ulasilabilirMax": 78,
        "durum": "ok",
        "uyarilar": []
      }
    },
    {
      "id": "ters-ham-100-004-imkansiz",
      "fonksiyon": "gerekenNot",
      "girdi": {
        "satirlar": [
          {
            "ad": "Vize",
            "not": 45,
            "agirlik": 40
          }
        ],
        "hedef": 78.0024,
        "finalAgirligi": 60,
        "baraj": 0
      },
      "beklenen": {
        "gereken": 100.00399999999999,
        "gerekenIkiOndalik": 100.01,
        "tamNot": null,
        "ulasilabilirMax": 78,
        "durum": "imkansiz",
        "uyarilar": [
          "HEDEF_ULASILAMAZ"
        ]
      }
    },
    {
      "id": "ileri-yari-yukari-10-075",
      "fonksiyon": "hesaplaOrtalama",
      "girdi": {
        "satirlar": [
          {
            "ad": "A",
            "not": 10.05,
            "agirlik": 50
          },
          {
            "ad": "B",
            "not": 10.10,
            "agirlik": 50
          }
        ],
        "orantila": false
      },
      "beklenen": {
        "ortalama": 10.08,
        "katkilar": [
          {
            "ad": "A",
            "not": 10.05,
            "agirlik": 50,
            "katki": 5.025,
            "katkiYuvarlanmis": 5.03
          },
          {
            "ad": "B",
            "not": 10.1,
            "agirlik": 50,
            "katki": 5.05,
            "katkiYuvarlanmis": 5.05
          }
        ],
        "agirlikToplami": 100,
        "uyarilar": []
      }
    },
    {
      "id": "ters-tam-100-ok",
      "fonksiyon": "gerekenNot",
      "girdi": {
        "satirlar": [
          {
            "ad": "Vize",
            "not": 11,
            "agirlik": 40
          }
        ],
        "hedef": 64.4,
        "finalAgirligi": 60,
        "baraj": 0
      },
      "beklenen": {
        "gereken": 100,
        "gerekenIkiOndalik": 100,
        "tamNot": 100,
        "ulasilabilirMax": 64.4,
        "durum": "ok",
        "uyarilar": []
      }
    }
  ],
  "invariantlar": [
    "durum=imkansiz ve HEDEF_ULASILAMAZ olduğunda gereken ham değeri 100'den büyüktür; alan 100'e kırpılmaz.",
    "durum kararları gereken, gerekenIkiOndalik veya ulasilabilirMax sunum değerlerinden değil ham formül değerlerinden verilir.",
    "durum=ok olduğunda gerekenIkiOndalik ile yeniden hesaplanan ortalama kayan nokta toleransı içinde hedefe eşit veya hedeften büyüktür.",
    "Matematiksel olarak tam 100 gereken vakalar ölçek-duyarlı 1e-9 penceresiyle kanonik 100'e eşitlenir ve durum ok olur; 100,004 gibi gerçek aşımlar imkansiz kalır.",
    "katki alanı not × ağırlık / 100 formülünün ham sonucudur; katkiYuvarlanmis iki ondalığa yuvarlanmış dönüşümdür. Yuvarlanmış katkıların toplamı (0,33+0,33+0,33=0,99) kesin toplam değildir; toplam her zaman ham katkılardan kurulur."
  ]
}
