Aklımda Kalası Kelimeler

* давайте работать вместе
* Zarf ve Mazruf, Zerafet(xHoyratlık) ile aynı kökten(za-ra-fe) gelir
* Bedesten
* Suç subuta ermiştir - Suç sabit olmuştur

21 Eylül 2016 Çarşamba

Elasticsearch ve Mapping

Aşağıda ilişkisel veritabanı ile ES arasındaki terminolojik bağlantıları göreceksiniz.

Şema kavramı ile Mapping arasında terminolojik olarak aynılığı yukarıdaki resimde gördünüz.
Tablo ile Tip arasındaki aynılıkta dikkatinizi çekmiştir.
O halde ilişkisel veritabanlarında bir tablonun şeması olduğunu yani içindeki kolonların hangi tiplerde veri aldığını belirttiğinizi hatırlarsanız, şema

Mapping nedir, nasıl belirtilir, nasıl yapılandırılır ve verimize nasıl uygulanır diye bakalım.
Şema, bir ya da daha fazla alanları olan belgenin tanımıdır. ES JSON tipinde verileri muhafaza ettiğinden dolayı, JSON verisinin içinde veri tipini bu verinin nasıl indekslenmesi gerektiğini "mapping" ile belirtiriz ki mapping ES dünyasında şema demektir.
ES içinde 0 ya da daha fazla index ve bu indexler 0 veya daha fazla document içerir. Bir başka deyişle; bir belgenin bir tipe ve bir index'e bağlı tanımlayıcısı vardır.

Yukarıdaki şekilde INDEX, TIP be DOKUMAN kutularını görüyorsunuz. A,B,X ve Y belgelerinin my_type adında bir tipi ve my_index adında bir indexi var. Aynı indeksi bir başka tip olan "another_type" ve bu tipi kullanan belgeler de kullanıyor. Yukarıdaki figürdeki TIP aslında

19 Temmuz 2016 Salı

ASP.NET 5 Üzerine

ASP.NET yeni, açık kaynak kodlu ve mac, linux, windows gibi işletim sistemlerinde çalışabilen(cross-platform) çatı olarak karşımıza geliyor. Web uygulamalarızı buluta taşımak konusunda daha esnek bir yapıda en baştan tekrar geliştirildi bu çatı.
ASP.NET 5 ile birlikte gelen komut satırı araçlarıyla Visual Studio dışından cross-platform ASP.NET uygulamalarını basit bir metin editörüyle(notepad gibi) geliştirebilecek visual studio çalıştırmadan CMD ya da Poweshell(windows üstünde tabii) derleyebileceğiz. Bu komutlar ASP.NET 5 içinde
  1. DNX (.Net Execution Environment-.Net çalıştırma ortamı) .NET 5 uygulamalarının ihtiyaç duyacağı bileşenleri içeren, eski usül .net çatısı olup içinde birden fazla .net versiyonunu içerebilmesi sayesinde dll cehennemini yaşamamızı sağlar,
  2. DNVM(.Net Version Manager) ile hangi DNX sürümünü kullanacağımızı seçeriz,
  3. DNU (DNX klasöründe bulunan DNU kütüphanesi sayesinde .NET 5 uyugulamasının project.json içinde tanımlanmış ihtiyaç duyacağı paketlerin yönetilmesini -yükleme(installation) veya geri yükleme(restoring)- sağlar.),

1 Temmuz 2016 Cuma

Pair Programming üzerine

Ne zaman roller değişmeli:

Diyelimki 4 takımın var ve elbette ikişer kişiden oluşuyor. Periyodik olarak takım üyelerinin yerlerini değiştirmek iyidir, candır.

19 Mart 2016 Cumartesi

npm ayarları

NPM SET INIT


NPM addUser

npm client için www.npmjs.com adresinde kayıtlı olan kullanıcı bilgilerinizi bir kerede girmeniz ve ileride gerekmemesi için gerekli ayarlar:


.gitignore Dosyasıyla Yoksayılacaklar


git add -A

Tüm dosyaları (.gitignore içinde olmayan tüm dosyaları) repository'e gönderecek şekilde işaretler.

git commit -m "mesajınız"

Yaptığınız değişiklikleri bir mesaj ile repoya gönderilecek şekilde işaretler

git push

Artık github'a gittiler git push ile.

npm publish

github üstünde artık kodlarınız bulunuyor ancak npm install paket_adi ile indirilebilimesi için npmjs.com adresine publish edilmesi gerekiyor.

git tag

Buraya kadar kodunuzu ilk kez git's yüklediniz ve npm paketinizi kayıt ettirdiniz. artık npm install paketinizin_adi diyerek kullandırabilirsiniz ama zaman içinde çeşitli sürümler yaparak hem eski sürümlerinize erişim hem de yenilerini kullanma imkanı sunmak istiyorsunuz. O halde git tag [versiyonNo] ile sürekli sürüm yapabilirsiniz git üstünde. Tabi bunları npm tarafında da güncel tutmanız gerekecek ama önce git etiketlemesine bakalım:
Artık github üstünde versiyonNo etiketli sürümünüzü görebilir buna bir başlık açabilir üstünden sorunları giderebilirsiniz.

Artık Yeni Sürüm


npm install

npm install paketAdi             // son stabil paketi
npm install paketAdi@beta        // son beta sürümünü
npm install paketAdi@versiyonNo  // son beta sürümünü


npm version patch

Sadece package.json içindeki sürüm bilgisinin patch sayısını bir arttırıp package.json içindeki bilgiyi güncelleyecektir. Tabii bu işi git üstünden yaptığı için (git içindeki git-tag-version ile) git versiyonu da değişecektir. Bunu git üstünden yapmamak için npm --no-git-tag-version version -f çalıştırmalısınız.
npm version major|minor|patch şeklinde çeşitlerini buradan bulabilirsin.

npm scripts

