C64/C128 Projects


HIZLI BASIC

Tuna ERTEMALP

Commodore Dergisi, Sayı 4, Haziran 1986

Siz de mi C64'ün -hızından- (daha doğrusu yavaşlığından) şikâyetçisiniz? Hani, "BASIC'de program yazılmaz, yazılırsa çalıştığını görmeye ömür yetmez!" diyenlerden misiniz? Ama biz diyoruz ki: HAYIR, C64 HIZLIDIR.

Şimdi de bazılarınızın, "Nayır, nolamaz, gene mi makina dili..." dediğini duyar gibiyiz. Ama yanılıyorsunuz. Bahsettiğimiz şey, bildiğimiz BASIC.

Şimdi size birkaç örnek programla birlikte, BASIC programlarınızı nasıl daha hızlı çalışacak biçimde yazacağınızı göstereceğiz. Örneğin, programlardan birinin çalışma süresini 10.45 saniyeden 0.96 saniyeye indireceğiz!! Evet, yanlış okumadınız; programı %90.81 hızlandıracağız!! Güzel değil mi? Ama bu kadar laf yeter, şimdi işbaşına...

Ama önce anlatım sırasında izleyeceğimiz yöntemleri biraz görelim. Örneğin, programların çalışma zamanını nasıl ölçeceğiz? Verdiğimiz örnek programların 10 ve 1000 numaralı satırlarına bakarsanız, hepsinde aynı olduklarını göreceksiniz. 10 numaralı satırda, bilgisayarın içindeki saati sıfırlıyoruz. 1000 numaralı satırda ise, 18. ekran satırına o anki saat değerini saniye cinsinden yazıyoruz. Dolayısıyla 10 ve 1000 numaralı satırlar arasında kalan program kısmının kaç saniye sürdüğünü öğrenebiliyoruz.

Öğreneceğimiz yöntemlerin bize olan faydalarını görmek için, önce bir program yazacağız ve bu programın çalışma süresini ölçeceğiz. Sonra aynı programın bazı komutlarını değiştirerek elde edeceğimiz zaman kazancını göreceğiz. Bu nedenle, ilk yazacağınız programı silmeyin. Böylece, sonradan gelen programları yeni baştan yazma zahmetinden kurtulacaksınız. Yeni program yazmanız gerektiğinde bu size belirtilecektir.

Bir diğer önemli nokta da, zaman ölçümlerini "temiz" Commodore ile yapmanız gerektiği. Yani, bilgisayarınızı kapatıp açın ve bu yazıyı okuyup uygulamaya ondan sonra başlayın. Bunu altında yatan neden şu: Eğer SIMON'S BASIC, EX-BASIC, SUPERGRAPHICS vs. gibi BASIC ilerletme programlarından yararlanmaya kalkışırsanız, ölçtüğünüz zaman değerleri uzayacaktır. Bu tip programlar ses, grafik vs. gibi işlemlerin dışında kalan programları yavaşlatırlar.

Bir de programı yazıp çalıştırdıktan sonra, bizim verdiğimiz zaman değerlerinden farklı sonuçlar elde ederseniz, sakın şaşırmayın. Eğer o programı birkaç kez çalıştırırsanız, çoğunlukla bizim verdiğimiz değeri elde ettiğinizi göreceksiniz.

Ve son olarak... Yazımız ilerledikçe, elde edeceğimiz önemli bilgileri, DİKKAT başlığı altında sırayla toparlayacağız, isterseniz bu kuralları bir kâğıda yazıp, bilgisayarlarınızın yanına koyun!

Şimdi ilk programımıza başlayalım. Bu programımız oldukça basit bir iş yapacak. Amacımız, ekrana 374 tane A harfi bastırmak. Önce TEST1 programını yazın. Ama yazarken lütfen gördüğünüzün aynısını yazın; bütün komutları, aynı satır numaraları ile ve komutlar arasındaki boşluklarla birlikte.

Bu ilk programda amacımızı POKE komutları ile gerçekleştiriyoruz. Önce ekran hafızasına, "A" harfinin kodunu yerleştiriyoruz, sonra da renk hafızasına gereken renk kodunu. Bu arada da, bir sayaç değişkeni ile kaç tane yazdırdığımızı kontrol ediyoruz. Zamanı ölçtüğümüzde 10.45 saniye elde ediyoruz. Çok can sıkıcı değil mi?

