nontechnical comments

Bir arkadaşımın gaza getirmesi sonucu başladı bu girişim. Bisiklet ile uzun zamandır pek alakam yoktu, çocukluğumuzun bisiklet üzerinde geçmesindendir belki hevesimi almıştım. Bisikleti hep zevk için değil de okula işe gitmek gibi bir amaç uğruna kullanmayı mantıklı buluyordum. Öyle bisikletimi alayım şurada gezeyim olayını sevmiyordum yani. İstanbul'da yaşayan biri olarak da bu amaç doğrultusunda bisiklet kullanamayacağınız malum. O yüzden sırf bu tur için bir bisiklet aldım, belki dönüşte satarım diyordum.

İşin içine girince kaybolacağınız türden işlerden biriymiş bu da, bir sürü marka var bunların farklı türdeki ve kalitedeki bisikletleri var, bana ne lazım tam bir fikrim yok, yeni mi alsam yoksa ikinci el bir şey işimi görür mü sorunu... Velhasıl tercih yapma süreci kolay olmadı. Kadıköy'deki Velespit Bisiklet'teki satıcının övmesi üzerine Trek markasını tanıdım ve ertesi gün sahibinden.com'da bulduğumuz bir ilan ile çok az kullanılmış bir Trek FX 7.3 bisiklet satın aldım. Almakla bitmedi tabii iş, üzerindeki eksikleri tamamladık hemen: çamurluk, port bagaj, ayaklık, zil, vs. taktırdık. Bisiklet işi bisikleti donatmakla bitmiyor, sürücünün de giydiği kask, eldiven, vs. gibi aksesuarlar var, bunları da Decathlon'dan tamamladık. Eşyalarımızı koymak için bisiklete özel heybelerden aldık, su geçirmez olmalarına dikkat ettik.

Bisiklet ile son zamanlarda öyle pek ilgim yok dedim ama bisikleti alıp eve getirdiğim gün işler değişti, adeta bir çocuk gibi heyecanlandım ve gece şu şekilde uyudum: "Bu bisikleti ben yarın süreceğim, kaçarı yok!". Sabah kalkar kalkmaz aldım bisikleti, fırladım İstanbul sokaklarına. Mecidiyeköy'den evden çıkıp Ortaköy'e indim oradan ver elini Bebek-Yeniköy-Tarabya. Biraz dinlendikten sonra Ortaköy'e döndüm, amacım Mecidiyeköy'e geri çıkmaktı ilk başta ama hem o yokuşu çıkmak pek yemedi hem de daha süresim vardı. Ben de devam ettim Beşiktaş-Fındıklı-Eminönü yönünde. Hala süresim var, devam... Sarayburnu'na gidip tekrar Eminönü'ne otobüs duraklarına döndüm. Burası Mecidiyeköy'e giden otobüslerin kalktığı durak, burada bisikleti otobüse koyup eve dönerim diyordum. Ancak hem otobüsün kalkmak bilmemesi hem de otobüs şoförünün mırın kırın etmesi üzerine eve kadar bisiklet ile dönmeye karar verdim. Unkapanı Köprüsü-Taksim Meydanı-Osmanbey yönünde sürüp eve vardım. Şaka maka ilk günden 55 km'lik bir tur yapmıştım ve bu kadar yapabileceğimi beklemiyordum. Bu biraz şevkimi artırdı, daha sonraki haftalarda da antrenman olsun mantığıyla Bahçeköy civarı ve Belgrad ormanında sürüşler yaptık, 50-60 km'leri rahat sürebiliyorduk.

Yunanistan için vize başvurularını tamamladık, beklediğimden çok hızlı bir şekilde hazırlandı vizeler. Süre olarak bir hafta izin alacaktık, diğer hafta da 2 gün Kurban Bayramı tatilinden gelince 11 günlük bir süremiz oldu. İlk planımızda Atina yoktu, İpsala sınır kapısından Selanik'e bisikletle gidip bisikletle dönecektik, böylece 350 + 350 = 700 km yol yapmış olacaktık. Ancak bu plandan iki sebepten ötürü vaz geçtik: bir, gitmişken bari Atina'yı da görsek iyi olurdu, iki, aynı yolu tekrar bisiklet ile tepmek ilki kadar zevkli olmayacaktı sanki. Bu yüzden planımızı Selanik'ten sonra Atina'ya doğru devam etmek ve dönüşte de tren ile dönmek şeklinde değiştirdik. Bu şekilde toplamda 850 km civarı yol yapmış olacaktık. Hedefimiz her gün 100 km civarı yol almak idi, daha önce hiç bu kadar yapmamıştık ve bunu her gün yapabileceğimiz konusunu da şansa bırakmıştık. Selanik'e bir şekilde gideriz diye düşünüyordum ben şahsen ama ondan sonra Atina'ya gidebilir miydik kafamda soru işaretiydi. Planımıza göre gündüz süreceğiz, geceleri ise vardığımız şehirlerde bir otelde kalacaktık. Selanik'e kadar olan gideceğimiz yerleri planlamış ve bunların otel rezervasyonlarını yapmıştık ama sonrası biraz kervan yolda düzülür mantığıyla ilerleyecekti ve zaten sonradan yaptığımız bir değişiklik olduğu için pek kafa da yormamıştık turun o kısmına.

Gün geldi çattı, sabah erkenden kalkıp bisikletleri arabaya attık, başlangıç noktamız olan İpsala sınır kapısına doğru yola çıktık. Yolda kahvaltı için Malkara civarında durduğumuz mekanda mekan sahibi ile geçirdiğimiz konuşma yöre insanından tam da beklenen bir diyalog idi:

Abi: Arabada bisikletler var, hayırdır?
Ben: Tura çıkıyoruz, önce Selanik'e sonra Atina'ya gideceğiz
Abi: Sebep?

Yolcudur Abbas
Yolcudur Abbas