Ref: http://blog.npmjs.org/post/118810260230/building-a-simple-command-line-tool-with-npm
Bir versiyon temel olarak major.minor.patch bölümlerinden oluşur.
Yamalamak için versiyonlama işi kısaca npm version patch ile olabilir ancak bu versiyonu npmjs.com adresine publish etmek içinde npm publish demek gerekecektir. Bunu otomatik hale getirmek için aşağıdaki blok iş görecektir. npm run patch-release ile tümünü tek bir kod ile yapabilirsiniz.
#package.json
{
  "name": "my-project",
  "version": "1.0.0",
  "scripts": {
    "patch-release": "npm version patch && npm publish && git push --follow-tags"
  }
}

Daha karmaşık bir yapıyı parçalara bölerek oluşturup tek elden çalıştırbilirsiniz npm run deploy ile.
"scripts": {
    "build": "...",
    "git-commit": "git add -A . && git commit -a -m 'gh-pages update'",
    "git-push": "git push origin gh-pages --force && git checkout master",
    "deploy": "npm run build && npm run git-commit && npm run git-push"
  },

git config --global credential.helper wincred

Git hesabınızı windows komut satırında kullanırken defalarca kullanıcı adınızın sorulmasını istemezseniz komut satırına
$ git config --global credential.helper wincred
yazmanız halinde artık kullanıcı bilgilerinizi windows tutacaktır. Yapmanız gereken git depolarından bir kaynak kodunuzla ilgili güncelleme yaparken bir kez kullanıcı adı ve şifrenizi girmek olacaktır. git config --list ile ayarlarınıza baktığınızda credential.helper=wincred satırını göreceksiniz ve sonraki tüm git işlemlerinizi komut satırından yaparken size kullanıcı adı ve şifresi sormayacak.

Windows credentials ile baktığınızda "Generic Credentials" kısmında github şifrenizin depolandığını göreceksiniz.

git config --list


cem.topkaya@CZC11141WZ C:\_Projeler\Cop\modules\kuark-istisna
$ git config --list
core.symlinks=false
core.autocrlf=false
color.diff=auto
color.status=auto
color.branch=auto
color.interactive=true
pack.packsizelimit=2g
help.format=html
http.sslcainfo=/bin/curl-ca-bundle.crt
sendemail.smtpserver=/bin/msmtp.exe
diff.astextplain.textconv=astextplain
rebase.autosquash=true
user.name=cemtopkaya
user.email=cem.topkaya@hotmail.com
gui.recentrepo=C:/Users/cem.topkaya/Documents/Visual Studio 2013/Projects/ConsoleApplication8/CSharp_Orneklerim_Git
credential.helper=wincred
http.postbuffer=524288000
core.repositoryformatversion=0
core.filemode=false
core.bare=false
core.logallrefupdates=true
core.symlinks=false
core.ignorecase=true
core.hidedotfiles=dotGitOnly
remote.origin.url=https://github.com/cemtopkaya/repo-adi.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*

cem.topkaya@CZC11141WZ C:\_Projeler\Cop\modules\kuark-istisna

git config --global push.default matching

Daha sade bir çıktı almak istersek kullanacağız. Yani, normalde $ git push aşağıdaki çıtıyı veriyorken:
$ git config --global push.default matching
Komutunu çalıştırarak sadece şu çıktıyı alıyoruz:

Bu çıktıyı şu config listelerindeki değişimlerde görelim:


20 Ocak 2016 Çarşamba