Haydi, bir-iki değişiklik yapalım, 30 ve 40 numaralı satırları şöyle değiştirelim (TEST2):

30 Z=0:VIDEO=1024:RENK=55296
40 POKE VIDEO+Z,1:POKE RENK+Z,14

Burada yaptığımız, kullandığımız bazı sayıları, daha önceden değişkenlere yüklemek oldu. Zamanı ölçelim... Aman Tanrım! A'lar uçuyor! 7.25 saniye.,.

Tam %30.62 hız kazancımız var.

TEST3 için, 30, 40 ve 60 numaralı satırları aşağıdaki gibi değiştirip, bu sefer tüm sayıları değişkenlere yükleyelim:

30 Z=0:BITISDEGERI=374:VIDEO=1024:
   RENK=55296:HARF=1:BASKI=14
40 POKE VIDEO+Z,HARF:POKE RENK+Z,BASKI
60 IF Z=BITISDEGERI THEN 1000

Ölçtüğümüzde, 6.03 saniye elde edeceğiz. TEST2'ye göre %16.82, TEST1'e göre %42.29 daha hızlı. Güzeeel...

TEST4 için, verdiğimiz programa bakarak gereken değişiklikleri yapın. Burada, daha önce kullandığımız değişken adlarını iki karakter uzunluğa kısalttık. Sonuç: 5.6 saniye. TEST3'den %7.13, TEST1'den %46.41 daha hızlı. Hatta TEST5 için, bu adları daha da kısaltıp tek karakterli yapalım. Gereken değişiklikler:

30 Z=0:B=374:V=1024:R=55296:H=1:A=14
40 POKE V+Z,H:POKE R+Z,A
60 IF Z=B THEN 1000

Ölçtüğümüzde elde edeceğimiz 5.483 saniye, TEST4'ten %2.08 ve TEST1'den de %47,53 daha hızlı. Aklınıza gelir miydi, değişkenlerin uzunluğunun bu kadar önemli olacağı? Programı hemen hemen, 2 kat hızlandırdık. Ama durun, daha bitmedi! Daha da hızlanacak. Daha önce, ilk kurallarımız yazalım:

 

!!! DİKKAT 1 !!!

* Programda sık sık kullanılacak olan, özellikle döngülerin içinde yer alan sayıların programın başında değişkenlere yerleştirilmesi gerekir.

* Bir değişkenin sahip olduğu değer, program içinde değişiyorsa bile, programın başında örneğin Z=0 gibi belirtilmesi faydalı olacaktır,

* Programın başında, sayıları değişkenlere yerleştirirken, en çok kullanılacak sayıyı ilk önce yerleştirmek hız kazandıracaktır (Bilgisayar, o değişkeni daha çabuk bulabilecektir).

* Şimdi TEST6'yı verildiği gibi yazın. Artık POKE komutu yerine, PRINT komutunu kullanıyoruz, ve yeni bir rekor: 4 saniye. TEST5'e %27.04, TEST1'e de %61.72 fark attık. Demek ki, PRINT komutu POKE'dan hızlı çalışıyor.

Ufak bir değişiklik yapalım. CHR$(65)'i önceden bir karakter değişkenine yükleyelim. Şu değişiklikleri yapın (TEST7):

30 Z=0:B=374:A$=CHR$(65)
40 PRINTA$;

Zaman ölçümü ve 3.05 saniye ile %23.75'lik bir hızlanma daha. TEST1 ise artık çok yavaş kaldı (%70.81 fark var!!).

Bu hızı, TEST8 ile azıcık da olsa artıracağız. Şu değişiklikleri yapın:

30 Z=0:B=374
40 PRINT "A";

2.983 saniye ile %2.19'luk bir hızlanma. Az ama önemli (TEST1'den %71.45 hızlı). Toparlayalım...

 

!!! DİKKAT 2 !!!

* Döngü halinde yazılması gereken yazıları POKE yerine, PRINT ile yazmak çok daha iyidir.

* PRINT komutunun arkasından gelenlerin ya önceden yazı değişkenlerine yüklenmiş ya da tırnak içinde yazılmış olması gerekir.

Gelelim TEST9'a... Küçücük bir değişiklik ve küçücük bir hızlanma:

