вторник, Февраль 07, 2012

Ошибки Eclipse и Android SDK

Я разрабатываю под ubuntu (на момент публикации 11.04).
Eclipse SDK Version: 3.7.1 Build id: M20110909-1335
$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) Server VM (build 20.1-b02, mixed mode)

При очередном старте проекта наткнулся на ошибку
parsesdkcontent failed android

проекты собирались, т.к. sdk не был загружен. Я попытался переустановить все с начала - не помогло. Попробовал обновить sdk через файл ./sdk/tools/android (Android SDK Manager), стали появляться следующие ошибки:
Failed to fetch URL http://dl-ssl.google.com/android/repository/addons_list-1.xml, reason: Failure initializing default SSL context
но файл по адресу открывается. Покопавшись в интернетах обнаружил вот это обсуждение.
Там сказано, что следует удалить gcj, позже я вспомнил, что недавно устанавливал этот пакет.
sudo apt-get remove gcj-*
Далее при попытке сборки в консоли эклипса появляется следующее
Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead. Please use Android Tools > Fix Project Properties.
Должно лечиться этими инструкциями, а именно Project properties -> Android Tools -> Fix Project Properties
Мне не помогло. Я попробовал перейти на openjdk.

sudo apt-get remove sun-java6-*
ubuntu сразу предложил поставить пакеты на замену

ca-certificates-java default-jre default-jre-headless icedtea-6-jre-cacao icedtea-6-jre-jamvm icedtea-netx libaccess-bridge-java libaccess-bridge-java-jni openjdk-6-jre openjdk-6-jre-headless openjdk-6-jre-lib tzdata-java

добавил путь /usr/lib/jvm/java-6-openjdk/jre/bin/ в bash_profile чтобы запускался eclipse

$ vim ~/.bash_profile
PATH=$PATH:/usr/lib/jvm/java-6-openjdk/jre/bin
export PATH

После этого все заработало, ура.

среда, Январь 25, 2012

Простой алгоритм случайной выборки с учетом веса

Часто необходимо обращаться к одной и той же задаче:
"случайная выборка с учетом веса".

Чтобы не забыть вот кратное описание взятое отсюда:

Простой алгоритм случайной выборки с учетом веса


В общем виде этот алгоритм можно описать так:

  1. Выбрать случайное число между еденицей и суммой “весов” всех элементов
  2. Спускаться по списку элементов добавляя к счетчику вес текущего элемента
  3. Проверить, если счетчик (шаг №2) больше или равен случайному числу (шаг №1), то закончить
  4. цикл и вернуть текущий элемент. В противном случае перейдите к шагу №2.
/**
 * Выборка случайного элемента с учетом веса
 *
 * @param array $values индексный массив элементов
 * @param array $weights индексный массив соответствующих весов
 * @return mixed выбранный элемент
 */
function weighted_random_simple ( $values, $weights )
{
    $total = array_sum( $weights );
    $n = 0;
 
    $num = mt_rand( 1, $total );
 
    foreach ( $values as $i => $value )
    {
        $n += $weights[$i];
 
        if ( $n >= $num )
        {
            return $values[$i];
        }
    }
}

$values = array('A', 'B', 'C');
$weights = array(3, 7, 10);
echo weighted_random_simple($values, $weights);

Алгоритм случайной выборки из тысяч элементов

Алгоритм может быть расширен, чтобы сделать его значительно быстрее. Вместо вычисления общего веса (шаг №1) и счетчика (шаг №2) каждый раз, можно сделать это один раз и сохранить значения счетчиков в массиве. Тогда мы сможем использовать бинарный поиск, чтобы быстро выбрать правильный элемент. Ниже приведен модифицированный вариант скрипта:
/**
 * Случайно выбирает один из элементов на основе их веса. 
 * Оптимизирован для большого числа элементов.
 *
 * @param array $values индексный массив элементов
 * @param array $weights индексный массив соответствующих весов
 * @param array $lookup отсортированный массив для поиска
 * @param int $total_weight сумма всех весов
 * @return mixed выбранный элемент
 */
function weighted_random($values, $weights, $lookup = null, $total_weight = null)
{
    if ($lookup == null OR $total_weight == null) 
    {
        list($lookup, $total_weight) = calc_lookups($values, $weights);
    }
 
    $r = mt_rand(1, $total_weight);
         
    return $values[binary_search($r, $lookup)];
}
 
/**
 * Создание массива используемого в бинарном поиске
 *
 * @param array $values 
 * @param array $weights
 * @return array
 */
function calc_lookups($values, $weights)
{
    $lookup = array();
    $total_weight = 0;
         
    for ($i=0; $i < count($weights); $i++)
    {
        $total_weight += $weights[$i];
        $lookup[$i] = $total_weight;
    }
     
    return array($lookup, $total_weight);
}
 
