InterRail

InterRail logo

Как я уже говорил, подготовка к поездке идёт полным ходом. Следующая часть — билеты. Если посмотреть на цены европейских перевозчиков (DBahn, SNCF), то можно сразу начинать расстраиваться. Поездка через всю Европу с десятком-другим остановок обойдётся в приличную сумму, размер которой, помимо объективных факторов, может зависеть ещё от расположения планет и угловой скорости вращения сферического коня в вакууме. Но мне повезло набрести на неплохое решение — InterRail. Это такой проездной для практически всех европейских железных и не только дорог. Конечно, цена на него может показаться довольно большой, шутка ли — 509 евро за проездной на 22 дня. Но если посчитать общую стоимость всего, что придётся потратить, если ехать без него, то понимаешь: нужно брать.

В нем, конечно, много особенностей. Например, проездной не оплачивает бронирование места, т. е. если поезд с обязательным бронированием, как французские TGV или немецкие ICE, то придётся доплатить, но обычно эта цена в пределах 4 евро, иногда до 10. Ещё проездным нельзя пользоваться в стране своего проживания, но нас это не касается: в Беларуси InterRail не работает вообще. Зато при необходимости можно бесплатно воспользоваться некоторыми паромами и даже автобусами (карту со всеми действующими маршрутами можно взять у них же на сайте).

Свои впечатления постараюсь описать после поездки. Но, может, кто-нибудь уже пользовался этой услугой и сможет поделиться своим опытом или даже предупредить о возможных подводных камнях? Я был бы весьма признателен.

UPD: Детали и впечатления можно прочитать тут.

Навеяно математикой

Сегодня я сдавал ЦТ по математике. И пока сидел в ожидании начала, вспомнил, как когда-то уже давным-давно сдавал экзамен по математике в школе. И тогда была нам предложена вот такая задача (точных цифр и формулировок я уже не помню).

Есть конус, повернутый основанием вверх, с радиусом основания \(R\) и высотой \(h\). Он на половину своей высоты \(h/2\) заполнен водой. В этот цилиндр погружается шар с радиусом \(r\). Какой объем шара будет погруженным в воду?

Не нашел, чем нарисовать подобную композицию, поэтому вот рисунок от руки:

Рисунок со сферой

Рисунок со сферой

Вышло так, что я до сих пор помню, как на протяжении практически всего экзамена пытался решить эту задачу, и в конце-концов учительница, видя что горит моя (и ее) 10-ка, просто дала мне списать решение из ответов. Каково же было мое удивление, когда я увидел решение. Тогда я пытался сказать, что решение неадекватно и не соответствует задаче, но меня никто не стал слушать.

И вот сейчас я вспомнил про нее и решил спросить у тех, кто что-то помнит в математике и стереометрии. Как бы вы решали подобную задачу? Не кажется ли вам, что ее нельзя решить, используя только школьный курс математики?

Жду комментариев. А потом расскажу о своем решении и решении Минобразования.

Хранение сессии на клиенте

Как вы, должно быть, знаете, хранить пользовательские данные на клиентской стороне плохо: их ведь может подделать злостный хакер. Но сегодня я вам расскажу, как можно безопасно хранить сессионные данные, не волнуясь за их сохранность. Расскажу на примере Snap Framework, на котором и написан этот блог.

Суть метода — шифрование (кто бы мог подумать). Snap для своих сессий использует библиотеку Web.ClientSession, а поэтому что и как обрабатывается можно смело подсмотреть в документации:

Изучая всякие википедии о AES, я не особо понял, какие преимущества нам даст режим CTR в плане безопасности, но судя по описанию коммитов к библиотеке в этом режиме результат получается чуть более компактным и сам алгоритм чуть проще реализовывается. Про любой другой язык я могу сказать, что почти наверняка есть библиотека, которая уже реализует этот алгоритм за вас, так что сильно думать не придется.

