Vodič za napuštanje BiH – odlazak u Njemačku

Ovaj blogpost je ispunjenje moga obećanja mnogobrojnim prijateljima i kolegama koji su me pitali “Kako si uspio pronaći posao?”, “Gdje si našao poslodavca?”, “Šta su te pitali?”, “Koliko ti je vremena trebalo?” i mnoga druga pitanja, a ja sam obećao da ću napisati odgovore, da se ne ponavljam, pošto zadnjih par godina nikako nemam viška vremena :)

Pošto su moje aktivnosti ponovo počele da poprimaju neke obrasce, pronašao sam malo vremena da počnem da pišem o ovoj temi, a ukoliko nešto izostavim, pitajte u komentarima, pa ću da obradim i to što vas zanima.

Na samom početku – prvo da pojasnim šta opisujem, i koji su bili moji motivi, pošto će nekima sigurno biti interesantniji prvi, jednostavniji model. Na rad u EU je moguće otići i ako ste zaposleni u firmi van EU, kao detaširani radnik, i vizu za to je relativno lako dobiti, jer možete da se obratite direktno recruiting agencijama koje će vas prodati krajnjem klijentu, u tom slučaju idete samo privremeno raditi, jer viza vrijedi samo za taj angažman, a ta firma u koju idete će vašoj firmi koja vas šalje najvjerovatnije potpisati izjavu da vas neće pokušati zaposliti (jer vaš poslodavac u BiH ne želi ostati bez radnika). Od samog boravka u EU možete očekivati neku dnevnicu ili dodatke povrh plate koju inače primate, tako da možete “vidjeti svijeta” (ako su vas poslali u zanimljiv grad) ili uštediti ako se toga odreknete. Mene to nije zanimalo jer time ne rješavam svoj status koji je u BiH bio bez ikakve perspektive, puko sastavljanje kraja s krajem, bez izgleda da se u idućih nekoliko godina bilo šta značajnije promijeni: moja karijera, ženino zaposlenje, kvalitet života…  Zapravo, izdaci su se zahvaljujući skoro svakodnevnim poskupljenjima povećavali brže nego primanja tako da se to mijenjalo, ali nagore. Dakle, moj cilj, ka kome sam napravio veliki korak, je da obezbijedim svojoj porodici neku perspektivu, da mogu da obezbijedim djetetu vrtić, da ne razmišljam kako ću mu kupiti bicikl, autosjedalicu, igračku, da ne moram strijepiti hoće li mi neko napasti dijete ili udariti autom vozeći kroz crveno “jer mu se može”… Neki će reći da se to može dogoditi bilo gdje, i to je istina, ali ko god je bio u uređenom društvu ne može poreći da je takvih stvari daleko manje i da je prekršitelja daleko manje (pošto su kazne brže, češće i bliže postignut je daleko veći stepen uređenosti i kultivisanosti), a isti ljudi koji poštuju zakon ovdje (u EU), kada dođu u zavičaj ga krše, jer je mala vjerovatnoća da će biti uhvaćeni, a velika da će i ako budu lako podmititi policajca. Uglavnom, oni koji ovo čitaju već znaju koliko naopako funkcioniše sistem u BiH i tu nema šta da se dodaje ili opisuje, ko god želi može da vidi koliko je sve pogrešno. Iz ove pozicije, moje divljenje odlazi onima koji mogu da odu ali ipak imaju hrabrosti da ostanu živjeti u neizvjesnosti.

Dakle, da biste dobili vizu za zaposlenje u Njemačkoj, osnovna stvar je da dokažete nekome (poslodavcu) u Njemačkoj da ste mu potrebni (baš vi). Ukoliko posjedujete neko strogo specifično znanje ili vještine, moguće je dobiti vizu čak i ako nemate formalno obrazovanje / fakultet (naravno, mnogo teže jer čak i u Njemačkoj ima nezaposlenih, i kada se ne radi o visoko obrazovanim radnicima, njemački državljani imaju prioritet). Ukoliko imate visoko obrazovanje, potrebno je i odlično znanje engleskog jezika, i vrlo poželjno njemačkog (ovo nije u potpunosti nužno, ali između dva kandidata od kojih jedan zna njemački, on uvijek ima veliku prednost). Što se tiče prizanja vaše diplome, resurs je anabin.de, gdje možete pronaći svoj fakultet i provjeriti da li ima H+ status (H+ status znači da je program priznat u potpunosti). Koliko sam uspio vidjeti, svi fakulteti državnih unverziteta u BiH imaju taj status.  Takođe, ukoliko odlično znate njemački, moguće je proći bez engleskog, ukoliko ne tražite posao u IT industriji. Najbolji resurs za sve informacije i veze ka drugim sajtovima je make-it-in-Germany. Što se tiče posla, posla ima, mnogo. Međutim, bar što se tiče posla u IT sektoru, skoro svi oglasi koje ćete pronaći na internetu za poslove vas vode recruiting agencijama. Razlog je jednostavan, velike firme, giganti, koji zapošljavaju najviše ljudi, na zapadu funkcionišu drugačije nego “kod nas”: nema odjela za ljudske resurse, nema knjigovodstva, obračuna plata, firma radi ono što joj je primarna djelatnost. Sve ostalo se “outsourc-a”, u ovom slučaju recruiting agencijama, preko kojih velike firme zapošljavaju skoro svo ljudstvo. Njihov cilj je imati na kraju mjeseca jedan račun/iznos (ili npr. dva, ukoliko ljudi dolaze iz 2 različite agencije), koji firma isplaćuje za sve lične dohotke i vezane troškove, bez komplikacija, obračuna, platnih lista… A kada zapošljavaju, dodatna prednost upotrebe agencije je što je u Njemačkoj ogromna mobilnost radne snage, i recruiting agencije već imaju ogromnu bazu stručnjaka iz koje mogu lako da im nađu odgovarajući profil kojem upravo ili uskoro završava projekat i može da dođe na idući. No, posla je više nego stručnjaka, i za ovo kratko vrijeme koje sam ovdje više je nego očigledno – velika je potražnja za dobrim ljudima, i to ne vrhunskog kalibra jer takvih je jako malo, ovdje su i natprosječni jako traženi (u timu od 20+ ljudi nema niko rođen u Njemačkoj, ima samo jedan član tima koji živi u Njemačkoj zadnjih 12 godina, ostali su svi sa strane). A same recruiting agencije ne zapošljavaju nikoga, one samo angažuju firme-podizvođače koje šalju ljude ovim prvima. U toj činjenici leži problem svih koji žele pronaći posao a nemaju vizu, jer oglasi ništa ne znače – recruiting agencije vas ne mogu zaposliti. Da biste dobili vizu koja vam omogućava da se doselite raditi u Njemačku, potrebno je da imate firmu u Njemačkoj koja će vam poslati ugovor o radu. Takvih je mnogo, ali treba ih tražiti pod imenom “[nešto] professionals”, “[nešto] solutions/services”, “staffing agency” i sl. Takve će vas prodati prvoj recruiting agenciji, za par stotina evra dnevno, ali to ne treba niti da vas zanima niti da vam bude krivo, jer jedino što je bitno je da dobijete ugovor koji vam garantuje minimalno 46.400 evra bruto godišnje, ili 36.192 ukoliko ste stručnjak iz polja matematike, informatike, prirodnih nauka ili tehnike, što su minimalni iznosi da biste dobili plavu kartu (Blue Card), a i sa minimalnom platom ćete sigurno živjeti bolje nego sa platom od 1000 evra u BiH. Na kraju krajeva, prva plava karta nakon 21 mjeseca (ukoliko položite B1 nivo njemačkog) može da se zamijeni za trajnu, koja nije vezana za poslodavca, i onda ste u situaciji da možete slobodno da mijenjate poslove i birate poslodavca (čak i da osnujete svoju firmu/obrt i onda prodajete sami sebe direktno recruiteru).

Da biste pronašli posao, preporučujem berzu poslova Njemačkog biroa za zapošljavanje: http://jobboerse.arbeitsagentur.de/ - tu sam i sam pronašao poslodavca.
Nakon što se registrujete kod njih, dobićete poštom inicijalni pin kojim ćete verifikovati svoju adresu, i onda možete koristiti sistem da pronađete posao. Tu ima mnogo više oglasa pravih firmi, koje ne traže contractor-e i koje mogu da vas zaposle. Ti oglasi su često generički, i postavljeni su sa ciljem da se nađe neko koga mogu lako preprodati recruiting agencijama, a same navedene vještine i iskustvo možda nisu tačne, odnosno recruiter može da traži nešto drugo, pa ništa ne košta da se prijavite i na poziciju koja nije baš 100% za vas, bitno je da napišete šta tačno znate, i kakvo iskustvo imate. Takođe, ukoliko vidite da je firma u koju se prijavljujete neka staffing/consulting agencija, ili ako vidite da su oni to po tome što traže da pošaljete svoj cv, listu projekata, sliku i sl (kreiraju vaš profil), objasnite im da će ako vam pronađu posao preko agencije, trebati minimalno mjesec dana do momenta kad možete početi raditi, možda i više, i da bi bilo dobro da vam pošalju ugovor ili obavezujuću ponudu sa kojom možete dobiti vizu, tako da možete brže biti raspoloživi kada vam nađu poziciju.

Što se tiče dobijanja posla, najviše bodova vam mogu donijeti preporuka od nekog iz Njemačke, odlično poznavanje njemačkog jezika, ili da neki recruiter koji vas je intervjuisao potvrdi da vam može lako pronaći poziciju. Ja sam imao preporuku od developera iz Njemačke, koji je bio voljan da telefonom potvrdi moje vještine i ličnost. Upoznao sam ga preko freelancing sajtova (elance, odesk) i za njegovu firmu odlično odradio par poslova. To ne zahtijeva previše vremena (ukoliko uspijete bez reputacije dobiti freelancing posao za nekog u Njemačkoj). Pametno je imati Europass CV, to je format u kom vam niko neće ništa zamjeriti, a ako poslodavac ima svoj template, popunite i to, kod njih se svaki trud cijeni. Takođe, jako je bitno da napravite nekakav excel u kome ćete nabrojati projekte na kojima ste radili, firme za koje su ti projekti rađeni, ako postoje adrese do web sajtova, trajanje od-do, vaša uloga na projektu i tehnologije koje ste pritom koristili. Ponavljam, posla ima, sa mnom rade ljudi iz Rumunije, Bugarske (oni su tamo zaposleni i ovde ih je poslala firma), Moldavije, Južne Afrike, Indije, Pakistana, Rusije… Ne bi svi bili ovde da ne nedostaje  radne snage. Samo je potrebno biti uporan i ne gubiti nadu. Slanje CV ne košta skoro ništa, a ako zakucate na dovoljno vrata, neko će sigurno otvoriti. Potrebno je imati samopouzdanja i biti uvjeren da su vaše vještine dovoljne da vas neko zaposli, i potruditi se da pokažete da znate dovoljno da će se njima isplatiti da vas zaposle. Kada počnu da vas zovu telefonom, ukoliko trebate da vi njih nazovete, ili žele da vas intervjuišu, uplatite Skype kredit i zovite ih sa Skype na njemačke fiksne linije (to vas košta oko 2 centa po minuti), i recite da je tako daleko jeftinije. To je mala investicija ali pokazuje da ste spremni preuzeti inicijativu i da ne čekate da neko dođe po vas.

