суббота, 1 февраля 2014 г.

Пингвины с чёткими яблоками или ставим Ubuntu на Macbook Pro Retina


2 года успешно пользовался макбуком 2010ого года c ubuntu 12.04, но у него со временем стал быстро садиться аккумулятор, пришло время поменять его на новенький Macbook Pro Late 2013. Подобные извращения люди уже описывали, но как-то они не везде сошлись с моим опытом, поэтому решил им поделиться. Этот способ не убивает MacOS, можно грузиться и в неё.

Ставим загрузчик

Сначала я прочитал статью, где используется стандартный макбуковский загрузчик, но там много магии, не особенно подробно описанной, у меня было мало времени(все-таки ноутбук нужен для работы, а не чтобы ставить на него линукс неделями), поэтому я плюнул и пошёл проверенным методом, который работал с предыдущим устройством. А именно поставил rEFInd. Самый простой(и рекомендованный его разработчиком) способ установки это из макоси.

Качаем binary zip file отсюда

Распаковываем, открываем консоль, запускаем install.sh

$ ./install.sh
Not running as root; attempting to elevate privileges via sudo....
Password:
Installing rEFInd on OS X....
Installing rEFInd to the partition mounted at '/'
Copied rEFInd binary files

Copying sample configuration file as refind.conf; edit this file to configure
rEFInd.

Installation has completed successfully.

Берём нужный образ и пишем его на флешку

В этой версии макбука, загрузчик умеет грузить обычный убунтовый образ с флешки(для этого после включения нужно держать alt), поэтому лучше качать его, а не *-mac вариант.

Люди пишут, что у них всё было хорошо с 13.10, но у меня почему-то нет. Проблемы были с драйвером видеоадаптера и при загрузке в установщик или liveCD режим, изображение было во-первых очень мелкое(retina же!), во-вторых с какими жуткими искажениями цветов и самого изображения. Параметрами ядра при загрузке за короткое время мне это исправить не удалось(читал тут), но было понятно, что проблема в драйвере, а драйвер в ядре, поэтому стоит попробовать ядро посвежее. Чтобы не мелочиться, решил попробовать 14.04(если вы читаете это через 5 лет, то тогда было полгода до релиза). Качал отсюда, вариант PC amd64. И о чудо, тут всё работало. Практически. :-)

Изображение было таким же мелким, но это легко исправлялось простой сменой разрешения.

Образ на флешку можно ставить через unetbootin как-то так:

Собственно установка

Дальше установка как обычно, отрезаем место от раздела макоси, разбиваем по вкусу, grub ставим в тот же раздел, где точка монтирования /.(вообще у меня не спрашивал, видимо нынешние установщики делают так по дефолту). Перезагружаемся, выбираем в rEFInd вновь появившийся пункт меню и загружаемся в новую систему.

Постустановка и впечатления

Проверял немного, работает wifi(c проприетарными драйверами bcmwl-kernel-sources), засыпает и просыпается от крышки, звук есть. Поставил awesome, накатил свои конфиги и наступило счастье. :-) Сегодня замерил батарею, в умеренном режиме(немного торрентов, немного видео, почти всё время музыка, браузер и wifi) проработал 6,5 часов, осталось 7 процентов.

Зачем это?!

Ко всем подобным постам самый популярный вопрос: "а зачем?!". Отвечу заранее. Макбук с точки зрения железа мне нравится. Экран, клавиатура, тачпад, достаточно мощная конфигурация при приличном времени работы. Макось мне не то, чтобы не нравится, но у меня уже есть настроенная среда, которую я подпиливал под себя последние несколько лет, привык к ней и мне в ней удобно и всё нравится. Я пробовал настроить макось в том же ключе, быстро у меня не получилось, а много времени на это жалко. Ломать свои привычки я не хочу.

Еще варианты/примеры:


Продолжение...


суббота, 11 января 2014 г.

Параллельные вычисления в python одной строкой(перевод)


Перевод статьи "Parallelism in one line"

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

У python ужасная репутация в параллельных вычислениях. Если забыть про обычные аргументы о потоках и GIL(которые довольно справедливы), настоящую проблему с параллельными вычислениями в python я вижу не в техническом аспекте, а скорее в педагогическом. Основные руководства про мультипоточность и мультипроцессинговость в Python слишком тяжеловесны. Они начинаются с каких-то глубоких вещей и заканчиваются до того, как объясняют что-то действительно полезное, применимое в ежедневных задачах.

Традиционный пример.

Беглый просмотр первых результатов DDG по запросу Python threading tutorial, демонстрирует, что практически каждый первый из них говорит об одном и том же и базируется на похожей Class + Queue модели.

import time
import threading
import Queue

