вторник, 1 января 2013 г.

Мое мнение. Клавиатура Rapoo 9070.

Клавиатура Rapoo 9070 мне очень понравилась когда я ее увидел. Она имеет расположение кнопок характерное для большинства ноутбуков, а значит не надо будет переключаться на разные раскладки на стационарном компьютере и ноутбуке. Когда клава попала мне в руки мне польстило качество сборки "брендового китая", оно на уровне хорошее, немного "пляшут" кнопки в рядах, но этого практически не видно.


Клавиатура действительно очень компактная, но не смотря на то что она имеет небольшие размеры. Клавиши довольно таки не малые. Клавиши имеют ход небольшой, но ощутимый. При нажатии где-то по середине хода кнопка имеет наибольшее сопротивление, продавив которое, кнопка стремительно проваливается и замыкает контакт. Шума от нажатия не много, в общем охарактеризую эту клавиатуру как тихую. Расположение кнопок относительно удобное, ноутбучное если можно так сказать. Не лишний, надо заметить и цифровой блок кнопок. Клавиатура успешно протестировалась на Win 7 и на Ubuntu 12.04. Работает отлично. Драйвера или спец, софт ставить вовсе не обязательно.
Я даже удивился немного когда увидел в других обзорах упоминание о том что мало софта для этой малышки. Если кто-то может объяснить чем это плохо, прошу в комменте отписать.

В работе показала себя хорошо. В особенности стоит отметить что клавиши курсора удивительно неплохо нащупываются. А вот чудо-клавиша "слеш", рядом с левым шифтом,  меня немного удивила, и именно из-за этой клавиши у меня на новой клавиатуре возникает большее количество опечаток. Это минус, такой противный и нехороший минус в адрес rapoo. Некоторые люди (видимо про-геймеры) пишут, что играть на ней не удобно. Странно, но мне удобно. Играл в шутер и реал-тайм стратегию. Что огорчило больше всего это то, что клавиатура бывает ни с того ни с сего теряет связь. Поиск дал смутный результат. Люди говорят что всему причина Wi-Fi приемник-передатчик по близости, увы у меня это так. И пока проверять не охота как оно будет без него. Не так уж часто она и "слепнет" :). Еще один недостаток, так это то, что нет индикатора CAPS LOCK'а, его действительно очень не хватает :(.
Питается девайс от двух элементов питания формата AAA (это те которые меньше "пальчиковых" батареек, если кто до сих пор не знает), у меня сейчас обычные батарейки, в дальнейшем думаю прикупить аккумуляторы.







P.S.: Давеча залита кофе, промыта, высушена - работает! Второй раз когда пролил на нее кофе и промыл с последующей сушкой, работать перестала, ремонтопригодность очень низкая, есть большой риск что после ремонта пользоваться вы ей не станете, появятся люфты искажения и прочие артефакты.

воскресенье, 25 ноября 2012 г.

Phantomjs. Кратко о webkit консольном браузере.

Отличный браузер, который дает нам дополнительные возможности в программной навигации по вебу. А также позволяет реализовать unit-тестирование javaScript, делать скриншоты страниц и другое. Это браузер позволяет нам работать с DOM так же буд-то мы находимся в самом обычном браузере с GUI. Краткая информация:
У меня лично были некоторые трудности с установкой из исходников. Ах, да совсем забыл Ubuntu :). Значит были сложности, т.к. требуется qt и еще ряд зависимостей, если кто-то хочет попробовать собрать, то подробная инструкция по этому вопросу есть на сайте продукта. Также я поставил изначально из пакетов:
sudo aptitude install phantomjs
Но, как известно, стандартные пакеты славятся отсталостью версий. Как же быть если пакеты в репозиторые старые, а из сырцов поставить не вышло? На официальном сайте есть бинарники. Там вы найдете бинарники для популярных ОС.
Как пользоваться. Очень просто, куда вы распаковали скачанный архив, там находите папку bin а в ней phantomjs, его можно вынести в удобное для вас место. Итак приступим.
Первый самый простой скрипт (hello.js) для нашего phantomjs.
console.log('Hello Phantom!!!');
Для запуска выполним
phantomjs hello.js
Получим сообщение в консоль. Ну, это по-моему очевидно. Далее чуть поинтереснее. Пример получения скриншота посещаемой страницы:

var page = require('webpage').create();
page.open('http://google.com', function () {
    page.render('google.png');
    phantom.exit();
});
 
Тут мы сначала подключаем необходимый нам модуль webpage. А затем открывает необходимую нам страницу, после успешной загрузки которой мы вызовим колбэк функцию. В этой функции мы сохраняем (рендерим) скриншот страницы в файл google.png и закрываем phantomjs.

Ниже приводится пример скрипта, который сможет подсчитать скорость загрузки страницы и вывести значение в консоль.

var page = require('webpage').create(),
    system = require('system'),
    t, address;

if (system.args.length === 1) {
    console.log('Usage: loadspeed.js ');
    phantom.exit();
}

t = Date.now();
address = system.args[1];
page.open(address, function (status) {
    if (status !== 'success') {
        console.log('FAIL to load the address');
    } else {
        t = Date.now() - t;
        console.log('Loading time ' + t + ' msec');
    }
    phantom.exit();
});

Запустив этот скрипт и передав в качестве параметра Web-адрес, мы получим ожидаемый результат, т. е. скорость загрузки страницы.

Гораздо больше примеров есть на официальном ресурсе, который указан вначале статьи. Штука удобная действительно. Я написал обертку на PHP для управления этим браузером, но она "дико" сырая, умеет выполнять только одно, вызывать обработчик phantomjs и делать скриншот в файл. Как будет что показать обязательно обновлю статью и укажу ссылочку на Git хаб.

Проброс портов в Windows

Ситуация проста. Имеем следующее. Виртуальную машину. Физическую машину на которой она крутиться. Если коротко то хост машина - Win7, гостевая - ubuntu-server 12.04., роутер. На роутере скорее всего для проброса портов будет пункт типа Virtual Servers. Там выбираем службу (или руками порты прописываем) IP машины на которую нам надо отправлять. Это сугубо индивидуально поэтому не могу ничего конкретно посоветовать. Смотрите документацию по своему роутеру. На тему "проброс портов".
Идем далее. На Убунте поднят апач, т.е. это 80 порт - это наша цель. Но роутер может обратиться только на наш физический IP адрес внутри локальной сети, на железную сетевую карту. Тут нам надо делать еще один проброс порта, того же 80го. Но только уже на нашем компьютере под управлением Win7 с железной карты, пускай у нее IP будет 192.168.1.101 на карту, которую добавит при установке, ваша виртуальная машина (у меня Virtual Box и карта которая соединяет виртуальные миры с физическими имеет адрес 192.168.56.1, ну шлюз, в смысле, соответственно машина с Апачем имеет IP равный 192.168.56.101). Итого, вкратце, надо пробросить 192.168.1.101:80 на 192.168.56.101:80 в операционной системе Windows 7 приступаем.
1. Запускаем консоль с правами администратора.
2. Запускаем netsh
и
netsh>interface
netsh interface>portproxy
netsh interface portproxy>add v4tov4 listenport=80 listenaddress=192.168.1.101 connectaddress=192.168.56.101 connectport=80
Проверяем все ли прошло гладко:
netsh interface portproxy>dump

#===========================
# Конфигурация портов прокси
#===========================
pushd interface portproxy

reset
add v4tov4 listenport=80 connectaddress=192.168.56.101 connectport=80


popd

# Конец конфигурации портов прокси
Да все нормально. Пробуем теперь обратиться локально по 192.168.1.101 и мы получим ответ от апача по адресу 192.168.56.101. Дальше пробуем уже по внешнему IP адресу, и вы должны получить тот же ответ что и от внутреннего адреса 192.168.56.101. Стоит уточнить, данный способ пробросит только TCP.

Если узрите неточности, прошу отметить в комментариях.


четверг, 30 августа 2012 г.

PHP. Работа с CSV файлами.