Hava pek de uygun değildi yola çıktığımızda, kara bulutlar ve hafif yağmur var, biraz da soğuk. Yaşadığımız ilk sorun arabayı bırakacak yer bulmaktı, İpsala'ya şehir merkezine girdik taksici bir abi burada bırakmayın girişteki petrol istasyonlarından birine bırakın önerisinde bulundu. O amaçla tekrar şehir dışına çıkarken emniyetin önündeki büyük alan gözümüze çarptı, izin istedik bir memurdan koyabilirsiniz dedi ama diğer bir memur burada durması doğru olmaz diyerek arabayı bırakmamıza izin vermedi, sınır kapısının orada bırakacağımız yer olduğunu ve oraya bırakmamızı tavsiye etti. Dediği gibi yaptık, kime ait olduğunu bilmediğimiz sınır kapısının hemen dibindeki oto parka arabayı dönüşte inşallah yerinde buluruz ümidiyle bıraktık. Bisikletleri çıkardık, heybeleri yerleştirdik, bisiklet aksesuarlarımızı kuşandık, gitmeye hazırdık! Ama benim lastikler biraz inmiş gibi göründü, şişirelim dedik, demez olaydık... Bir gün önce Decathlon'dan 10 lira civarı bir paraya aldığım dandik pompa çok kullanışsız çıktı, ne ucu tam oturdu ne de bastığı hava lastiği şişirebildi. Arkadaşımın pompa ile biraz şişirebildik, Allah'a emanet yola çıktık, daha ilk dakikadan çok zaman kaybetmiştik bu işle. Buradan çıkardığım iki ders şunlar: bir, aletini tanı, pompayı daha önceden denemem gerekiyordu, iki, ucuz etin yahnisi yavan olur.

Türkiye çıkışında 15'er liralık vergi harçlarımızı ödedik, şaşkın bakışlar içinde Yunanistan girişine geldik. Oradaki memurun "I admire your courage guys." ("Cesaretinizi takdir ediyorum çocuklar.") demesi biraz moral oldu :) Çanta vs. arama olaylarına girmeden işimiz hallettik ve yola koyulduk. Vardığımız ilk nokta Feres isminde küçük bir kasaba idi, şansımıza bir lastikçiye denk geldik benim lastiği ona şişirttik. Çat pat Türkçe bilen abi pek yakındı, borcumuz ne gibisinden soru sorduk, bizden olsun demek istedi hareketleriyle :) Karşılıksız kalmasın diye biz de yanımıza enerji için aldığımız cezeryeden ikram ettik :) İlk gün öğle molası vereceğimiz şehir Alexandroupoli (Dedeağaç'a) vardık. Fast food tarzı dükkanda tarzanca anlaşarak yiyecek bir şeyler aldık, gezi boyunca daha çok yiyeceğimiz pide (pita) ekmeği arasına bir şeyler koydurma olayını burada öğrendik. Turumuz gayet güzel gidiyordu, hava da biraz düzelmişti ta ki Makri denen bölgeye gelene kadar. Gelmez olaydık... sürekli rakım kazanıyoruz, etrafımızda sarp tepeler, deli gibi rüzgar esiyor (özellikle yolun etrafındaki tepelerden boğaz oluşan yerlerde). İndik bisikletlerden, yürüyerek devam edelim dedik. Tur boyunca "Biz ne yapıyoruz?" sorusunu kendimize ilk defa burada sorduk galiba. Çok yordu burası bizi, neyse bir noktada bitti. Yol düzgünleşti ama rüzgar hala devam ediyordu, bir taraftan da hafif hava kararmaya başladı. İlk gün hedefimiz olan Komotini (Gümülcine) şehrine 20-25 km kalmıştı ama bizde takat kalmamıştı sürecek, üstüne arkadaşımın dizi basamayacak noktaya gelmişti. Bir benzin istasyonunun orada durduk, dışardaki kamyoneti gözümüze kestirmiştik, bisikletleri buna atıp oradaki abiden bizi Komotini'ye kadar atmasını rica edecektik. Girdik, sordum abiye Türkçe biliyor musun diye, "biraz" dedi. Kafaya almış beni, adam şakır şakır Türkçe konuşuyor, Türk'müş :) Anlattık durumumuzu, yardımcı olmaya çalıştı, kendisi dükkanı bırakamayacağından bir kaç kişiye telefon etti ama bizi götürebilecek birisini bulamadı. Sonra bize yakında bir köye gitmemizi, oradaki Türk kahvesinden yardım istememizi söyledi. Dediğini yaptık, köy kahvesine gittik, çok iyi karşılandık hemen oturtup bize bir çay ikram ettiler, sallama mallama içtik. Nedense bu kahvede demleme çay içmiyorlar, daha ilginci ortamdaki bir amcanın köy kahvesinde Frappe siparişi vermesi baya garibimize gitti. Kahvenin garsonu genç arkadaş hemen bize bir taksi buldu, taksinin bagaja attık bisikletleri tuttuk yolumuzu Komotini'ye doğru. Otele vardık, yerleştik ama daha ilk günden bu şekilde başlamak biraz enerjimizi düşürdü, biraz fazla bir hedef mi koymuştuk kendimize?

İkinci gün Kavala'ya doğru yola çıktık. Arkadaşım merhem, sargı bir şekilde dizini sararak ağrıyı azaltmaya çalıştı, işe de yaradı. Bugünkü turda benim sol diz de ağrımaya başladı. Yol nispeten daha rahat idi ama yol üzerindeki Vistonida gölünün oradan geçerken yine hava çok rüzgarlı idi ve sürüşü etkiliyordu. Şehir girişindeki yokuş aşağılar sağ olsun Kavala şehrine vardık. Tam otele varmak üzereydik ki bir kaç tane yokuş çıkmak zorunda kaldık. Buralarda 3 kere falan vites düşürürken zincirim attı. Bizim gibi bisikletlerimiz de havlu mu atıyordu ne? O gün otele varınca ilk iş internetten bu zincir atma mevzusunu araştırdım, bu tarz dik yokuşlarda bisiklet yükteyken vites düşürmek zincir atmasına hatta kopmasına neden olabiliyormuş, geç de olsa öğrendim. Ayrıca yine bilmediğim ön ve arka viteslerin birbiriyle uyumlu kombinasyonlarının olduğunu öğrendim. Neyse ki tur boyunca bir daha bu sorunla karşılaşmadım. Akşam yemek için dışarı çıktığımızda Kavala Kurabiyesi satan yerlere rastladık, yarın yola çıkmadan alırız dedik ama almayı unuttuk. Yola çıkmadan şehirde açık bir eczane bulup dizlerimizdeki sorunu dilimiz döndüğünce anlatmaya çalıştık. Eczacı kadın bize bir sporcu jeli verdi bir kaç tane de sargı bezi aldık, bunları sarıp yola koyulduk.