class Consumer(threading.Thread):
        def __init__(self, queue):
                threading.Thread.__init__(self)
                self._queue = queue

        def run(self):
                while True:
                        # queue.get() блокирует текущий поток до получения данных
                        msg = self._queue.get()
                        # Проверяем, является ли текущее сообщение "Poison Pill"
                        if isinstance(msg, str) and msg == 'quit':
                                # Если является, выходим из цикла
                                break
                        # Обработка(в данном случае печать) элемента очереди
                        print "I'm a thread, and I received %s!!" % msg
                # Всегда будь дружелюбен!
                print 'Bye byes!'


def Producer():
        # Queue используется для доступа к данным из разных потоков
        queue = Queue.Queue()

        # Создаём воркер
        worker = Consumer(queue)
        # Вызываем внутренний run() метод, чтобы запустить поток
        worker.start()

        # переменная, чтобы следить когда мы начали
        start_time = time.time()
        # Пока меньше 5 секунд
        while time.time() - start_time < 5:
                # Вычислить часть данных и положить их в очередь
                queue.put('something at %s' % time.time())
                # Вздремнуть немного, чтобы избежать огромного количества сообщений
                time.sleep(1)

        # Используем "poison pill" метод, чтобы убить поток
        queue.put('quit')
        # Ждем, пока поток закроется
        worker.join()


if __name__ == '__main__':
        Producer()

Хм, да тут пахнет Java.

Но я не хочу создать впечатление, как будто я думаю, что Producer/Consumer способ взаимодействия с мультипоточностью/мультипроцессностью неправильный - потому что это определённо не так. Это отличный подход для целого ряда задач. Тем не менее, я практически уверен, что это не самый лучший вариант для ежедневных скриптовых задач.

Проблемы(как я их вижу).

Во-первых, вам нужен класс, который по сути не делает ничего полезного. Во-вторых, вы должны обслуживать очередь через которую вы должны передавать объекты, и в конце концов, вам нужны методы на обоих концах цепочки, чтобы делать собственно то, что вам нужно.(например использовать другую очередь, если вы хотите сохранить результаты)

Больше обработчиков - больше проблем

Теперь вы захотите сделать набор таких обработчиков, чтобы попытаться выжать какое-то ускорение из Python. Ниже пример кода из отличного учебника от IBM по многопоточности. Это очень распространённый сценарий, где вы решаете задачу загрузить веб страницы в нескольких потоках.

import time
import threading
import Queue
import urllib2

class Consumer(threading.Thread):
        def __init__(self, queue):
                threading.Thread.__init__(self)
                self._queue = queue

        def run(self):
                while True:
                        content = self._queue.get()
                        if isinstance(content, str) and content == 'quit':
                                break
                        response = urllib2.urlopen(content)
                print 'Bye byes!'


def Producer():
        urls = [
                'http://www.python.org', 'http://www.yahoo.com'
                'http://www.scala.org', 'http://www.google.com'
                # и т.д.
        ]
        queue = Queue.Queue()
        worker_threads = build_worker_pool(queue, 4)
        start_time = time.time()

        # Добавляем ссылки на обработку
        for url in urls:
                queue.put(url)        
        # Добавляем poison pill
        for worker in worker_threads:
                queue.put('quit')
        for worker in worker_threads:
                worker.join()

        print 'Done! Time taken: {}'.format(time.time() - start_time)

def build_worker_pool(queue, size):
        workers = []
        for _ in range(size):
                worker = Consumer(queue)
                worker.start()
                workers.append(worker)
        return workers

if __name__ == '__main__':
        Producer()

Работает прекрасно, но посмотрите на весь этот код! Вы должны написать методы, списки потоков, чтобы следить за ними, и что хуже всего, если вы склонны к dead-lock также как и я, куча конструкций join дадут вам возможность ошибиться. И это становится всё сложнее и сложнее.

Чего мы добились, написав столько кода? Практически ничего. Весь этот код это чистая обвязка, он не несёт полезной нагрузки и содержит много мест, чтобы в них ошибиться(Чёрт! Да я забыл вызвать task_done() у объекта очереди, пока писал это(Я слишком ленив, чтобы исправить это и сделать другой скриншот)) и это слишком много кода, который делает слишком мало. К счастью, есть способ лучше.

Вступление: Map

Map это небольшая классная функция, и ключ к простому добавлению распараллеливания в ваш код на Python. Для тех, кто с ней не знаком, map это что-то пришедшее из функциональных языков, таких как Lisp. Это функция, которая сопоставляет другую функцию последовательности, например так:

urls = ['http://www.yahoo.com', 'http://www.reddit.com']
results = map(urllib2.urlopen, urls)

Это применяет метод urlopen к каждому элементу последовательности и сохраняет все результаты в список. Это более-менее эквивалентно такому:

results = []
for url in urls: 
    results.append(urllib2.urlopen(url))

Map совершает итерацию по последовательности, применяет фукнцию и сохраняет результы в список.

Что это даёт нам? Дело в том, что с правильными библиотеками, map может выполнять это параллельно поразительно просто.

Параллельная версия map предоставляется двумя библиотеками: multiprocessing, и её малоизвестный, но в равной степени фантастический потомок multiprocessing.dummy.

Небольшое отступление: Как так? Никогда не слышали о потоковом клоне multiproccessing названном dummy? Я тоже не слышал до самого недавнего времени. В доментации на multiprocessing есть всего одно предложение о нём. И оно сводится к "О да, и такое есть". Это слишком скромно для него, поверьте мне.

Dummy это точный клон модуля multiprocessing. Единственное отличие в том, что multiprocessing работает с процессами, а dummy использует потоки(что приносит все их ограничения. Таким образом всё, что применимо к одному, можно применить и к другому. Что особенно хорошо, для исследовательских задач, когда вы не до конца уверены, вызов какого-то фреймворка будет потреблять CPU или IO.

Начнём.

Чтобы получить доступ к параллельным версиям map, первым делом нужно импортировать модули, которые её содержат.

from multiprocessing import Pool
from multiprocessing.dummy import Pool as ThreadPool

И создать набор объектов

pool = ThreadPool()

Эта короткая инструкция делает всё, что мы делали за 7 строк в функции build_worker_pool из example2.py. А именно, она создаёт набор обработчиков, запускает их и сохраняет в переменной, для простого доступа.

Набор объектов принимает несколько параметров, но сейчас нас интересует только первый: processes. Он устанавливает количество обработчиков в наборе. По умолчанию он равен количеству ядер в вашем процессоре.

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

pool = ThreadPool(4) # Устанавливает размер набора в 4

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

Теперь обработчики созданы и простая параллелизация буквально у нас на кончиках пальцев, давайте перепишем задачу из example2.py

import urllib2
from multiprocessing.dummy import Pool as ThreadPool

urls = [
        'http://www.python.org',
        'http://www.python.org/about/',
        'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html',
        'http://www.python.org/doc/',
        'http://www.python.org/download/',
        'http://www.python.org/getit/',
        'http://www.python.org/community/',
        'https://wiki.python.org/moin/',
        'http://planet.python.org/',
        'https://wiki.python.org/moin/LocalUserGroups',
        'http://www.python.org/psf/',
        'http://docs.python.org/devguide/',
        'http://www.python.org/community/awards/'
        # etc..
        ]

# Создаём набор обработчиков
pool = ThreadPool(4)
# Открываем ссылки в собственных потоках и возвращаем результаты
results = pool.map(urllib2.urlopen, urls)
#закрываем набор и ждём, пока работа будет закончена
pool.close()
pool.join()

И что у нас получилось? Код, который решает задачу состоит из 4 строк, 3 из которых только подготовка к реальной работе. Вызов map с лёгкостью делает всё то же, что и наш предыдущий 40 строчный пример. Ради смеха, я замерил время выполнения обоих подходов с разным размером набора обработчиков.

Sigle thread:  14.4 seconds
4 Pool:         3.1 seconds
8 Pool:         1.4 seconds
13 Pool:        1.3 seconds

Потрясающе! И также показывает, что правильно поиграть со значением размера набора обработчиков. На моей машине любое значение больше 9 минимизует время выполнения.

Второй пример из реального мира

Изготовление тысяч миниатюр

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

Для одного процесса, без распараллеливания.

import os
import PIL

from multiprocessing import Pool
from PIL import Image

SIZE = (75,75)
SAVE_DIRECTORY = 'thumbs'

def get_image_paths(folder):
        return (os.path.join(folder, f)
                        for f in os.listdir(folder)
                        if 'jpeg' in f)

def create_thumbnail(filename):
        im = Image.open(filename)
        im.thumbnail(SIZE, Image.ANTIALIAS)
        base, fname = os.path.split(filename)
        save_path = os.path.join(base, SAVE_DIRECTORY, fname)
        im.save(save_path)

if __name__ == '__main__':
        folder = os.path.abspath(
                '11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840')
        os.mkdir(os.path.join(folder, SAVE_DIRECTORY))

        images = get_image_paths(folder)

        for image in images:
            create_thumbnail(Image)

Немного подправлено для примера, в реальности, папка передаётся в программу, собираются все изображения в ней, создаются миниатюры и кладутся в свою отдельную папку. На моём компьютере, это занимает 27.9 секунд для обработки 6000 изображений.

Если мы заменим цикл for на вызов параллельного map:

import os
import PIL

from multiprocessing import Pool
from PIL import Image

SIZE = (75,75)
SAVE_DIRECTORY = 'thumbs'

def get_image_paths(folder):
        return (os.path.join(folder, f)
                        for f in os.listdir(folder)
                        if 'jpeg' in f)

def create_thumbnail(filename):
        im = Image.open(filename)
        im.thumbnail(SIZE, Image.ANTIALIAS)
        base, fname = os.path.split(filename)
        save_path = os.path.join(base, SAVE_DIRECTORY, fname)
        im.save(save_path)

if __name__ == '__main__':
        folder = os.path.abspath(
                '11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840')
        os.mkdir(os.path.join(folder, SAVE_DIRECTORY))

        images = get_image_paths(folder)

        pool = Pool()
        pool.map(create_thumbnail, images)
        pool.close()
        pool.join()

5.6 секунд!

Это очень заметное ускорение, полученное заменой лишь нескольких строк кода. Продакшен версия этого даже еще быстрее, потому что задачи потребляющие процессор и ввод-вывод, разделены там в соотвествующие отдельные процессы и потоки. Однако, благодаря прозрачной природе map и отсутствию необходимости ручного управления потоками, на самом деле просто смешивать и сочетать эти подходы, и результат получается простой, надёжный и легко поддающийся отладке.

Собственно это оно. Параллельные вычисления одной(практически) строкой.


Продолжение...


среда, 20 ноября 2013 г.

Еще одни микрозаметки из django и md файлов.


Заметил(в последние три года), что blogger не самая удобная платформа для мелких заметок для себя. Хранить их в локальных файлах тоже не очень хочется, чтобы не терять возможности посмотреть их с другого компьютера. Есть много онлайн сервисов для этого, но с текстовым редактором они интегрируются слабо, да еще и временами перестают существовать(я пользовался catch.com, пока он не закрылся). Поэтому решил поднять какую-нибудь простенькую штуку на своём сервере. Вот что получилось.
За основу я взял django, и к шаблону проекта дописал буквально пару строк.
django-admin.py startproject myblog
cd myblog
python manage.py startapp blog
myblog/urls.py
from django.conf.urls import patterns, include, url

urlpatterns = patterns('',                                                      
     url(r'^$', 'interface.views.post'),                                        
     url(r'^(?P<post_id>\w+)/$', 'interface.views.post'),                       
)
blog/views.py
import markdown                                                                 
import interface.static as s
from django.http import HttpResponse

def post(request, post_id='index'):
    f = open(s.POST_PATH % post_id, 'r')
    result = s.PAGE_TEMPLATE % markdown.markdown(f.read().decode('utf-8'))
    f.close()
return HttpResponse(result)
И еще вам пригодится css файл
На всякий случай вот еще репозиторий целиком. Теперь я пишу свой поток сознания прямо в sublime в markdown разметке, нажимаю "сохранить", SFTP плагин загружает файл в папку на сервере и он тут же правильно отображается в браузере. Понятно, что это не продакшен решение для миллионов пользователей, но такой задачи у меня и не было. Если кто-то увидел в этом страшный велосипедизм и знает разумные способы, как добиться такого же результата, делитесь.

Продолжение...


четверг, 10 октября 2013 г.

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


У меня задача была такой: есть несколько школьников(до 10 человек) со своими ноутбуками. На них винда разных версий и степени рабочести. Хотелось как-то задешево сделать им всем одинаковое рабочее окружение на их компьютерах, ничего им не сломав. И совсем хорошо потом иметь между этими окружениями какую-то синхронизацию. Решал я это так:
Вообще ничего сверъестественного я не делал, пост больше как подтверждение возможности реализации такой идеи.
А что делал-то:
1. Купил флешки kingston на 8GB.
2. Поставил на одну из них Xubuntu через VirtualBox(можно и обычным методом, но это нужно выключать компьютер и внимательно выбирать диск при разметке. Установка через VB таких проблем лишена)
3. Загрузился снова через VirtualBox, поставил обновления и нужный софт, настроил синхронизацию.
4. С помощью dd клонировал эту флешку на все остальные.
Собственно всё. Теперь немного подробнее.

Вот флешки:


Для теста взял 4 штуки, если проблем не выявится, докуплю еще.

Ставим линукс.

Качаем образ нужного линукса:
wget http://mirror.yandex.ru/ubuntu-cdimage/xubuntu/releases/12.04.3/release/xubuntu-12.04.3-desktop-i386.iso
Создаём виртуальную машину
Подключаем флешку.
Немного отмечу процесс разбивки диска. Сейчас в компьютерах относительно много ОЗУ(от 1ГБ), и восьмигиговая флешка по сравнению с этим не такая большая. Поэтому я предпочитаю отдавать всё под / и не делать swap. Если так почему-то вообще нельзя делать никогда, расскажите мне почему.

Включаем и настраиваем.

Поставился, теперь попробуем в него загрузиться. По умолчанию VirtualBox так не умеет, но несложно его научить. Хотя официальный представить Oracle и уверяет, что это невозможно. Нужно добавить своего пользователя в группу disk
usermod -aG disk triklozoid
После этого перелогиниться и выполнить такую команду:
sudo VBoxManage internalcommands createrawvmdk -filename ~/temp/usbdisk.vmdk -rawdisk /dev/sdb
где
~/temp/usbdisk.vmdk это где создать файла диска
а
/dev/sdb устройство вашей флешки
В настойках виртуальной машины добавляем диск:
На этом этапе могут появиться какие-нибудь ошибки доступа, нужно проверять права на свежесозданный файл ~/temp/usbdisk.vmdk
Теперь включаем машину, она должна нормально загрузиться с флешки.
Делаем sudo apt-get update && sudo apt-get upgrade(yum, pacman, emerge или что там у вас).
Устанавливаем нужные приложения, настраиваем что нужно.

Про синхронизацию

Для синхронизации я использовал клиент Яндекс.Диска под линукс.
Качаем cтавим настраиваем по официальным докам.
Я использовал такую схему: Зарегистрировал один новый аккаунт на яндексе. Сделал папку у себя и дал доступ на чтение новому аккаунту. И авторизовался в линукс клиенте новым аккаунтом.
Можно конечно как-то усложнить схему и сделать на каждой флешке отдельный аккаунт, но мне лень. :-)