Работая надо одним проектом, часто приходилось работать с данными полученными из разных источников. Все эти данные были сформированы в виде CSV файлов. Причем все имели разные форматы. Нужен был инструмент для быстрой и удобной работы. Решил написать. Т.к. из того что я нашел не было ничего подходящего.

Итак что умеет этот класс. Главное это то что он осуществляет удобную загрузку данных CSV и, путем несложного дополнения, можно экспортировать данные в другой формат, а также формирование и сохранение данных в CSV формат. Все делается очень просто и без особых усилий. Из способностей этого класса есть еще такие "недопиленные" фишки как поиск по колонкам и по строкам, пока в некоторых случаях срабатывает некорректно. Но от класса этого и не требовалось, так сказать это побочный положительный эффект.
Итак по порядку. Класс можно забрать на Gitgub'e.
Использовать его очень просто. Ниже пример инициализации и загрузки CSV данных.

$options = array(
    'splitter' => ';', // Это разделитель "колонок" в CSV файле
    'wrapper' => '"', // А это то во что "завернуты" значения "колонок"
);
$csv = new Csv($options);
А вот так просто мы можем добавить строку в CSV файл, но данные сохранятся только после вызова метода Csv::save([file_name])
// Можно передать и в конструктор в виде параметра file => 'filename.csv'
$csv->file('./users.csv');
$csv->add(
    array ('id', 'user', 'name', 'email')
);
// Если как в этом примере мы указали имя файла то просто вызываем Csv::save если нет, то передаем в качестве параметра имя файла
$csv->save()

Если мы заранее указали имя файла с которым работаем, то и этот метод вызываем без параметров. Это загрузка CSV файла и его парсинг.

$csv->load();
или
$csv->load("./users.csv');

Этот класс так может выполнять операции по получению данных из опреденных ячеек, а так же можно задать названия столбцов. Несколько примеров по работе с данными

$csv->rows(); // Получаем все распарсенные строки из файла (в виде массива)
$csv->row(1); // Получи первую строку, причем если вы укажите в параметрах конструктора параметр columnNames, то это строка выведет данные а не названия столбцов
$csv->cell(10, 3); // Выведет данные из 10 строки 3 колонки
$csv->remove(3); // Удалит 3ю строку из файла
$csv->readOnly(true); // Пометить объект как "только чтение" и методы add и remove будут генерировать исключения
$data = $csv->columns() // Получить все колонки
$userNames = $csv->column('name'); // Получить колонку с именами (если конечно был задан map колонок)

// Весь поиск прекращает работу и возвращает строку как только будет найдена первая строка удовлетворяющая поиску
$csv->find('Vasya'); // Будет работать медленее всего, вернет первую строку в которой есть 'Vasya', регистр важен
$csv->find('Vasya', 2); // Будет работать быстрее чем предыдущий вариант, с таким же результатом, но не по всей таблице а только по 3й колонке
$csv->find('Vasya', 2, Csv::FIND_SENS_CASE); // Быстрый регистронезависимый поиск по 3й колонке
$csv->save(); // Сохраняем все изменения если конечно объект не помечен как "только чтение"
Замечу, что поиск работает очень быстро, разумеется для этого типа данных. Я потратил наверное больше всего времени на этот кусочек реализации. Думаю вы оцените, для сравнения, поиск по списку из 450 тыс. (колонок было 13), данные из середины, находились без указания колонки поиска за ~2с. а с указанием за ~0.5), конечно, эти данные абсолютно ни о чем не говорят, а просто приблизительно показывают, что поиск вполне можно использовать.
Благодаря этому классу, я смог быстро реализовать импорт/экспорт данных из CSV в Ms Excel XML и из CSV в MySQL, с минимальным набором логики, как вы заметили есть методы, которые позволяют манипулировать данными, думаю это очень важно.
И мне показалось, что не поделиться им с вами, будет не честно, зачем ему валяться без дела, пускай людям приносит радость и экономит время.

Скачать класс с Github
Можно забрать с composer

пятница, 10 августа 2012 г.

MySQL. Отключение логирования запросов без индексов.

