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)

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.

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

Jebem ti državu!

Dobijem ti ja uputnicu za ultrazvuk. Čuj dobijem, zaradim – nakon svetog januara dobijem glavobolju (a nikad me glava ne boli), izmjerim tlak kad ono oba preko 100. Odem kod svoje doktorke, dam malo krvi, vagnu me, kaže ti si debeo. Dobro, to sam znao. Kaže izgleda da ti je i jetra masna (ne bi me čudilo), al da mi budemo sigurni da nije šta drugo, aj ti na ultrazvuk. I tako ja dobijem tu uputnicu.
Naivan, kao i mnoga čeljad koja hoće da isprave krivu drinu i da doprinesu da ovaj sistem bude bar malo bolji, naručiću se ja gore na Paprikovac. Kontam, bolje nek oni nešto rade, slabe su im plate, a i uslovi za rad. Nazovem klinički centar, tu mi dadnu jedan broj telefona. Nazovem taj broj, javi se teta kaže, eee mi smo u istoj zgradi al nije ovaj broj, zovi ovaj sad… (a nemate centralu???), al dobro, nazovem ja taj treći, opet se javi treća teta, kaže e to je to. Super, reko’ ja bih da se naručim na ultrazvuk. E, to ne može, evo već je 16h, nema sad ovde više nikog, sutra ti nazovi, al prije podne. Nazovem ja sutra, kažem tako, kaže meni četvrta teta ima termin za desetak dana (o, pa izgleda da oni imaju sasvim dovoljno pacijenata???), reko dobro, može tad, kaže ujutro u 8:00, nemoj doručkovati.
Dođe i taj dan, ja ustanem, spremim se, ne doručkujem i zapalim gore. Malo gužva usput, a malo (mnooooogo) i na parkingu, al stignem ja tamo, zakasnim samo 2 minuta. Predam knjižicu i uputnicu, i kaže meni teta 15 maraka košta pregled. Reko dobro, vadim pare, i kontam, a koliko bi tek koštao da mi ne odbija fond svaki mjesec 200-300 maraka od plate? Kaže meni teta, u stvari aj se ti prvo pregledaj pa ćeš onda da platiš (k’o da je znala…), idi gore do kraja hodnika pa lijevo.
Odem ja tamo, ono tu u tom hodniku rentgen, konsultacije za dojku, mamografija i ultrazvuk. Čeka tu masa naroda, al malo bolje pogledam većinom neko doveo ženu, neko majku, pitam jel čeka neko ultrazvuk, ono niko, svi gore na konsultacije i mamografiju. Dobro, pokucam uđem u ultrazvuk, ono nema nikog. Kaže čovjek ispred, maloprije izađe sestra. Sačekam ja još malo, nema nikog, a ja nervozan kad ne doručkujem. Vratim se tamo na recepciju, kažem nema nikoga tamo, odgovara mi teta, eto sad je sestra otišla. Ja opet tamo, stanem malo, još malo, izlazi sestra i kaže sjedi dečko i ode negdje. Ja kontam šta ja čekam ovdje, više me košta ovo vrijeme nego da platim sve što treba u privatnoj klinici, i odlučim, ode ja. Vratim se na recepciju, reko tako, sad je gotovo pola devet, ja da sam znao da je situacija ovakva, ja se gospođo ne bi ni naručivao. Kasnim na posao, treba li da vam šta platim? Kaže ona ne trebaš ništa, samo, jel vam dala sestra vašu knjižicu i uputnicu? Reko’ nije, jel mogu doći po to oko 17h? Kaže ajoj ne može, ček sad ću ja nju zvati. Nazove, čeka, niko se ne javlja, nazove drugi broj, treći, kaže momak mora na posao može li dobiti knjižicu, ova joj odgovara “šta bi mu ja”. Kaže meni ta teta tako je, doktor će doći sigurno do 11, pa ako može da tad dođeš ponovo, biće i knjižica? Hvala vam gospođo doviđenja! Donikad!
Napustio ja i bolnicu, i brdo, i kontam, učini mi žena uslugu. Ovdje, ko ima knjižicu ne može se osjećati bolje. A, ako nije crno, onda je bijelo. Evo ja se već osjećam bolje bez svoje. Sad bar znam na čemu sam, i mogu bar u to da se uzdam.