Linq ile GroupBy ve Sum örneği

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication6
{
    class Tax
    {
        public int Orani;
        public int Amount;
        public int ReasonCode;
        public string Reason;
        public override string ToString()
        {
            return string.Format("Oranı:{0}, Amount:{1}, ReasonCode:{2}, Reason:{3}", Orani,Amount,ReasonCode,Reason);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {

            List lst = new List()
                            {
                                new Tax(){Amount = 10, Orani = 18},
                                new Tax(){Amount = 5, Orani = 18},
                                new Tax(){Amount = 0, Orani = 0, Reason = "351", ReasonCode = 351},
                                new Tax(){Amount = 0, Orani = 0, Reason = "251", ReasonCode = 251},
                                new Tax(){Amount = 6, Orani = 8},
                                new Tax(){Amount = 16, Orani = 8},
                            };
            // Sum Amount
            var total = (from l in lst
                select l.Amount).Sum();
            Console.WriteLine("Toplam Vergi: "+total);

            // GroupBy
            var a = from l in lst
                group l by l.Orani
                into g
                orderby g.Key
                select g;
            foreach (IGrouping g in a)
            {
                Console.WriteLine(g.Key);
                foreach (Tax tax in g)
                {
                    Console.WriteLine(tax);
                }
            }
        }
    }
}
Çıktısı:

7 Ocak 2016 Perşembe

Dosyayı, sunucudaki adından farklı kaydetmek

Amacım DWelle RSS'indeki Almanca mp3 eğitim dosyalarını eğitimin başlığıyla kaydetmek. Elimizdekiler:
Öncelikle mp3 dosyalarına tıkladığımızda kaydetmek için karşımıza gelecek dosya adı şöyle gözüküyor:
Biz ise kaydederken adının title alanına ".mp3" eklenmiş halini Ders 10 - Bir oda rezervasyonu yaptırmak istiyorum.mp3 istiyoruz. Eğer a etiketi içinde href özelliği bir adresi değilde doğrudan dosyayı içeriyor olsaydı kaydetmek için istediğimiz dosya adını download özelliğine yazmamız ve tıklamamız yeterliydi. <a download="logo.png" href="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">Download transparent png</a> RSS içindeki bilgileri çekmek için XPath kullanabilirsiniz. Bunu da Chrome browser ile yapabilirsiniz. Güzel bir anlatım için aşağıdaki resimlere bakabilirsiniz:
Kaynak: http://yizeng.me/2014/03/23/evaluate-and-validate-xpath-css-selectors-in-chrome-developer-tools/ Bizim a etiketlerimiz şöyle olacak:
<a href='http://radio-download.dw.de/Events/podcasts/tur/3803_DKpodcast_dwn1_tur/DWN_Tuerkisch_Serie1_Lektion01-podcast-3803-293588.mp3' data-saveas='Ders 01 - Bu bir şarkı.mp3'>Ders 01 - Bu bir şarkı</a>
data-saveas içinde yeni dosya adı, href içinde ise sunucudaki dosyanın adresini tutacağız. Haydi başlayalım ! Aşağıdaki kodu Chrom'un Console sekmesinde çalıştırdığınızda xpath ile sogulamalar için hızlı ve manipule edebileceğiniz bir fonksiyonu yüklemiş olursunuz.
var xpath = function(xpathToExecute){
  var result = [];
  var nodesSnapshot = document.evaluate(xpathToExecute, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
  for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ ){
    result.push( nodesSnapshot.snapshotItem(i) );
  }
  return result;
}
Bu kod ile indirilecek a etiketlerini oluşturalım
var aDizi = [], 
    arrTitle= xpath("//item/title/text()"), // Tüm title içindekilerini alalım. Bunlar bizim mp3 dosyamızı kaydederken kullanacağımız dosya adlarımız olacak
    arrUrl=xpath("//item/enclosure/@url/text()");// Tüm mp3 dosyalarının URL adreslerini alalım. Önce stream olarak alıp blob olarak saklayacak ve tıkladığımız a etiketlerinden diskimize kaydedeceğimiz akışlar

arrTitle.forEach(function(_title, _idx){
  console.log(_idx)
  console.log(arrUrl[_idx])
  aDizi.push("<a href='"+arrUrl[_idx].value+"'>"+_title+"</a>");
})
console.log(aDizi); // Ekranda görelimki listeyi kopyalayıp html dosyamıza yapıştırarak indireceğiz
jQuery candır. Onu sayfamıza bir ekleyelim.
<html>
<head>
    <script src=http://code.jquery.com/jquery-2.1.4.min.js></script>
Sayfamızda data-saveas propertysi olan a etiketlerinin üstünden geçerek href özelliklerindeki adresten akışı indireceğiz ve Blob'a yazarak tekrar a etiketine bağlayacağız.
    <script type=text/javascript>
        $(function() {
            // iterate over all the items that are marked as saveas
            $('a[data-saveas]').each(function() {
                var $this = $(this);

                // İndirmek istediğimiz adres ve diske hangi isimle kaydetmek istiyorsak, yeni dosya adı
                var target = $this.prop('href'),
                    saveas = $this.data('saveas');

                // kaynaktan dosyayı indirmek için ajax kullanacağız
                $.ajax({
                    url: target,
                    type: 'GET',
                    mimeType: 'text/plain; charset=x-user-defined', 
                    error: function(a, b, c, d) {
                        debugger;
                    }
                }).done(function(data, textStatus, jqXHR) {

                    // VERİYİ ÇEKTİK VE ŞİMDİ BLOB OLARAK SAKLAYACAĞIZ
                    var bufferBos = new Int8Array(new ArrayBuffer(data.length));
                    for (var i = 0; i < data.length; i++) {
                        var charCode = data.charCodeAt(i); // ascii
                        bufferBos[i] = charCode; // gelen her byte'ı 8 bitlik(octet) elemanlar olarak diziye yerleştirelim
                    }
                    // Blob oluşturmak yapıcı olarak veriyi ve verinin tipini vermemiz gerekiyor
                    // new Blob([bufferlanmış veri], { type: mimeString })
                    var mimeString = jqXHR.getResponseHeader('Content-Type');
                    var blob = new Blob([bufferBos], { type: mimeString });


                    // ŞİMDİ DEFAULT HREF BİLGİLERİNE GÖRE KAYDETMEMEK İÇİN DÜZENLEYELİM
                    // Blob içine kaydettiğimiz veriye erişebilmek için URL oluşturacağız.
                    var href = (window.webkitURL || window.URL).createObjectURL(blob);
                    $this.prop({
                        // Tıklandığında download propertysinden yer alan ad ile kaydedecek
                        'download': saveas,
                        'href': href,
                        'draggable': true
                    }).data({
                        // <a href="#" class="dnd" data-downloadurl="MIME_Type:File_Name:Blob_URL"></a>
                        // Örneğin:
                        // <a href="#" class="dnd" data-downloadurl="image/jpeg:Penguins.jpg:https://www.box.net/box_download_file?file_id=f66690"></a>
                        'downloadurl': [mimeString, saveas, href].join(':')
                    });
                });
            });
        });
    </script>
</head>
HTML dosyamıza bağlantılarımızı da ekleyerek tamamlayalım. Sayfa yüklendiğinde tüm a elemanlarının içinde dolaşarak ilgili dosyaları blob halinde browser'da tutacak ve tıkladığımızda belirttiğimiz dosya adıyla kaydetmiş olacağız.
<body>
    0: <a href='http://radio-download.dw.de/Events/podcasts/tur/3803_DKpodcast_dwn1_tur/DWN_Tuerkisch_Serie1_Lektion01-podcast-3803-293588.mp3' data-saveas='Ders 01 - Bu bir şarkı.mp3'>Ders 01 - Bu bir şarkı</a>
    <br />1: <a href='http://radio-download.dw.de/Events/podcasts/tur/3806_DKpodcast_dwn3_tur/00eb5664-podcast-3806-306737.mp3' data-saveas='Ders 26 - Yalnızca birlikte olmak istiyoruz.mp3'>Ders 26 - Yalnızca birlikte olmak istiyoruz</a>
    <br />2: <a href='http://radio-download.dw.de/Events/podcasts/tur/3806_DKpodcast_dwn3_tur/00eb5675-podcast-3806-306736.mp3' data-saveas='Ders 25 - Önce ufak siparişler gelmesini umuyorum.mp3'>Ders 25 - Önce ufak siparişler gelmesini umuyorum</a>
..
...
....

</body>
</html>
Haydi sonucuna bakalım. Önce dosyanın indiğini chrome network sekmesinden görelim:
Şimdide tıkladığımızda ne olduğuna:
Hepsi bu :)

3 Ocak 2016 Pazar

Dipkazimi