Üçüncü gün Allah'ın unuttuğu, yaş ortalamasının 80 olduğu, Volvi gölünün kenarındaki Loutra Volvis denen bir yere vardık. Otel sahibinin zerre kadar İngilizcesi yoktu, o kadar ki bizi gördüğünde iki avcunu birleştirip kafasının sağına getirerek "Uyumak (kalmak) mı istiyorsunuz?" işareti yaptı. Evet, uyumak istiyorduk. O akşam yemeği kasabadaki tahminimizce tek restoran olan göl kenarındaki bir mekanda yedik. Bizim dışımızda 10-15 kişilik bir aile masası vardı, Yunan şarkıları çalıyor, uzolar içiliyor, ailenin genç erkek çocuğu sirtaki oynuyor, yaşlı teyzemiz şarkının sonunda önündeki tabağı alıp yere fırlatıyor. Tam bir Yunanistan deneyimi yaşadık diyebiliriz :)

Dördüncü gün ilk büyük hedefimiz olan Selanik'e doğru yola koyulduk. Bugün biraz daha az yolumuz vardı zira şehre öğlen gibi varıp öğleden sonra da şehri gezmeye zaman ayırmak istiyorduk. 50 km civarı bisiklet sürdük, şehrin girişinde kısa bir süre otobana girmek zorunda kaldık, bu sırada acayip bir yokuş tırmanıp afedersiniz neticemiz seleye yapıştı, ama bu yokuşun inişi ile süper hızlı bir şekilde şehre giriş yaptık. Şehirde trafik ve trafik ışıkları ile biraz zaman kaybettikten sonra otele vardık. Otel diyorum ama en fazla hostel diyebiliriz, bu kadar dandik bir yer olabilir, bir hastalık kapmadan buradan ayrılırız ümidiyle girdik. Haritadan Atatürk'ün Selanik'teki evini bulduk onu ziyaret ettik. Selanik Başkonsolosluğumuz'un bitişiğinde buluna ev 3 katlı, müzeye çevrilmiş. Ziyaret için isminize girişteki Türk görevliye yazdırıp bir ücret ödemeden giriyorsunuz. Buradan ayrıldıktan sonra bir şeyler yemek için sahile doğru yola çıktık. Yol boyunca sokak aralarında ve özellikle sahil şeridi boyunca gördüğümüz yiyecek mekanları çok dikkatimi çekti. O kadar çok mekan var ve hepsi de o kadar dolu ki, sanki burada yaşayanların evlerinde mutfak yok, herkes dışarda yiyip içiyor diye düşünüyor insan. Selanik'te zamanımızın bir kısmını ne yazık ki bir Internet Cafe'de geçirmek zorunda kaldık. Arkadaşımın iPhone'u daha ikinci günden bozulmuştu, ona yeniden yazılım yüklemeye çalıştık ama nafile, yapamadık. Ayrıca yolun kalan kısmını burada bilgisayar başında planladık, yine günde 100 km civarı gidebileceğimiz noktaları gözümüze kestirdik. Bu sefer otel rezervasyonu yapmamıştık zira hedeflerimize varabileceğimizden pek emin değildik.

Ata'nın huzurunda :)
Ata'nın huzurunda :)

Selanik'ten ayrılıp Paralia Panteleimonos denen küçük kasabaya doğru yola koyulduk beşinci gün. Selanik çıkışı berbattı, bir sanayi bölgesinde geçtik, yollar kötü, yanımızdan geçen tırlar falan var. Bu civardan tam ayrılırken bisikletten bir şey düştü diye durduk, yerde bir metal parçası bulduk. Bir şeye benzetemediğimiz bu metal parçasını yolun kenarına fırlatıp devam ettik. Daha sonra anladık ki benim port bagajın bağlantı noktasında düşen bir parçaymış bu. Bir ders daha çıkardık bundan, bir parça düşürürsen bunu saklayacaksın. Neyse fazla kritik bir parça değilmiş ki turumuzu etkilemedi. Hedefimize varmak üzereyken benim sağ diz de alarm vermeye başladı. Sürüşümüzü ciddi şekilde etkiledi, güzelim düz yolları ağır ağır gitmek zorunda kaldık ve bu insana koyuyordu açıkçası. Paralia Panteleimonos'a vardığımızda bir gün önce gözümüze kestirdiğimiz "Fasoli Studios" isimli oteli bulmaya çalıştık. Tam bulamayacağımızı düşünmeye başlamıştık ki "ϕ" harfi ile başlayan tabelalı bir yere rastladık. Bir insan bir harfi gördüğüne bu kadar sevinebilir mi? (Seviniyor işte, ama bu harfi gördüğümüze bir daha sevineceğiz tur boyunca) Girişte hemen otel sahibi olan, hafif yaşını almış Polonyalı bir abla karşıladı. Gezi boyunca kaldığımız herhalde en sevecen yer burasıydı. Ablamız sağ olsun çok yardımcı oldu, kendi çamaşır makinesini kullanmamıza izin verdi, bize meyve sebze ve kendi yaptıkları şaraptan ikram etti. Daha sonra kocasıyla da tanıştık, karı koca burayı işletiyorlarmış, neredeyse bizim kadar oğulları varmış, Türkiye'ye yakın Yunan adalarının birinde çalışıyormuş. Ertesi sabah yolumuzu kısaltacak süper bir yol tarifi alıp vedalaştık.

Bu köprüden tır geçti!
Bu köprüden tır geçti!