60 IF Z=B GOTO 1000

THEN yerine GOTO koyduk ve program 2.96 saniye ile %0.77 daha hızlandı.

Bir ufak değişiklik daha ve (TEST10):

60 IF Z<>B GOTO 40

Bu sırada, 70 numaralı satırı silebilirsiniz, çünkü artık bir işe yaramıyor. Dolayısıyla programımızı bu ufak değişiklikle, bir satır kısaltmış olduk. Hızımız 2.93 saniye ile % 1.01 daha arttı. TEST1'den ise %71.96 daha hızlıyız.

 

!!! DİKKAT 3 !!!

* Döngülerde IF...GOTO komutu, IF...THEN komutundan daha hızlıdır.

* Kontrollerde eşit olmama durumunun kontrol edilmesi, eğer programdan satır eksiltiyorsa yararlı olacaktır.

Bu arada programlarla örnek vermeden bir diğer kural daha göstereceğiz, hazır laf IF..THEN komutundan açılmışken. Şöyle bir program parçası düşünün:

100 IF A=1 AND B=2 AND C=3 THEN 999
110 GOTO 50

Bilgisayar, her defasında her üç şartı da kontrol edecektir ve ancak her üçü de doğru ise 999'a gidecektir. Diyelim ki, C'nin 3 olma ihtimali çok az, ama A=1 ve B=2 her zaman olabilir. Bu durumda C=3 olmadığı durumlarda da, diğer iki şart kontrol edilecek ve bu da boşuna zaman kaybı olacak. Ancak şöyle bir satır düşünün:

100 IF C=3 THEN IF B=2 THEN IF A=1 THEN 999

Bu durumda, sadece ve sadece C = 3 olduğunda diğerleri kontrol edilecektir. Hatta A'nın kontrolü için de B=2 şartı aranacaktır. Bunun getireceği hızlanma herhalde tarafınızdan takdir olunur...

 

!!! DİKKAT 4 !!!

* Birbirine AND ile bağlanmış birden fazla şarttan oluşan IF...THEN komutlarının, en ender olandan en sık olana doğru sıralanmış bir IF...THEN zincirine çevrilmesi gerekir.

Şimdi sıra geldi TEST11'e... Artık biraz stil değiştirmenin zamanı geldi. Deminden beri kullandığımız GOTO komutlarının yerine. BASIC'in bize bahşettiği başka bir komutu, daha doğrusu komut ikilisini kullanacağız: FOR..NEXT

Şimdi klavye başına geçin ve şu değişiklikleri yapın:

30 FOR Z=1 TO 374
40 PRINT"A";
50 NEXT Z

60 numaralı satırı da silebilirsiniz. Yeniden zaman ölçümü yaptığımızda yeni bir hızlanma daha görüyoruz: 1.1 saniye. TEST10'dan %62.45 ve TEST1'den de %89.47 daha hızlı.

Biliyorsunuz, COMMODORE 64 için program yazarken, NEXT komutunun arkasında yer alan değişken adı yazılmasa da oluyor. Bir de bunu deneyelim, bakalım ne olacak?

50 NEXT

Böylece elde ettiğimiz TEST12'nin zamanı, 1 saniye ile TEST11'e %9.09 ve TEST 1'e de %90.43 fark atıyor. Eh artık iyice hızlandı. Acaba biraz daha?... Ama önce yeni kurallarımız:

 

!!! DİKKAT 5 !!!

* Döngüleri kurarken, IF...THEN yerine FOR...NEXT komutunu kullanmak avantaj sağlayacaktır.

* NEXT komutunun arkasından gelen değişken adı yazılmadığında, programın hızı artacaktır.

Şimdiye kadar programı hep hızlandırdık, biraz da yavaşlatalım. TEST13'ü verildiği gibi yazın. Burada programı biraz süslemek, biraz da açıklayıcı hale getirmek için REM komutları kattık. Ölçüm sonucunda da göreceğiniz gibi, programımız 1.2 saniye ile %20 yavaşladı (TEST12'ye göre).

Eğer bu REM komutlarını ve diğer komutlar arasında bulunan ve programın okunaklılığını artıran boşlukları ortadan kaldırırsak, dökümünü verdiğimiz TEST14'ü elde ederiz. Çalışma zamanı olarak ölçeceğimiz 1 saniye, sanki bize "Aferin, iyi ettiniz!" der gibi, di mi?

