Sunday, December 26, 2010

О маразме некоторых преподавателей информатики

СПбГУ. Специальность "Прикладная математика и информатика", 1 курс. Лекции читает некто К. Для пущей определённости могу заметить, что его фамилия и слово "кретин" различаются лишь 2-й и 3-й буквами.

Итак, дело дошло до зачёта. Мне там выпал билетик про каноническую форму перестановок. Программу этот <censored> принял, но его придирки были фееричненькие. Там критиковать их было, наверное, бессмысленно (всё равно такие не лечатся, да и вообще — на зачёте себе дороже), так что раскритикую здесь. В пух и прах.

Friday, December 24, 2010

Sort of introduction to J.

Firstly, what is J? Yeah, it's a letter in English alphabet. But other than that, J is a programming language. As I suppose, this is a language for lazy mathematicians—so hopelessly lazy that they don't want to type long function names. Thus it's VERY concise language.

Let's consider just one example. Suppose we wanna investigate the sequence of first digits of powers of 2. (1,2,4,8,16,32,64,128,256,...) The question is: what's the frequency of the digit 7? (You can find via search engines several versions of this problem: this, for example.)
Using J, we can find (well, estimate) the answer in one line:
(+%~(#&I.&(7=<.&(10^1|(10^.2)&*&i.)))) 1000000
0.05799
The exact answer is
.
That follows from the equidistribution theorem.

So, what does this mess of symbols mean?

Monday, December 20, 2010

GPS & Ruby: dealing with performance bottlenecks

About a month ago, I posted about how to convert pure GPS data into Ruby class instances. But as it turned out this converting in general takes more time than processing the data.

For tests I've used 2.7MB .nmea file. It contains about 5 thousand GPRMC sentences from which about 3 thousand contain useful information.

The first version of readNMEA function takes about 0.87 seconds (on my Asus EeePC 1001P) to make an array of GPRMC class instances. How can we improve that?

Firstly, access to the elements of an array (by index) is faster than access to the elements of a hash (by key). Thus using old-style regular expressions decreases the time from 0.87 to 0.72 seconds:

Monday, December 13, 2010

И ещё чуть-чуть о программизме.

Ну вот, за две недели нарешал сотню задач на projecteuler.net на Common LISP-е. Вообще говоря, таким способом изучить все возможности языка оказалось совершенно нереально. Может быть, стоит попробовать pythonchallenge попроходить. Оно, конечно, для питонеров, ну да и то лучше. Потому как для projecteuler не требуется ничего, кроме массивов, стеков, хэшей и соображающей головы, набитой уймой математических знаний. К программированию это имеет мало отношения.

Вот. Теперь немного о самом LISP. При исключительно императивном программировании код выглядит... эм... не то чтобы ужасно, но непомерно раздуто. Скажем, доступ к i-му элементу вектора vec записывается как (aref vec i) , а присваивание ему значения a — (setf (aref vec i) a). Однако не стоит думать, что это сказывается на скорости программирования. Отнюдь! Дело в том, что в си-подобных языках при стандартной постановке пальцев очень много работы отводится мизинцу: доступ к элементу массива — [ ], блок кода — {}, присваивание — =, разделение операторов — ; . Поэтому я всегда использую нечто нестандартное, и скорость печати вследствие этого снижается. В LISP же в основном используются только латинские буквы, дефис и чёртова уйма скобочек, так что никакой особой распальцовки не требуется.

А может, я отстал от жизни, и у сегодняшних "программистов" (да-да, в кавычках) наипопулярнейшей комбинацией клавиш является Ctrl-Space. (Об этом меня заставил задуматься тот факт, что вчера на турнире по программированию я решил задачу на Java, не писав на ней до этого ни разу и пользуясь лишь автодополнением, предоставляемым Eclipse.)
Помнится, как-то раз попал в плацкартном вагоне в одно купе с одним
90;аким "программистом". Тот кодил в какой-то конторе уже лет 5 (на C#, ЕМНИП) и тем не менее, как выяснилось, не знал о существовании Python, который сейчас, в общем-то, весьма активно используется в веб-разработке. И при этом (NB!) жаловался, что наскучила ему разработка, понимаешь. Как будто втемяшили себе в голову, что окромя мейнстримовых языков (то бишь "святой троицы" C++, C#, Java) и не существует ничего =/ Брр.

Tuesday, December 7, 2010

clisp && sbcl

Всё-таки множество интерпретаторов/компиляторов языка — это замечательно.

Изначально я установил только CLISP и довольно долго был уверен, что этого мне будет достаточно. Ан нет: эта штука генерирует весьма тормозной байткод. Для работы в интерактивном режиме лучше CLISP ничего не придумаешь, а вот для исполнения программ, связанных с перебором... это полная жуть. Казалось бы, чего тут такого — перебрать все перестановки 10 элементов? Каких-то там 3628800 итераций, фи. А на CLISP этот перебор отнял секунд 15 времени (и это при том, что я несколько советов из книжки "ANSI Common LISP" для оптимизации заюзал). Жуть.

В общем, поставил я SBCL. Результаты превзошли все ожидания: большинство написанных мной функций стали выполняться быстрее раз эдак в 10-15 и теперь по скорости сравнимы с сишным кодом. Единственное, что пришлось поменять в коде, так это вызовы функций, связанных с регулярными выражениями (установил cl-ppcre). Ну оно и к лучшему, PCRE рулят =) (В CLISP встроены только POSIX-регулярки, насколько я понял.)

Monday, December 6, 2010

В продолжение обзора ЯП

К чему приходит тот, кого во всех языках достаёт ограниченность синтаксиса? Правильно, к Common Lisp-у =) Единственное, чего я опасаюсь, так это того, что буду строчить на нём всякую невменяемую хрень, потому что то, что язык позволяет выразить на нём всё что вздумается, не всегда полезно. Потому что вздуматься может всякое. Вот сегодняшний пример: надо было цепную дробь вычислить (на projecteuler.net зарегистрировался ради того, чтобы было на чём новый язык поизучать). Взбрела в голову шальная мысль: а что, если не сразу вычислять, а сперва выражение составить? Ну и набыдлокодил в итоге:

(defun generate-continued-fraction (lst)
  (loop with sexp = (list '+ (first lst) (list '/ 1 (second lst)))
        for num in (rest (rest lst)) do
        (loop for to-change = sexp then (third to-change)
              until (atom (third to-change))
              finally (setf (third to-change)
                            (list '+ (third to-change) (list '/ 1 num))))
        finally (return sexp)))