Клонирование.

После того, как настройка всего закончена, можно приступить к магии dd.
Хотя команда очень простая, совсем не магическая, если кто знает магические ключи, которые улучшают всё в миллион раз, делитесь.
КОМАНДУ ЗАПУСКАТЬ АККУРАТНО, С УСТРОЙСТВАМИ НЕ ОШИБАТЬСЯ
А то всё потрёте нафиг.
dd if=/dev/sdb of=/dev/sdc bs=16M
if - откуда
of - куда
bs - размер блока

Конец

Собственно на этом всё, всё работает, можно пробовать. Работает достаточно шустро(особенно питоновая консоль :-)), проблем с железом пока не было. Кроме синхронизации папки с файлами, хотелось бы конечно и набор пакетов тоже синхронизировать, например, через puppet, но на первое время хватит и такого.

Продолжение...


понедельник, 9 сентября 2013 г.

Делимся Linux скриншотами в один клик


Это супер короткий пост-заметка, как в Linux сохранять скриншоты на Яндекс.Диск и сразу получать ссылку. Ставим консольный клиент отсюда. Делаем такой скрипт:

#!/bin/bash
xfce4-screenshooter -s ~/Yandex.Disk/screenshots/ -r
yandex-disk sync
yandex-disk publish "$(ls -td ~/Yandex.Disk/screenshots/*|head -n 1)"|xclip