Altıncı gün hedefimiz önce Larissa'ya daha sonra Farsala'ya varmak idi. İki dizim de sakat olduğundan 1 km bile süremeyeceğim gibi şüphelerim vardı yola çıkmadan. Eski, kullanılmayan bir tren tünelinden geçerek yolumuzu kısaltmış, gereksiz yokuşları tırmanmaktan da kurtulmuştuk. Ama yine de dizlerimde ağrılar devam ediyordu, daha şöyle 1 saat falan sürmüşken "Yok, yapamayacağım" noktasına geldim ama sonra ne olduysa sürmeye devam edebildim. Maceralı geçen günlerden biriydi altıncı gün. Önce yolun bir kısmında otobana girmek zorunda kaldık. Gişelere geldiğimizde görevli burada sürmemizin yasak olduğunu, geçmemize izin vereceğini ama 1 km ötede Rapsani'de trene binmemiz gerektiğini söyledi. Tamam dedik, ama trene binmedik tabii ki, bastık devam ettik :) Etmez olay mıydık? Yolda emniyet şeridi çok dardı, çok fazla trafik vardı ve geçen araçların çoğu tırlar idi. Biraz gittikten sonra otoban devriyesinin aracı geldi bizi durdurdu, neden size dediğimiz şekilde trene binmediniz dedi, bir şey diyemedik. Polis geliyor falan dedi, dedik araca bizi alıp götürün. "Olmaz" dedi, "araçta kameralar var sizi alamam". "Olabildiğince hızlı gidin, yolun bu kısmını bitirin." dedi. O gaz ve adrenalin ile diz ağrısı falan kalmadı bende, bastık gittik, yolun o kısmını bitirdik. Larissa'ya vardığımızda hızlıca bir şeyler atıştırıp şehrin içine girmeden, çevreyolundan Farsala'ya doğru yola koyulduk. Tam şehirden çıkmıştık ki günün ikinci kabusuyla baş başa kaldık. Bisiklet sürerken başım dönmeye başlamıştı, ilk seferinde zor kaldırımda durabildim. İlk önce anlayamadım sorun bende mi yoksa bisiklete bir şey oldu da sağa mı çekiyor. Bisikleti kontrol ettik bir şey yok. Tekrar denedim, yok sorun bendeydi, gözlerim kararıyor gibi oluyor bisikleti kontrolü edemiyordum. Biraz daha dinlendik, şekerim falan düşmüştür belki diye bir elma falan yedim ama nafile. 50-100 metre sürebiliyordum anca. Sonra bir kafe bulup adam akıllı mola verelim dedik. Sert bir kahve içtim, arkadaşımın tavsiyesi üzerine biraz tuz yedim, tuzlu su falan içtim :) Yarım saat falan öyle dinlendik, ama işe de yaramıştı, bisiklet sürmeye devam edebiliyordum. Pamuk tarlalarının arasında geçtik, biraz yokuş tırmandık ama o yokuşun inişi her zamanki gibi çok güzeldi. Yakılan anız kokularının eşliğinde Farsala şehrine hava karardıktan sonra girebildik, "ϕ" harfini gördüğümüze bir kez daha çocuklar gibi sevindik. Şehirde gözümüze kestirdiğimiz bir tane otel vardı ama biraz şehrin ters tarafında, dışındaydı. Şehir merkezinde başka otel vardır ümidiyle merkeze gittik, orada birilerine otel sorduk ama şehirde tek otel olduğunu söylediler, çaresiz o otele kadar daha sürdük. Otele vardığımızda yorgunluktan ölüyorduk, yemek için şehir merkezine dönmeyi göze alamadık, otele yemek siparişi verdik.

Farsala'dan Lamia'ya doğru yola çıktık. Yedinci gün yolumuz nispeten kısa idi ama önce 500 metrelere tırmanacak daha sonra biraz inip bunu 700 küsur metrelere çıkaracaktık. Şehirden çıkmamızdan kısa bir süre sonra ilk ciddi köpek karşılaşmamızı yaşadık. 4-5 tane köpekten oluşan bir çete yanlarından geçerken havlıyor, lider ruhlu 2 tanesi de üzerimize doğru yaklaşıyordu. Bisikletlerden indik, kah köpek kovucuyu tutarak, kah bağırarak ya da taş atarak yavaşça bölgeyi geçtik. Tur boyunca 4-5 kere köpeklerle karşılaştık, genelde yavaşlayıp geçtik, basabileceğimiz yerde de basıp gittik. Yolun devamında ilk tırmanışa geldiğimizde olmadı bisikleti elime alır öyle çıkarım dedim ama gerek kalmadı, en düşük viteste dinlene dinlene çıktık burayı. Ama daha sonraki tırmanışa geldiğimizde hava da bozmuştu, bir taraftan yağmur yağıyor bir taraftan sis görüşümüzü çok kısıtlıyordu. Sürmeyi bırakıp bisikletler elimizde öyle devam ettik. En tepe noktada yol kenarında sebze, karpuz, vs. satan (kime sattığını çok merak ettiğim) bir abi bizi yanına davet etti. Oturduğu yerin yanına bir de ateş yakmıştı, ateşe yaklaşınca üzerimizden buharlar çıkıyordu. Abi tek kelime İngilizce bilmiyor ha bire Yunanca bir şeyler anlatıyor ve bizden anlamamızı bekliyordu. İki shot bardağı çıkartıp pet şişeden su gibi şeffaf bir şey koydu bizim için, için dedi. İçtik :) Daha sonra bu içkiden bir bardağa az bir şey koyup ateşin üstüne attı, ateşi baya bir harladı artık neyse bu. İçimiz de ısınmıştı birden :) Adama teşekkür ettik yola koyulduk. Tam 11 kilometre boyunca tek pedal çevirmeden adeta uçarcasına yağmur damlalarının arasından geçerek Lamia şehrine indik. Donumuza kadar da ıslanmıştık. Hava daha erkendi, biraz daha sürebilir miyiz diye düşündük ama sırılsıklam olmuştuk, Lamia'da kalmaya karar verdik.