Ну а чё, работает же даже:

(generate-continued-fraction '(2 1 2 1 1 4 1))
(+ 2 (/ 1 (+ 1 (/ 1 (+ 2 (/ 1 (+ 1 (/ 1 (+ 1 (/ 1 (+ 4 (/ 1 1))))))))))))

Но вот о производительности такой функции лучше не думать, особенно с учётом того, что потом ещё и eval вызывается. На любом обычном языке мне б и в голову, наверное, не взбрело подобный бред писать, написал бы что-нибудь навроде
(defun continued-fraction (lst)
  (loop with rlst = (reverse lst)
        with frac = (pop rlst)
        for num in rlst do
          (setf frac (+ num (/ 1 frac)))
        finally (return frac)))

Так что надо порядок в голове наводить... %-)

Saturday, November 27, 2010

Почему не следует изучать OCaml.

Ответ простой: потому что этот язык — полное дерьмо! Подробно о том, почему это так, можете почитать в статье "OCaml Language Sucks". Я же отмечу здесь лишь то, что внушает особое отвращение лично мне:

1) отсутствие ad-hoc полиморфизма. Если вы (вдруг) не понимаете сути этого словосочетания, поясняю: представьте себе, что vkontakte.ru писался бы изначально на OCaml-е. И был бы там какой-нибудь счётчик типа int — а хер ли, любительский же проект, каким фигом он там зашкалит за два миллиарда? А вот когда он приблизится к своему пределу, окажется, что просто int на int64 не поменяешь: надо рефакторить всё к чёртовой матери, потому что конструкция a := !a + 1 уже не будет работать, надо писать a := Int64.add !a 1L — потому что функция (+) определена только для int.