İnsanın tarım yoluyla ürün elde etme çabası başladığından buyana insanoğlu, elde ettiklerini nitelik ve nicelik yönünden daha artırmak, ucuzlatmak ve kolaylaştırmak için çabalar harcamıştır. Tarımda alet- makinalı hizmetin başladığı 18. yy. dan günümüze kadar büyük ve hızlı bir gelişme olduğu görülmüştür. Günümüzde tarım, alet ve makinasız yapılamayacak bir düzeye ulaştırılmıştır.

Ülkeler, birim alandan en fazla verim alabilmek amacıyla tekniğin bütün imkanlarından faydalanmak için büyük çaba sarfetmektedirler. Ürün artışının faydalanmasında, uygun toprak işlemenin ve iyi bir tohum yatağı hazırlanmasının rolü büyüktür. Ancak bu şartları sağlamak için tarlaya sokulan her türlü toprak işleme aleti toprağın fiziksel yapısının bozulmasına neden olmakta ve bu aletlerin aynı derinlikleri işlemesi sonucunda da, toprak profilinin bu derinliğinde pulluk tabanı denilen sert bir tabaka oluşmaktadır. Bu sert tabakanın oluşmasına sadce sürüm aletleri neden olmamaktadır. Topraktaki bazı mineraller ve oluşumlar da sert tabakanın oluşmasına neden olmaktadır. Makinaların kullanılmasıyla sert tabakanın oluşmasında toprak nemi çok önemli bir faktördür. Ağır tavda yapılan sürümler bu tabakanın daha çabuk oluşmasına neden olmaktadır. Bu tabaka sert olduğu için toprağa giren suyu pulluk tabakasının altına geçirmez. Bitki köklerinin derinlere ulaşmasını önler. Bu yüzden bu tabakanın belirli aralıklarla kırılması, kabartılması gerekir. Bu amaç için de dipkazan aletleri kullanılır.

Toprakların traktörle işlenmesi sonucu oluşan sert tabaka, genellikle 20-25 cm. derinlikte bulunmakta, bu tabakanın kalınlığı da 6-18 cm arasında değişmektedir. Ağır bünyeli topraklarda sert tabaka toprak yüzeyinden daha derinde (yaklaşık olarak 35-40 cm) teşekkül eder. Ancak orta ve hafif bünyeli topraklarda sert tabaka oluşumu, ağır bünyeli topraklara oranla daha çabuk ve daha sert olmaktadır.

Sert tabaka oluşmasının zararları

Sert tabaka oluşması toprağın gözenekliliğini azaltır. Toprak sıkıştığından bitki köklerinin gelişmesi için ihtiyaç duyulan oksijen miktarı azalır. Kökler iyi gelişemez.

Sert tabaka toprağın geçirgenliğini azaltır. Yağmur, sulama suyu şeklinde toprağa giren sular sert tabakadan geçemez, bunun sonucu olarak toprak derinliğine işleyemez. Dolayısıyla toprakta yeterince su depolanamayacağından bitkiler kurak dönemlerde ihtiyaç duydukları suyu toprakta bulamayacaklar ve sonuçta verim düşüşü kaçınılmaz olacaktır.

Bitki kökleri sert tabakayı geçemeyecekleri için yukarı veya yana doğru kıvrılarak topraktaki bitki besin maddelerinden ve mevcut toprak suyundan yeterince yararlanamayacaklardır. Tüm bunların sonucunda verimde bitki çeşidine bağlı olarak %25- 30 oranında azalma olacaktır.

Sert tabaka hangi aletlerle kırılmalıdır?

Toprakta genellikle pulluk sürümü derinliğinde oluşan sert tabakanın kırılması, yani patlatılması gerekir. Bunun için en uygun zaman da toprağın hangi derinlikte oluştuğunu ve kalınlığının kaç santimetre olduğunu bilmeliyiz ki, ona uygun bir alet seçelim. Bunun için toprak incelenir. Yapılan çalışmanın sonucuna göre;

* Sert tabaka toprak yüzeyinden 20-25 cm. derinlikte oluşmuş ise çizel aleti kullanılır.

* Sert tabaka toprak yüzeyinden 30-40 cm. derinde oluşmuş ise subsoiler (dipkazan) aleti kullanılmmalıdır.

* Sert tabaka toprak yüzeyinden 65-70 cm derinlikte oluşmuş ise riper aleti kullanılmalıdır.

Sert tabakanın kırılmasının faydaları:

Sert tabakadan dolayı ıslaklık sorunu olan yerlerde sert tabaka kırılarak geç tava gelme durumu ortadan kalkar, erken veya zamanında ekim yapılması sağlanır. Toprağın havalanması ve toprağın su tutma kapasitesi artar. Toprağın derinlerinde bulunan besin maddelerinin alınması kolaylaşır.

Beklenen faydaların olabilmesi için;

* Sert tabakanın iyice parçalanması ile bunu sağlayacak çizel, dipkazan ve riper aletlerinin çekimi için en uygun zaman toprağın kuru olmasıdır. Bu nedenle sert tabakanın kırılması yaz aylarında yapılmalıdır.

*Sert tabakanın çok iyi parçalanması için çizel veya dipkazan aletinin yırtıcı kısımları (derinliği bakımından) sert tabakanın hemen altından geçirilmelidir.

* Sert tabakayı kırmak için kullanılan aletin çok sık veya çok seyrek aralıklarla çekilmesi beklenen faydayı sağlamaz. Aletin 90X90 cm. aralıklarla çekilmesi halinde sert tabaka iyice parçalanmakta ve rantabl olmaktadır.

* Sert tabakanın kırılmasında çizel ve dipkazan kullanılması halinde 4-5 yılda bir, riper kullanılması halinde ise 8-10 yılda bir kırma işlemi yeniden yapılmalıdır.

11 Kasım 2015 Çarşamba

Marvel pluginini nasıl yükleriz?

ES klasörüne gidelim
C:\>cd C:\Program Files\Elasticsearch\bin
C:\Program Files\Elasticsearch\bin>Plugin.bat -i elasticsearch/marvel/latest
Eğer yüklemede sorun yaşarsanız bilinki bu klasöre yazma hakkınız olmayabilir Failed to install elasticsearch/marvel/latest, reason: plugin directory C:\Program Files\Elasticsearch\plugins is read only” then create a ‘plugins’ directory to root of your ElasticSearch installation path and make it write and Read write permissions for all user. ElasticSearch servisini yeniden başlatalım. Şimdi browserda görelim: http://localhost:9200/_plugin/marvel ‘Dashboard’ menüsünden ‘sense’ seçeneğini seçerek kod yazabilirsiniz.

