Sacred: Gold в Ubuntu 14.04 - 86_64

Sacred: GoldРешив поиграть во что-то старенькое и интересное под Ubuntu наткнулся на Sacred: Gold в ихнем магазине. Купив себе эту игру и настроившись в нее поиграть сразу же столкнулся с серьезной проблемой - все тексты в игре были нечитабельны и нормально поиграть не получилось.

Любые попытки связаться с тех. поддержкой Linux Game Publishing(Ребятами, которые портировали игру на Linux) не к чему не привели(0 ответов). Сейчас их сайт вообще лежит.

Немного покопавшись в интернете наткнулся на решение в комментариях, которое помогло мне исправить проблему. Там предлагалось удалить устаревшие версии библиотек из игры и тогда будут использованы системные. После попытки это сделать игра перестала запускаться полностью. Методом проб и ошибок мне удалось разобраться какие именно библиотеки нужно удалить.

MySQL Использование Count в LEFT JOIN

До сегодняшнего дня ни раза не использовал LEFT JOIN и COUNT вместе в одном запросе. Проходя собеседование в одной компании мне предложили написать подобное решение. Сразу сделать его прямо на собеседовании я не смог, по этому решил почитать документацию и все проверить в свободное время.

Для примера давайте возьмем 2 таблицы. Первая будет таблица пользователей, а вторая ихних сайтов.

Таблица пользователей:

--
-- Структура таблицы `users`
--

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

--
-- Дамп данных таблицы `users`
--

INSERT INTO `users` (`id`, `username`) VALUES
(1, 'test1'),
(2, 'test2');

Таблица сайтов:

--
-- Структура таблицы `sites`
--

CREATE TABLE IF NOT EXISTS `sites` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL,
  `domain` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `user_id_2` (`user_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

--
-- Дамп данных таблицы `sites`
--

INSERT INTO `sites` (`id`, `user_id`, `domain`) VALUES
(1, 1, 'test1.com'),
(2, 1, 'test2.com'),
(3, 2, 'test3.com');

--
-- Ограничения внешнего ключа таблицы `sites`
--
ALTER TABLE `sites`
  ADD CONSTRAINT `sites_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
  ON DELETE CASCADE ON UPDATE CASCADE;

Форматирование JavaScript и JSON в консоли Linux

ExtJS Tree PanelДля того что бы форматировать JavaScript код существует множество сервисов и один из самых популярных http://jsbeautifier.org. Мне довольно часто доводилось пользоваться им для форматирования json или обфусцированного JavaScript кода. Сервис хорош всем, кроме одного, когда я пытаюсь форматировать файл большого размера (Более 2 мб) браузеры начинают жутко тормозить при попытке добавить такой объем данных в textarea.

Зайдя на сайт Online JavaScript beautifier и посмотрев через firebug ихние скрипты вы можете увидеть что они использует файл beautify.js, который к тому же распространяется под лицензией MIT, которая позволяет его использовать, изменять и передавать третьим лицам. При этом она допускает его использование коммерческих проектах тоже.

Теперь когда мы разобрались со всем необходим можем приступить непосредственно к созданию вспомогательной утилиты. Давайте скачаем и сохраним файл beautify.js:

greed@laptop:~/bin$ wget http://jsbeautifier.org/js/lib/beautify.js

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

    } else if (typeof exports !== "undefined") {
        // Add support for CommonJS. Just put this file somewhere on your require.paths
        // and you will be able to `var js_beautify = require("beautify").js_beautify`.
        exports.js_beautify = js_beautify;
    }

NodeJS Ошибки в NPM и установка из исходников

Работая над второй частью статьи по NodeJS столкнулся с проблемой работы NPM из стандартного репозитория пакетов в Ubuntu. В целом все работало нормально, установка, удаление и просмотр информации о пакетах, но при любой попытки поиска пакета я получал в консоль следующею ошибку:

greed@laptop:~$ npm search mysql
npm http GET https://registry.npmjs.org/-/all/since?stale=update_after&startkey=1396395215219
npm http 200 https://registry.npmjs.org/-/all/since?stale=update_after&startkey=1396395215219
npm ERR! TypeError: Object.keys called on non-object
npm ERR!     at Function.keys (native)
npm ERR!     at stripData (/usr/share/npm/lib/search.js:89:28)
npm ERR!     at Array.map (native)
npm ERR!     at filter (/usr/share/npm/lib/search.js:73:6)
npm ERR!     at /usr/share/npm/lib/search.js:63:21
npm ERR!     at /usr/share/npm/node_modules/npm-registry-client/lib/get.js:89:14
npm ERR!     at /usr/lib/nodejs/graceful-fs/graceful-fs.js:103:5
npm ERR!     at Object.oncomplete (fs.js:107:15)
npm ERR! If you need help, you may report this log at:
npm ERR!     
npm ERR! or use
npm ERR!     reportbug --attach /home/greed/npm-debug.log npm