2) примерно такие же пироги с массивами и строками: обращение к элементу массива — a.(i), к элементу строки — s.[i] — то бишь по гибкости OCaml даже C++ уступает, в котором хоть шаблоны есть. Для моей функции может быть неважно, массив ей дают или строку: один хер последовательность ведь! Мне что, два варианта писать, что ли?

3) из отсутствия нормального полиморфизма напрямую следует убогость всей стандартной библиотеки: скажем, String.concat для List-ов существует, а для Array-ев — чёрта с два, либо свой велосипед пиши, либо перегоняй Array в List (за O(длина_массива), разумеется). П***ец, одним словом.

Tuesday, November 23, 2010

Нумерология

Недавно заметил одну забавную штуку.

(Пояснение для нематмеховцев)
Единственный некоммерческий автобус, на котором можно доехать от студгородка до метро без пересадок — 210-й. Ходит он, между прочим, от Кировского завода (тут ещё такое совпадение, что я родом из Кирова, но это не особо удивляет, ибо от коммуняг чёртова уйма одинаковых названий осталась).

Так вот, типичный путь от зданий универа на Ваське до этого самого Кировского завода таков: 1 станция по 3-й линии, потом 2 станции по 2-й линии и 3 станции по 1-й линии. Адовая симметрия. А потом в идеале оттуда на 210-м до общаги (тоже: 2-1-0), но это редко получается, чаще приходится на 200-м и 359-м ездить =(

Sunday, November 21, 2010

Theorems graph.

Now that almost everybody's heard about the mind map concept, it seems a little weird to me that I wasn't able to find via Google anything like that:
In my opinion, it's really fucking convenient to be able to answer the question "for what the hell do I need this theorem?!" at a glance (In fact, this question is just a rephrasing of "why the hell should I know its proof?!": you know about the lazy evaluation concept, don't you?). It's especially helpful right before exams (and especially for me 'cause I've got the damn habit to devote no more than three days to an exam preparation ^____^).

By the way, GraphViz tools were used to plot this graph. If you wanna look at the source or modify it, you can download it from here.

And yeah, for the sake of showing you how devilishly horrible automatically generated graphs might be: http://llvm.org/docs/UsingLibraries.html

Saturday, November 13, 2010

GPS & Ruby: Introduction

This is the beginning of post series devoted to playing with data obtained by a GPS receiver. Here I assume that you are familiar with basic concepts of object-oriented programming and also assume that you don't know Ruby (honestly, neither do I, but that's gonna change eventually). So don't you worry, there will be a few comments about the code ;-)

In this post I'm gonna acquaint you with the NMEA format used in GPS receivers. Actually, you can read about that in details here, for example. In fact, it's a proprietary one but it's too old to not to be reverse-engineered :-)

We're gonna use just one type of NMEA sentence, namely GPRMC.

Friday, November 12, 2010

just to clarify

From now on I'm gonna write posts, which might be in interest not only for Russians, in English.

There're several (and at least three worth to mention) reasons to proceed in that way. Firstly, because such posts are gonna appear soon (frankly speaking, I don't think anything I've written until now could be ascribed to this category). Next, it seems to me like a chance to improve my English and at the same time to reach a wider audience (yep, I'm damn selfish). And last but not least — who knows, maybe my posts will be really helpful/interesting for some people? :-)

Thursday, November 11, 2010

Digma M1

Прикупил вот себе недавно GPS-приёмник Digma M1 - дёшево и сердито (за 1260р.).

Из минусов можно отметить разве что то, что нет работы по Bluetooth, присоединяется только по USB (ну а хрен ли вы хотели от столь дешёвой шняги? :-) )
Из плюсов — внутри всобачен нехилый магнит, так что шнягу можно прикрепить к любому железному элементу одежды/сумки/whatever.

Немного о настройке: чтобы устройство работало под Linux, надо лишь настроить создаваемый системой последовательный порт (у меня это /dev/ttyUSB0). Если ничего подобного при подключении не появляется — google pl2303. Так вот, надо поставить minicom и там, поковырявшись в настройках, выставить скорость 4800 бод и сохранить настройки (уж в псевдографическом интерфейсе разобраться можно даже без мануала, я гарантирую это). В общем-то всё, должно работать. (При успешной настройке команда "sudo cat /dev/ttyUSB0" должна выводить нечто читабельное. Чтобы читабельное стало ещё и осмысленным, нужно вытащить девайс на открытое пространство и подождать несколько минут, пока ищутся спутники.)