Omlet sa sirom i slaninom

Ponovo pišem recept, ništa ukusniji od prošlog (iako neki sumnjaju u moje prošlo remek djelo :) ), ali ovoga puta malo sofisticiraniji. Vrlo jednostavno jelo, idealno za one koji ne znaju ama baš ništa u kuhinji :)

Za početak, potrebni resursi:

  • 2 jaja (kokošijih)
  • 200g svježeg sira
  • komad pancete (slanine)
  • list gauda sira
  • masline
  • ~ 15 minuta vremena

Algoritam:

  1. Staviti tavu da se grije sa par kapi ulja
  2. Razmutiti jaja (u tanjiru ili sl.)
  3. Ako se tava ugrijala, dodati jaja u tavu,
    u suprotnom ih dodati čim se ugrije :)
    (drugi thread radi dalje, ovaj ovde čeka
    i provjerava)
  4. Isjeći slaninu na sitne komadiće
  5. Isjeći masline na sitne komadiće
  6. Čim jaja počnu da koagulišu od
    temperature, dodati isjeckanu slaninu
    i masline
  7. Namazati svježi sir na gauda sir
  8. Presjeći gauda po pola, pa ga staviti
    na jaja
  9. Kada se gauda počne topiti, presaviti
    omlet, peći još minut i skinuti
  10. Jesti!
Jaja sa slaninom i maslinama

6. Jaja sa slaninom i maslinama

Svježi na gauda siru

7. Svježi na gauda siru

Sir dodan na omlet

8. Sir dodan na omlet


Omlet sa sirom i slaninom
Omlet sa sirom i slaninom

Fix selected tab in SharePoint top links menu

Fastest way to accomplish this is to use jquery! :)

function fixTabs(){
    $.each($(".customNavTabActive"), function() {
        $(this).removeClass("customNavTabActive");
        $(this).parentsUntil("table").each(function() {
            $(this).removeClass("customNavTabActive");
        });
    });
    $.each($("a.customNavTab"), function() {
        if (this.href == document.location.href || this.href + "/default.aspx" == document.location.href) {
            $(this).parent("td").addClass("customNavTabActive");
        }
    });
}

Update: I have improved this code a little bit :)

function fixTabs(){
    var normalNavTavCss = "customNavTab";
    var firstCellActiveCss = "customNavTabActive";
    var firstCellCss = "customNavTab";
    var lastCellActiveCss = "customNavTabActive";
    var lastCellCss = "customNavTab";
    var cellActiveCss = "customNavTabActive";
    $.each($("." + cellActiveCss), function() {
        $(this).removeClass(cellActiveCss);
        $(this).parentsUntil("table").each(function() {
        $(this).removeClass(cellActiveCss);
        });
    });
    var lastCell;
    var lastCellSelected;
    $.each($("." + normalNavTavCss + " a"), function(i) {
        lastCell = $(this).parent("td");
        var location = document.location.href.replace("/default.aspx", "");
        var link = this.href.replace("/default.aspx", "");
        lastCellSelected = (link == location || location.indexOf(link) &gt; -1);
        if (lastCellSelected) {
            if (i == 0) {
                lastCell.addClass(firstCellActiveCss);
            }
            else {
                lastCell.addClass(cellActiveCss);
            }
        }
        else if (i == 0) {
            lastCell.addClass(firstCellCss);
        }
    });
    if (lastCellSelected) {
        lastCell.removeClass(cellActiveCss);
        lastCell.removeClass(firstCellActiveCss);
        lastCell.addClass(lastCellActiveCss);
    }
    else {
        lastCell.addClass(lastCellCss);
    }
}