10 Kasım 2015 Salı

ConEmu ile notepad++ kullanarak dosyayı ilgili satırda açmak

DosyaYolu(argumanlar...) ile istediğiniz parametreyi geçirebilirsiniz.

JSON Schema da null olabilen boolean alan (nullable boolean property)

Şema:
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "id": "http://jsonschema.net",
  "type": "object",
  "properties": {
    "c": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ]
    }
  }
}
{c: null}

5 Ekim 2015 Pazartesi

json-schema-defaults ile node.js üstünde .json uzantılı şemaları dinamik yüklemek

Tüm kodunu en aşağıya yapıştırdım ama ekelediğim yeri biraz anlatmış olayım:
var getRemoteRef = function (_uri, definitions) {
// loadschema ileride async olarak şema yüklemelerini sağlamak için kullanacağım için şimdiden hazır edeyim dedim.
    var loadSchema = function (uri, callback) {
        var request = require('request');
        request(uri, function (err, res, body) {
            console.log(body); // Bu gelen şemayı doğrulamaya göndermeden önce JSON'a çevirmelisiniz.

            if (err || res.statusCode >= 400)
                callback(err || new Error('Loading error: ' + res.statusCode));
            else {
                callback(null, JSON.parse(body));
            }
        });
    };

    // node uygulamasının hangi fiziksel klasörde olduğunu buluyorum
    var appRoot = require('app-root-path'),
        // dosya yolunun schema'lı halini oluşturuyorum
        indexOfSchema = _uri.indexOf('/schema/');

    // .json dosyasının tam yolunu bulduktan sonra 
    var filePath = appRoot + "/node/" + _uri.substr(indexOfSchema);
    console.log("Path: " + filePath);

    // reuqire ile çekiyoruz
    var result = require(filePath);

    if (!isObject(result)) {
        return result;
    }
    return cloneJSON(result);
}
(function (root, factory) {

    'use strict';

    if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
        // CommonJS
        module.exports = factory();
    } else if (typeof define === 'function' && define.amd) {
        // AMD
        define('json-schema-defaults', [], function () {
            return factory();
        });
    } else {
        // global with noConflict
        var jsonSchemaDefaults = root.jsonSchemaDefaults;
        root.jsonSchemaDefaults = factory();
        root.jsonSchemaDefaults.noConflict = function () {
            var defaults = root.jsonSchemaDefaults;
            root.jsonSchemaDefaults = jsonSchemaDefaults;
            return defaults;
        };
    }

}(this, function () {

    'use strict';

    var ajv = null;

    /**
     * check whether item is plain object
     * @param {*} item
     * @return {Boolean}
     */
    var isObject = function (item) {
        return typeof item === 'object' && item !== null && item.toString() === {}.toString();
    };

    /**
     * deep JSON object clone
     *
     * @param {Object} source
     * @return {Object}
     */
    var cloneJSON = function (source) {
        return JSON.parse(JSON.stringify(source));
    };

    /**
     * returns a result of deep merge of two objects
     *
     * @param {Object} target
     * @param {Object} source
     * @return {Object}
     */
    var merge = function (target, source) {
        target = cloneJSON(target);

        for (var key in source) {
            if (source.hasOwnProperty(key)) {
                if (isObject(target[key]) && isObject(source[key])) {
                    target[key] = merge(target[key], source[key]);
                } else {
                    target[key] = source[key];
                }
            }
        }
        return target;
    };

    /**
     * merge list of objects from allOf properties
     * if some of objects contains $ref field extracts this reference and merge it
     *
     * @param {Array} allOfList
     * @param {Object} definitions
     * @return {Object}
     */
    var mergeAllOf = function (allOfList, definitions) {
        var length = allOfList.length,
            index = -1,
            result = {};

        while (++index < length) {
            var item = allOfList[index];

            item = (typeof item.$ref !== 'undefined') ? getLocalRef(item.$ref, definitions) : item;

            result = merge(result, item);
        }

        return result;
    };

    /**
     * get object by reference. works only with local references that points on
     * definitions object
     *
     * @param {String} path
     * @param {Object} definitions
     * @return {Object}
     */
    var getLocalRef = function (path, definitions) {
        path = path.replace(/^#\/definitions\//, '').split('/');

        var find = function (path, root) {
            var key = path.shift();
            if (!root[key]) {
                return {};
            } else if (!path.length) {
                return root[key];
            } else {
                return find(path, root[key]);
            }
        };

        var result = find(path, definitions);

        if (!isObject(result)) {
            return result;
        }
        return cloneJSON(result);
    };


    var getRemoteRef = function (_uri, definitions) {
        var loadSchema = function (uri, callback) {
            var request = require('request');
            request(uri, function (err, res, body) {
                console.log(body); // Bu gelen şemayı doğrulamaya göndermeden önce JSON'a çevirmelisiniz.

                if (err || res.statusCode >= 400)
                    callback(err || new Error('Loading error: ' + res.statusCode));
                else {
                    callback(null, JSON.parse(body));
                }
            });
        };

        var Path = require('path'),
            appRoot = require('app-root-path'),
            indexOfSchema = _uri.indexOf('/schema/');

        var filePath = appRoot + "/node/" + _uri.substr(indexOfSchema);
        console.log("Path: " + filePath);
        var result = require(filePath);
        if (!isObject(result)) {
            return result;
        }
        return cloneJSON(result);
    }


    /**
     * returns a object that built with default values from json schema
     *
     * @param {Object} schema
     * @param {Object} definitions
     * @return {Object}
     */
    var defaults = function (schema, definitions) {
        console.log("schema: " + JSON.stringify(schema, null, ' '));
        console.log("definitions: " + JSON.stringify(definitions));
        if (typeof schema['default'] !== 'undefined') {

            return schema['default'];

        }
        else if (typeof schema.allOf !== 'undefined') {

            var mergedItem = mergeAllOf(schema.allOf, definitions);
            console.log("MergedItem: " + JSON.stringify(mergedItem));
            return defaults(mergedItem, definitions);

        }
        else if (typeof schema.$ref !== 'undefined') {
            console.log("Reference name: " + schema.$ref);
            var reference;
            if (schema.$ref.indexOf("http") == 0) {
                reference = getRemoteRef(schema.$ref, definitions);
                //reference= getRemoteRef("http://localhost:3000/schema/providers/login/test.json", definitions);
            } else {
                reference = getLocalRef(schema.$ref, definitions);
            }

            console.log("Refernce: " + JSON.stringify(reference));
            return defaults(reference, definitions);

        }
        else if (schema.type === 'object') {

            if (!schema.properties) {
                return {};
            }

            for (var key in schema.properties) {
                if (schema.properties.hasOwnProperty(key)) {
                    schema.properties[key] = defaults(schema.properties[key], definitions);

                    if (typeof schema.properties[key] === 'undefined') {
                        delete schema.properties[key];
                    }
                }
            }

            return schema.properties;

        }
        else if (schema.type === 'array') {

            if (!schema.items) {
                return [];
            }
            return [defaults(schema.items, definitions)];

        }
        else if (schema.type && typeof(schema.type) === 'object') {

            console.log("Reference name: " + schema.type.$ref);
            var reference = getLocalRef(schema.$ref, definitions);
            console.log("Refernce: " + JSON.stringify(reference));
            return defaults(reference, definitions);

            if (!schema.items) {
                return [];
            }
            return [defaults(schema.items, definitions)];

        }

    };

    /**
     * main function
     *
     * @param {Object} schema
     * @param {Object|undefined} definitions
     * @return {Object}
     */
    return function (schema, definitions, _ajv) {
        ajv = _ajv;

        if (definitions && Array.isArray(definitions)) {
            var defs = {};
            definitions.forEach(function (_definition) {
                defs = merge(_definition, schema.definitions);
            });
            definitions = defs;
        }

        if (typeof definitions === 'undefined') {
            definitions = schema.definitions || {};
        }
        else if (isObject(schema.definitions)) {
            definitions = merge(definitions, schema.definitions);
        }

        return defaults(cloneJSON(schema), definitions);
    };

}));