npm ERR! System Linux 3.11.0-19-generic
npm ERR! command "/usr/bin/nodejs" "/usr/bin/npm" "search" "mysql"
npm ERR! cwd /home/greed
npm ERR! node -v v0.10.15
npm ERR! npm -v 1.2.18
npm ERR! type called_on_non_object
npm ERR! 
npm ERR! Additional logging details can be found in:
npm ERR!     /home/greed/npm-debug.log
npm ERR! not ok code 0
greed@laptop:~$ 

Поиски подобной ошибки ничего не дал, по этому я решил ее исправить установив последнюю версию NodeJS из репозитория github. По скольку NPM идет вместе с NodeJS это должно решить мою проблему. Для того чтобы сборка прошла успешно нам необходимо установить некоторые пакеты, которые необходимы нам для получения исходного кода и последующей сборки:

sudo apt-get install python g++ make checkinstall git

NodeJS получение Post JSON

ExtJS Tree PanelВ качестве небольшого дополнения к статьям Curl Post JSON и NodeJS Установка и использование решил написать от том как получать Post JSON в NodeJS. За основу возьмем http-сервер который мы уже создавали в статье NodeJS установка и использование. Я приведу сразу готовый класс сервера на основе, который будет принимать post JSON:

var http = require('http');
var port = 1337;
var host = '127.0.0.1';

http.createServer(function(request, response) {
    console.log('From: '+request.connection.remoteAddress+', Path: '+request.url);

    if(request.method === 'POST'){
        var text = '';
        request.addListener('data', function(chunk) {
            text += chunk;
        });
        
        request.addListener('end', function() {
            if(text){
                try {
                    var jsonObject = JSON.parse(text);
                    response.writeHeader(200, {
                        'Content-Type': 'application/json'
                    });
                    response.end(JSON.stringify({
                        success: true,
                        username: jsonObject.username
                    }));
                } catch(e) {
                    response.writeHead(500, {
                        'content-type': 'text/plain'
                    });
                    response.end('Post json data cannot be parsed: '+e);
                }
            } else {
                response.writeHeader(200, {
                    'Content-Type': 'text/html'
                });
                response.end('No Data Provided!');
            }
        });
    } else {
        response.writeHeader(200, {
            'Content-Type': 'text/html'
        });
        response.end('No Data Provided!');
    }
}).listen(port, host);

console.log('Server start at http://'+host+':'+port+'/');

PHP - Curl Post JSON

Довольно часто мне приходилось передавать данные на сервер в различными способами таких как GET или POST, но существует еще один удобный способ передачи данных на сервер это Post JSON. Его удобно использовать в тех случаях когда мы передаем сложные структуры данных. Давайте представим с вами ситуацию когда мы хотим передать на сервер объект/массив(данные пользователя) и сопутствующие к нему связи. На пример мы хотим отправить Пользователя, его статьи и комментарии для этих статей. 

Для примера мы можем использовать ассоциативный массив следующего вида:

<?php
$user = array(
    'id' => 1,
    'username' => 'jon123',
    'first_name' => 'Jon',
    'last_name' => 'Dou',
    'articles' => array(
        array(
            'id'=>1,
            'title' => 'My First Page',
            'content' => '<h1>Hello it my first page</h1>',
            'comments' => array(
                array(
                    'id'=>1,
                    'username' => 'Jack',
                    'text' => 'Hey it is a great blog!'
                ),
                array(
                    'id'=>2,
                    'username' => 'Nick',
                    'text' => '+100500!'
                )
            )
        ),
        array(
            'id'=>2,
            'title' => 'Free time',
            'content' => 'Do you have any free time?',
            'comments' => array(
                array(
                    'id'=>3,
                    'username' => 'Nick',
                    'text' => 'Free time? You are joking?'
                )
            )
        )
    )
);

Зачем нам передавать его через Post JSON, если его можно передать через обычный POST-запрос? Одна из причин это удобство работы с форматом JSON. нам не придется придется преобразовывать имена параметров в запрос приводя их к виду article[1][commet][1][name] = 'Hey it is a great blog!' для того что бы получить такой же массив при получении данных на сервере, другая заключается в том, что если принимающей стороной будет не PHP, а к примеру NodeJS работать с полученными данными будет намного удобней. Также стоит отметит что количество передаваемых данных будет немного ниже чем при обычном POST запросе.

Част 1. NodeJS Установка и использование

ExtJS Tree PanelNodeJS - серверная реализация JavaScript получившая в последние время большое распространение. Многие крупные интернет-сервисы такие Amazon, ВКонтакте используют его для снижения нагрузки на своих серверах. Главным критерием для выбора NodeJS обычно является скорость его работы, простота в написании кода и низкое потребление памяти по сравнению с такими гигантами, как Java или Ruby. В этой статье я хочу рассказать, о том как нам установить NodeJS и подготовить его к работе. Мы также напишем несколько простых приложений которые на помогут с ним разобраться.

Установка

Для дальнейшей работы NodeJS на нужно установить 2 пакета, один это сам nodejs и второй npm (Node Package Manager)- пакетный менеджер для NodeJS, который нам даст возможность быстро и удобно устанавливать библиотеки и фреймворки для nodejs. В ubuntu 13.10 для установки этих двух пакетов на необходимо выполнить команду:

sudo apt-get install nodejs npm