Saturday, November 6, 2010

D.

Занялся вот серьёзным изучением языка D, скачав с rutracker.org вышедшую в июне книжку А. Александреску "The D Programming Language" (рекомендую к прочтению хотя бы ради того, чтобы оценить чувство юмора автора).

Язык сам по себе прекрасен. Я недостатков для себя не нашёл, разве что отсутствие чего-нибудь вроде C#-ского "implicit operator". То есть для написания какой-нибудь абстрактной хрени навроде реализации арифметики поля частных над кольцом гауссовых целых чисел — самое то.

Но вот как только дело доходит до сугубо прикладных задач, начинается лютый гемор. Потому что, скажем, нет нормальных биндингов к SQLite или хотя б PostgreSQL. Дико. Что ужаснуло, так это то, что язык per se содержит все новомодные штуковины (delegates, lambda functions, UTF-8/16/32 строки, ассоциативные массивы, slices, ...), а вот библиотеки, к нему прилагающиеся, за временем явно не поспевают.

Tuesday, October 26, 2010

I'll be back...

...to C++. Как только его стандартная библиотека станет более самодостаточной.

C# меня ужасает своей негибкостью.

Во-первых, нет никакого аналога привычному scanf (или cin - кому как), и массивы приходится считывать какими-то извращенскими методами (разбивание строки методом Split и последующее конвертирование элементов массива строк в массив того_что_мне_нужно. То есть - лишняя память и угрызения совести, потому что можно же сделать лучше, чёрт возьми...)

Но это ещё цветочки.

Во-вторых, какая-то нахальная политика в плане перегрузки операторов. А именно: я не могу перегрузить operator+=, operator-= и всё в таком духе. Видите ли, компилятор позаботится, применив перегруженный operator+/operator-. Нет, ну нихера себе забота! operator+ создаёт новый объект, который никому нафиг не сдался: если операцию можно проводить in-place, то это нехилая потеря производительности. И это не пустая болтология, человек вот по этой ссылке утверждает, что падение в скорости работы доходило до 50 раз!!! Дикость. И самая жесть в том, что никто это менять не собирается, судя по ответу Microsoft в том треде. А дело было ещё в 2005 году.

Sunday, October 24, 2010

Выбор между Java и C#

Как ни странно, С++ мне уже не хватает. Казалось бы, нет более гибкого языка. Но...

Для решения всяких мелких (а порой и не очень) прикладных задач я обычно использую Python/Ruby. Однако после поступления в универ понадобилось нечто среднее между ними и С++, ибо:
1) в компьютерных классах попросту нет этих самых Python/Ruby;
2) всё-таки нужна производительность. Увы, скриптовые языки в этом плане от С++ отстают на порядок. Основной помехой в этом, наверное, является. концепция "всё что угодно есть объект". Теоретически — это изумительно: ах, вы только поглядите, у числа "2" вон сколько методов! А в Ruby on Rails и вовсе чёрт-те что можно творить, скажем, 2.hours вернёт 7200, а 7200.from_now вернёт время, которое будет через два часа. Так что вообще можно писать 2.hours.from_now. Изящно? А то! Но когда эти числа-объекты используются при перемножении матриц, весь их объектный характер нахрен никому не сдался, а лишние память и время жрутся.

А отчего же не продолжать использовать С++? Дело в том, что:
1) его стандартная библиотека содержит мало что. После использования Python кажется, что там вообще почти ничего нету. Java в этом плане великолепна.
2) непонятно, когда наконец выйдет новый стандарт, содержащий в себе кучу вкусностей — C++0x. А я тащусь от лямбда-функций, замыканий и всего такого. Кроме того, в стандарте С++ нет такой стандартнейшей (сорри за каламбур) вещи, как Dictionary (хэш-таблица). И меня убивает, когда только из-за этого к алгоритму добавляется логарифмический множитель.

Возможные варианты перехода — С#, Java, Delphi. Последний отпадает моментально, потому что... Да хотя бы потому, что мне лень эти проклятые begin-end-ы писать. Так что остаются первые два.