Первую строчку естественно можно заменить на запуск вашей любимой скриншотилки, если ей можно передать параметр, куда сохранять файл. Команду xclip можно заменить на xclip -selection clipboard, если вы хотите вставлять ссылку не средней кнопкой мыши, а по ctrl+v. Подробнее например здесь.

Продолжение...


воскресенье, 24 октября 2010 г.

GIMP печатает пустые листы.

После очередного обновления своего Archlinux'а, обнаружил следующую проблему: при печати из GIMP в превью нет изображения и на печать выводится пустой лист. Через неделю нагуглил-таки решение, выкладываю.

Сначала я поставил gutenprint плагин, из него всё работало, но я не нашёл как там менять качество печать и решил починить стандартную функцию печати. На launchpad(!) нашёл совет какого-то доброго человека, что нужно сделать downgrade библиотеки cairo до версии 1.8.10. Так и сделал.
Сначала нужно удалить установленную у нас версию cairo.

sudo pacman -Rnd cairo

Потом качаем, распаковываем, собираем и ставим версию 1.8.10.

wget http://cairographics.org/releases/cairo-1.8.10.tar.gz
tar xf cairo-1.8.10.tar.gz
cd cairo-1.8.10
./configure --prefix=/usr/lib
make
sudo make install

Запускаем GIMP, наблюдаем положительный результат, радуемся и надеемся, что в следующем релизе cairo или GIMP'a всё починят и оно будет работать без дополнительных костылей и ударов молотком. :-)



Продолжение...


понедельник, 26 апреля 2010 г.

Настройка Wifi на нетбуке HP Mini 501 под Tiny Core Linux

Пару месяцев назад приобрёл себе новый нетбук. Дефолтный SLED меня не порадовал своей тормознутостью, захотелось чего-нибудь быстрого и экзотичного. И вот на welinux наткнулся на заметку про Tiny Core. Понравилось, поставил, столнулся с проблемой неработающего Wifi. Начал копать и откопал.