Lamia'dan ana hedefimiz olan Atina'ya 220 km civarı kalmıştı, arada gidecek bir yer daha bulmamız gerekiyordu ama pek uygun bir yer yoktu. Bir günde gidebileceğimiz uzaklıktaki güzargahlar sürüş açısından yorucu olacaktı. Biz Thiva şehrini gözümüze kestirdik. 130 km gibi bir yol yapmamız gerekecekti ama yol en azından fazla yokuşlu değildi, yalnız yolun bir kısmında gidebileceğimiz yol bitecekti, orada bir karar veririz dedik. Biraz da erken yola koyularak sekizince gün sürüşümüze başladık. İlk 40 km çok iyi gitti, Kamena Vourla diye şirin bir tatil kasabasında kahve molası verdik, standart yol yiyeceğimiz olan muzdan aldık. Yolun kalan kısmında bir kez daha otobana girmek zorunda kaldık, yine otoban devriyesine yakalandık, bize ilk çıkışa kadar eskortluk ettiler. Bu sefer polis de geldi, uyardı bizi ve gitti. Otoban devriyesine o emin olmadığımız biten yolu sorduk, net bir şey söylemedi, sorun olursa tekrar otobana girin biz sizi buluruz dedi :) Yliki gölünün oraya geldiğimizde o biten yolun harbiden bittiğine tanık olduk. Yol ilk önce toprak yola dönüştü, sonra da bir noktada kesildi. Bisikletten inip keşif için yürüyerek ilerde gözüken ve sanki bir zamanlar bu yolun devamı olan yola kadar gittik. Bisikletleri elimize alıp buraya kadar getirip yola buradan devam edebilirdik ama bu yolun da tam olarak bizi nereye götüreceğine emin olamadık. Geri dönüp otobana girmeye karar verdik. Geri dönüşte giderken rastladığımız köpekler ile bir daha haşır neşir olmak zorunda kaldık. Şimdiye kadar hiç aynı yolu geri tepmediğimize seviniyordum, bu sefer şansımız yaver gitmedi. Otobana girdik, 100 metre sürdük sürmedik otoban devriyesi peşimize takıldı, dedik "Birader biz de meraklı değiliz otobana girmeye ama yol yok, ne yapalım?". Yine bize eskortluk ederek Thiva çıkışına kadar götürdü. O gün en uzun mesafemiz olan 147 km'yi yapmıştık, akşam 9 civarı şehre vardık. Şehirde 3 tane otel vardı ama bizimki de şans, o hafta sonu şehirde bir drag racing aktivitesi varmış, tüm oteller dolu. Alternatif olarak ne yaparız planlarını yapıyoruz, şehirde tren istasyonu var onun bekleme salonunda yatarız falan. Otellerden birindeki görevli sağ olsun çok yardımcı oldu, "Bir odamın rezervasyonunu yaptıranlar daha gelmedi, 1 saat daha gelmezse size veririm, siz gidin yemeğinizi yiyin." dedi. Şanslıymışız ki o odayı tutabildik ve geceyi sokakta geçirmekten kurtulduk :)

Artık Atina'ya varmak için bir günlük yolumuz kalmıştı, tek motivasyonum buydu :) Thiva'dan ayrılıp 90 km civarı sürerek Atina'ya vardık. Yolda öğle molasında yine çok fazla yememeyi planlamıştık ama yine çok fazla yedik, yemek sonrası sürüşler hele bir de yokuş çıkılacaksa çok zahmetli oluyor, son gün olmasının da verdiği rehavet ile fazla kasmadık. Atina'da şehir içinde azımsanmayacak kadar yol yapıp merkeze vardık, öğle molasında rezervasyon yaptırdığımız oteli bulup bisikletleri bıraktık. Akşam yemeği, dönüş tren biletini almak ve şehri turlamak için dışarı çıktık. Vakit biraz geç olduğu için Acropolis ziyaretini ertesi güne bıraktık, o akşam internetten Atina'da nereler gezilmeli not ettik. Ertesi gün ilk defa 10 gün sonra bisiklet sürmeyecektik :) Bir gün önceden planladığımız yerleri gezdik, turistik şehir turu yapan otobüslere binerek en az sürede en çok yeri görmeye çalıştık. Gece yarısı dönüş trenimiz vardı, otelden bisikletleri alıp istasyona gittik. Trene bisikleti koyma ile ilgili hep bir sorun çıkacak şeklinde şüphelerim vardı, yersizmiş, sorunsuz bir şekilde bisikletleri teslim ettik. 14 saat süren, pek de rahat olmayan bir yolculuk sonrası Alexandroupoli'ye vardık. Biletimiz aslında hemen yakınındaki Feres kasabasına idi, burada başka bir trene aktarma yapmayı bekliyorduk ama öyle olmadı. Aktarmayı otobüs ile yapacaktık. Otobüs şoförü her ne kadar olmaz dese de bisikletleri bagaja attık, Feres'e vardık. Burada son defa bir 15 km civarı yol alarak Türk sınırına vardık. Bayram dönüşünden dolayı olsa gerek girişte araç kuyruğu vardı, rica ettik, kuyruk beklemeden giriş işlemlerimizi tamamladık. Arabayı da koyduğumuz yerde bulunca derin bir nefes aldık, attık bisikletleri arabaya ve İstanbul'a doğru yola koyulduk.

Acropolis'teki Parthenon
Acropolis'teki Parthenon

Zaman zaman "Biz ne yapıyoruz?" sorusunu sordurtsa da planladığın bir hedefe ulaşmanın verdiği tatmin insanı mutlu hissettiriyor. Bu yaptığımız ilk ciddi tur olduğu için çok şey öğrendik, ikincisinde muhtemelen çok daha rahat olacağızdır. Bu tarz bir gezide içime sinmeyen tek şey kısıtlı sürede zamanının büyük kısmı yol kat etmekle geçiyor ve yanından geçtiğiniz görülmeye değer yerlere sapmanız pek mümkün olmuyor.