/**
 * Ищет в массиве элемент по номеру и возвращает элемент если он найден.
 * В противном случае возвращает позицию, где он должен быть вставлен, 
 * или count($haystack)-1, если $needle больше чем любой элемент в массиве.
 *
 * @param int $needle
 * @param array $haystack
 * @return int
 */
function binary_search($needle, $haystack)
{
    $high = count($haystack) - 1;
    $low = 0;
 
    while ( $low < $high )
    {
        $probe = (int)(($high + $low) / 2);
 
        if ($haystack[$probe] < $needle)
        {
            $low = $probe + 1;
        } 
        elseif ($haystack[$probe] > $needle) 
        {
            $high = $probe - 1;
        } 
        else
        {
            return $probe;
        }
    }
 
    if ( $low != $high )
    {
        return $probe;
    } 
    else
    {
        return ($haystack[$low] >= $needle) ? $low : $low + 1;
    }
}

// Рассчет массивов (1 раз)
list($lookup, $total_weight) = calc_lookups($values, $weights);
//....
// Каждый раз когда вам необходимо выбрать случайный элемент:
$val = weighted_random($values, $weights, $lookup, $total_weight);

понедельник, Октябрь 31, 2011

Основы работы с git

Основной и полноценный документ http://githowto.com/

забрать код
git clone git@github.com:companyname/projectname.git

если
Cloning into mambaandroid...
Permission denied (publickey).
fatal: The remote end hung up unexpectedly
то
ssh-keygen -t rsa -C "your_email@youremail.com"
cat ~/.ssh/id_rsa.pub
и скопировать его в настройки своего аккаунта на гитхабе

тест коннекта
ssh -T git@github.com

иногда надо добавить идентит
ssh-add ~/.ssh/id_rsa

список бранчей
git branch -a

переключиться в бранч
git checkout version-0.8

если вставить этот код в конец своего .bashrc
PS1="\[\033[38m\]\u@\h\[\033[01;34m\] \w \[\033[31m\]\`ruby -e \"print (%x{git branch 2> /dev/null}.grep(/^\*/).first || '').gsub(/^\* (.+)$/, '(\1) ')\"\`\[\033[35m\]$\[\033[00m\] "

то будет подсвечиваться текущий бранч прямо в консоли

забрать все новое с удаленного репа и попытаться авто-смерджить с текущим состоянием
git pull origin version-0.8

добавить все данные в локальной копии и зафиксировать
git add .
git commit -m 'desc'
или
git commit -a -m 'desc'

пушнуть в удаленный реп
git push origin version-0.8

отменить локальные изменения (svn revert)
сбросить все
git reset --hard HEAD

только определенный файл
git checkout -- hello.rb
git checkout HEAD hello.rb

ревертнуть последний коммит
git revert HEAD

еще примеры здесь

смерджить код из обного бранча в другой
git checkout version-0.9
git pull origin version-0.9
git merge version-0.8
git log
git push origin version-0.9

смерджить код в мастер и навесить таг
git checkout master
git merge version-0.8
git tag -a version-0.8.1-release -m "0.8.1 фикс-версия"
git push --tags origin master

четверг, Февраль 10, 2011

Как на самом деле работает присваивание и передача по ссылке объектов в php5

Как-то давно, когда только появился php5, я думал, что разобрался с ООП, а именно с присвоением объектов. Но из-за того, что много времени проводил с java стал под забывать как это работает в php5.
В штатном режиме, если всегда помнить о том, что в php5 присваивание происходит по ссылке, то нет никаких проблем, пока не используешь знак &.
http://www.php.net/manual/en/language.oop5.basic.php
<?php
class SimpleClass{}
class SimpleClass
{
    // property declaration
    public $var = 'a default value';

    // method declaration
    public function displayVar() {
        echo $this->var;
    }
}
?>

Но подлинный смысл раскрывается этим комментарием:
http://www.php.net/manual/en/language.oop5.basic.php#79856
Я позволил себе его вольно перевести:
В php необходимо думать о переменных как о ячейках памяти. У каждой переменной если имя, которое ссылается на ячейку памяти(переменную), где хранится значение простого типа: число, строка, массив, и т.д. Когда вы создаете ссылку(&), вы создаете второе имя, которое ссылается на ту же саму ячейку памяти. Когда вы присваиваете одну переменную другой, вы копируете содержимое ячейки памяти в другую ячейку памяти.
Но присваивание экземпляров классов(далее объект) происходит не так как присваивание простых типов. Объекты не хранятся в ячейках памяти, которые программист "видит" на прямую. Вместо этого в ячейке памяти хранится указатель на объект. Таким образом указатель ведет себя как примитивный тип.
Когда вы присваиваете значение ссылки объекта одной переменной другой, обе переменные могут менять состояние одного и того же объекта. Но переменные не являются ссылками на объект, т.к. если присвоить одной из переменных новое значение, то это не отразится на другой переменной.
<?php
// Assignment of an object
Class Object{
   public $foo="bar";
};