Так вот, результаты сравнения Java и C# (большое спасибо английской Википедии):
Java привлекает своей офигенной по размеру стандартной библиотекой. Прям как Python, идущий "с батарейками". Также здорово, что имена методов пишутся с маленькой буквы (я ж лентяй, шифт нажимать влом). Т.е. System.out.println мне нравится куда больше, чем System.Console.WriteLine.
Однако C# содержит вещи, без которых кодинг — тоска зелёная. Как можно жить без operator overloading, вы мне скажите, а?! Среди приятных вещей (в отличие от Java) также есть properties (ням-ням-ням!), лямбда-функции и замыкания, а также комплексные числа (начиная с .NET 4.0).

Так что, несмотря на всю свою нелюбовь к Microsoft и .NET, я пришёл к выводу, что пришла пора учить C#. Вот так вот.

Sunday, October 17, 2010

[c++] век живи — век учись...

Сколько себя помню, всегда писал в циклах for постинкрементный оператор. А вот оказывается, лучше использовать преинкремент и предекремент:
//make all characters in the list uppercase
list::iterator pos;
for (pos = coll.begin(); pos != coll.end(); ++pos) {
     *pos = toupper(*pos);
}
Note that the preincrement operator (prefix ++) is used here. This is because it might have better performance than the postincrement operator. The latter involves a temporary object because it must return the old position of the iterator. For this reason, it generally is best to prefer ++pos over pos++.
Так-то!

Friday, September 24, 2010

О достаточности буквы ы и <Shift>

Вот некоторые говорят, что общение посредством одной буквы "ы" невозможно. Может, оно и так. Но если добавить хоть ещё один символ (скажем, "Ы") в алфавит, то вполне достаточно: действительно, отобразим {(a₁, a₂, ..., a₈) | a_i ∊ {'ы', 'Ы'} } в, скажем, набор cp1251 (однобайтная кодировка) таким образом: i-й бит нашего байта равен 0, если a_i = 'ы', и 1 в противном случае. Очевидно, что такое отображение биективно. (Если кому-то так же, как мне, не хватает cp1251, используйте просто отображение {'ы','Ы'} → {0,1} и UTF-8. Идея тут ясна.)


...теперь про изображения. Конечно, можно и тупо все байты в кучу 'ы' и 'Ы' перегнать, но это же так скучно, правда?..
Так что предлагаю рассмотреть следующий язык для рисования чёрно-белых изображений. Представим себе черепашку (как в Лого Мирах, лол), которая начинает из верхнего левого угла картинки идти вниз (для определённости) с поднятым пером. Введём следующие команды:

ы - поворот против часовой стрелки на 90°
Ы - прохождение на один пиксел в текущем направлении.

Теперь смотрите. Если мы натыкаемся на "ыыыы" в исходной строке (естественно, окружённую не 'ы'), будем считать это командой "инвертировать состояние пера": действительно, поворот на 360° — совершенно бессмысленное занятие, так что лучше бы эта подпоследовательность что-нибудь значила.

Аналогично, бессмысленную команду "ыыыыыыыы" задействуем в качестве команды окончания рисунка.
Т.е.: если менее 4 'ы' подряд — всё ОК, 4 'ы' - инвертирование пера, от 4 до 7 'ы' включительно - инвертирование пера + поворот (заметим, что поскольку поворот не меняет состояние рисунка, эти два действия можно выполнять в любой последовательности, так что двусмысленность отсутствует), 8 'ы' и более - завершаем выполнение программы.

*фух, выдохнул*

Sunday, September 5, 2010

[Real World Haskell] Йоу, я осилил третью главу =)

(Если кто не знает, "Real World Haskell" — это название одной очумительной книжки).

На последнее задание (13-е) угробил несколько часов. Требовалось написать алгоритм построения выпуклой оболочки по Грэхему. Код жуткий, но работает =)))

import Data.List (sortBy, minimumBy)

-- 10 --
data Direction = DirLeft | DirRight | DirStraight
                deriving (Eq, Show)
data Point = Point {
              xcoord :: Double,
              ycoord :: Double
              } deriving (Eq, Show)