Skein — это просто хороший алгоритм хеширования. К сожалению, он не победил в конкуре на замену SHA-2, и название SHA-3 получил другой алгоритм. Поэтому самое время заменить Skein на новоявленный SHA-3 — Keccak.

Ну и напоследок несколько мыслей. Во-первых, этот метод хранения несколько надежнее традиционных, т.к. никакой форс-мажор на сервере не позволит данным потеряться. А если что-нибудь произойдет со стороны клиента и кука исчезнет, то на сервере у нас не останется никаких мусорных данных об уже не существующей сессии. Во-вторых, таким образом не получится хранить большие объемы данных, т.к. размер куки ограничен, да и передача каждый раз пары десятков-сотен килобайт вполне может увеличить нагрузку на сервер. В-третьих, увести сессию можно точно так же, как и обыкновенную, поэтому увеличения безопасности тут не будет.

В общем, идея имеет право на жизнь. Особенно на небольших, как в моем случае, объемах хранимых данных. Лично я храню только одно поле: является ли текущий пользователь админом или нет.

Хозяйке на заметку: чтобы вашу сессию нельзя было увести с помощью JavaScript, добавьте в заголовок Set-Cookie параметр HttpOnly. Куки с таким параметром не появляются в document.cookie.

Осталась одна загадка, связанная с моим сайтом. Кука _session передается как сессионная и должна удаляться с закрытием браузера. Так и происходит в Opera, но не Google Chrome и Firefox. Может есть какая-то стандартизированная или неофициальная фича, которая не дает сессионным кукам удалиться?

Inherited.js design solutions

Итак, я написал некоторое количество тестов, поправил несколько багов. Пришла пора задуматься: что же делать дальше? Как должно выглядеть API будущей библиотеки? Пожалуй, я выложу несколько вариантов своего видения, чтобы вы могли высказать свои за и против. Очень надеюсь на ваши комментарии.

Вариант 1:

NewClass = Class.extend("OptionalDisplayName", {
    constructor: function () {},

    properties: {
        property1: {
            set: function(value) {this.properties_.property1 = value;},
            get: function() {return this.properties_.property1;},
            initial: 'Initial value'
        },
        property2: { // Property with default getter and no setter
            get: true
        }
    },

    statics: {
        staticField1: null,
        staticMethod1: function(arg1) {return arg1;},

        properties: {
            staticProperty1: {get: true, set: true}
        }
    },

    field1: null,
    method1: function() {}
});

NewClass2 = NewClass.extend({
    constructor: function () { this.inherited(); },
    method1: function() { this.inherited(); },
    method2: function() {}
});

Вариант 2:

NewClass = createClass({
    __name__: "OptionalDisplayName",
    constructor: function () {},

    property1: __property__({
        set: function(value) {this.properties_.property1 = value;},
        get: function() {return this.properties_.property1;},
        initial: 'Initial value'
    }),

    property2: __property__({ // Property with default getter and no setter
        get: true
    }),

    staticField1: __static__(null),
    staticMethod1: __static__(function(arg1) {return arg1;}),

    staticProperty1: __staticProperty__({get: true, set: true}),

    field1: null,
    method1: function() {}
});

NewClass2 = createClass({
    constructor: function () { this.inherited(); },
    extend: NewClass,

    method1: function() { this.inherited(); },
    method2: function() {}
});

Какой из вариантов кажется более логичным и удобным? Может, составить какой-то смешанный вариант или у вас есть предложения, кардинально отличающиеся от этих двух? Не стесняемся, пишем комментарии.

Капсула времени

«Капсулу с посланием потомкам заложат в основание белорусской АЭС 3 августа».

Вот допустим, вы решили посадить сына построить дом. И тут вам на голову упало яблоко или кирпич: вы решили заложить в основание послание к потомкам. Что вы там напишете?

Мой вариант: «Молодец! Ты снес к чертям эту халупу. А теперь еще 25 метров вниз и там будет клад. Можешь не благодарить. Твои предки».