Для начала нужно определить название Wifi чипа.
Для этого используем lspci. В Tiny Core по умолчанию этой команды нет, необходимо установить пакет pci-utils.
Анализируем вывод и находим такую строчку:

08:00.0 Network controller: Broadcom Corporation BCM4312 802.11b/g (rev 01)

Из неё делаем вывод, что чип у нас broadcom bcm4312.
Далее идем на linuxwireless.org и читаем мануал.
Пишут там следующее

lspci -vnn | grep 14e4

08:00.0 Network controller [0280]: Broadcom Corporation BCM4312 802.11b/g [14e4:4315] (rev 01)

Отсюда можно узнать точную модель. В данном случае "4315".
На сайте есть таблица, по которой можно понять поддерживается ли ваш чип и какой версией ядра.
Напротив моего чипа в таблице было следующее:

supported 2.6.32 and later

А ядро по умолчанию в Tiny Core 2.6.29. "Надо собрать своё" - догадался Штирлиц.
Будем собирать. Для сборки нам понадобится, как минимум, gcc и make. Их надо поставить через пакетный менеджер.
Качаем с kernel.org текущее стабильное ядро.

wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.33.2.tar.bz2
tar xf linux-2.6.33.2.tar.bz2
cd linux-2.6.33.2

Качаем стандартный для Tiny Core конфиг ядра тут. (Main - Downloads - Current Release - src), кладем в папку с исходниками ядра и переименовываем в ".config"

wget http://distro.ibiblio.org/pub/linux/distributions/tinycorelinux/2.x/release/src/config-2.6.29.1-tinycore
mv config-2.6.29.1-tinycore .config

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

make menuconfig
make
make bzImage
make modules
make INSTALL_MOD_PATH=./mod_dir modules_install