minus (Point x1 y1) (Point x2 y2) = Point (x1-x2) (y1-y2)
cross (Point x1 y1) (Point x2 y2) = x1*y2 - x2*y1
-- 11 --
dirTriple :: Point -> Point -> Point -> Direction
dirTriple a b c 
          | crossprod < 0 = DirRight
          | crossprod > 0 = DirLeft
          | otherwise     = DirStraight
          where crossprod = (b `minus` a) `cross` (c `minus` b)
-- 12 --
dirListTriple :: [Point] -> [Direction]
dirListTriple (x:y:z:xs) = [dirTriple x y z] ++ dirListTriple (y:z:xs)
dirListTriple _ = []

-- 13 --
comparePointsByPos (Point x1 y1) (Point x2 y2)
        | cmpYResult == EQ = compare x1 x2
        | otherwise        = cmpYResult
        where cmpYResult = compare y1 y2

mostBottomLeft x = minimumBy comparePointsByPos x

sortByAngle p ps = p: (sortBy cmpByAngle (filter isNotMin ps)) ++ [p]
        where findCos x = (xcoord x - xcoord p)/(sqrt (distSqPoints p x))
              distSqPoints (Point x1 y1) (Point x2 y2) = (x2-x1)**2+(y2-y1)**2
              isNotMin x = x/=p
              cmpByAngle a b
                    | cmpCosRes /= EQ = cmpCosRes
                    | otherwise  = compare (distSqPoints p a) (distSqPoints p b)
                    where cmpCosRes = compare (findCos b) (findCos a)

sortPoints ps = sortByAngle p ps
        where p = mostBottomLeft ps

convexHull a = init (reverse (__convexHull (reverse (take 2 zs)) (drop 2 zs)))
        where zs = sortPoints a
              __convexHull (t1:t2:ts) (x:xs) 
                  | dirTriple t2 t1 x == DirRight = __convexHull (t2:ts) (x:xs)
                  | otherwise = __convexHull (x:t1:t2:ts) xs
              __convexHull ys _ = ys 
--------------------------------------------------------------------------------
plist = [(Point 100 50), (Point 110 70), (Point 110 40), 
         (Point 112 55), (Point 120 100), (Point 125 70),
         (Point 128 10), (Point 129 50), (Point 139 91),
         (Point 140 45), (Point 145 75), (Point 150 60),
         (Point 160 35), (Point 165 45), (Point 170 45),
         (Point 180 60), (Point 200 30), (Point 210 55)]

main = putStr (show (convexHull plist))

Monday, August 16, 2010

CHDK — "прокачиваем" Canon-овские мыльницы.



CHDK == Canon Hacker Development Kit. Суть этой приблуды в том, чтобы обеспечить доступ ко всем возможным настройкам фотоаппарата.

Если с английским совсем плохо — зайдите на chdk.clan.su Официальная же wiki находится по адресу chdk.wikia.com

Преимущества следующие:

  • a. Enhanced ways of recording images - you can capture still pictures in RAW format (as well as JPEG), and for video images you can have increased recording time and length (1 hour or 2 GB), and a greatly increased range of compression options.
  • b. Additional data displays on the LCD screen - histogram, battery life indicator, depth of field, and many more.
  • c. Additional photographic settings that are not available on the camera by itself - longer exposure times (up to 65 seconds), faster shutter speeds (1/25,000 sec, and faster in some cases), automatic bracketing of exposure, etc.
  • d. The ability for the camera to run programs ('scripts', written in a micro-version of the BASIC language) stored on the memory card - these programs allow you to set the camera to perform a sequence of operations under the control of the program. For example, a camera can be programmed to take multiple pictures for focus bracketing, or take a picture when it detects that something in the field of view moves or changes brightness.
  • e. The ability to take a picture, or start a program on the memory card, by sending a signal into the USB port - you can use the USB cable to take a picture remotely.
  • f. The ability to do a number of other more useful (and fun) things, such as act as a mini file browser for the memory card, let you play games on the LCD screen, etc.

Для автоматической загрузки со своей старенькой 16GB SDHC воспользовался этой инструкцией.

Русский язык во всех новых менюшках, между прочим, поддерживается, так что тем, кто не в ладах с английским, бояться нечего =)

Friday, July 23, 2010