Bisiklet ile aldığımız yollar kabaca şu şekilde:

  1. Gün: İpsala-Alexandroupoli-Komotini, 90 km
  2. Gün: Komotini-Xanthi-Kavala, 110 km
  3. Gün: Kavala-Asprovalta-Loutra Volvis, 115 km
  4. Gün: Loutra Volvis-Selanik, 54 km
  5. Gün: Selanik-Katerini-Paralia Panteleimonos, 106 km
  6. Gün: Paralia Panteleimonos-Larissa-Farsala, 95 km
  7. Gün: Farsala-Lamia, 70 km
  8. Gün: Lamia-Thiva, 147 km
  9. Gün: Thiva-Atina, 93 km

Yunanistan özelinde gözüme çarpan şu noktalar oldu:

  • Yemek porsiyonları çok büyük, yediğimiz her yemek sonrası kendimizi kötü hissettirecek kadar büyüktü porsiyonlar.
  • Kızarmış patatesi çok seviyorlar, bir yerde yemeğe ulaşabilmek için yemeğin üzerini kaplayan patatesleri yemek zorunda kaldım.
  • Çoğu yemeğin yanında bir iki dilim limon illa ki oluyor, pek anlam veremedim.
  • Yemek veya içmek için gittiğin her mekanda eksiksiz masaya su geliyor ve devamlı tazeleniyor bu su. Bir çok yerde de kurabiye ikram edildiğini gördük.
  • Çok fazla fiş kesiyorlar. Artık maliye korkusundan mıdır nedir, yemeğe eklettiğimiz her şey için ayrı bir fiş geliyor.
  • Trafik ışık süreleri çok kısa, yaya geçidinin yarısında kırmızıya döndüğüne denk geldik birçok seferinde.

.net comments

Starting from Windows Vista, you should have noticed that actions which require administrative privileges and needs to elevate the current process, displays a shield icon right next to them. For example the Change date and time... button on Date and Time dialog requires admin rights to modify system date, hence displays a UAC shield right next to it:

Date and Time

If your application has any buttons or menu items like this, to conform the Windows UX Guidelines, it is a good idea to display a UAC shield icon on your controls. This CodeProject article has a good example that shows how to add shield icons to regular WinForms buttons. The gist is the following P/Invoke code:

const int BCM_FIRST = 0x1600; //Normal button
const int BCM_SETSHIELD = BCM_FIRST + 0x000C; //Elevated button

static void AddShieldToButton(Button b)
{
  b.FlatStyle = FlatStyle.System;
  SendMessage(b.Handle, BCM_SETSHIELD, 0, 0xFFFFFFFF);
}

Simply pass your Button instance reference to AddShieldToButton and you will have a nice UAC shield icon on your button on Windows Vista and above.

If you are using a third party library for your user interface controls (like DevExpress WinForms) or you need to add an icon to a menu item rather than a button, this method won't work unfortunately. There is a support ticket on DevExpress Support Center about this issue and the suggested workaround is to use the Image property of SimpleButton class. So you can save a 16px * 16px version of this shield icon in your project resources and then use it. This has a minor issue though, if you want to strictly stick to the look and feel of the operating system, you may have problem while using a single hard-coded image. The reason is, this icon on Windows Vista was a shield icon with 4 colors (red, green, blue and yellow) but since Windows 7, it has only 2 colors (blue and yellow). Who knows what it will become on Windows 9 (do not get surprised if this icon becomes a flat metro-style icon). Not a big deal but if you really want to blend in with Windows desktop, these small things matter.

UAC Shield Icons on Windows Vista

Windows stores these resources in its DLL files and it is a good idea to reuse them. This way, we will stick to what operating system has as the UAC shield icon and won't need to maintain that image resource in our project. Even WinForms has a managed API to access these kind of icons like error, warning, information, shield, etc. You can get a shield Icon instance by accessing SystemIcons.Shield property since .NET Framework 2.0 SP1. There are 2 issues with this approach:

  1. SystemIcons.Shield returns an Icon instance whereas SimpleButton.Image expects an Image instance.
  2. The icon is in 32px * 32px size but a regular button on Windows should have a small 16px * 16px icon. (On 96 DPI desktops)

To resolve these issues, I have come up with the following piece of code:

static void AddShieldToButton(SimpleButton b)
{
  var icon = Icon.FromHandle(SystemIcons.Shield.Handle);

  var iconSize = SystemInformation.SmallIconSize;
  var bitmap = new Bitmap(iconSize.Width, iconSize.Height);

  using (var g = Graphics.FromImage(bitmap))
  {
      g.InterpolationMode = InterpolationMode.HighQualityBicubic;
      g.DrawIcon(icon, new Rectangle(0, 0, iconSize.Width, iconSize.Height));
  }

  b.Image = bitmap;
}

This is what you get as a result with DevExpress controls using this method:

DevExpress UAC SimpleButton

This is ugly, huh? The issues are:

  1. Even though I am on Windows 8.1, I am getting Windows Vista's 4 color UAC shield icon. If you dig down the SystemIcons.Shield code with Reflector, you will see that the getter of this property first tries to load the system UAC shield icon using a P/Invoke code to LoadIconWithScaleDown function of comctl32.dll. This call fails, you can see that on your Visual Studio output pane reporting a first chance exception of type EntryPointNotFoundException thrown. The reason is, LoadIconWithScaleDown seems to be removed on a later version of comctl32.dll. Fortunately, the getter has a backup method which gets the icon loaded from the System.Drawing.dll embedded resources, which unfortunately is the old UAC shield icon:

    new Icon(typeof(SystemIcons), "ShieldIcon.ico");
    
  2. The resized icon looks rubbish. Even though we are using InterpolationMode.HighQualityBicubic, scaling down a 32px icon to 16px doesn't end well.

Digging down a bit more, I have finally managed to get all these issues sorted with the following piece of code:

[DllImport("user32.dll")]
static extern IntPtr LoadImage(
    IntPtr hinst, 
    string lpszName, 
    uint uType, 
    int cxDesired, 
    int cyDesired, 
    uint fuLoad);