AJV'yi JSON doğrulamalarında kullanmak




Node.js üstünde AJV'de harici referansları olan ".json" uzantılı şemaların yüklenmesini birazcık anlatayım. Kodları test etmeden yazıyorum asıl olan temelde neyin döndüğüdür.

Ana şemamız index.json ve içinde harici referans olarak test.json'ı içersin (bkz. definitons -> "TW": {"$ref": "http://localhost:3000/schema/providers/login/test.json"}
{
  "id": "http://localhost:3000/schema/providers/login/index",
  "title": "Providers",
  "$schema": "http://json-schema.org/draft-04/schema#",
  "description": "Kullanıcı Giriş Sağlayıcıları",
  "type": "object",
  "definitions": {
    "TW": {"$ref": "http://localhost:3000/schema/providers/login/test.json"}
  },
  "additionalProperties": false,
  "properties": {
    "TW": {"$ref": "#/definitions/TW"}
  }
}
test.json
{
  "id": "http://localhost:3000/schema/providers/login/test.json",
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "id": {
      "type": "integer",
      "default": 0
    },
    "id_str": {"type": "string"},
    "name": {
      "type": "string",
      "default": ""
    }
  },
  "required": [
    "id",
    "name"
  ]
}
Her iki şemanın ID'sinin, URL adresleri olduğuna dikkat! Çünkü bu sayede hem eşsizliği sağlamış olursunuz hem de bağlantılarını kopartmamış olursunuz. Ayrıca $ref kısmını definitions içinde veriyor ve properties içindeki özelliklere buradan verdiğimiz için aynı tipi başka bir yerde kullansakta bir kez http talebi yapmış olacağız (Örn. properties:{ ev_adresi:{$ref:'http:/..../adres.json'}, is_adresi:{$ref:'http:/..../adres.json'}, ..} olsaydı aynı json 2 kez çağrılmış olacaktı).

addSchema metodu

2 Parametre alıyor; ilki şemanın kendisi(json nesnesi olacak), ikincisi ise eğer şemanın içinde "id" tanımlanmamışsa kullanılması için sizin belirteceğiniz "id" değeri(string olacak).
var Ajv = require('ajv'),
    ajv = Ajv({removeAdditional:true});

function addSchema() {

    var schTest = require('./providers/login/test.json');
    var schIndex = require('./providers/login/index.json');
    ajv.addSchema(schTest);
    ajv.addSchema(schIndex);
    var bValid = ajv.validate(schIndex.id, {TW: {id: 2, a: 1, name: "cem"}});
    if (!bValid) {
        console.log("Hatalıysam ara: ");
        console.log(ajv.errors);
    }else{
        console.log("Herkül müsün kardeşim:");
        var sch2 = ajv.getSchema("http://localhost:3000/schema/providers/login/index");
        console.log(sch2.schema);
    }
}
addSchema();

compile metodu

var Ajv = require('ajv'),
    ajv = Ajv({removeAdditional:true});

function compile() {

    var schTest = require('./providers/login/test.json');
    var schIndex = require('./providers/login/index.json');
    ajv.addSchema(schTest);  // önce test şemasını ekleyelimki index.json içinde kullanılmadan önce hazır olsun
    var validate = ajv.compile(schIndex); // index.json'ı derleyerek doğrulayacak fonksiyonumuza ulaşalım.
    console.log(validate.schema) // şemamızın içinde test.json'ı referans olarak görürüz ama doğrulama sırasında bu referanslara bakarak veri nesnesini doğrulayacaktır
    var a = validate({TW: {id: 2, name: "cem"}})  // hata vermez ve başarıyla doğrulanmış olur

    if(validate.errors){
      console.log(validate.errors)
    }else{
      console.log(a);
    }
}
compile();

compileAsync metodu