[жж] поступил

В СПбГУ на матмех. Чему и рад вполне.

Wednesday, July 21, 2010

[небольшой хак] WiFi в МФТИ

Довелось тут пожить пару неделек в МФТИ. Доступ к инету там осуществляется авторизацией посредством веб-формы на https://wlan.mipt.ru. Логин и пароль можно получить, заключив договор c провайдером.


Однако можно получить инет и без всяких логинов и паролей. Логика следующая: поскольку соединение как-то должно держаться (причём по всем протоколам, а не только в браузере), юзера как-то нужно запоминать. Единственный возможный вариант — идентифицировать клиента по его MAC-адресу, не так ли?


Вроде бы в таком подходе нет ничего плохого, но на самом деле есть один нюанс: MAC-адреса wifi-адаптеров можно выставлять программно (например, в linux это делается примерно так: ifconfig wlan0 hw ether XX:XX:XX:XX:XX:XX).


Так вот, как выяснилось, сессия сохраняется в течение некоторого времени, даже если клиент вышел из сети. Поэтому (упрощённый) алгоритм действий таков:
1) сканим сетку nmap-ом с ключом -sP
2) повторяем п. 1) спустя несколько минут
3) смотрим разницу результатов (для этого существуют такие вещи, как diff)
4) видим, какие MAC-и вышли из сети, и живёхонько меняем MAC-адрес своего адаптера. Если тот юзер был залогинен на wlan.mipt.ru, у вас тоже будет инет.


Впрочем, честно говоря, для инета лучше использовать телефон. А описанный выше метод полезен лишь тогда, когда надо что-то слить из локалки (в которой, btw, много всякого добра валяется).

Tuesday, June 22, 2010

Need for s... tatistics.

Почему-то всегда хочется добыть максимум возможной информации из того, что доступно. Поясню на примере.

Взять, скажем, сайт edu-43.kirov.ru.
Что доступно извне? Изображения с гистограммами, отображающими количество сдавших в каждой из школ (от 0 до 9 вкл., 10-19 и т.д.; 100-балльники занимают отдельный столбик).

Пример:


Чего хочется? Ну, например, список школ, в которых есть люди, написавшие от 80 до 100 баллов, м? Любопытно же, какие школы рулят в плане конкретного предмета.


На самом деле скрипт пишется просто, единственной загвоздкой было то, как узнать, наличествует ли столбик в конкретной позиции.
Наиболее адекватным решением выглядит такое: смотрим цвет некоторого конкретного пиксела картинки, который однозначно соответствует наличию столбца. Как нетрудно догадаться, такими пикселами являются те, которые расположены прямо над чёрной линией горизонтальной оси.
Для простоты конвертируем png в bmp, у него спецификация крайне проста, из-за чего можно выяснить то, что нужно, не используя никаких библиотек для работы с изображениями (тупо вычисляем номер нужного нам байта).
Если кому интересно, исходник выложил здесь. Там есть ещё что допиливать (например, выдача названий ОУ вместо их кодов), но мне уже лень.
Пример работы для такого предмета, как биология:
100 points:
"940018"

90 and more points:
"860009, 940030, 940064"

80 and more points:
"520001, 530010, 550011, 550013, 560001, 570010, 590008, 590009, 600003, 610011, 630009, 640007, 660003, 660004, 670001, 670007, 670008, 690004, 710002, 720014, 740006, 770001, 810006, 840007, 850006, 850017, 870001, 870004, 880007, 880010, 900001, 900003, 910006, 910007, 910008, 920003, 930004, 930007, 940012, 940023, 940036, 940037, 940040, 940052, 940056, 940067, 940069, 940076, 940210"
Отталкиваясь от этого, можно и немного дальше проанализировать. Скажем, 940018 — это лицей №21, там учится некая Ксюша, которая на всерос по биологии ездила (между прочим, призёр), так что ежу понятно, у кого 100 баллов...


P.S.: что-то как-то сумбурненько получилось, ну да ладно))

Автобусы и правила Кирхгофа.

Вы никогда не задумывались, что интервалы хождения автобусов (обозначим их T) сродни сопротивлению? Можно даже проводимости складывать, как при параллельном соединении (если несколько автобусов подходят) и получить среднее время ожидания.