static void AddShieldIcon(SimpleButton button)
{
  var size = SystemInformation.SmallIconSize;
  var image = LoadImage(IntPtr.Zero, "#106", 1, size.Width, size.Height, 0);

  if (image == IntPtr.Zero)
  {
    return;
  }

  using (var icon = Icon.FromHandle(image))
  {
    var bitmap = new Bitmap(size.Width, size.Height);

    using (var g = Graphics.FromImage(bitmap))
    {
      g.DrawIcon(icon, new Rectangle(0, 0, size.Width, size.Height));
    }

    button.Image = bitmap;
  }
}

And this is the result:

DevExpress UAC SimpleButton

Much better, if I may say so myself. This one uses LoadImage P/Invoke call to get the correct size of the icon, so we don't need to scale it down. Since this function returns an icon handle, we are just converting the icon to a bitmap. Using this method, you can even put UAC shield icons to your menu items:

WinForms UAC menu item

Or you can get each and every size of the UAC shield icon, just because...you can:

UAC icons

.net comments

If you ask this question on Google, you will find the following code snippet all over the web:

var text = "lorem ipsum dolor sit amet";
var bytes = Encoding.UTF8.GetBytes(text);
var stream = new MemoryStream(bytes);

This totally answers the question and works fine, but you should weigh your requirements while using this code. With short strings, that shouldn't be much problem but if you are working with larger ones, the call to GetBytes() method will allocate a huge array at least the length of your string. And worse, if this byte array is larger than 85.000 bytes, it will go into the Large Object Heap (LOH) which we should avoid as much as we can. Think also about this, if you need to pass that string to a consumer which expects a Stream, this should hint that this consumer won't need that bulk of bytes at a single point of time, rather it will read those bytes batch by batch using regular streaming interface techniques.

Stephen Toub, on one of his MSDN Magazine blog posts writes about this very issue and comes up with 3 solutions. The first two are very much like the code snippet above, only the second one is a bit refactored version of it but it has still the same semantics.

On the other hand, the third solution illustrates a quite nice approach as you can see on Figure 1 Alternate StringStream Implementation code listing. Possibly due to recent style changes on MSDN pages, the code is quite garbled but you can copy it over to Visual Studio and auto format it. This is a regular .NET Stream implementation code with the required overridden implementations. The interesting part is the Read() method which performs the real work:

public override int Read(byte[] buffer, int offset, int count)
{
  if (_position < 0) throw new InvalidOperationException();

  int bytesRead = 0;

  while (bytesRead < count)
  {
    if (_position >= _byteLength) return bytesRead;
    char c = _str[_position / 2];
    byte b = (byte)(_position % 2 == 0 ? c & 0xFF : (c >> 8) & 0xFF);
    buffer[offset + bytesRead] = b;
    Position++;
    bytesRead++;
  }

  return bytesRead;
}

This method, on each call, tries to fill the given buffer with the byte representations of the remaining string until either the buffer is full or it reaches to the end of the underlying string. Since .NET strings are UTF-16 encoded, each char is represented with 2 bytes. The while loop in this method on each iteration writes a single byte, hence writing out a single char takes 2 iterations, one for lower byte and the other for upper byte. You can see this StringStream implementation in action with a code like this:

var text = "lorem ipsum dolor sit amet";

using (var stream = new StringStream(text))
using (var reader = new StreamReader(stream, Encoding.Unicode))
{
  var read = reader.ReadToEnd();

  Assert.AreEqual(text, read);
}

Here I am providing a text to StringStream constructor, giving that stream to a StreamReader, reading to the end of the stream and what I read back is the exact same string I have provided in the first place. But notice that the second parameter of StreamReader constructor which is Encoding.Unicode, that is required in this case because StreamReader defaults to Encoding.UTF8 in the absence of an encoding parameter. We need to explicitly specify the encoding because the underlying stream implementation will spit the bytes according to Unicode (UTF-16) encoding rules.

If the consumer of your stream instance doesn't use Unicode encoding while decoding the bytes that come out of your StringStream.Read() method, it will fail to get the desired string decoded. In the previous code snippet, go either delete the second parameter of StreamReader constructor or replace it with Encoding.UTF8, you will read a string like this:

"l\0o\0r\0e\0m\0 \0i\0p\0s\0u\0m\0 \0d\0o\0l\0o\0r\0 \0s\0i\0t\0 \0a\0m\0e\0t\0"

This string has a null char for every other char, this is because UTF-8 represents the characters in English alphabet (or any character in ASCII subset for that matter) with a single byte and secondary 0x00 bytes are represented as null chars in this string. The encoding assumption of StringStream class fails the consumer of this stream. To fix this issue, the StringStream class must know the desired encoding to use when spitting out bytes. I have modified this class to accept an encoding in its constructor and produce bytes according to the specified encoding rules. Here is what Read() method became with this implementation:

public override int Read(byte[] buffer, int offset, int count)
{
  if (_position < 0)
  {
    throw new InvalidOperationException();
  }

  var bytesRead = 0;
  var chars = new char[1];

  // Loop until the buffer is full or the string has no more chars
  while (bytesRead < count && _position < _str.Length)
  {
    // Get the current char to encode
    chars[0] = _str[_position];

    // Get the required byte count for current char
    var byteCount = _encoding.GetByteCount(chars);

    // If adding current char to buffer will exceed its length, do not add it
    if (bytesRead + byteCount > count)
    {
      return bytesRead;
    }

    // Add the bytes of current char to byte buffer at next index
    _encoding.GetBytes(chars, 0, 1, buffer, offset + bytesRead);

    // Increment the string position and total bytes read so far
    Position++;
    bytesRead += byteCount;
  }

  return bytesRead;
}

The key point in this implementation is that we are first making sure there is enough room to put the byte(s) of current char to buffer, to do that we are using Encoding.GetByteCount() method. If there are no rooms left to encode current char, the method simply returns with the total bytes read count so far, leaving the rest of reading to next Read() method call. If there is room, then the method uses Encoding.GetBytes() method to write current char byte(s) to buffer at next index.

You can find the source code of this class at my GitHub repository.

.net comments