Проверим версии только что установленных пакетов. Именно под эти версии будет писаться статья. Скорее всего код который будет здесь представлен будет работать и на более новых версиях:

greed@laptop:~$ npm -v
1.2.18
greed@laptop:~$ nodejs -v
v0.10.15
greed@laptop:~$ 

PHP - Преобразование XML to Array

Для работы с xml в php, есть удобное расширение SimpleXML, которое помогает вам производить манипуляции с DOM. К недостаткам стоит отнести неудобства по работе с объектом который мы получаем и в результате работы simplexml_load_string. Совсем другое дело обстоит с json, нам все навсего нужно использовать метод json_encode, чтобы получить из него объект или массив. Здесь будет показано каким образом получать массив из xml.

После небольшого поиска в интернете, мне удалось найти два решения, которые соответствовали всем необходимым мне требованиям. Для проверки работы кода будет использован следующий XML:

<?xml version="1.0" ?>
<states>
    <state id="AL">     
     <name>Alabama</name>
    </state>
    <state id="AK">
        <name>Alaska</name>
    </state>
</states>

Как оказалось самый простой способ - это преобразовать объект XML в json строку и затем преобразовать обратно в объект/массив:

<?php
function xml2array($text, $is_array = true) {
    $xml = simplexml_load_string($text);
    $json = json_encode($xml);
    return json_decode($json, $is_array);
}
?>

Как видим мы получаем компактный метод, но из-за преобразования скорость работы будет не самой быстрой. Такое решение подходит любителям минимализма и компактного кода. Результатом выполнения этого метода будет:

Array
(
    [state] => Array
        (
            [0] => Array
                (
                    [@attributes] => Array
                        (
                            [id] => AL
                        )

                    [name] => Alabama
                )

            [1] => Array
                (
                    [@attributes] => Array
                        (
                            [id] => AK
                        )

                    [name] => Alaska
                )

        )

)

PHP - GeoIP Модуль

GeoIP MapПолучение данных о место нахождении пользователя может быть очень полезной и удобной функцией. Это может оказаться полезным, если у вас есть форма регистрации в которой есть поля 'Страна', 'Город' и 'Индекс' или вы хотите просто собирать как можно больше информации о пользователе для дальнейшего ее анализа. В рамках этой статьи мы попробуем с вами сделать небольшую форму, в которой мы заполним поля данными полученными с помощью GeoIP модуля.

Установка GeoIP

Для того что бы использовать этот модуль для начала его нужно установить. Я использую Ubuntu 13.10 по этому установка и настройка приведена именно для этой системы:

sudo apt-get install php5-geoip

Для того что бы получать актуальные данные вам необходимо скачать последнюю базу GeoIP. Сделать вы этому можете по этому адресу http://dev.maxmind.com/geoip/legacy/geolite/. После того как вы скачали последнюю базу ее необходимо распаковать. У вас должно быть 2 файла GeoIP.dat и GeoLiteCity.dat (его нужно переименовать в GeoIPCity.dat), которые нужно скопировать в директорию /usr/share/GeoIP. После этого приготовления к использованию завершены и мы можем проверить работу этот модуля.

Теперь когда у нас все готов мы можем использовать  метод geoip_record_by_name, который и вернет нам все необходимые данные.

<?php  
$data = geoip_record_by_name('8.8.8.8');
print_r($data);
?>

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

Array
(
    [continent_code] => NA
    [country_code] => US
    [country_code3] => USA
    [country_name] => United States
    [region] => CA
    [city] => San Francisco
    [postal_code] => 94107
    [latitude] => 37.76969909668
    [longitude] => -122.39330291748
    [dma_code] => 807
    [area_code] => 415
)

Сортировка массива в JavaScript

Недавно ко мне подошел один мой знакомы, программист с опытом в 3 года в frontend-разработке и попросил помочь объяснить почему функция sort в javascript работает неправильно. Был массив из цифр [1, 2, 15, 3] и при вызове метода sort результатом сортировки должен быть массив [1, 2, 3, 15], а не результат который он получал [1, 15, 2, 3]. Я был немного удивлен т.к. для меня это было очевидно. Пообщавшись еще с несколькими программистами я понял, что понимание каким именно образом работают сортировка массивов в javascript есть далеко не у всех. Здесь я постараюсь рассказать как работает сортировка массива sort и какие подводные камни нас ждут.

Для начала что бы понять как работает sort в javascript возьмем два массива:

  1. [1, 2, 15, 3] - массив значений типа Integer.
  2. ['1', '2', '15', '3'] - массив значений типа String.

Если мы попытаемся сортировать оба этих массива мы получим [1, 15, 2, 3] и ['1', '15, '2', '3'] соответственно для обоих случаев. С точки зрения сортировки строк мы получаем правильное значение т.к. тут идет посимвольная сортировка. Число(строка) '15' разбивается на две части на 1 и на 5. В начале идет сравнение первого числа с элементами массива. 1 < 2 и будет поднято в вверх на одну позицию. При сравнении с 1 и 1 они будут равны и и по этому сортировка будет для них происходить по второму числу у '1' его нет а у '15' это 5 и пустое значение меньше 5. В результате мы получим что '15' попадает на второе место.