Bu fonksiyonu kullanmadan önce asenkron olarak yükleme işini yapacak fonksiyonu tanımlamalısınız ve yükleme tamamlandıktan sonra doğrulama yapacak callback fonksiyonunu girmelisiniz. Bunun için AJV'nin options larından loadSchema'yı kullanacağız.

ajv = Ajv({
    loadSchema: function (uri, callback) {
        var request = require('request');
        request(uri, function (err, res, body) {
            console.log(body); // Bu gelen şemayı doğrulamaya göndermeden önce JSON'a çevirmelisiniz.

            if (err || res.statusCode >= 400)
                callback(err || new Error('Loading error: ' + res.statusCode));
            else {
                callback(null, JSON.parse(body));
            }
        });
    }
});

function compileAsync() {
    var sch = require('./providers/login/index.json');
    console.log("sch--------------");
    console.log(JSON.stringify(sch));

    ajv.compileAsync(sch, function (err, validate) {
        console.log(validate); // görelim ne var elimizde

        if (err) return; // hata varsa dön bebeğim

        var a = validate({TW:{id: 2, name: "cem"}});
        console.log(validate.errors); // null döner
        console.log(a);  // true döner(hatasız);
    });
}
compileAsync();
Tüm kod:
var Ajv = require('ajv'),
//sch = require('./index'),
    ajv = Ajv({removeAdditional: true}); // options can be passed
ajv = Ajv({
    loadSchema: function (uri, callback) {
        var request = require('request');
        request(uri, function (err, res, body) {
            console.log("request ended");
            console.log(body);

            if (err || res.statusCode >= 400)
                callback(err || new Error('Loading error: ' + res.statusCode));
            else {
                callback(null, JSON.parse(body));
            }
        });
    }
});


function compile() {

    var schTest = require('./providers/login/test.json');
    var schIndex = require('./providers/login/index.json');
    ajv.addSchema(schTest);
    var validate = ajv.compile(schIndex);
    console.log(validate.schema);
    var a = validate({TW: {id: 2, name: "cem"}});
    console.log(validate.errors);
    console.log(a);
}
//compile();

function compileAsync() {
    var sch = require('./providers/login/index.json');
    console.log("sch--------------");
    console.log(JSON.stringify(sch));

    ajv.compileAsync(sch, function (err, validate) {
        console.log(validate);
        console.log("neredeyim")
        console.log("err: " + err);
        if (err) return;

        var a = validate({id: 2, name: "cem"})
        console.log(validate.errors)
        console.log(a);

        console.log("buradayım");
    });
}
//compileAsync();

function addSchema() {

    var schTest = require('./providers/login/test.json');
    var schIndex = require('./providers/login/index.json');
    ajv.addSchema(schTest);
    ajv.addSchema(schIndex);
    var bValid = ajv.validate(schIndex.id, {a: 1,TW: {id: 2, name: "cem"}});
    if (!bValid) {
        console.log("Hatalıysam ara: ");
        console.log(ajv.errors);
    }else{
        console.log("Herkül müsün kardeşim:");
        var sch2 = ajv.getSchema("http://localhost:3000/schema/providers/login/index");
        console.log(sch2.schema);
    }
}
//addSchema();

29 Eylül 2015 Salı

Elasticsearch ile sorgulama

Search API

Önce ekşideki bilgi hapları alalım:
en önemli özelliği distributed ve real-time olması.
solr gibi core olarak lucene kullaniyor (yani datastore aslinda lucene dokumanlari). kabuk demek daha dogru olur kanimca, daha cok orchestrator gibi
aslında bir nosql databasedir. datayı relational olmayan bir şekilde store ettiği için bayılmadan full text search yapabiliyorsunuz
kendi query-dsl'ini de üzerine barındırması fevkalade bir durum
query dsl'i biraz karışık ve aslında birbirinin yaptığı işleri aynen yapan farklı fonksiyonlar var
Peki QUERY DSL ile sorgulama konusunda bool query'ye temel bakış atalım:
{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "FIELD": {
                            "value": "VALUE"
                        }
                    }
                },
                {
                    "query_string": {
                        "default_field": "FIELD",
                        "query": "this AND that OR thus"
                    }
                }
            ],
            "should": [
                {
                    "match": {
                        "FIELD": "TEXT"
                    }
                }
            ],
            "minimum_number_should_match": 1,
            "must_not": [
                {
                    "range": {
                        "FIELD": {
                            "from": "10",
                            "to": "20"
                        }
                    }
                }
            ],
            "boost": "4"
        }
    }
}

localhost:9200/index/type URL yapısında sorgulama yapmak için _search api ile sorgulamak istenildiğinde localhost:9200/index/type/_search şeklinde sorgu yazılabilir. Search API aynı zamanda Faceting ve Filtering sağlayacaktır.
Aşağıdaki sorgu sadece size ve query parametrelerinin atandığı facet ve filter'ın ise olmadığı temel bir sorgudur:
{ 
   "size": 3, 
   "query": { 
       "match": {
          "hobbies": "skateboard"
        }
    }
}
Bu sorgu sadece hobiler içinde skateboard terimini aradığımız bir sorgudur ve hem GET hem POST metotlarıyla sadece urlnin sonunda _search olacak şekilde çalıştırılabilir.


Temel sorgulama tipleri:
  1. Term
  2. Match
  3. Range
  4. Filters

Ref: http://exploringelasticsearch.com/searching_data.html
http://www.slideshare.net/clintongormley/elasticsearch-query-dsl-not-just-for-wizards

Mapping durumunu görüntüleme

Sadece bir indexin mappingi için

GET http://10.214.66.90:9200/_mapping/ihale

Birden fazla indexin mappingi için

GET http://10.214.66.90:9200/_mapping/ihale,Firma

Bir filed(alanın) mappingi için

GET http://10.214.66.90:9200/_mapping/ihale/field/Konusu

14 Eylül 2015 Pazartesi

zkemkeeper.dll ve Asp.Net uygulaması