Собранные модули нужно добавить в initrd следующим образом(инструкция[eng]:

mkdir extract
cp /mnt/sda1/boot/tinycore.gz ./extract
cd extract
zcat tinycore.gz | sudo cpio -i -H newc -d
rm -rf lib/modules/2.6.29.1-tinycore
cp -r ../mod_dir/lib/modules/2.6.33.2-tinycore ./
cd ..
sudo depmod -b extract 2.6.29.1-tinycore
sudo ldconfig -r extract
find extract| sudo cpio -o -H newc | gzip -2 > ../tinycore.gz
advdef -z4 tinycore.gz

Всё собрано, осталось перенести в нужное место и подготовить загрузчик.

cp tinycore.gz /mnt/sda1/boot/tinycore2.gz
cp arch/x86/boot/bzImage /mnt/sda1/boot/bzImage2

Далее открываем /mnt/sda1/boot/grub/menu.lst любым редактором и добавляем туда.

title tinycore2
kernel /boot/bzImage_tr quiet
initrd /boot/tinycore2.gz

Сохраняем, перезагружаемся.
После перезагрузки набираем iwconfig.
Должен появиться наш интерфейс.
Но и это еще не всё!
Еще нам нужна прошивка. Cтавим из репозитория b43-fwcutter. А потом делаем так(тоже с linuxwireless)

wget http://mirror2.openwrt.org/sources/broadcom-wl-4.150.10.5.tar.bz2
tar xjf broadcom-wl-4.150.10.5.tar.bz2
cd broadcom-wl-4.150.10.5/driver
sudo b43-fwcutter wl_apsta_mimo.o
sudo mkdir /lib/firmware
sudo cp -r b43 /lib/firmware/

Ну и перезагружаем модуль:

sudo rmmod b43
sudo modprobe b43

Далее "sudo wicd-start" ну и wicd-curses, например. Где и видим-таки наши долгожданные сети.
Проверил, работает, не ломается при переходе в suspend и обратно. В общем всё супер.
В качестве бонуса после пересборки ядра заработала прокрутка на тачпаде, с которой достаточно долго ковырялся до этого.



Продолжение...


суббота, 19 декабря 2009 г.

Прошивка Cyanogen Mod в HTC Magic.

Обзавелся таким девайсом и сразу же решил чего-нибудь эдакое туда залить.
Прочитал этот обзор и выбрал прошивку Cyanogen Mod. Успешно ее залил, рассказываю как у меня это получилось.

Для начала нужно определить тип вашего устройства. Их бывает два: 32А и 32В. Отличаются аппаратной частью, в частности объемом оперативной памяти. Делается это следующим образом.
1. Выключаем полностью телефон.
2. Удерживая кнопку Назад(со стрелкой) нажимаем кнопку включения.
3. Должен появиться вот такой веселый экранчик Fastboot.

4. На нем я подчеркнул красным интересующие нас цифры и букву. Как видно, у меня оказалась версия 32В. И дальше рассказ идет про нее. Если у вас вдруг 32А, то чем отличается ее прошивка можно почитать на wiki(eng) CyanogenMod.
Теперь нам надо скачать следующие файлы:
Последний Android SDK.
Бинарник утилиты fastboot.
Последнюю CM recovery.
Образ базового Android 1.6.
Сам CyanogenMod.
Суммарно все весит мегабайт 150, поэтому, если вы не счастливый обладатель N-мегабитной безлимитки, лучше все поставить на загрузку и сходить погулять.

Скачали - едем дальше.
Распаковываем архив с SDK, например в /usr/local/. Папку tools для удобства желательно добавить в PATH. Бинарник fastboot кладем в tools и делаем исполняемым(chmod +x fastboot). Оставшиеся 3 файла копируем в корень SD карты.
Телефон подключаем к компьютеру проводом, загружаем опять в fastboot(экран с тремя зелеными андройдами).
На компьютере в терминале из под суперпользователя выполняем

fastboot boot cm-recovery-1.4.img

В выводе терминала должно появиться:

downloading 'boot.img'... OKAY
booting... OKAY

а телефон загрузится в Recovery mode.
Теперь, собственно сам процесс прошивки.
1. Выбираем пункт wipe data/factory reset. (очистка данных и сброс на заводские настройки)
2. Потом пункт apply any zip from sd, в нем выбираем DRC83_base_defanged.zip. Соглашаемся кнопкой Home(с домиком), ждем.
3. Ни в коем случаем НЕ надо перезагружать устройство.
4. Снова пункт apply any zip from sd, но теперь выбираем update-cm-4.2.x-signed.zip. Опять соглашаемся, опять ждем.
5. Вот теперь можно перезагрузиться соответствующим пунктом или нажатием на Home+Back.
6. Первый раз Magic будет грузиться долго, наберитесь терпения и ничего не трогайте.

Все, с прошивкой закончено, еще пара дополнительных моментов.
Можно установить напостоянную Recovery Mode. Для этого:
1. Подключаем загруженный и работающий аппарат к компьютеру проводом.
2. Последовательно выполняем команды в терминале компьютера(если вы не используете sudo, то сервер надо запускать из-под root):

adb kill-server
sudo adb start-server
flash_image recovery /sdcard/cm-recovery-1.4.img

И все, теперь, если при включении держать кнопку Home, телефон загрузится в Recovery Mode.

На этой прошивке встретилась небольшая проблема с Android Маркетом. Он вывешивает лицензионное соглашение, а кнопки "Принять" там нет. Чтобы обойти это надо в настройках(Меню -> Настройки -> Язык и текст -> Основной язык) выбрать English, принять соглашение(под ним появится кнопка Accept), а потом обратно включить Русский.

И напоследок расскажу, как поставить удобную экранную клавиатуру от HTC - Touch input.
1. Качаем ее отсюда.
2. Закидываем на SD карту.
3. Открываем с помощью файлового менеджера, например Astro File Manager(ставится из маркета).
4. Теперь ее надо включить. Идем в Настройки - Регион и ввод текста, ставим галочку напротив Touch Input. Потом в любом поле ввода удерживаете палец и из меню выбираете Touch input.
5. Чтобы появилось переключение на русский, надо повернуть телефон горизонтально. :-)

Вроде бы ничего не забыл, если соберусь расскажу о общих впечатлениях от устройства и приложениях.

Продолжение...


пятница, 11 декабря 2009 г.

Мышь в 3D приложениях под wine.

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

Я пробовал это решение на двух играх: Aliens versus Predator(3D action) и Clusterball(аркадная леталка)
Проблема примерно в следующем: мышь перемещается только в пределах разрешения экрана, из-за этого нельзя развернуться больше чем на 180 градусов в AvP, а в леталке поворачивать можно только короткими рывками.
Ход действий таков:
Надо скачать архив с исходниками, например так:

wget http://downloads.sourceforge.net/project/wine/Source/wine-1.1.33.tar.bz2?use_mirror=sunet

Потом распаковываем их

tar xf wine-1.1.33.tar.bz2

Переходим в папку с нужном файлом

cd ./wine-1.1.33/dlls/dinput

Создаем здесь файл mouse.patch со следующим содержанием(взят отсюда, там много других еще есть, для определенных игр и т.д.)

--- dlls/dinput/mouse.c_old 2008-03-03 11:14:47.000000000 +0100
+++ dlls/dinput/mouse.c 2008-03-10 19:23:21.000000000 +0100
@@ -306,7 +306,7 @@
wdata = pt1.y;
}