Artık son adıma geldik, TEST1'in alabileceği son hızı şimdi göreceksiniz. Her şeyi tek satırda toparlayacağız. Ama bunun için COMMODORE 64 elkitabında belirtilen komut kısaltma yöntemlerine ihtiyacınız var. Biz gene de bir özetleyelim:

PRINT için ? işareti, CHR$ için C ve SHIFT-H, FOR için F ve SHIFT-O, NEXT için N ve SHIFT-E, POKE için P ve SHIFT-O.

Artık TEST15'i yaratabiliriz:

10 TI$="000000":PRINTCHR$(147);:
   FORZ=1TO374:PRINT"A";:
   NEXT:POKE214,18:PRINT:
   PRINTTI/60"SANIYE":END

Elde ettiğimiz 0.96 saniye ile TEST14'den %4 ve TEST1'den de %90.81 hızlı bir program elde ettik. Düşünün 10.45 saniyeden 0.96'ya inebildik. Hani COMMODORE 64 yavaştı?

 

!!! DİKKAT 6!!!

* REM komutları ve komutlar arasında boşlukları olmayan programlar daha hızlı çalışır.

* Satır sayısını azaltmak amacıyla, bir satıra sığdığı kadar emir koymak da hız sağlayacaktır.

Ancak, bu son kuralların programın okunurluluğunu da tamamen ortadan kaldırdığını unutmayın lütfen!

Başta, makina dile yok demiştik. Ama gene de, deminden beri uğraştığımız şeyi, yani 374 tane A yazma işini yapan bir makina dili programının da süresini ölçelim dedik. Hadi şimdi de TEST16'yı yazıp çalıştırın. Sonuç 0.083 saniye ile TEST1'e %99.20 fark!!! Fazla söze gerek yok...

Bundan sonra, BASIC'in değişik yönlerini inceleyeceğiz. Örneğin, iki sayıyı 300 kere birbiriyle çarpalım. Bunun için önce TEST17'yi yazın. Çalıştırıp, zamanı ölçmeye kalkıştığınızda lütfen sabırlı olun: 13.083 saniye. Kaplumbağalar kıskanacak?

Ufak bir numara yapalım, iki sayının yerini değiştirelim. Şu ufak değişiklikle TEST18'i hazırlayın:

40 A=0.123456789*3

Zamanı ölçtüğümüzde, gerçekten de bir hızlanma görüyoruz. 12.683 saniye ile az ama gene de %3.05'lik bir hızlanma. Tıpkı 15643*5'in hesaplanmasının 5*15643'ün hesaplanmasından daha kolay olması gibi.

Haydi, minicik bir değişiklik daha yapalım. Ondalık noktasından önce gelen sıfır rakamını atalım (TEST 19):

40 A=.123456789*3

12.483 saniye ile TEST17'den %4.58 daha hızlı olduk.

 

!!! DİKKAT 7 !!!

* Bir çarpma işlemi sırasında, daha uzun olan sayının ilk sayı olarak yazılması gerekir.

* Sıfır sayısı yerine sadece ondalık nokta koymak daha fazla hız sağlayacaktır (A=0 yerine A=.). Ayrıca, ondalıklı sayılarda -1 ile 1 arasındaki değerleri yazarken, ondalık noktasından önce gelen sıfır rakamı yazılmamalıdır.

Bir de daha önceden öğrendiğimiz, değişken metodunu uygulayarak TEST20'yi elde edelim:

25 B=.123456789:C=3
40 A=B*C

Göreceğiniz gibi, aniden %88.53'lük bir hızlanma ile 1.5 saniyeye geleceğiz. Nasıl ama?!

Şimdi de aynı programı, bilgisayarımızın üslü sayıları hesaplamaktaki hızını görmek için kullanalım. Verdiğimiz TEST21'i yazın ve çalıştırın. Göreceğiniz gibi, 4'ün kübünü 300 kere almak bize 10.53 saniyeye patlıyor.

Eh, biz de sayıları değişkenlere yerleştiririz. Hemen bir TEST22'yi yazalım:

25 B=4:C=3
40 A=B^C

