Cascading select lists with KnockoutJS

HTML

<script src="https://dl.dropbox.com/u/6378864/countries.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<p>Region:
    <select data-bind="options: regions, optionsText: 'Name', optionsValue: 'ID', value: selectedRegion"></select>
</p>
<p data-bind="visible: selectedRegion">Country:
    <select data-bind="options: countries, optionsText: 'Name', optionsValue: 'ID', value: selectedCountry"></select>
</p>
<p data-bind="visible: hasCity">City:
    <select data-bind="options: cities, optionsText: 'Name', optionsValue: 'ID', value: selectedCity"></select>
</p>

JavaScript

(function ($, ko, newData) {

    // объявляем нашу viewModel
    var ViewModel = function () {

        this.selectedRegion = ko.observable();
        this.selectedCountry = ko.observable();
        this.selectedCity = ko.observable();
        this.hasCity = ko.observable(false);

        // как только список выше поменялся, дропаем выбранные значения
        this.selectedRegion.subscribe(function () {
            this.selectedCountry(undefined);
        }, this);

        this.selectedCountry.subscribe(function () {
            this.selectedCity(undefined);
        }, this);

        this.regions = asyncComputed(function () {
            return fakeDataProvider('regions');
        }, this);

        this.countries = asyncComputed(function () {
            return fakeDataProvider('countries', this.selectedRegion());
        }, this);

        this.cities = asyncComputed(function () {
            return fakeDataProvider('cities', this.selectedRegion(), this.selectedCountry());
        }, this);
        
        this.cities.subscribe(function () {
            this.hasCity(this.cities().length !== 0);
        }, this);

    };

    var model = new ViewModel();
    ko.applyBindings(model);

    // сервисный код

    // Обертка для работы с jQuery реализацией deferred объектов
    // подробнее можно почитать в доках
    // http://api.jquery.com/category/deferred-object/
    // https://github.com/knockout/knockout/wiki/asynchronous-dependent-observables#dependent-observables-that-return-deferred-results
    function asyncComputed(evaluator, owner) {
        var result = ko.observable();

        ko.computed(function() {
            evaluator.call(owner).done(result);
        });

        return result;
    }

    // просто так... потому что я так хочу
    function cleanUpList(list) {
        return list.map(function (item) {
            return {
                ID: item.ID,
                Name: item.Name
            };
        });
    }

    // утилитка для поиска по...