MySQL при включенном slow log логирует и запросы которые не содержат в себе индексов. Порою возникает необходимость такую "фичу" отключить для этого необходимо найти конфигурационный файл mysql. В случае если это Debian то это будет /etc/mysql/my.cnf и добавить туда в секцию MySQL директиву log-queries-not-using-indexes. Что приведет к игнорированию запросов которые не используют индексы, только если, конечно, время выполнения такого запроса будет ниже чем установленный long-query-time

вторник, 3 июля 2012 г.

Разработка. Как передать HTTP_REFERER из flash.

Предыстория такова. Есть на некоем ресурсе флеш-виджет которые выполняет какие-то операции с пользовательским контентом. В моем конкретном случае, это фотографии. Задача стояла следующим образом. Необходимо собирать статистику показов с внешних ресурсов, т.е. сколько раз и где флешка засветилась на экранах пользователей. задача так же усложнялась и тем, что по сути показы должны были учитываться не самой флешки, а меняющихся в ней фотографий. Если же вам так же понадобится учитывать показ контента внутри флеш, то, увы, прийдется обратиться к флешеру, сваявшего этот виджет. Зачем я объясню позже.
Итак приступим. Все мы прекрасно знаем, что флешка передать реферера не может, вернее может, но этот реферер будет физическим адресом размещения самой флешки. Что не есть хорошо и нам абсолютно не надо. Так как же передать реферера? Очень просто, достаточно обвернуть выдачу флешки в php-скрипт. В котором мы будем выхватывать реферера учитывать показ. Если же у вас задача, так же как и у меня, "со звездочкой", то делаем нехитрый трюк с редиректом и добавлением параметра в запрос, таким вот образом. Получив реферер, в PHP скрипте, мы генерируем новый запрос к флешке и делаем по нему редирект. Флешка в своб очередь, получив этот параметр, добавляет его к каждому запросу (в моем случае фотографии) к нашему серверу, где этот запрос, обрабатывается скриптом, который учитывает всю необходимую нам информацию, включая реферера. Теперь чтоб совсем все стало ясно, приведу небольшой пример утопического кода (без проверок и пр. только логика, так что, пожалуйста не возмущайтесь понапрасну):

// Файл flashcatch.php
$file = './flash.swf';
$referer = $_SERVER['HTTP_REFERER'];
// Если не надо делать никаких более действий, то прямо здесь счетаем показ
// ...
// Устанавливаем тип содержимого
header('Content-Type: application/x-shockwave-flash');
// Читаем и отдаем флешку.
echo file_get_content($file);
exit();

Если понадобиться добавить параметр для последующего учета показов контента внутри самой флешки то код немного усложниться.

// Файл flashcatch-trick.php
$file = './flash.swf';
$referer = $_SERVER['HTTP_REFERER'];
// Добавляем параметр к запросу на флешку например referer.
if (strpos($_SERVER['REQUEST_URI'], '?')) {
    $connector = '&';
} else {
    $connector = '?';
}
$newRequest = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'] . $connector . 'referer=' . $referer;
// Если запрос является внешним и запрос не содержит в себе параметра referer то делаем редирект
if (isExternalRequest() && !$_REQUEST['referer']) {
    header ('Location: ' . $newRequest);
    exit();
}
// Устанавливаем тип содержимого
header('Content-Type: application/x-shockwave-flash');
// Читаем и отдаем флешку.
echo file_get_content($file);
exit();

И вот тут вспоминаем про флешера, во флешку передаем новый параметр в котором прописан реферер, в моем случае это параметр referer :). А флешер формируя запросы к к серверу для получения фотографий (аудио, видео), подставляет его и сервер при выдаче содержимого флешке учитывает реферера и показ, соответсвенно.

Функция isExternalRequest не приведена, ее не составит труда написать самому. Суть ее думаю ясна, вернет труЪ если это внешний запрос и фальс если свой же сервер запросил флешку.

среда, 27 июня 2012 г.

Google Maps. Курсоры рук для карты.

Если вдруг вам понадобяться такие вот руки как при перемещении курсора над картой или же при перемещении с нажатой кнопкой мыши то вот:
http://maps.google.com/mapfiles/openhand.cur
http://maps.google.com/mapfiles/closedhand.cur