Ölçüyoruz... Olamaz, sadece %1.7'lik bir hızlanma ile 10.35 saniye. Hayır, hiçbir şeyi yanlış yapmadık. Sorun, COMMODORE 64'ün üs almada kullandığı metodun kötülüğünde yatmakta. Öyleyse ne yapalım?

Bir-iki ufak değişiklik ile elde edeceğimiz TEST23, bize cevabı verecek:

25 B=4
40 A=B*B*B

Yaptığımız, üs alma yerine çarpma kullanmak oldu. Sonuç şaşırtıcı: 2.05 saniye ile TEST22'ye göre %80.53'lük bir hızlanma

 

!!! DİKKAT 8 !!!

* Üs alma işlemi, mümkün olduğu kadar çarpma haline dönüştürülmelidir.

Artık, altprogramları incelemeye geçebiliriz. Önce TEST24'ü yazın.

Gördüğünüz gibi, burada altprogramı GOTO komutu ile çağırıp, altprogramdan da gene GOTO komutu ile geri dönüyoruz. Süreyi ölçtüğümüzde, 3.25 saniye elde edeceğiz.

Peki, GOTO yerine GOSUB... RETURN kullanırsak ne olacak? TEST25 için şu değişiklikleri yapalım:

40 GOSUB 40000
60000 RETURN

Ölçtüğümüzde elde ettiğimiz 3.15 saniye, TEST24'den %3.07 daha fazla.

Bir başka önemli nokta, altprogram ile programın başlangıcı arasındaki uzaklıktır. Şimdi, deminki programlarımızı biraz değiştirelim ve altprogramlarımızı program başına alalım. Önce TEST26'yı yazın. Süremiz, 3.06 saniye ile TEST25'den bile az olacaktır (%2.85).

TEST27 için şu değişiklikleri yapın:

6 RETURN
33 GOSUB4

GOTO yerine GOSUB koyduğumuzda. 2.93 saniye ile daha hızlı bir program elde ediyoruz, gördüğünüz gibi. Bu TEST24'den %9.84 daha hızlı bir değerdir. Yeni kurallarımızı toparlayacak olursak:

 

!!! DİKKAT 9 !!!

* Altprogramları GOSUB ile çağırıp, ana programa RETURN ile dönmek, aynı işlemleri GOTO ile yapmaktan daha hızlıdır.

* Sık sık kullanılan altprogramların, anaprogramın başlarında olması, hız sağlayacaktır.

Artık birkaç ufak-tefek nokta daha kaldı. Önce TEST28'i yazın. Zaman olarak 2.883 saniye olacaktır. Şimdi, DİKKAT7'de belirttiğimiz kurallardan birini deneyelim. 30 numaralı satırdaki A1=0 yerine A1=. koyarak TEST29'u elde edelim ve zamanı ölçelim. Gerçekten de 2.283 saniye ile %20.81'lik bir artış oldu.

Şimdi de aynı satırdaki A1 değişkeninin yerine AA değişkenini koyalım ve böylece oluşturduğumuz TEST30'u ölçelim. Elde ettiğimiz 2.3 saniye bize açıkça bir yavaşlamanın varlığını göstermektedir.

TEST31'de ise, AA yerine sadece A harfini kullanalım, 2.23 saniye ile TEST28'den %22,65 daha hızlı program elde ettik.

Son olarak da, karakter değişkenlerine değer konmasını inceleyeceğiz. Şimdi TEST32'yi yazın. Süresi, 2.45 saniye olacaktır.

TEST33'ü elde etmek için 25 numaralı satırı silin ve şu değişikliği yapın:

30 FORI=1TO1000:A$="TT":NEXT

Elde edeceğimiz 2.316 saniye, TEST 32'den %5.46 daha hızlı olacaktır.

 

!!! DİKKAT 10 !!!

* Eğer iki karakterden oluşan değişken isimleri kullanılıyorsa, ikinci karakterin bir rakam olmasına dikkat edilmelidir. Ancak en iyisi tek karakterli değişken adlarıdır.

* Karakter dizileri, bir karakter değişkenine yüklenirken tırnak içinde verilmişlerse, daha önce bir başka değişkene yüklenmiş olmalarına oranla daha hızlı işlerler.

Artık bitti! Herhalde birçok önyargı bu yazıyı okurken yıkılıp gitmiştir. Şimdi daha hızlı programlar yazacağınız günler sizi bekliyor!!!

TEST1