Sam proces dobijanja vize je, isključivo zbog predaje aplikacije u Sarajevu, vjerovatno najkomplikovaniji korak cijelog odlaska, ali uz par informacija može biti lakši. Trenutni skup dokumenata koji je potreban se može vidjeti ovdje. Obrazac za vizu je takođe dostupan na sajtu ambasade u Sarajevu. Ukoliko imate ugovor na neodređeno vrijeme, za predviđeno trajanje boravka stavljate “unbefristet” (trajno). Što se tiče zdravstvenog osiguranja, ne morate stavljati da ga imate niti ga plaćati, jer oni znaju da ćete biti osigurani kada budete zaposleni. Diplome prevedite kod sudskog tumača, i tražite da imaju Apostille pečat, time prevodi postaju važeći dokumenti bez prisutstva originala (ali zbog needukovanog osoblja na ulazu u ambasadu koje vas neće pustiti, obavezno ponesite originale na uvid, i njihove fotokopije, fotokopije vam ne trebaju za vizu, ali treba da biste došli do šaltera, nažalost). Zahtjevi za vize idu u Njemačku srijedom, tako da vam je svejedno da li ste predali zahtjev u četvrtak ili idući utorak. Mene su nazvali da je viza odobrena 6 dana nakon te srijede (prvi sljedeći utorak). Pametno je, ukoliko znate da nećete putovati, ostaviti pasoš u ambasadi, i 15KM da vam ga pošalju FedEx-om kada zahtjev bude obrađen. Time štedite vrijeme i novac za još jedan put u Sarajevo, ako ne živite u istom. Još jedna vrlo bitna napomena, kada dođete po vizu, prijavite se radniku na ulazu, jer oni koji podižu vizu ne moraju čekati skupa sa onima što podnose, jer podizanje vize traje 5 minuta. Takođe, kada ste gore na šalteru, možete zamoliti ostale koje čekaju da vas puste da podignete vizu, jer predavanje traje pola sata a podizanje 5 minuta, vjerovatno vam niko neće praviti problem.

Viza se dobija na 90 dana, i ima svrhu dok vam ne budu gotovi elektronska boravišna dozvola i plava karta. Za podnošenje zahtjeva za plavu kartu vam je potreban pasoš sa vizom, diploma (nije naodmet ponijeti prevod, ali to će ured za strance već imati, jer se javljate istom uredu koji vam je odobrio vizu, u mjestu poslodavca koji vas je zaposlio), i 110 evra (ovo možete platiti i kada dođete podići plavu kartu). Cijeli proces traje oko 25 minuta, potrebno je da popunite jedan zahtjev, date otiske sa 2 prsta i visinu. Izrada plave karte traje 2-4 sedmice, i izdaje se na trajanje ugovora o radu (ako je na neodređeno onda se smatra da je ugovor na 4 godine) + 3 mjeseca, ili ukoliko vam pasoš ističe prije tog datuma, onda važi koliko i pasoš.

Informacije vezane za vizu za spajanje porodice su takođe dostupne na sajtu ambasade. Ovdje ne piše, ali bračni drugovi nosioca plave karte ne moraju prilagati dokaz o poznavanju njemačkog jezika (ovo ću još provjeriti kada moja porodica bude podnosila zahtjev), a osim toga, bračni drug nosioca plave karte takođe ima pravo da dobije istu, koja predstavlja i radnu dozvolu, te ne mora čekati 2 godine da bi tražio posao, što je slučaj kada se osnov spajanja porodice osoba koja ima boravišnu dozvolu ali nema plavu kartu.

Vjerovatno će svima najveća briga biti budžet, jer sam odlazak nema smisla ako je ekonomska održivost upitna. Za ove “početne” plate od oko 35-45 hiljada evra (kakvu ćete i tražiti jer ne možete očekivati da će vam ponuditi više “na neviđeno”) možete očekivati da će vam neto iznos, ukoliko niste u braku, biti oko 61% od bruto iznosa, dakle kao u BiH (s tim da ćete za razliku dobiti značajno bolje zdravstveno osiguranje i ulog u penzionom sistemu koji se mooožda neće raspasti dok vi dočekate penziju). Ukoliko ste u braku, i vaš bračni partner ima manja ili nikakva primanja, tada spadate u “Steuerklasse III”, koja je manje oporezovana i možete očekivati blizu 70% od bruto iznosa. Dodajte na to oko 2000 evra godišnje dječijeg dodatka, po svakom djetetu i imate otprilike budžet. S obzirom da ćete stan u Njemačkoj i u najskupljim gradovima kao što su Minhen ili Frankfurt pronaći za manje od 1000 evra sa režijama (ovo je baš najgori mogući ishod, najbolje da provjerite ovdje sami za koliko možete pronaći stan, često će to biti i ispod 500 evra sa režijama, ne samo u malim gradovima, Berlin npr ima jako jeftine stanove, čak i za kupovinu, cijena se kreće oko 900 evra po kvadratu), to znači da možete računati sa najmanje 1000 evra za ostale potrebe. Vjerujem da je to više nego što bilo ko ko čita ove redove sada ima kao budžet nakon plaćanja stana i režija. Pri tome je potrebno imati na umu da što se tiče cijena, očekujete skuplji stan i režije, a ukoliko ne pušite sve ostalo će biti značajno jeftinije (uz malo praćenja akcija i sl. svi ostali troškovi mogu biti i do duplo jeftiniji nego u BiH). Dobar resurs za to je kaufda.de. Čak i ako budete trošili isto kao u BiH, ponovo ćete imati pozitivan iznos na kraju mjeseca. Plus, za svako dijete po oko 190 evra mjesečno, do 23. godine djeteta, znači da možete da planirate i proširenje porodice.

Umalo sam zaboravio, ukoliko vas prodaju kao konsultanta, velike firme koje zapošljavaju kontraktore često plaćaju i sve troškove (to se zove All-Ex contract, kada krajnji klijent plaća sve troškove). Pod tim se, u mom slučaju, podrazumijeva smještaj u hotelu, hrana, pranje veša, prevoz između hotela i firme (autobus, pošto su contractor-i smješteni u 3 hotela koji su blizu međusobno pa ih autobus kupi ujutro i razvozi popodne), let kući svake 3 sedmice (4. se radi od kuće), ili za one koji su bliže, let kući svaki vikend. Ukoliko ne dobijete ovakav ugovor, vjerovatno ćete imati neki dodatak na platu koji će pokrivati odvojeni smještaj dok vam se porodica ne doseli u Njemačku.

To je sve za sada. Uskoro ću da provjerim koliko mora da se plati polaganje vozačkog ispita (BiH vozačka važi 6 mjeseci nakon doseljenja, ako imate Hrvatsku ili Slovenačku možete je zamijeniti za Fuhrerschein), pa ću dopuniti članak sa tom informacijom, i sa odgovorima ukoliko bude pitanja.

 

Script resource localization in ASP.NET MVC

As modern web applications are becoming more and more reliant on JavaScript, and world of SPA is getting new members every day, I wanted to be able to localize JavaScript resources, so my dialogs and other JS-generated gui is localized.

As I’m doing development in ASP.NET, I already use resx files for my resources. And, with having my plan to localize SPA without reload, logical first step would be to be able to get localized resource values as JSON. So, I made simple ScriptsController and turned it into snippet for VS.

You can take this snippet, create ScriptsController.cs as empty mvc controller, and then use snippet inside your namespace to replace complete ScriptsController class. The only thing you need to replace is alias for Resource in using directives:

script controller

 

This works as it is for JSON request, but for standard request, you also need to add Resources.cshtml view, also available as snippet. This view basically creates a <script> tag with JS variable named Resources by default, which contains all items in it:

Resource.cshtml

 

How this looks like in practice?

JSON request:

json resource request

 

 

 

“Normal” request:

text resources requestresponse window - resource

 

 

 

 

 

 

 

 

 

In next post, I will use these resources to change localization language in Single Page App without reload.

Composite keys in EF CodeFirst

 

It is not very often a case that you need composite key in your db, but when you have such domain then you cannot make a good model if your orm tool does not support composite keys. EF CodeFirst has recently improved this support (last time I needed it it was not any good), but there are not many resources/samples out there. Here is one.

Model:

addressIt is a simple hierarchy with no surrogate, only natural keys. Address object/table actually contains all the data as there are no additional attributes in other entities, but this is only a example, and you can easily imagine that you have additional properties in i.e. city (coordinates, or link to map). If you don’t need additional properties in your entities, then you can tell EF modelBuilder to create complex types for them and you will have composite keys automatically.

One downside of this “manual” approach is that you need to have both primary key and related object property in your entity (i.e. State has string Country_Name and Country Country properties), but that is not a big problem, and in most scenarios you will want that as you will have data that you need without join or loading another object (that is the purpose of natural keys).


address-db

This is the db schema that I want, each dependent object inherits primary keys from its principal, so when I read Address record, I already have all the data that I need, and in at least 90% of reads there is no need to do join with other tables.

This diagram is actually created from the database which was created from my model, using EF CodeFirst. To get these composite primary keys, I used mappings described below.


Mapping configuration (in DbContext.OnModelCreating):

modelBuilder.Entity<Country>().HasKey(c => c.Name)
.HasMany(c => c.States)
.WithRequired(s => s.Country)
.HasForeignKey(s => s.Country_Name);

modelBuilder.Entity<State>().HasKey(s => new { s.Country_Name, s.Name })
.HasMany(s => s.Cities)
.WithRequired(c => c.State)
.HasForeignKey(c => new { c.Country_Name, c.State_Name });
modelBuilder.Entity<City>().HasKey(c => new { c.Country_Name, c.State_Name, Name = c.Name })
.HasMany(c => c.Streets)
.WithRequired(s => s.City)
.HasForeignKey(s => new { s.Country_Name, s.State_Name, s.City_Name });
modelBuilder.Entity<Street>().HasKey(s => new { s.Country_Name, s.State_Name, s.City_Name, s.Name })
.HasMany(s => s.Addresses)
.WithRequired(a => a.Street)
.HasForeignKey(a => new { a.Country_Name, a.State_Name, a.City_Name, a.Street_Name });
modelBuilder.Entity<Address>().HasKey(a => new
{
a.Country_Name,
a.State_Name,
a.City_Name,
a.Street_Name,
a.Number,
a.ZIP,
a.Line1,
a.Line2
});



Note that EF will by default choose nvarchar(128) for primary keys. As nchar has better properties when used as primary key or index in rdbms, I configured my primary keys to be nchar:

var keytype = "nchar";
int keylength = 50;
modelBuilder.Entity<Country>().Property(c => c.Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<State>().Property(c => c.Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<State>().Property(c => c.Country_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<City>().Property(c => c.Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<City>().Property(c => c.State_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<City>().Property(c => c.Country_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<Street>().Property(c => c.Name).HasColumnType(keytype).HasMaxLength(80);
modelBuilder.Entity<Street>().Property(c => c.City_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<Street>().Property(c => c.State_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<Street>().Property(c => c.Country_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<Address>().Property(c => c.Street_Name).HasColumnType(keytype).HasMaxLength(80);
modelBuilder.Entity<Address>().Property(c => c.City_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<Address>().Property(c => c.State_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<Address>().Property(c => c.Country_Name).HasColumnType(keytype).HasMaxLength(keylength);
modelBuilder.Entity<Address>().Property(c => c.Number).HasColumnType(keytype).HasMaxLength(20);
modelBuilder.Entity<Address>().Property(c => c.ZIP).HasColumnType(keytype).HasMaxLength(5);
modelBuilder.Entity<Address>().Property(c => c.Line1).HasColumnType(keytype).HasMaxLength(50);
modelBuilder.Entity<Address>().Property(c => c.Line2).HasColumnType(keytype).HasMaxLength(50);

kick it on DotNetKicks.com

Why uptime on WP7 cannot be longer than 24.9 days?

This morning I saw in System View on my Samsung Omnia 7 that uptime is “more than 24.9 days”, and boot time is “earlier than 30-Dec-11 13:07:24”. At first I was amazed, how can it be “earlier than”, and how that reference in time is not fixed (it was 29-Dec yesterday). Then I realized that phone does not “remember” its time of boot, but has some sort of incrementing register for counting uptime, and it hits its limit on 24.9 days. It would be interesting for how long this phone can work without reboot, as it seems very stable, but it seems that cannot be known without manual recording of boot time Disappointed smile.

I did some calculations, and it seems that phone is using SIGNED int as register value which counts number of MILISECONDS since boot. As 25 days has about 2’160’000’000 milliseconds, and 2^31 is 2’147’483’648, it starts to seem logical where did number 24.9 days came from Nerd smile. It is logical that boot time itself is not recorded, as there it would be a possibility of reporting “fake” uptimes by setting the clock on the phone. However, in my opinion, method used is also not optimal.

So, what could be better here? Light bulb

- For start, it could be unsigned int, so the OS would be able to keep track for more than 49 days of uptime.
- It could also count seconds instead of milliseconds, that would make possible to count more than 1300 years of uptime Smile, or if for some reason needs to keep milliseconds (i.e. does not want to break all existing functionalities?), unsigned long (int64) could be used (although I don’t remember if it is available in WP7), to give overkilling amount of almost 585 millions of years Hot smile.

All this considered, it seems that 49 days would be enough, change would not break anything, and it requires changing only one variable declaration.

Vikend akcija (Nova perspektiva, ali još novija kaže da je ipak sve po starom)

Mnogi su, vjerujem, dobili protekle sedmice sms poruku identičnog sadržaja kao i ja:

Vikend akcija: U Tempu u petak 4.11. Duel 3kg-6.00KM. U Maxiju, u petak 4.11. batak sa karabatakom 4.55KM/kg, a u subotu 5.11. Premia ajvar 720ml-2.45KM.

TempoMaxi

Meni je ova poruka stigla u četvrtak, 3.11. u 12:47. Da ne bude zabune, svi oni koji nisu primili ovu poruku, mogu vidjeti o čemu govorim na stranici http://www.maxi.ba/akcija/vikend-akcija/, ali pošto očekujem da će i ona uskoro biti zamijenjena akcijom za idući vikend, evo trenutni izgled:

Slika maxi web sajta na dan 06.11.2011., u 12:50

 Nije prvi put da primam ovu obavijest (iako nisam dobio potrošačku karticu, kada sam došao po nju nisu je mogli pronaći, pa su mi ljubazno ponudili da ponovo popunim pristupnicu, što je za mene uvreda i znak nepoštovanja jer već imaju podatke u sistemu (kako mi inače šalju sms i e-mail?), tako da sam ostao bez iste, a i nije da sam nešto i propustio), ali pošto se ne sjećam da sam prije viđao artikle najavljene na akciji u Tempu, a volim ajvar (naročito ljuti), odlučio sam da, prilikom subotnjeg odlaska u kupovinu, usput iskoristim i ovu ponudu za ajvar.

Došla subota, došao i ja u Tempo sa porodicom, i dok je žena kupovala ono što treba, ja sam vozao bebu, obilazio promocije i razgledao. Interesantan za pomenuti je bio štand čokolade “Najljepše želje”, gdje je vršena promotivna degustacija proizvoda od crne čokolade. Nakon što sam odbio da probam istu (jer sam je već jeo mnogo puta) i otišao da kupim nekoliko primjeraka modela sa narančom, bio sam iznenađen činjenicom da ne mogu da nađem baš te čokolade. Vratim se do štanda i pitam ih gdje se nalaze te čokolade pošto hoću da kupim, i dobijem odgovor od hostese da ih nema u prodaji!?

- Kako nema, ja sam ih kupovao već mnogo puta?

 - Nema, nestalo, ostale su još ove gratis.

Ne znam koja logika stoji iza toga, a voljeo bih znati, da neko zaposli hostesu (zapravo dvije hostese) da vrši (vrše) promociju proizvoda koji se ne može kupiti u supermarketu koji je mjesto promocije?

Da se ja vratim ajvaru, vidim stoji Premia ajvar među ostalim stvarima koje su na vikend akciji, cijena 3,40KM. Odem na informacije i pokažem im poruku koju su mi poslali uz pitanje gdje je ovaj ajvar, i dobijem tumačenje poruke – u Tempu je akcija bila u petak, i u akciju je uključen Duel. Ajvar je na akciji u Maxiju, jer se taj dio poruke za subotu nadovezuje na onaj od petka koji se odnosi na Maxi. Jeste, stvarno, čitao sam poruku kao običan čovjek a ne kao inženjer, jer sam odmah trebao da vidim da je to za Maxi. Dobro, izvininem se ja i zahvalim na tumačenju. Kaže mi djevojka niste jedini, mnogi su pitali od jutros, već sam ja zvala marketing da ne šalju dvosmislene poruke.

Nakon završene kupovine povedem svoje ukućane u šetnju, i kad smo bili pored Maxi-ja u Boriku, oko 16h, uđem da vidim gdje je taj ajvar. Tamo ajvar izložen, na njemu ona crvena cijena za posebne ponude – 3.40KM. Na informacijama nema nikoga. Pitam radnicu na kasi: “Gdje vam je ajvar iz ove poruke?”

- “Imamo problem sa programom, znate, nismo uspjeli postaviti cijenu, ali možda će biti do kraja dana…”

Što se mene tiče može i biti. Ko je planirao u kupovinu do 16h je obavio. A mnogo ljudi je došlo u Maxi (a i u Tempo sudeći po tome što su pitali), i sigurno je da mnogi od njih ne bi ni došli u kupovinu da su znali da je poruka laž. Dakle, sa stanovišta uspješnosti – uspješna kampanja, mora se priznati. Samo, ono što mi nikako nije jasno, a nadam se da će neko od vas znati da mi to kaže, dragi čitaoci, je kako taj Tempo/Maxi planira poslati sledeći vikend neku ponudu? Zašto misli da će iko da im vjeruje i da dođe? Meni lično ne smeta što je ajvar bio 3.40, ali mi jako smeta što to nije pisalo i u poruci.  Zar se isplati zbog 50 kupaca više koji su došli jedan vikend trajno izgubiti tih 50 kupaca? Ili oni misle da su ljudi ovce, pa kad trpe ovakvu državu i tolike laži pred izbore, mogu i ovakve marketinške kampanje? Možda su i u pravu, možda dobiju nove stalne klijente. Šta vi mislite o tome? I da li je neko uspio ne ispasti ovca i kupiti ajvar po reklamiranoj cijeni?

14.11.2011 – Nova perspektiva

Nakon što sam napisao ovaj članak, bio sam ubijeđen da je razlog svemu to što Delta (odnosno Delez) kompaniju-grupu nije toliko briga za pojedinačne kupce već da se sve odvija kao i kod drugih “biznisa” na Balkanu – profit je na prvom mjestu, ako se negdje omakne nezadovoljan kupac, nema veze – ima kupaca. Ono što izgleda u Delezu znaju, a što većina odlučujućih fakotra koji vode “biznise” ne zna je da dugoročno profit najviše zavisi od stava prema kupcima i od toga koliko se kupac osjeća bitnim i posebnim (jedna od bitnih stavki u Apple-ovim marketinškim kampanjama, a Apple nije bez razloga trenutno najvrijednija kompanija na tržištu). Dakle, nakon što sam napisao članak prošli vikend, kliknuo sam na link u mailu da se odjavim sa mailing liste (kakva mi je korist da čitam ako informacije nisu tačne?) i dobijem poruku o grešci (samo error bez objašnjenja). Zbog toga sam ostavio komentar na stranici, i poučen dosadašnjim iskustvom sa sličnim formularima nisam mislio da će ga iko ikada pročitati. Zbog toga je moje iznenađenje bilo još veće kada sam u srijedu, 9. novembra dobio sledeći e-mail (izvorni tekst s tim da sam ja konvertovao naše znakove š i ž i uklonio svoj broj telefona):

Poštovani,

Prije svega veliko izvinjenje zbog svih neugodnosti koje ste doživjeli u našim marketima!

Vašu e mail adresu ste uspješno izbrisali iz naše baze podataka i ubuduće nećete primate naša e mail obavještenja (ne znam zbog čega dobijate obavještenje “error”)

U bazi “Klub osmijeha”, na Vaše ime registrovan je broj 387 65 /moj broj telefona/. Ovaj broj smo takođe izbrisali iz baze za slanje poruka. Unaprijed se izvinjavamo jer smo nalog za slanje porukama za ovosedmičnu akciju u kome se nalazi i Vaš broj već poslali, ali nakon sutrašnje poruke, nećete više biti na našim listama. Ukoliko imamo pogrešan broj, zamolila bih Vas da mi dostavite broj na koji ne želite primati naše poruke.

Pročitala sa Vaš post na blogu koji se odnosi na našu vikend akciju tj na neugodnosti koje ste doživjeli u našim marketima. Za jedan dan bilo ih je isuviše! Mogu da Vam ponudim samo izvinjenje i objašnjenje ukoliko Vam nešto znači.

U subotu u Maxi marketu u Boriku zaista jestu imali problem sa programom koji koriste što naravno nije opravdanje za postavljanje stare umjesto akcijske cijene na proizvodu koji ste željeli da kupite (Premia ajvar). Dakle, naša greška je što ponuda (ajvar) nije bila uklonjena jer zbog tehničkih problema u sistemu nismo bili u mogućnosti da kupcima ajvar prodajemo po cijeni od 2.45KM što je bila predviđena akcijska cijena kao što ste bili i obaviješteni.

Kada je riječ o sms obavještenjima do sada nismo imali pritužbe na nejasnoću tj. konfuznost samih obavještenja ali ćemo u buduće svakako obratiti pažnju na ovo.

Kada je riječ o kartici Kluba osmijeha, još jednom Vam se izvinjavam! Ukoliko želite možemo Vam poslati novu karticu, ovog puta na kućnu adresu .

Organizaciju promocija ne radimo direkno mi, ali je pravilo da se ne rade promocije proizvoda koji se ne mogu kupiti u marketu, upravo iz razloga koji se Vama desio. Potrudićemo se da se ovakve situacije ne ponove.

Još jednom Vam se zahvaljujem na informacijama koje ste nam poslali tj objavili u Vašem postu. Sve te informacije sam proslijedila kolegama iz prodaje kako bi mogli da otklone nedostatke koje ste naveli.

Još jednom Vam se izvinjavam zbog svih neugodnosti koje ste Vi i Vaša porodica doživjeli u našim marketima.

S poštovanjem,

Dijana Milanković Kusturić
PR menadžer
Delez Grupa Srbija, Bosna i Hercegovina i Crna Gora

Prvo, moram da priznam da nisam očekivao da ću ovo doživjeti u Bosni i Hercegovini. Tačno poželim da i u državnim službama zaposle više ovako pismenih ljudi da odgovaraju građanima na primjedbe i pitanja, pa kad već “nisu u mogućnosti” ispraviti nešto (nemoguća misija je promijeniti radni tok u nekoj državnoj instituciji, od upisa u knjigu rođenih do upisa u knjigu umrlih, službenici koji tamo ništa ne rade uvijek imaju jake razloge zašto rade upravo tako) pa da se čovjek ne osjeća kao stoka kada dobije odgovor na primjedbu, ako već mora kao stoka da stoji u redovima za dokumente i uvjerenja.

Da se vratim na temu, Tempo ima osobu koja čita vaše primjedbe, i čini se da ne ostaje sve samo na odgovoru, (npr. ovaj vikend nije bilo promocije najljepših želja od tamne čokolade, ali nažalost nije još ni stigla čokolada :) ). I vi svoje primjedbe na Tempo/Maksi možete ostaviti ovdje.

Kako sam kasnije saznao, moj tata je u Novom Gradu iskoristio ovu akciju, a već sledeći vikend je ista akcija napravljena u Tempo marketima (i stvarno je bio ljuti ajvar po reklamiranoj cijeni), tako da je potpuno isključena mogućnost da se radilo o bilo kakvoj namjernoj prevari. Takođe, odgovora koji sam dobio na svoju primjedbu ne bi se postidjela čak ni njemačka ili švicarska kompanija (a greška može ipak da se dogodi svakome). Na ovom polju, ima konkurencije koja bi mogla učiti od Tempa (nekima je jedini način da kupci stupe u kontakt s njima upisivanje u knjigu primjedbi na licu mjesta, što većina onih koji pišu po njoj ne koristi za tu svrhu), ali ima i svijetlih primjera koji pokušavaju otići čak i korak dalje u pružanju mogućnosti za kontaktiranje (npr. besplatni 0800 info telefon, ali ne znam da li ih iko zove, a ja nisam zvao pa ne znam da li se javlja živa osoba).

Čisto radi poređenja odnosa ka kupcima opisaću svoj nedavni doživljaj u jednoj od poznatijih banjalučkih prodavnica laptopa i druge IT opreme, gdje sam često kupovao i već sam bio poznat i radnicima i šefu. Ušao sam tamo da tražim brz usb flash disk. Ponudili su mi svoj standardni, Transcend, ili Kingston (oba najjeftiniji i najsporiji mogući modeli). Rekao sam da mi ne treba takav disk, jer takav već imam, potreban mi je brz, ako je to sve što imaju, onda bih da naručim neki brži model pa da dođem po njega kada ga nabave. Na to sam od šefa dobio odgovor tipa “ne možemo mi naručivati nešto što nema u asortimanu našeg dobavljača, a sa drugim dobavljačima ne radimo jer mi sad tebi naručimo stik, nakon 6 mjeseci taj dobavljač propadne i kome ćemo mi reklamirati tvoj stik ako se pokvari?” Nije mi baš bilo jasno šta će biti ako za 6 mjeseci propadne njihov trenutni dobavljač i kome će onda reklamirati robu, ali mi je bilo jasno da njima nije mnogo stalo da prošire svoj posao, već samo da održe trenutno stanje (interesantan cilj u doba današnje tržišne ekonomije), ili su možda ubijeđeni da će kupac ako nema ono što on hoće kupiti ono što oni imaju. Uglavnom, sada mislim da zbog stvari koje se mogu kupiti preko ebay-a, ne treba ni ulaziti u lokalne prodavnice.

01.09.2012 – Sve po starom

Izgleda da sam ipak džabe bio oduševljen misleći da je Tempu stalo da popravi svoj način poslovanja. Na T-AT je osvanuo novi blog post koji pokazuje da se ove stvari i dalje dešavaju. Ono što je pozitivno u svemu tome, mene su stvarno izbrisali iz baze i više nikad nisam dobio sms sa obavještenjima o vikend akcijama, a to mi je očigledno uštedilo nekoliko nerviranja.

Check which rule is not fullfiled in jQuery validate plugin

Recently, I have encountered a situation where I used jQuery validation plugin and needed to know which of validation rules are failing. After asking this question on http://stackoverflow.com/questions/7648727/jquery-validate-check-which-rule-is-not-fullfiled and receiving no answers for 15 days, I have spent some time to solve it by myself.

It turned out quite easy, after inspecting source code of plugin on https://github.com/jzaefferer/jquery-validation/blob/master/jquery.validate.js, I have found out that this can be done by adding my own function to it:

 

$.validator.prototype.ruleValidationStatus = function( element ) {
    element = $(element)[0];
    var rules = $(element).rules();
    var errors ={};
    for (var method in rules ) {
        var rule = { method: method, parameters: rules[method] };
        try {
            var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
 
            errors[rule.method] = result ;
 
        } catch(e) {
            console.log(e);
        }
    }
    return errors;
}

This function returns list of validation rules with their results, and usage is simple:

$("#myform").validate().ruleValidationStatus($("#myField"));

Simplify common data access functions by using Entity Framework extension points

 

Whenever there is a new project with database, there is substantial amount of time spent on design of that database, as changes to database later cause much more overhead and problems than in beginning. In today’s conditions, however, it is very rare that database schema is not changed even during implementation (or immediately after deployment Smile). That is one of reasons why we now have CodeFirst workflow in EntityFramework.  It is great to have one common set of properties in one place (base object) inherited into all tables (i.e. UserCreated, DateCreated etc), and not having to think about it in individual objects.

It is even better to have all logic that uses those common properties in one place, but that tends to be hard to implement if repository pattern is used with all “common” logic implemented in common repository containing basic CRUD operations and data context as a dependency object. The problem is that each repository will inherit from common repository, and all will have “same” behavior, but EF allows you to save complex objects at once, and this can make your life bitter when you have common repository. The thing is, your custom behavior is executed for object you are saving, but not for referenced objects which are also saved when you add or update your main object. Workaround is to have instance of repository for each type which is referenced in your main object, save each first through “its” repository, and then save your main object which references all of them. As thing always can be made better (and better is more simple for me), I tried to find an answer for this problem. My answer is on github and if you are interested check it out (it has sample which works out of the box), and read description here.

There is a simple solution for this problem – common repository is code first context! It has couple of extension points (virtual methods left which can be overriden) where you can implement your own logic to handle journaling, validation, business rules… Almost everyone who worked with CF has used (overriden) OnModelCreating method, as it is very common in tutorials, but there are couple more:

bool ShouldValidateEntity(DbEntityEntry entityEntry)

System.Data.Entity.Validation.DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)

int SaveChanges()

ShouldValidateEntity and ValidateEntity are usefull places to call from your business rules and all possible validators, as there is no way that something will go to database by not passing through these (often ignored methods). These extension points are fairly simple to use and domain-specific, and I will not write about them in this post. My target of interest is SaveChanges.

go.DB.JournalingBase is simple project featuring usage of EntityFramework CodeFirst and overriding SaveChanges method of DBContext in order to keep record of changes on entities in database. There is a simple usage sample project and a test project with couple of test cases to confirm that everything is working. Database is SQLCompact, so no SQL Server is necessary and everything works on “F5”.

This is the idea: I have one “base” object – JEntity from my database objects inherit, and have corresponding DBContext, from which my repository(ies) inherit. Common object has Id property and other common properties I want all my journaling objects to have:

public abstract class JEntity
    {
        /// &lt;summary&gt;
        /// Gets or sets the id.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The id.&lt;/value&gt;
        public int Id { get; set; }
 
        /// &lt;summary&gt;
        /// Gets or sets the original id.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The original id.&lt;/value&gt;
        public int OriginalId { get; set; }
 
        /// &lt;summary&gt;
        /// Gets or sets the date created.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The date created.&lt;/value&gt;
        public DateTime DateCreated { get; set; }
 
        /// &lt;summary&gt;
        /// Gets or sets the date deleted.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The date deleted.&lt;/value&gt;
        public DateTime? DateDeleted { get; set; }
 
        /// &lt;summary&gt;
        /// Gets or sets the user created.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The user created.&lt;/value&gt;
        public string UserCreated { get; set; }
 
        /// &lt;summary&gt;
        /// Gets or sets the user deleted.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The user deleted.&lt;/value&gt;
        public string UserDeleted { get; set; }
    }

This object has OriginalId property, as a reference to “original” object – the first one that was added to database. When objects are updated, new version is created each time, “old” object is marked as deleted (DateDeleted is set in this case). All versions of same object share same OriginalId value, which is the same as Id value of oldest version.

Mapping to database is done using IEntityMap class, so this one is clean and simple, and does not have database metadata. The reason is that in real life you often have to refactor your code and change something. If model is created from metadata, then any change will cause your existing database to be “broken” and you will have to recreate it. This is good strategy in the beginning when you initialize your database with test data every time and test through unit tests, but if you have some staging environment where application is deployed and tested by users/testers they may have problems with that (whereee areee all thoose records I entered in friday?? Smile). This is especially important if you are making some serious enterprise application that will have longer lifecycle, and you want to make support easier (we do not want to have a “bomb” which will delete production database).

public IEntityMap()
	{
		//// Primary key
		this.HasKey(t => t.Id);
 
		//// Properties
 
		this.Property(t => t.OriginalId)
			.IsRequired();
 
		this.Property(t => t.DateCreated)
			.IsRequired();
 
		this.Property(t => t.DateDeleted)
			.IsRequired();
 
		this.Property(t => t.UserCreated)
			.IsRequired()
			.HasMaxLength(50);
 
		this.Property(t => t.UserDeleted)
			.IsOptional()
			.HasMaxLength(50);
 
		//// Column mappings
		this.Property(t => t.Id).HasColumnName("Id");
 
		this.Property(t => t.DateCreated).HasColumnName("DateCreated");
 
		this.Property(t => t.OriginalId).HasColumnName("OriginalId");
 
		this.Property(t => t.DateDeleted).HasColumnName("DateDeleted");
 
		this.Property(t => t.UserCreated).HasColumnName("UserCreated");
 
		this.Property(t => t.UserDeleted).HasColumnName("UserDeleted");
	}


So,  separate mapping class allows you to refactor properties without having to change their names in database, or to manually sync your database with your model, as everything is clean and readable.

The context – JContext overrides SaveChanges method, which takes care of actions necessary for journaling:

public override int SaveChanges()
{
	// We need same time for all entities updated in same transaction.
	DateTime now = DateTime.Now;
	// Get reference to user to avoid multiple getter calls.
	string user = System.Threading.Thread.CurrentPrincipal.Identity.Name;
 
	//// Detect changes in case that change tracking is turned off
	if (!this.Configuration.AutoDetectChangesEnabled)
	{
		this.ChangeTracker.DetectChanges();
	}
	List&lt;JEntity&gt; insertedList = new List&lt;JEntity&gt;();
	List&lt;JEntity&gt; invalidList = new List&lt;JEntity&gt;();
	foreach (var entry in this.ChangeTracker.Entries())
	{
		// Make sure that this customized save changes executes only for entities that
		// inherit from our base entity (IEntity)
		var entity = (entry.Entity as JEntity);
		if (entity == null) continue;
 
		switch (entry.State)
		{
			// In case entity is added, we need to set OriginalId AFTER it was saved to
			// database, as Id is generated by database and cannot be known in advance.
			// That is why we save reference to this object into insertedList and update
			// original id after object was saved.
			case System.Data.EntityState.Added:
				entity.UserCreated = user;
				entity.DateCreated = now;
				insertedList.Add(entity);
				break;
 
			// Deleted entity should only be marked as deleted.
			case System.Data.EntityState.Deleted:
				if (!entity.IsActive(now))
				{
					invalidList.Add(entity);
					continue;
				}
				entry.Reload();
				entity.DateDeleted = now;
				entity.UserDeleted = user;
				break;
 
			case System.Data.EntityState.Detached:
				break;
 
			case System.Data.EntityState.Modified:
				if (!entity.IsActive(now))
				{
					invalidList.Add(entity);
					continue;
				}
				entity.UserCreated = user;
				entity.DateCreated = now;
 
				JEntity newVersion = this.Set(entity.GetType()).Create(entity.GetType()) as JEntity;
				newVersion = this.Set(entity.GetType()).Add(newVersion) as JEntity;
				this.Entry(newVersion).CurrentValues.SetValues(entity);
 
				this.Entry(entity).Reload();
 
				entity.DateDeleted = newVersion.DateCreated;
				entity.UserDeleted = user;
				break;
			case System.Data.EntityState.Unchanged:
				break;
			default:
				break;
		}
	}
	if (invalidList.Count == 1)
	{
		throw new InvalidJournalingEntityException(invalidList[0], invalidList[0].GetType().Name);
	}
	else if (invalidList.Count &gt; 1)
	{
		throw new MultipleInvalidJournalingEntityException(invalidList);
	}
	int result = base.SaveChanges();
 
	if (insertedList.Count &gt; 0)
	{
		insertedList.ForEach(t =&gt; t.OriginalId = t.Id);
		base.SaveChanges();
	}
 
	return result;
}


The method handles cases when object is added, modified or deleted. When added, it must save reference to it and set OriginalId after it was assigned Id. As object does not have Id until sql server generates one for it, this has to be done after SaveChanges. Theese few lines should in serious system be inside one transaction, just in case.

When object is changed, change is canceled and  only DateDeleted and UserDeleted is set (same as when object is deleted). Instead, new object is added as new version of changed object.

All this is used from sample project, where new entities and context are created, with no code for usage of theese features except inheritance from JEntity and JContext.

If something is not clear, the best option is to start test project and set breakpoints at places of interest, or ask your question in comments!

kick it on DotNetKicks.com

Solution for VHD_BOOT_HOST_VOLUME_NOT_ENOUGH_SPACE error in windows 8

If you are using VHD method of installing windows 8 to virtual disk on physical machine (Scot Hansellman has great tutorial: http://www.hanselman.com/blog/GuideToInstallingAndBootingWindows8DeveloperPreviewOffAVHDVirtualHardDisk.aspx) and you get VHD_BOOT_HOST_VOLUME_NOT_ENOUGH_SPACE error after installation, then your problem is probably dynamic VHD and not enough free space on disk containing that drive. I had the same problem, and googling for it did not solve it, as there is one little catch that is not very known:

You need to have enough free space on physical disk containing VHD that it can contain whole VHD IF IT WOULD GROW TO MAXIMUM DECLARED SIZE! So 100GB VHD on a 90GB free space is a no-go, it does not matter that Windows 8 will use only about 11GB after clean installation.

Windows 8 setup does not check for this, so you may be able to install it, and not able to boot it :)

Example of great user management policy

 

image

Log on to windows as a local user without computer name

Yes, you all know that you can use computername\user or 192.168.x.y\user, or even domain\user when logging on to machine.

But, when you want to login as local user and don’t know computer name, and do not want to type IP address, you can use any\user where any can be anything.

Nice little security flaw?

Gdje to mi živimo?

 

Vrlo naivno pitanje, na prvi pogled, koje na ovome mjestu, gdje živimo, očigledno niko ne shvaća ozbiljno. Čuje se ponegdje da smo zemlja apsurda, ali oni čiji su glasovi najglasniji kažu da smo mi u Evropi, pa čak i da smo bolji od nekih drugih mjesta. Možda i jesmo? Teško je, a i vrlo neodgovorno donijeti takav sud naprečac, ali u tekstu koji slijedi ću pokušati bar malo da odredim našu poziciju u odnosu na ostatak svijeta.

Zašto?

Mnogi koji su počeli ovo čitati će se vjerovatno zapitati koji je moj motiv za pisanje ovoga teksta, i vjerovatno niko neće ispravno pretpostaviti isti. Razlog je što sam postao otac, povodom čega sam primio mnogo čestitki i želja da novi član moje porodice ima puno sreće u životu. Razmišljajući o tome, zapitao sam se i kakav to život može da očekuje jedna beba, i počeo da zapisujem stavke koje slijede. Takođe sam htio da oni koji eventualno čekaju bebu imaju poneku informaciju koja im može pomoći.

Poređenje ovoga mjesta sa “normalnim” mjestima za život

Prva stvar koju ću da uporedim je ono u šta sam najbolje upućen, a to su uslovi za život koje može imati prosječna mlada osoba (dobro, ne baš prosječna, pošto posmatram sa gledišta visokoobrazovane osobe sa poprilično dobrim zaposlenjem, a to je ovdje statistički šiljak koji popravlja prosjek). Pod normalnim ću smatrati sve ono što se manje-više podrazumijeva u zemljama u bližem okruženju.

Obrazovanje i posao

Izbor fakulteta je dobar. Ništa bolji nego u ostatku svijeta, ali ne zaostajemo previše. Moguće je, uz malo truda i mnogo novca, upisati i završiti bilo koji faks. To je otprilike sva sličnost sa ostatkom svijeta. Prosječna porodica ne može bez značajne žrtve “izškolovati” jednog studenta, a o dva ne smije ni razmišljati. Tako je i u “boljim” društvima, reći će mnogi. Jeste, ali u našem ne postoje krediti za školovanje, stipendije su neadekvatne, a studenti nemaju mogućnost da rade i poprave svoju situaciju.

Sam kvalitet obrazovanja je, pa, kakav god da je, i dalje potpuno nebitan. Odnosno jeste, svuda osim ovdje. Zašto? Završen fakultet znači početak samostalnosti – posao u roku od par mjeseci, finansijska nezavisnost, mogućnost da se živi sam, postavljaju ciljevi i odlučuje zašto se radi. To imaju mladi u svijetu. Ovdje? Pošto ne postoji nikakva strategija, niti razvojna niti neka druga, nema niti plana koliko gdje studenata se može upisati i šta će biti s njima kada završe. Stoga prosječan student uz diplomu može očekivati i par godina na birou. Za razliku od društava kojima težimo, ne postoji nikakva nadoknada od države koja vam ne može obezbijediti posao, iako će uredno naplatiti porez ukoliko ga sami pronađete. Volio bih znati postoji li neko u ministarstvu obrazovanja ko zna koliko ovo društvo košta jedan obrazovan čovjek? Siguran sam da nema, kao što sam siguran i da u prosjeku ne košta manje od 50000KM, iako je vjerovatno u pitanju i veća cifra. Šta onda znači stotinu obrazovanih ljudi na birou? 5 miliona maraka propale investicije. Nije strašno? Ne bi bilo da ne postoje hiljade a ne stotine takvih. Da li je bolje imati 150 hiljada nezaposlenih, ili 150 hiljada nezaposlenih i 150 miliona maraka koje nisu potrošene na školovanje nezaposlenih? Zašto država dopušta da stotine miliona maraka ovoga društva propadaju? Zašto ne smanji broj, ili ukine potpuno fakultete i smjerove za koje nema posla? Bar na državnom univerzitetu? Vjerovatno zato što nikoga nije ni briga za to. Onda nije ni bitno da li je diploma samo papir, ionako će vas i vaše obrazovanje dok dobijete posao pregaziti vrijeme. Uz jedan od najvećih (vjerovatno i najveći) procenat nezaposlenosti visokoobrazovanih na svijetu, ovdje je svrha fakulteta da odvlači mladima pažnju i energiju sa bitnih stvari, izmori ih i spriječi da usmjere energiju protiv društvene truleži.

Porodica i brak

Ukoliko upoznate osobu sa kojom možete da se složite oko bitnih stvari u životu, i da organizujete zajednički život tako da poželite stupiti u brak, država će vas obradovati – čak 3 dana plaćenog odmora, a ako ste obrazovani, obradovaće vas i beneficirana stopa IRB stambenog kredita. Super. Jest da ova 3 dana nisu potrebna, meni je recimo bio dovoljan i jedan, a da sam se ženio subotom, onda mi ne bi trebao ni jedan. Ali dobro su došli za selidbu. No, kad razmislim, nema razloga zašto država ne bi dala 3 danaza ženidbu kada više od pola osoba koje stupaju u brak nisu zaposlene, pa i nije neki trošak, zar ne? Ta tri dana služe samo da bi postojao još jedan apsurd – 1 dan odsustva za rođenje djeteta. Logično zar ne? A tek druga pogodnost – beneficirana kamatna stopa za stan – to je tek sjajno. Beneficirana kamatna stopa je duplo veća od stopa komercijalnih stambenih kredita u Evropi, ali šta očekivati kada su sve banke prodane inostranim vlasnicima? Neće na svojim građanima zarađivati, jer oni imaju državu koja se brine za svoje građane. No, ni ta kamatna stopa nije bitna, jer ni uz platu koja je deset puta veća od prosječne, (ako je nemate vidite da vam ni ne treba, a ako ste zaposleni onda vam bračni drug ne radi pa vam se i to malo kreditne sposobnosti umanji) ne možete dobiti ovaj kredit, ukoliko nemate drugu nekretninu da stavite pod hipoteku. A da bi uopšte mogli dobiti kredit ne smijete je imati. Apsurd? Ma kakvi, može i žirant umjesto hipoteke. Bračni drug? Da ali u prosječnoj porodici radi manje od jednog člana domaćinstva. Recimo da imate 14 baš dobrih prijatelja (puno više nego što imate, ali optimista sam), koji bi bili voljni da vam budu žiranti. 7 ne može jer su nezaposleni. Od ovih ostalih 7 što rade, 1 ne može jer je već bio žirant i sada plaća tuđi kredit, dvojica ne mogu jer su bili žiranti previše puta i neki od kredita se neredovno otplaćjuju. Od preostale četvorice dvojica imaju dovoljno visoku platu da zadovolje kriterije banke, ali jedan već ima stambeni kredit pa ne može a drugi ne radi u državnoj firmi. Da, banke traže žiranta iz državne firme. Zna se da je ovdje država parazit a ne faktor koji obezbjeđuje dobru poslovnu atmosferu, i da će privreda propasti nauštrb države, a banke ne žele da budu na gubitku zbog toga. Tako se dođe do situacije da ja živim u stanu koji iznajmljujem. A najam plaćam manje-više koliko bi bila rata za takav stan u normalnom društvu.

Zdravstveno osiguranje i djeca

Zdravstveno osiguranje? Naravno, imam ga, i molim boga da mi ne zatreba, jer ako mi zatreba neće mi biti od prevelike pomoći, o čemu sam već pisao. Mnogo bolje bih mogao da iskoristim novac koji mi država otima od zarade nego da se “liječim” u državnoj “bolnici”, koja ima najsavremeniju opremu u Evropi na odjelu radiologije, koja košta kao flota autobusa koji ne čade, ali se ne koristi nešto mnogo, nema dovoljno obučenog kadra, uputnice se kradu a pregledi ne obavljaju, a ni mnogi građani ne znaju za postojanje ovako opremljenog centra. Ista ta bolnica nema pelena za umotavanje novorođenčadi, porodilje po nekoliko dana leže na krvavoj posteljini, a vikendom nema dežurnog doktora, pa dijete rođeno u petak naveče do ponedeljka ujutro ima dovoljno vremena da razvije razne infekcije. Ukoliko neka žena ima tu nesreću da zatrudni u ovome društvu (naglašavam ovo, jer je samo taj drugi dio nesreća), vrlo vjerovatno će imati prednost u svim redovima gdje se nešto čeka. To je sličnost sa ostatkom svijeta. Osim toga će dobiti otkaz ako je imala posao, država joj neće platiti nadoknade za trudničko bolovanje, sama će platiti školu za trudnice i imat će jedinstveno iskustvo porođaja. Naime, kod nas imaju u bolnici jedinstvene spavaćice – takve možete vidjeti samo u kaubojskim filmovima, kada se neki glumac skine u “pidžamu”, oni poparani dronjci tako izgledaju. Takođe, naši su doktori čuli za neki tamo drip. Izolovali farmaceuti aktivnu supstancu, koja izaziva i pojačava porođajne bolove. Čuli oni da se to daje tamo u Evropi, trudnicama na porođaju. Cijene oni mnogo prirodu i prirodni porođaj, ali cijene mnogo više tu Evropu i evropske vrijednosti, ipak su oni društvena elita koja treba da nam donese te novosti. Jedino što ne mogu da obezbijede i druge stvari iz Evrope, koje nisu u njihovoj moći, kao npr. bolničke papuče koje treba donijeti od kuće, ili “pamperse” za bebe, ali zato mogu da dadnu dripa desetine puta više nego što ga imaju u Evropi, nema isključivanja nakon prvog sata kao tamo, tako da time nadoknade sve što oni imaju a mi nemamo. To se dešava svim trudnicama, a ne samo mojoj. To je jedini kriterij po kome nema nikakve diskriminacije, ni po kakvom osnovu. Zahvaljujući tome prirodan porođaj postaje neprirodan kada od te supstance nateknu mišići koji treba da donesu dijete na svijet i tako mu onemoguće izlaz. Iako je u tom momentu i sestrama bilo jasno da je porođaj nemoguć, doktor je htio moju trudnicu ostaviti još par sati, ne bili se nekim čudom ipak porodila. Srećom, ona nije prosječna trudnica koja poštuje princip “ćuti i trpi” koji vrijedi za prosječnog člana našeg društva, nego je “izgubila strpljenje” kako kaže babica Mira, pa su je morali poroditi na carski rez, “samo” 5 sati nakon što su joj izazvali bolove i probili vodenjak. A babica Mira je osoba koja se samo zove babica, njeno radno mjesto se zove “uzimač mita”, jer ona ne porađa, bar je se moja žena ne sjeća. To joj nije smetalo da nakon porođaja izađe i pružajući ruku kaže “ja sam babica Mira, ja sam porodila vaše dijete, sve je u redu”. Ukoliko joj pružite ruku neće se nasmijati i čestitati nego se smrknuti i poći nazad. A kad vam doveze dijete da ga vidite, što joj je posao, još jednom će ponoviti isto. Reći će vam i da ne prima nikakvo milošte, ukoliko na njemu nije naslikan Jovan Dučić (ne tim riječima ali bit će vam jasno), a ako ga dobije umjesto zatvaranja vrata pred nosom ljubazno će vam odgovoriti na pitanja koja imate i objasniti vam gdje ćete, i kada, moći vidjeti novopečenu mamicu. Zbog pet sati porođajnih muka koje su prethodile njihovom genijalnom zaključku da je potreban carski rez, bio sam toliko bijesan da je i Mira vidjela da se tresem i pokušala da objasni da nisu oni krivi, ali doktor se, vjerovatno za svaki slučaj, ipak nije pojavio. Vjerovatno zato što on i nije planirao još da radi porođaj, ali je moja ženica “izgubila strpljenje” i počela ustajati sa kreveta, galamiti, grebati doktore koji priđu i uopšte biti nemoguća čime ih je prisilila da urade ono što su, prema njihovim riječima, “već znali da mora da se učini”. Ne znam mu ni ime, tom doktoru, čini mi se Đukić, ali ne bih htio da stanem iza toga i oklevetam pogrešnu osobu, jer vjerujem/čuo sam da ima među njima i neki dobar doktor/doktorica, koji bi mnogo bolje obavljali posao da nemaju iznad sebe takvog, koji dođe porodilji koji dan kasnije i pokuša objasniti otoke i infekcije namučenog novorođenčeta uzrocima kao što su plodova voda, infekcija majke i sl. Nakon što ona spomene činjenicu da je kontrolisala te parametre i da je sve bilo u redu 3 dana prije poroda, on kaže pa dobro, ja sam taj i taj, ako sve bude u redu recite svima da sam vas ja porodio, a ako ne bude nemojte me spominjati. Pa sjajno, to je baš sjajno. Ja volim preuzeti zasluge a nemati odgovornost za eventualne posljedice. Iako mi žena kaže da nije tako zvučao i izgledao, nadam se da se šalio, jer smo i bez toga propali. Prema tome, i prema strašnoj, žalosnoj i nedopustivoj činjenici da je dan nakon poroda moje žene umrlo dijete nakon što su ženu porađali 12 sati, su ostale gluposti, poput one da trudnice ne smiju preći vrata iz “svog” u hodnik posjetilaca i obrnuto, nego svi moraju da se nabiju u što manji prostor na vratima ne bili lakše razmijenili bakterije i viruse, naprosto zanemarive i suvišne za spominjati, ali ja ću ipak to da učinim. Da pojasnim, posjeta porodiljama izgleda otprilike ovako: ulaz u odjel su dvokrilna vrata, na kojima se otvara veće krilo, širine oko 1m. Sa jedne strane vrata tu dođe desetak nesretnica – porodilja, a sa druge dvadesetak posjetilaca, i svako pokušava da malo bude sa svojom porodiljom. Samo radi poređenja, u Sloveniji muž može biti prisutan na porođaju, doći kod porodilje u sobu i biti s njom 2 sata dnevno, i dobiti 15 dana plaćenog odsustva, a kod nas ništa od toga. Tamo porodilja ne mora nositi od kuće spavaćice, papuče, čiste peškire kojima će prekriti jastuk i na koje će staviti dijete, jednokratne gaćice, hranu (doručak je jedna viršla i četvrtina čaše mlijeka), pelene za dijete… ne mora nositi ništa. Kod nas porodilište najviše liči na zatvor. Jedine svijetle tačke su sestre, bar većina, koje i pored svih teških uslova čine sve što je u njihovoj moći da to iskustvo bude manje traumatično. Ipak se nadam da moja žena nikada više neće posjetiti ovo porodilište. Neko drugo da, ali ne ovo. Svakoj trudnici je bolje da se porodi kod kuće nego gore. Mislim da će ove slike iz porodilišta da pomognu ilustrovati kako izgleda boravak gore:

Razumijem da stanje može da bude lošije nego što bi trebalo biti, jer se planira preseljenje u novu zgradu, nekada jednom kada ona bude gotova. Ali da li je to razlog da čistačice ne očiste kupatilo, ne izvade skakavce iz svjetla iznad kreveta i ne ubace vrećicu u kantu za smeće? I da se ne može popraviti česma iz koje non-stop curi voda, i to topla! Pa čemu onda zabrana ulaza na odjel za posjetioce, svakome je čistije kod kuće, ili odakle je već došao, i sigurno je da je manje vjerovatno da će se neko zaraziti ako svako bude kod svoje porodilje nego svi na jednom mjestu, gdje ako dođe jedan zaražen ima da zarazi i sve trudnice (i djecu) i sve posjetioce…

U društvu u kome su ljudi zadnji u sistemu društvenih vrijednosti ne može da postoji stabilna država, jer bez ljudi nema ni države. Ostajanjem ovdje i plaćanjem poreza i doprinosa samo podržavamo ovakvo stanje. Ne želim nikoga da uvrijedim, ali od sada ću mislim da je glup svako kome se pruži ikakva prilika da napusti ovo mjesto, a on odluči da ostane, jer je nemoguće očekivati da se nešto može promijeniti u društvu u kome prosječan posjetilac bolnice ne zna čak ni lift pozvati u smjeru u kom želi ići. I ne samo što ne zna pozvati lift, nego ubijeđen da sve zna ne želi dok čeka pročitati uputstvo za upotrebu… Od dva zvona na ulazu na odjel, na kojima na jednom piše “Zvono za žene” a na drugom “Zvono za bebe – otpust”, dođe lik sa nosiljkom za bebu, u 12h kad je otpust, i zvoni 4 puta na zvono za žene, a onda počne da komentariše kako “nema nigdje nikoga”… Pa uzalud je ovdje pisati uputstva, kućni red, upozorenja, uzalud i ja pišem ovo, to može pomoći u društvu u kom ljudi čitaju, znaju da ne znaju i žele da nauče nešto.

Srećom, sada više nemam članova porodice u bolnici, i imam par godina do polaska prinove u školu, period u kome mogu čak i ovdje da  omogućim svome djetetu djetinjstvo približno onakvo kakvo imaju i normalna djeca, iako u ovoj “državi” nema dječijeg dodatka. A nakon toga – ponovo jedna državna ustanova. A kakva “država” takva i “škola”. Čitav svijet je u 2011. godini a naše su škole još u 1980. Ne uči se kod nas ništa što se desilo posle toga, a ne uči se ni voziti bicikl, skijati, plivati, pjevati niti išta što se uči van škole. Ovdje je to bukvalno, kada djeca idu u školu, ona idu u onu zgradu na kojoj piše škola, i to se misli pod pojmom “ide u školu”. Da stanje neće biti bolje može se vidjeti i na vijestima, kažu smanjuje se budžet za prosvjetu, ukida se x područnih škola, zbrinjavaju se radnici, ide se u propast… Samo se u skupštini, vladi i javnoj upravi ne smanjuju plate i ne zbrinjavaju radnici.

Nakon što sam sagledao ove činjenice, shvatio sam da ni jedno dijete ovdje ne može imati djetinjstvo dostojno djeteta, kao što ni građani nemaju život dostojan čovjeka, i zaključio da to zavisi od društva u kome odrasta u tolikoj mjeri da za to nije moguće napraviti kompenzaciju nikakvim drugim sredstvima. Zato se nadam svojoj prilici da mi vidite leđa…

Unobtrusive attachment of functions to events in jQuery

 

Lets say I have text input field that is part of search form, and when user clicks on find, it gets results in another part of screen. What I want is, when user changes value in some of the inputs of search form, that search results be invalidated/removed as they are not actual anymore.

As search form can have many fields, I decided to make one function for resetting search, and to make unobtrusive attachment for “change” event. I did that by adding “change” attribute to input field:

<input name="Search.SomeValue" class="valid" id="Search_SomeValue" change="resetSearch" type="text" />

This attribute is consumed by this function:

$("[change]").each(function(){
        var functionName = $(this).attr("change");
        var change = window[functionName];
        $(this).change(change);
    });

What this code does is:

- For each element with change=”something”, read something (in this case “resetSearch”) into functionName variable

- Read function from window object. Window object contains all globally defined functions

- Set this function to execute on every change of input field

 

Deserialize form from JSON data using jQuery

Recently, I got task to make feature which will make possible for user to update form data based on some unique “search” field (like VIN or SSN). I wanted to make this short and simple, and above all reusable. So, I made some investigation this weekend and came up with simple solution to use same model object that is used as type of view in asp.net mvc. It is simple javascript function:

 

var formPrefix = 'myFormPrefix';
$('sometextbox').change(function () {
 var myValue = $(this).val()
 $.ajax({ type: 'POST',
  url: 'ajaxcontroller/getcarbysomething',
  data: { something: myValue },
  success: function (data) {
  if (data){
   $("input[name*='" + formPrefix +"'],select[name*='" + formPrefix + "']").each(function () {
    var itemName = $(this).attr("name");
    var prop = itemName.substring(itemName.indexOf(formPrefix) + formPrefix.length);
    var itemValue = data.person[prop];
    if (itemValue && itemValue.substring &&
      itemValue.substring(0, 1) == "/" &&
      itemValue.substring(itemValue.length - 1) == "/") {
         itemValue = "new" + itemValue.substring(1, itemValue.length - 1);
         itemValue = eval(itemValue);
         $(this).datepicker("setDate", eval(itemValue));
    }
    else if (itemValue) {
     $(this).val(itemValue);
    }
   });
 
   }
  }
 });
});

So, to use this you need to make controller action that returns JsonResult and Json(model) instead of View(model). If form is partial view (preffered) or has explicit prefix, formPrefix is place to set it. Each form input element’s name is used to index json object returned from controller and value (if any) is set back into input element.

Autocompleting cascading dropdowns

 

Starting point for this post is source code for last one, available on bitbucket.

I want to replace dropdown list with jQuery autocomplete, like in this example. There are two reasons for this:

  • When there is very large number of records to choose from, then standard dropdown list is not very user friendly
  • When user is entering name of item, besides autocompleting from known items, we can implement addition of new item if item user needs to enter is not present in codebook. This will be done in next post.

For start, I will copy example from jQuery demo, and add textbox in which I will implement this functionality.

image

I have added this code to Index.chtml, which is label for manufacturer, hidden field with id for chosen value from dropdown, and textbox for autocomplete. I have added three attributes for this textbox:
- autocomplete-for is target (hidden field) into which I want to place chosen value
- from-url is address where I will get items for autocomplete
- parent is field for cascading functionality (this will be optional)

Client side code for autocomplete is based on jsonp example from jQuery ui demo:

image

I have added this init function to document ready event. What is happening here is simple: for each input element that has “autocomplete-for” attribute, jQuery autocomplete is added, with custom function as data provider. This function is using ajax to request data for dropdown from from-url specified in view. Parameters are MaxItems (amount of items to show in autocomplete), ParentFilterId (selected value of parent field – for cascading support) and NameStartsWith, which is text entered into dropdown which is autocompleted.

Success function maps “items” collection in response to label, value and id. label and value are automatically used by autocomplete plugin to show label for item in dropdown and to set textbox value when item is selected, and I added id to set hidden field in select event.

To make this work, there is one thing left: controller action which will return items. As you can see in first screenshot, I decided to use Manufacturer controller and action named Autocomplete.

To make parameter passing easier, I have created model for data passed in request:

image

I will receive this object as parameter in my action.

This is how implementation of autocomplete action looks:

image

This is fairly simple – query is filtered by name for NameStartsWith parameter, and I used ToLower method of string, to compare case insensitive, as StartsWith with string comparison options parameter is not supported in linq to entities.

If request contains parent filter id or max items number, then these are taken into account, and response is formed as collection of items with Text, Value and Id properties, which are used in success function of ajax request.

Time to see how it works:

imageimageimage

As this is working nicely, time for little makeup, as I want this more reusable, and not having to remember html attributes that need to be used. So, that smells like html helper:

image

Actually, it is two helpers – one for cascading case, and one for “normal”. It is the same code as in cshtml view, but creating hidden and text field in one method, and when I add comments here (removed to make screenshot smaller), I will have nice intellisense to use this function whenever I need, only having to copy and adjust controller action, which also can be made pretty generic.

 

image

This is how autocomplete is used now. I’m ready to call this a day, and source code from this post is in this changeset on bitbucket.

ASP.NET MVC3 app (part 3) – ajax cascading dropdown–unobtrusive version

 

In part 2, I made cascading dropdowns by calling selectFromAjax javascript function from my view:

image

This function has 3 arguments: address of service which provides data based on second argument – formData (in this case only id of selected item in current dropdown), and target – select list into which items from service are injected, replacing its current contents. These three parameters are almost enough to know that there is dependency between two dropdowns. Why almost? Because there is one implicit parameter – this function is part of “change” event of another dropdown – source of this event. So, source dropdown is fourth parameter. That four things are everything that client needs to know to be able to implement intended behavior of UI.

I will make this functionality unobtrusive by placing necessary information into target dropdown. Why? Because it seems most straightforward and “unobtrusive” to me, that dropdown list says “My contents depend on item selected in dropdown list X, and you need to call service Y to find out what should I show”. It is not ok to have information about MY behavior in some other dropdown X Smile. Besides, with this approach, I’m eliminating one parameter, as I have only two now: dropdown X and service Y. Third was value of dropdown X, and fourth is target dropdown itself, into which I’m adding these attributes. Value of dropdown X I can read if I know which is dropdown X, so this parameter for function anyway must be determined at the moment of changing value in X.

So, if I make my select look like

image 

then my dropdown contains all information needed to remove script from view, and place it in global js file, or make jQuery plugin. To make this information automatically embedded into my dropdown, I need to make html helper for this. If wee look at first overload of DropDownListFor in System.Web.Mvc.Html.SelectExtensions, we can easily see how new method should look:

image

My html helper will have another two arguments – depends on and load from:

image

It is using DropDownListFor helper from Microsoft, and I won’t render my own html code (and so make more space for bugs Smile).

So, view from part 2 should now look like this:

image

and generated html is:

<select cascading-dependson="ProductType" cascading-loadfrom="/Home/Manufacturers" id="Manufacturer" name="Manufacturer"></select>

Now, all that is left, is to automatically attach event handler onto “master” dropdown. It is easy using jQuery:

imageThis is adding initializeCascader to list of functions that are run on document load. This function goes through each select that has cascading attributes and attaches onchange event to element with id in cascading-depenson attribute, with self as a target for selectFromAjax function (from part 2), and value of cascading-loadfrom attribute as a url.

This is very simple concept, but can be used for chaining random number of dropdowns, and can easily be expanded to make dropdown values dependent not only on “master” dropdown, but to depend on whole form. Further improvement of this could be custom data annotation attribute, which could be used for decorating property of model, so html helper does not have to be explicitly called.

Source code for this post can be downloaded here.

UPDATE: I have uploaded source code to bitbucket.

Back to part 2

ASP.NET MVC3 app (part 2) – ajax cascading dropdown

 

To make cascading dropdowns in application from part 1, I created ProductFilter:

image

I will use this class as model for my home controller Index method:

image

Here you can also see Manufacturers JsonResult method, which is used for asynchronous refresh of second dropdown:

imageimage

Manufacturer dropdown is loaded with manufacturers which produce models of chosen product type. This is made possible with simple jquery function:

image

This function accepts url of method which provides json list of items for dropdown, passes formData parameter with id, and places results into target for which selector “target” is provided.

This is how my view from which this method is called looks:

image

Two dropdowns are created using standard MVC helpers, and onchange event function is attached using jquery. More dropdowns can be chained in the same way, there is only necessary to add change function in the same manner. However, this is no good, as event attachment is manual, and script must be written, and included into view as selectors are generated here. My goal is to make these event attachments unobtrusive, and I will write about that in part 3.

For now, you can download project source code here.

Back to part 1

ASP.NET MVC3 app (part 1) – Entity Framework and code first

How often you need to have cascading choices on UI in order to make your application user friendly? In my experience, almost every modern application has some form of hierarchy, and that is where cascading dropdowns are used. But, I want to make this less repetitive and more elegant. So, let’s begin. In first part (this) I will create an simple web app using entity framework code-first and make simple model which will be used for creating this functionality. It is one speedy run-through of new features, without advanced topics, so mind some bad practices, this blog post is not about good programming, first part is for MVC3/.NET 4 beginners with experience with older versions of MVC and .NET.

It will be an mvc3 razor internet application:

image

With latest MVC tools update there are already almost all necessary NuGet packages installed in new project:

image

I will just update all of jQuery packages as they have updates at the moment, and add EntityFramework.SqlServerCompact (NuGet will add dependencies), so SQL server won’t be needed.

As this is demo app, I will put everything into single project. It will be an product catalogue.

This is data model:

image

Central object will be product model (I will use vehicles domain), which has type, version, trim level and manufacturer. Simple enough. Objects on diagram are simple POCO objects with collection properties marked as virtual, so entity framework can override them and inject DynamicProxy objects for lazy loading.

This will be my repository:

image

For this DbContext to work, I need to do one more thing – to put connection string into my web.config:

image

As I don’t want to create test data every time I change my model, I can use database initializer class to create test data (this is useful for unit testing):

image

And this is it. I now have database and data. Actually, I will have it when I start my application, if I add this to global.asax:

image

To test this, I will use controller autoscaffold feature of new MVC tools update:

image

This will autocreate controller and all views Smile. After this action, starting app and visiting http://localhost:57095/Manufacturer will give:

image

Note that only manufacturers for which I created Models are in database. This is because I only added Models, and EF added all related objects, and BMW was not among them.

Using auto scaffold I created controllers for all model objects in couple of minutes.

This is end of part 1, I now have application which will I use to create unobtrusive cascading dropdowns. In the next part I will make cascading dropdown loading using standard methods (jQuery and ajax).

For more info about EF Code First, visit

http://www.hanselman.com/blog/SimpleCodeFirstWithEntityFramework4MagicUnicornFeatureCTP4.aspx

and

http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

UPDATE: Added part 2

Take my work with me

How often did I need to copy whole virtual machine because I needed to continue work on another location? A way too often. And moments when I wait for 20-30GB to copy, sometimes seem like eternity.

Well, I spent couple minutes last night to prevent that :)

Here is a batch script which copies folder with my work from hdd and takes backup of database. Even more, it restores everything back when I arrive at another location :)

So, save this script as common.bat:

@echo off
set server=HOSTNAME\INSTANCE
set dbName=DATABASE
set projFolder="C:\Users\gorano\Documents\visual studio 2010\Projects"
set backupFolder=%CD%
 
if "%1"=="leaving" GOTO backup
if "%1"=="arriving" GOTO restore
echo Invalid first argument, must be "leaving" or "arriving"
GOTO end
 
:backup
echo backup database %dbName%
@echo on
sqlcmd -E -S %server% -Q "BACKUP DATABASE [%dbName%] TO  DISK = N'%backupFolder%\%dbName%.bak' WITH NOFORMAT, INIT, NAME = N'%dbName%-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10"
xcopy %projfolder% %backupFolder%\Projects  /E /I /Y /Q
GOTO end
 
:restore
if "%2"=="DeleteOld" GOTO deleteold
:restoreNoDelete
echo restore database %dbName%
sqlcmd -E -S %server% -Q "RESTORE DATABASE [%dbName%] FROM DISK = N'%backupFolder%\%dbName%.bak' WITH  FILE = 1,  NOUNLOAD,  REPLACE,  STATS = 10"
xcopy %projfolder% %projfolder%.backup  /E /I /Y /Q
xcopy %backupFolder%\Projects %projfolder%  /E /I /Y /Q
GOTO end
 
:deleteold
@echo Press any key to delete database %dbName% on sql server %server%
pause
sqlcmd -E -S %server% -Q "ALTER DATABASE [%dbName%] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE"
sqlcmd -E -S %server% -Q "DROP REMOVETHISWORD DATABASE [%dbName%]"
GOTO restoreNoDelete
 
:end
pause

To run this easily, make “i’mleaving.bat” with

common leaving

and “i arrived.bat” with

common arriving DeleteOld

All you need to change is to set your server\instance, database name, folder with projects, and to delete “REMOVETHISWORD” under :deleteold, as words DROP and DATABASE does not stand well together (I don’t want to hack wordpress script injection protection to post this) :)
In combination with DropBox, this is great thing. You can also add 7z line to compress/decompress these files so dropbox sharing is more meaningfull (if you have large database).

Najbolji komšija

Naš najbolji komšija je vrlo popularan u našem malom gradu, i tamo (skoro) svakog utorka srećem mnoštvo poznatih lica sa (sve manjim) mnoštvom artikala u kolicima i korpama. Ima taj čarobni popust ko redovno troši, došle barabe iz Evropske Unije a tamo je to već stari fazon. Al’ što bi oni nama nudili najnovije loyalty programe kad se i ovako ljudi pokidaše, svađaju se ko je na redu da mu ona teta (ili u zadnjoj sceni kojoj sam bio svjedok – bato) nasjecka salamice…

Vjerovatno neki psihički hendikep ljudskih stvorenja utiče na to da nas onih 10% popusta privlači, iako nam je svima poznato da to nije nikakav poklon za potrošače (naprotiv, tek tada su cijene normalne, a oni artikli koji su već po normalnim cijenama “nisu podobni za popust”). To našem najboljem komšiji služi da ne bi radnici sjedili skrštenih ruku, nego svaki dan ima popust ili nagradna igra. Čak i penzioneri imaju svoj dan, dan kada mogu da ostvare popust bez ikakvih preduslova, osim da su penzioneri. Sve to lijepo separatiše nas potrošače, pa ne navaljujemo odjednom, komšija je uspio da nas rasporedi na cijelu sedmicu, tako da mora manje radnika da zaposli, a da one koje je zaposlio što bolje iskoristi. Optimizacija. A ne kao kod nas… Primjera je bezbroj, ali jedan ipak najviše upada u oči. Vjerovatno ne samo nama nego bilo kome ko dođe iz Evrope. Kod nas predsjednik ide na posao sa 4 auta. Kao da smo u Americi (samo što oni imaju jednog predsjednika na 300 miliona, pa je to daleko manje predsjednika po glavi stanovnika i mogu si to priuštiti). A u Norveškoj predsjednik vlade ide na posao sam, svojim privatnim autom. Prekorači ograničenje, zaustavi ga policija i napiše mu prijavu, a on da ostavku jer ga je sramota da se tako neodgovorno ponašao… U Sloveniji dječiji dodatak 150 evra po djetetu, kod nas ga ni nema… Bolje da ne gledamo u evropu i da nam niko ne priča kako je tamo jer ćemo samo shvatiti koliko smo jadni.

Elem, naš najbolji komšija, o kom počeh da pričam, je izgleda vidio gdje je došao, i da smo mi ovce. Prilagodio se dobro, vidi ovje je normalno da najboljem komšiji budeš žirant pa onda otplaćuješ njegov kredit, ili da te na neki drugi način zaj…. I ne čudi onda da su na mnogim artiklima koji stoje jedni do drugih nazivi slični ili isti, a cijene vrlo različite, i često je teško zaključiti koliko nešto košta bez da se uporede bar-kodovi na artiklu i na cijeni ispod. Ali dobro, pažljiv čovjek pogleda, uporedi i zna. Ali, sada se pojavilo nešto novo! Ne, ne mislim na nove cijene i na pojavu da je sada svaka kupovina (makar i najosnovnijih namirnica) “podobna” za sveti kupon za iduću sedmicu, jer je nemoguće kupiti nešto i imati račun ispod 50KM. Ne mislim ni na začuđena lica bakica koje kupuju pileća krilca i u čudu gledaju moju suprugu koja kupi čitav kilogram fileta, vjerovatno misleći “koji je ova buržuj”. Te stvari je svako mogao primijetiti. Novo je da se komšija odvažio. Na odjelu sa voćem i povrćem ima, između ostalog i krompira. Uvijek bilo. Ima onaj crveni, i bijeli. Crveni je sad “star” pa je cijena oko marku i deset. A bijeli je “mladi” pa je skoro duplo skuplji. I može se natrpati u kesicu, ili ko je baš buržuj, ima vreća od oko 10kg, i jednog i drugog. Crveni je u crvenim vrećama, a bijeli u žutim. No, tu se sada komšija potrudio da nam olakša i napravio i srednja pakovanja, od po 2,5kg. I fino piše ispod boksa u kome su žute vrećice sa mladim krompirom da košta oko 4 i po marke. I logično, kad se pomnoži ona cijena za kilogram – to je to. Ali nema cijene za te crvene vrećice, a baš su zgodne, nema veze kupiću ih, ima cijena ovamo po kilogramu – to je to. No da ipak pogledam bar-kod? Vidim, na crvenoj bar-kod sa one cijene od 4 i po marke. Za 2 i po kile starog krompira koji košta po marku  i deset? Kako to može biti preko 3 marke? Pogledam onu žutu vrećicu sa mladim krompirom, ono na njoj isti bar kod. Pitam prodavačicu jel ovo stari i mladi krompir, kaže da. Pa koliko košta ovaj “stari”, kaže eto cijene. Ali gospođo, ovo je cijena od mladog, zar ne? Kaže, jeste. Pa jel ovo u ovoj vreći mladi krompir? Kaže ona “Sve je to krompir”. Pa dobro, ali jel pošteno prodavati ovaj stari po cijeni mladog? Ona uzvija ramenima i kaže “Ne znam ja, tako je to stiglo, ja samo radim ovdje”…

Vidio komšija od nas 100%. Šta misliš da to napravi gore kod kuće? Pa ne smije ni pomisliti, jer imaju uređenu državu u kojoj se ne smije tako ponašati, potrošač je bog. Ali bog je zato što sam sebe tako vidi, zato je i država takva. Nije nama kriva država, MI SMO KRIVI. Svako treba dvaput da pogleda šta kupuje i po kojoj cijeni. I ne samo to, treba se buniti kada kupi tako nešto, zvati šefa, zvati upravnika. Hoću pismeno izvinjenje! Da nije naš narod stoka, ne bi niko kupio ni jednu vrećicu tog krompira, i propalo bi im sve. Pa se ne bi ponovilo. Rastužuje me što će mnogi da ga kupe, i da ni ne skontaju da su prevareni. Ovo je moj glas upozorenja. Nema na čemu! I “Vidimo se opet” :)

Pravda iz m:tel-a – imate prijatelje :)

Čini se da ovaj sistem “dok ćutiš – j…. ćemo te” funkcioniše i kod nas, jer čak i giganti popuštaju kad se malo pobunimo. Iako sam ja svoju pobunu počeo davno prije Tunisa, Egipta i RS, tek sad je nastupio rezultat:

Odgovor m:tel-a na moj prigovor

Odgovor iz m:tel-a na moj prigovor

Šta da kažem nego – zadovoljan sam. Još da su im telefoni malo jeftiniji nego što su u prodavnicama… možda čak ne raskinem pretplatu jednog dana kada/ako mi firma vrati broj :)

Sad, mnogi će reći da 13 maraka (+PDV) i nije nešto značajno, ali to je 13 maraka (+PDV) koje ja NISAM potrošio a (greškom?) su mi naplaćene. Nije bitna količina, bitan je princip. I bitno je da bar nešto funkcioniše kako treba. Danas m:tel, a sutra će neko dobiti povrat novca za artikal koji je lažno reklamiran ili povrat obaveza koje je platio državi a zatvorio je preduzeće prije isteka uplaćenog perioda ili ima pravo na umanjenje… bitno je suprotstaviti se. Tek kada bude dovoljan broj onih koji se suprotstavljaju, a vjerujem da će ih biti, onda će onome ko odgovara na sve te prigovore dop….. pa će sistem da se popravi tako da se više ne čine te greške.

Update – 2011/02/14 16:10

Pošto sam dobio par pitanja u vezi svoje žalbe, pronašao sam i nju:

Prigovor koji sam poslao u m:tel povodom računa na kom nije obračunan bonus

Prigovor na račun iz m:tel-a