Thursday, June 3, 2010

Занятная статистика

Есть у нас такая вещь, как общеобластной форум ADSLьщиков. В случае различных аварий у провайдера он становится чуть ли не единственным местом, где об этом можно посрать кирпичами =) Дальше, пожалуй, no comments.

Киров. Май, 2010 год. 30 мая 2010 года в 10-00 часов произошла авария на основном магистральном интернет-канале в направлении Нижнего Новгорода. В 16.00 часов на том же направлении был поврежден резервный интернет-канал, в связи с чем доступ к ресурсам внешнего Интернета для жителей Кировской области был временно недоступен.
К ликвидации аварийной ситуации приступили немедленно, однако восстановить резервный канал удалось только к 22-30 часам 30 мая 2010 года, с этого времени доступ к сети был частично восстановлен.


Saturday, May 29, 2010

libxml-ruby1.9.1 и Unicode

Вот почему
parser = XML::HTMLParser.string((IO.read 'page.html'),
:encoding => XML::Encoding::UTF_8)
doc = parser.parse
obj = doc.find('//tr/td/font[@color="#cc0000"]')
content = obj.first.content.force_encoding("UTF-8")
p content.index "не найден"

выводит 80, а если то же самое, только вместо первой строки — 

parser = XML::HTMLParser.file('page.html',
:encoding => XML::Encoding::UTF_8)
, выводит nil?

Переезд на Ruby 1.9.1

Вообще говоря, Ruby я увлёкся недавно — около месяца тому назад. Особенно меня философия Rails привлекла, да и сам язык довольно красив.

В процессе освоения 1.8, который идёт в Дебиане по умолчанию, столкнулся с пиздецом в виде строк, которые почему-то ведут себя тупо как последовательности байтов. После Питона (в котором, надо сказать, проблемы с Юникодом тоже были немалые) с этим ужасом работать невозможно.

Поэтому поставил ruby1.9.1. После этого попытался запустить Rails. (Естественно, поставил его gem-ом, чтоб поновее был.) 

Во-первых, пришлось вручную сделать ln -s /usr/bin/ruby1.9.1 /usr/bin/ruby и для rake точно так же, иначе неудобно работать.

Во-вторых, кучу библиотек за собой ruby1.9.1 почему-то не потянул. А зря: пришлось вручную потом apt-cache-м искать нужные пакеты (libopenssl-ruby1.9.1, ruby1.9.1-dev, libsqlite3-ruby1.9.1, libxml-ruby1.9.1, возможно, ещё какие-то понадобятся...)

В-третьих, старые проекты пришлось немного модифицировать. А именно, в config/environment.rb заменить версию рельсов, а также переименовать session_key в key; потом запустить rake rails:update (так надёжней, хотя возможно, что достаточно просто переименовать application.rb в application_controller.rb).

В-четвёртых, пришлось заюзать костыль: http://gist.github.com/339265

В-пятых, пришлось немножко подправить код из-за следующего:

Ruby 1.9 introduces an incompatible syntax change for conditional statements such as 'if' and 'case/when'. Previously a colon could be used as a shorthand for a 'then' statement

Немного о блоге

(Тут ранее был написан какой-то полубред)

Изначально блог был just for fun. Однако со временем его стиль сменился в сторону публицистического (и даже матерные слова теперь заменяются всякой #&*^!*), ибо я осознал, что подобных мне психопатов на этом шарике не так уж мало, как казалось ранее.

Аудитория делится на две основные составляющие (исхожу из данных StatCounter и впиленной в blogger статистики):
а) всякие любопытные личности типа тебя (кстати, среди них можно выделить и особо упоротых, которые мой никнейм зачем-то в поисковик вбивают — всё равно всё, что там можно найти, было давно и неправда). И вообще, если ты сейчас это читаешь, то тебе явно делать нефиг. А ну брысь матан учить! (ну или ещё чем полезным займись, если весь матан уже заботал(-а))
б) пришедшие с Google/Yandex (другими поисковиками в этой стране, похоже, и не пользуются). Эти радуют больше, потому что своим существованием показывают, что всякая муть, которую я строчу, кому-то и вправду полезна.

Такие дела.