The other day I was tasked to load XML and JSON documents to a WinForms TreeView control. Nothing fancy, obviously a recursive method will do the job but I thought this should be one of those already solved problems and I can easily find a snippet on the interwebs. For XML a simple Google search lead me to the expected source code snippet and after a few refactoring here and there, I was done.

But for the JSON, the first page of Google search results failed me and I couldn't find that single method snippet, preferably using the great Newtonsoft.JSON library. So I have given it a spin and get my hands dirty, after all it is good to refresh my rusty recursive coding skills :) I hope the next guy finds the following code useful and saves him a better half/one hour time.

void LoadJsonToTreeView(TreeView treeView, string json)
{
  if (string.IsNullOrWhiteSpace(json))
  {
    return;
  }

  var @object = JObject.Parse(json);
  AddObjectNodes(@object, "JSON", treeView.Nodes);
}

void AddObjectNodes(JObject @object, string name, TreeNodeCollection parent)
{
  var node = new TreeNode(name);
  parent.Add(node);

  foreach (var property in @object.Properties())
  {
    AddTokenNodes(property.Value, property.Name, node.Nodes);
  }
}

void AddArrayNodes(JArray array, string name, TreeNodeCollection parent)
{
  var node = new TreeNode(name);
  parent.Add(node);

  for (var i = 0; i < array.Count; i++)
  {
    AddTokenNodes(array[i], string.Format("[{0}]", i), node.Nodes);
  }
}

void AddTokenNodes(JToken token, string name, TreeNodeCollection parent)
{
  if (token is JValue)
  {
    parent.Add(new TreeNode(string.Format("{0}: {1}", name, ((JValue)token).Value)));
  }
  else if (token is JArray)
  {
    AddArrayNodes((JArray)token, name, parent);
  }
  else if (token is JObject)
  {
    AddObjectNodes((JObject)token, name, parent);
  }
}

That's fine and dandy, but how about adding some unit tests, there are quite lot of code execution paths over there, right? How would you test such a piece of code? The first thing comes to my mind is to not directly code against UI components like TreeView and TreeNodeCollection, but creating a generic view model and testing that model on your unit tests. This also decouples the design from the UI framework, so that you can easily port your code to another UI framework, say WPF. But still, I couldn't think of an easy and maintainable way to write your assertions. This brings me to this great unit test helper library I have discovered recently, Approval Tests.

Simply put, Approval Tests diffs the results of your test code output with the output you have expected. The comparison can be made on either regular texts or on images if you are testing some UI code. You can watch Using ApprovalTests in .Net 16 WinForms to get the idea. Here is a simple unit test that uses Approval Tests to perform assertion:

[Test]
public void Should_load_simple_json()
{
  var treeView = new TreeView
  {
    BorderStyle = BorderStyle.None,
    Width = 400,
    Height = 400,
  };

  LoadJsonToTreeView(treeView, "{ 'foo': 'bar', 'baz': [ 42, 'quux' ] }");
  treeView.ExpandAll();

  WinFormsApprovals.Verify(treeView);
}

The test first creates a WinForms TreeView control and calls the LoadJsonToTreeView() method (System Under Test) with a simple JSON string. Then ExpandAll() method is called on TreeView instance to get all nodes visible, since we are going to take a snapshot on the last line, all nodes better be visible. When you run this unit test for the first time, the test fails and you get the screen shot of the WinForms control that is produced:

Received Image

In Approval Tests terms, this is a received image which shows the actual output of current unit test code. What you do next is to simply approve this result if that looks correct. To approve a result, you need to create the image of the expected result. Approval Tests helps you here by providing the necessary move command on your unit test failure message, something along these lines:

move /Y "Test_name.received.png" "Test_name.approved.png"

If you also prefer to use ClipboardReporter as another reporter for your unit tests, this command will automatically copied to your clipboard to be able to quickly run it, which is a great time saver.

Just run this command on your command prompt and the image you have just seen will be renamed and from now on, it will work as the expected result for this unit test. If you change the code and break the unit test, a nice side-by-side comparison view of the actual and expected images will show on a TortoiseDiff window. TortoiseDiff seems to be a hard dependency of Approval Tests and I am not sure how it is discovered on your system or any chance to change it to another diff viewer for that matter.

I have created a sample project and unit tests project on GitHub, send me a pull request if I am missing anything :)

PS: I am curious whether Approval Tests handle the different control styles across different operating systems, i.e. you create your approved images on a Windows 8 box but if your build server runs your tests on a Windows Server with classic Windows theme, you will end up having different images. Please let me know if you have any idea about this in comments.

javascript comments

Suppose you have the following form on your HTML page:

<form id="MyForm" action="process.aspx" method="POST">
  <input type="text" name="foo" />
  <input type="submit" name="submit" value="Send" />
</form>

Seems pretty innocent right? No. At least until you try to submit that form using JavaScript code. Try running the following JavaScript code on a page that contains this form inside developer tools console of your favorite browser:

document.getElementById('MyForm').submit()

You will get a lovely error, on Chrome:

TypeError: Property 'submit' of object #<HTMLFormElement> is not a function

On Internet Explorer:

Member not found.

But how come? Is submit() broken? Chrome's error message hints that a property named submit exists but not a function. Let's see what it is:

document.getElementById('MyForm').submit

This call will return a reference to submit button element in the form. Apparently you can access child form input elements as properties of parent form element, neat! But seriously, I need to call the submit() method. To do that I need to have a reference to the overridden function. If I had a reference to that function I know I can call it with the form reference I have in hand, thanks to call() method exists on all JavaScript functions. Using the call() method I can execute the submit() function with any instance I want. OK then, how about using another form reference's non-overridden submit() method, let's try this:

document.createElement('form').submit(document.getElementById('MyForm'))

Bingo! It worked. But it doesn't feel quite right, especially creating another form element to solely access one of its methods? There should be a better way. A little research took me to this: HTMLFormElement which represents the base of all form elements and has references to all form functions accessible through its prototype, great! Let's give the following revised code a chance:

HTMLFormElement.prototype.submit.call(document.getElementById('MyForm'))

This worked and is a reasonable solution for this problem.