- This->need_warp = (pt.x || pt.y) && dwCoop & DISCL_EXCLUSIVE;
+ This->need_warp = (hook->pt.x<2 || hook->pt.y<2 || hook->pt.x>((2 * This->win_centerX)-2) || hook->pt.y>((2 * This->win_centerY)-2) );
break;
}
case WM_MOUSEWHEEL:

и накладываем патч

patch -p1 mouse.c mouse.patch

Потом переходим в папку с исходниками, и командуем обычные:

./configure
make
sudo make install

Перед make install желательно убедиться, чтобы в системе не был установлен пакет родной wine, если установлен - удалить.
Должно собраться и поставиться без ошибок.
Потом идем в папку с игрой и запускаем как обычно

wine AvP.exe

У меня главное меню запускается в окне, но потом разворачивается на весь экран и работает нормально.

Решение конечно не лучшее, как минимум потому, что не рекомендуется ставить софт из исходников в пакетных дистрибутивах без сборки пакета. Но зато работает.

Продолжение...


пятница, 4 декабря 2009 г.

MOC + last.fm + русские тэги в UTF-8

Прочитал про этот плеер, понравился, начал пользоваться. Нашлись два маленьких неприятных момента: кривое отображение моих русскоязычных utf-8 тэгов и отсутствие скробблинга на last.fm. Чуток поковырявшись, оба решил, делаю пометку, чтобы не забыть как.

У меня нет раздела с windows, вся музыка хранится на ext3 разделе и тэги сконвертированы в utf-8 с помощью tag2utf. Но MOC отображает их точками, а если в конфиге выставить параметр ID3v1TagsEncoding=UTF-8, то решеточками. Оказалось, что проблема в тэгах ID3v1 и чтобы ее решить, надо их поудалять, а оставить ID3v2. Чтобы решать проблему комплексно, одновременно с конвертированием, надо делать так:
Ставим пакет python-mutagen(в ubuntu называется так). И даем команду

find -iname '*.mp3' -print0 | xargs -0 mid3iconv -eCP1251 --remove-v1

Команда перебирает все mp3 файлы в текущем каталоге и подкаталогах, обрабатывая их нужным образом. Готово, теперь вся наша музыка в пригодном для переваривания MOC'ом виде.

Теперь к скробблингу. Для его организации нам будет нужна опция OnSongChange в конфиге. Ее наличие зависит от версии MOC. Мне пришлось обновиться на вариант devel(2.5.0-alpha4), так как в обычном этой опции не было.
Кроме этого надо поставить пакет lastfmsubmitd. В конфиге(/etc/lastfmsubmitd.conf) прописать данные своего аккаунта. Если будет ругаться на отсутствие данных аккаунта, значит что-то с правами доступа к этому файлу.
Потом создать скрипт moc_submit_lastfm, вот такого содержания:

#!/usr/bin/env python

from datetime import datetime
from optparse import OptionParser
from subprocess import call, Popen, PIPE
import time

parser = OptionParser()
parser.add_option("-a", "--artist", dest="artist")
parser.add_option("-t", "--title", dest="title")
parser.add_option("-A", "--album", dest="album")
parser.add_option("-l", "--length", dest="length")

# Treating everything as bytestrings throughout seems to work OK even
# with non-ASCII characters in song titles etc (at least with a UTF-8
# locale).

def still_playing(artist, album, title):
p = Popen(["mocp", "-i"], stdout=PIPE)
out, err = p.communicate()
lines = out.split("\n")
for s in ["Artist: %s" % artist, "Album: %s" % album, "SongTitle: %s" % title]:
if not s in lines:
return False
return True

def submit_to_lastfm(artist, album, title, length):
args = ["/usr/lib/lastfmsubmitd/lastfmsubmit", "--artist", artist, "--title", title, "--length", length]
if album is not None:
args.extend(["--album", album])
call(args)

def main():
options, args = parser.parse_args()
if any(not options.__dict__.get(k) for k in ["artist", "title", "length"]):
print "All of artist, album, length must be specified"
exit(1)
if ":" in options.length:
mins, secs = options.length.split(":")
length = int(mins) * 60 + int(secs)
else:
length = int(options.length)
# wait until song is half played
wait = length/2

start = datetime.now()
while True:
time.sleep(5)
if not still_playing(options.artist, options.album, options.title):
exit(1)
if (datetime.now() - start).seconds > wait:
submit_to_lastfm(options.artist, options.album, options.title, options.length)
exit(0)

if __name__ == '__main__':
import sys
main()

И в конфиге .moc/config задать вышеуказанную OnSongChange:

OnSongChange = "/home/triklozoid/bin/moc_submit_lastfm --artist %a --title %t --length %d --album %r"

заменив путь на путь к созданному Вами скрипту.

Вот и все, вроде ничего не забыл.

Про скробблинг прочитал здесь, про перекодирование здесь, про MOC тут и там.



Продолжение...