$objectVar = new Object();
$reference =& $objectVar;
$assignment = $objectVar

//
// $objectVar --->+-----------+
//                |(указатель1)----+
// $reference --->+-----------+    |
//                                 |
//                +-----------+    |
// $assignment -->|(указатель2)----+
//                +-----------+    |
//                                 |
//                                 v
//                  Object(1):foo="bar"
//
?>
Значение переменной $assignment отличается от $objectVar, но эти значение ссылаются на один и тот же объект. Это поведение делает похожим на механизм передачи по ссылке. Если вы используете переменную $objectVar, чтобы поменять состояние объекта, то эти же изменения появятся и в переменной $assignment, т.к. они указывают на один и тот же объект.


<?php
$objectVar->foo = "qux";
print_r( $objectVar );
print_r( $reference );
print_r( $assignment );

//
// $objectVar --->+-----------+
//                |(указатель1)----+
// $reference --->+-----------+    |
//                                 |
//                +-----------+    |
// $assignment -->|(указатель2)----+
//                +-----------+    |
//                                 |
//                                 v
//                  Object(1):foo="qux"
//
?>

Но с передачей значения по ссылке (&) дело обстоит совсем иначе. Если вы обнулите $objectVar, вы замените значение указателя в ячейке памяти на NULL. Это означает, что $reference, которая ссылается на туже ячейку памяти, также будет NULL. Но $assignment, которая ссылается на другую ячейку памяти, будет так же хранить копию указателя на объект, и она не будет равна NULL.

<?php
$objectVar = null;
print_r($objectVar);
print_r($reference);
print_r($assignment);

//
// $objectVar --->+-----------+
//                |  NULL     | 
// $reference --->+-----------+
//                           
//                +-----------+
// $assignment -->|(указатель2)----+
//                +-----------+    |
//                                 |
//                                 v
//                  Object(1):foo="qux"
?>


К примеру, если взять java, где все переменные если ссылки на объекты, тот же пример выполняется так как и в php5 без символа &:

import java.util.*;

class ObjectReference {
    public static void main(String[] args) {
        class Obj {
            int var = 1;
        }
        
        Obj objectVar = new Obj();
        Obj reference = objectVar;
        objectVar.var = 2;
        System.out.println("objectVar.var="+objectVar.var);
        System.out.println("reference.var="+reference.var);
        
        objectVar = null;
        
        if (reference == null) {
            System.out.println("reference is null");
        } else {
            System.out.println("reference is not null");
        }
    }
}
ответ:
objectVar.var=2
reference.var=2
reference is not null

четверг, Январь 20, 2011

Программа для сбора логов в клиентов

Очень полезно, когда у клиента что то не работает и ты не знаешь чем помочь
http://code.google.com/p/android-log-collector/

Как сбросить logcat в файл


try {
File filename = new File(Environment.getExternalStorageDirectory()+"/logfile.log");
filename.createNewFile();
String cmd = "logcat -d -f "+filename.getAbsolutePath();
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

пятница, Декабрь 24, 2010

А как умеет ваш язык это делать?

Результат будет одинаковый:
about_logo

python -c 'import re;s="http://www.google.ru/intl/ru/images/about_logo.gif"; m = re.match(".*\/(.*)\.gif$",s); print m.group(1)'
perl -e '$e="http://www.google.ru/intl/ru/images/about_logo.gif"; $e =~ /.*\/(.*)\.gif$/i; print $1."\n";'
php -r '$e="http://www.google.ru/intl/ru/images/about_logo.gif"; $pat = "/.*\/(.*)\.gif$/"; preg_match($pat,$e,$m);print $m[1]."\n";'

вторник, Декабрь 07, 2010

Android SDK 2.3 - "Unknown Android Packaging Problem"

После обновления SDK согласно документам
http://developer.android.com/intl/zh-TW/sdk/adding-components.html
http://developer.android.com/intl/zh-TW/sdk/installing.html
http://developer.android.com/intl/zh-TW/sdk/eclipse-adt.html

перестала работать отладка adb
Эта программа переехала в другую папку, нужно обновить .bashrc
export PATH=${PATH}:/tools:/platform-tools
т.е. по сути добавить папку platform-tools
Далее перестала работать сборка, выходит следующая ошибка
Error generating final archive: java.io.FileNotFoundException: 
/home/user/android/bin/resources.ap_ does not exist
Android
Unknown Android Packaging Problem

Решение нашел здесь
http://stackoverflow.com/questions/4372574/many-errors-in-android-project-after-i-upgraded-to-android-sdk-2-3
Вкратце, если в файле res/values/strings.xml вы используете конструкции вида
<string name="page_number">%d results, showing page %d of %d</string> 
то теперь нужно использовать индексы для элементов больше одного, т.е. вот так
<string name="page_number">%1$d results, showing page %2$d of %3$d</string>