10 TI$="000000"
20 PRINT CHR$(147)
30 Z=0
40 POKE 1024+Z,1:POKE 55296+Z,14
50 Z=Z+1
60 IF Z=374 THEN 1000
70 GOTO 40
1000 POKE 214,18:PRINT:PRINT TI/60 "SANIYE":END
READY.

TEST4

10 TI$="000000"
20 PRINT CHR$(147)
30 Z=0:BI=374:VI=1024:RE=55296:HA=1:BA=14
40 POKE VI+Z,HA:POKE RE+Z,BA
50 Z=Z+1
60 IF Z=BI THEN 1000
70 GOTO 40
1000 POKE 214,18:PRINT:PRINT TI/60 "SANIYE":END
READY.

TEST6

10 TI$="000000"
20 PRINT CHR$(147)
30 Z=0:B=374
40 PRINTCHR$(65);
50 Z=Z+1
60 IF Z=B THEN 1000
70 GOTO 40
1000 POKE 214,18:PRINT:PRINT TI/60 "SANIYE":END
READY.

TEST13

10 TI$="000000"
12 REM ************************
13 REM *                      *
14 REM *TEST-PROGRAMI*        *
15 REM *                      *
16 REM ************************
20 PRINT CHR$(147);:REM EKRANI SILMEK
30 FOR Z=1 TO 374:REM 374 KARAKTER
40 PRINT"A";
50 NEXT
999 REM ZAMANI GOSTERME
1000 POKE 214,18:PRINT:PRINT TI/60 "SANIYE":END
READY.

TEST14

10 TI$="000000"
20 PRINT CHR$(147);
30 FOR Z=1 TO 374
40 PRINT"A";
50 NEXT
1000 POKE214,18:PRINT:PRINTTI/60"SANIYE":END
READY.

TEST16

5 GOTO2000
10 TI$="000000"
20 PRINT CHR$(147);
30 SYS7168
1000 POKE214,18:PRINT:PRINTTI/60"SANIYE":END
2000 PRINTCHR$(147)
2010 FORA=7168TO7200
2020 READB
2030 POKEA,B
2040 NEXT
2050 DATA162,0,169,1,157
2060 DATA0,4,169,14,157,0,216
2070 DATA232,224,0,208,241,169,1,157
2080 DATA254,4,169,14,157,254,216
2090 DATA232,224,120,208,241,96
2100 PRINT"MAKINA DILI PROGRAMI OKUNDU."
2120 PRINT:PRINT"BASLATMAK ICIN BIR TUSA BASINIZ..."
2140 GETA$:IFA$=""THEN2140
2160 GOTO10
READY.

TEST17

10 TI$="000000"
20 PRINTCHR$(147)
30 FORZ=1TO300
40 A=3*0.123456789
50 NEXT
60 PRINTA
1000 POKE214,18:PRINTiPRINTTI/60"SANIYE":END
READY.

TEST21

10 TI$="000000"
20 PRINTCHR$(147)
30 FORZ=1TO300
40 A=4^3
50 NEXT
60 PRINTA
1030 POKE214,18:PRINT:PRINTTI/60"SANIYE":END
READY.

TEST24

10 TI$="000000"
20 PRINTCHR$(147)
30 FORZ=1TO300
40 GOTO40000
50 NEXT
60 PRINTA
1000 POKE214,18:PRINT:PRINTTI/60"SANIYE":END
40000 B=4
50000 A=B*B*B
60000 GOTO50
READY.

TEST26

3 GOTO 10
4 B=4
5 A=B*B*B
6 GOTO50
10 TI$="000000"
20 PRINTCHR$(147)
30 FORZ=1TO300
33 G0T04
50 NEXT
1000 POKE214,18:PRINT:PRINTTI/60"SANIYE":END
READY.

TEST28

10 TI$="000000"
20 PRINTCHR$(147)
30 FORI=1TO1000:A1=0:NEXT
1000 POKE214,18:PRINT:PRINTTI/60"SANIYE":END
READY.

TEST32

10 TI$="000000"
20 PRINTCHR$(147)
S5 T$="TT"
30 FORI=1TO1000:A$=T$:NEXT
1000 POKE214,18:PRINT:PRINTTI/60"SANIYE":END
READY.


C64/C128 Projects  by  Quick Turkish   Changelog   Site Map   Index