Öncelikle biyometrik okuma cihazına bağlanmak için zkemkeeper.dll ve sdk'nın diğer dll dosyalarını registry'e kaydetmelisiniz. Bu aslında com bileşeni olarak sistemin erişebileceği bir id ile windows içinde kaydının oluşturulması demek oluyor. Bunu yapmak için zksoftware içinde gelen bat dosyasını çalıştırmanız yeterli.
copy .\sdk\*.dll %windir%\system32\
regsvr32 %windir%\system32\zkemkeeper.dll

Buna göre sdk içindeki tüm dll dosyalarını C:\Windows\system32 dizinine kopyalayıp zkemkeeper.dll dosyasını da registry'ye kaydetmiş oluyoruz. zkemkeper.dll için bir uygulama idsi oluşturdu {FE9D.....32C7} diye ve bunu da {00853....61F} ile çağırabilir bir DCOM objesi olarak sisteme kaydetti.

Normal olarak demo uygulamalarını bu kayıt işlemi yapılmadan önce çalıştırdığımda şu hatayı alıyordum: FAE has stopped working

DLL register edildikten sonra uygulama çalışıyor ve biyometrik cihazlara bağlantı sağlıyordu ama başka makinelerde aldığım bir sorunun ekran görüntüsünü şöyle alıyordum:

Bu hatayı elde etmek için program FAE hatası almasın diye dll register ettim ve uygulama açıldıktan sonra unregister ederek bağlanmayı deneyince ekrandaki Error mesajını aldım. Bu mesaj biyometrik cihazın çeşitli hata seviyelerinden(sanırım 6-7 tane var) biri. Maksadım bunu gördüğünüzde neden olduğunu bir nebze anlamanızı sağlamak.

Şimdi "happy path"(mutluluğa giden keçi yoluna bakalım :) )
Dll kaydedildi ve demo uygulamasıyla cihaza bağlanalım:

ASP.NET uygulamamda ise şu hataları alıyordum:
  1. Class not registered diyerek CZKEMClass'tan bir nesne yaratmama müsade etmiyordu
  2. Başka bir makinede ise nesne yaratıyor ama aktif cihazlara peş peşe bağlantı sağla dediğimde sorun çıkartmazken, pasif bir cihaza bağlan dediğimde bir sonraki aktif cihaza bağlantı sağlamayı denemeden cihaza ulaşılamadı diyordu

1. Madde için aldığım sorunu göstereyim:
Retrieving the COM class factory for component with CLSID {00853A19-BD51-419B-9269-2DABE57EB61F} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

2. Madde için ekran görüntüsünü yaratamıyorum ama ikisinin çözümünü nerede bulduğumun ekranını paylaşayım:
IIS Express'in 64 bit versiyonunu çalışmaya zorlayınca dll'lerin register edildiği versiyona erişmesini sağlamış oldum. Çünkü zkemkeeper.dll'i kaydetmek istediğinizde 32/64 bit seçeneklerinden eğer 64 bitlik sistem üstünde koşuyorsanız 32 liğini yükleyemiyorsunuz(klasör adı "Communication Protocol SDK(32Bit Ver6.2.4.1)" olanı yükleyemiyorsunuz çünkü içeriğindeki zkemkeeper.dll 32 uyumlu değil).
Ancak Communication Protocol SDK(64Bit Ver6.2.4.1) klasöründeki zkemkeeper.dll dosyasını sisteme kaydedebiliyorsunuz. Bu durumda ASP.NET uygulamanızın IIS Express versiyonununda 64 bit olması için zorlamanız gerekiyor.

Ve tekrar çalıştırdığımda uygulamamı:

Lotus Notes ile gönderdiğiniz iletileri başka bir eposta hesabına gönderebilmek

Tüm kodumuz burada ve ekran görüntüleri de aşağıda olacak. Anlaşılmasında sorun çıkarsa yardım etmeye çalışırım.
Sub Initialize
 
 
 Dim s As New NotesSession 
 Dim db As NotesDatabase       ' current mail file
 Dim lupV As NotesView        ' docs in forwarding folder
 Dim lupDoc As NotesDocument     ' current lupE doc being forwarded
 Dim counter As Long         ' counter, use for limit
 Dim dc As notesdocumentcollection
 
 Set db = s.CurrentDatabase
 Set dc=db.UnprocessedDocuments
 Set lupDoc = dc.GetFirstDocument
 
 Do While Not(lupDoc Is Nothing)
  
  If (ProcessEmail(s, db, lupDoc, "cem.topkaya@hotmail.com")=1) Then
   Set lupDoc = dc.GetNextDocument(lupDoc)
  End If
  counter =counter+1
 Loop
 
SkipDone:
 Print "Es geçilen belge"
 Exit Sub
 
ErrorHandler:
 Print "Unexpected Error: " & Cstr(Err) & " " & Error$ & ", on line: " & Cstr(Erl)
 
End Sub

Function ProcessEmail(s As NotesSession, db As NotesDatabase, lupDoc As NotesDocument, newSendTo) As Integer
 ' forwards current entry/doc, and returns 1 if successful
 ' newSendTo should be internet address or Canonical Notes name
 Dim mDoc As NotesDocument ' new memo doc created from original doc
 
 On Error Goto FErrorHandler
 
 ' create new doc from current document
 Set mDoc = db.CreateDocument()
 Call lupDoc.CopyAllItems(mDoc, True)
 mDoc.SaveMessageOnSend = False
 
 ' remap from/sendto/replyto so when forwarded still be from original person
 Call mDoc.ReplaceItemValue("SendTo", newSendTo)
 Call mDoc.ReplaceItemValue("CopyTo", "")    ' otherwise another copy will be sent
 Call mDoc.ReplaceItemValue("BlindCopyTo", "")  ' otherwise another copy will be sent
 
 ' send new doc
 Call mDoc.Send(False, newSendTo)
 ' reset to nothing
 Set mDoc = Nothing
 
 ' başarılı bir eposta gönderimi yaptık
 ProcessEmail = 1
 
FExit:
 Exit Function
 
FErrorHandler:
 Print "(ProcessEmail) Unexpected Error: " & Cstr(Err) & " " & Error$ & ", on line: " & Cstr(Erl)
 ProcessEmail = 0
 Exit Function
End Function