Как изменить цвет нажатого пункта overflow меню

Шаг 1

Создаем стиль для выпадающего списка:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyTheme"
           parent="@android:style/Theme.Holo">
        <item name="android:dropDownListViewStyle">@style/MyTheme.DropDownListViewStyle</item>
    </style>
    <style name="MyTheme.DropDownListViewStyle"
           parent="android:style/Widget.Holo.ListView.DropDown">
        <item name="android:listSelector">@drawable/selectable_background</item>
    </style>
</resources>

Шаг 2

Создаем селектор res/drawable/selectable_background.xml, используемый на предыдущем шаге:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@android:color/holo_green_light"/>
    <item android:drawable="@android:color/transparent"/>
</selector>

Стеммер Портера для русского языка

Стеммер Портера – алгоритм стемминга (нахождения основы слова для заданного исходного слова), опубликованный Мартином Портером. Алгоритм не использует баз основ слов, а работает, последовательно применяя ряд правил отсечения окончаний и суффиксов.


Сначала введем некоторые определения:

  • Гласные буквыа, е, и, о, у, ы, э, ю, я. Буква ё считается равнозначной букве е.
  • RV – область слова после первой гласной. Она может быть пустой, если гласные в слове отсутствуют.
  • R1 – область слова после первого сочетания "гласная-согласная".
  • R2 – область R1 после первого сочетания "гласная-согласная".

Пример

В слове противоестественном:

  • RV = тивоестественном.
  • R1 = ивоестественном.
  • R2 = оестественном.

Теперь определим несколько классов окончаний слова. Я оставлю их оригинальные названия из исходного описания алгоритма.

PERFECTIVE GERUND

  • Группа 1: в, вши, вшись.
  • Группа 2: ив, ивши, ившись, ыв, ывши, ывшись.

Окончаниям из группы 1 должна предшествовать буква а или я.

ADJECTIVE

ее, ие, ые, ое, ими, ыми, ей, ий, ый, ой, ем, им, ым, ом, его, ого, ему, ому, их, ых, ую, юю, ая, яя, ою, ею.

PARTICIPLE

  • Группа 1: ем, нн, вш, ющ, щ.
  • Группа 2: ивш, ывш, ующ.

Окончаниям из группы 1 должна предшествовать буква а или я.

REFLEXIVE

ся, сь.

VERB

  • Группа 1: ла, на, ете, йте, ли, й, л, ем, н, ло, но, ет, ют, ны, ть, ешь, нно.
  • Группа 2: ила, ыла, ена, ейте, уйте, ите, или, ыли, ей, уй, ил, ыл, им, ым, ен, ило, ыло, ено, ят, ует, уют, ит, ыт, ены, ить, ыть, ишь, ую, ю.

Окончаниям из группы 1 должна предшествовать буква а или я.

NOUN

а, ев, ов, ие, ье, е, иями, ями, ами, еи, ии, и, ией, ей, ой, ий, й, иям, ям, ием, ем, ам, ом, о, у, ах, иях, ях, ы, ь, ию, ью, ю, ия, ья, я.

SUPERLATIVE:

ейш, ейше.

DERIVATIONAL

ост, ость.

ADJECTIVAL

ADJECTIVAL определяется как ADJECTIVE или PARTICIPLE + ADJECTIVE. Например: бегавшая = бега + вш + ая.

Правила

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

Все проверки производятся над областью RV. Так, при проверке на PERFECTIVE GERUND предшествующие буквы а и я также должны быть внутри RV. Буквы перед RV не участвуют в проверках вообще.

Шаг 1

Найти окончание PERFECTIVE GERUND. Если оно существует – удалить его и завершить этот шаг.

Иначе, удаляем окончание REFLEXIVE (если оно существует). Затем в следующем порядке пробуем удалить окончания: ADJECTIVAL, VERB, NOUN. Как только одно из них найдено – шаг завершается.

Шаг 2

Если слово оканчивается на и – удаляем и.

Шаг 3

Если в R2 найдется окончание DERIVATIONAL – удаляем его.

Шаг 4

Возможен один из трех вариантов:

  1. Если слово оканчивается на нн – удаляем последнюю букву.
  2. Если слово оканчивается на SUPERLATIVE – удаляем его и снова удаляем последнюю букву, если слово оканчивается на нн.
  3. Если слово оканчивается на ь – удаляем его.

Исходный код

Алгоритм реализован на Python 3 и проходит тест Портера. Актуальный исходный код можно найти на GitHub'е.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
The Snowball stemmer.
Pavel Perestoronin © 2013
"""

import re
import unittest


class Stemmer:
    # Helper regex strings.
    _vowel = "[аеиоуыэюя]"
    _non_vowel = "[^аеиоуыэюя]"

    # Word regions.
    _re_rv = re.compile(_vowel)
    _re_r1 = re.compile(_vowel + _non_vowel)

    # Endings.
    _re_perfective_gerund = re.compile(
        r"(((?P[ая])(в|вши|вшись))|(ив|ивши|ившись|ыв|ывши|ывшись))$"
    )
    _re_adjective = re.compile(
        r"(ее|ие|ые|ое|ими|ыми|ей|ий|ый|ой|ем|им|ым|ом|его|ого|ему|ому|их|ых|"
        r"ую|юю|ая|яя|ою|ею)$"
    )
    _re_participle = re.compile(
        r"(((?P[ая])(ем|нн|вш|ющ|щ))|(ивш|ывш|ующ))$"
    )
    _re_reflexive = re.compile(
        r"(ся|сь)$"
    )
    _re_verb = re.compile(
        r"(((?P[ая])(ла|на|ете|йте|ли|й|л|ем|н|ло|но|ет|ют|ны|ть|ешь|"
        r"нно))|(ила|ыла|ена|ейте|уйте|ите|или|ыли|ей|уй|ил|ыл|им|ым|ен|ило|"
        r"ыло|ено|ят|ует|уют|ит|ыт|ены|ить|ыть|ишь|ую|ю))$"
    )
    _re_noun = re.compile(
        r"(а|ев|ов|ие|ье|е|иями|ями|ами|еи|ии|и|ией|ей|ой|ий|й|иям|ям|ием|ем|"
        r"ам|ом|о|у|ах|иях|ях|ы|ь|ию|ью|ю|ия|ья|я)$"
    )
    _re_superlative = re.compile(
        r"(ейш|ейше)$"
    )
    _re_derivational = re.compile(
        r"(ост|ость)$"
    )
    _re_i = re.compile(
        r"и$"
    )
    _re_nn = re.compile(
        r"((?&lt;=н)н)$"
    )
    _re_ = re.compile(
        r"ь$"
    )

    def stem(self, word):
        """
        Gets the stem.
        """

        rv_pos, r2_pos = self._find_rv(word), self._find_r2(word)
        word = self._step_1(word, rv_pos)
        word = self._step_2(word, rv_pos)
        word = self._step_3(word, r2_pos)
        word = self._step_4(word, rv_pos)
        return word

    def _find_rv(self, word):
        """
        Searches for the RV region.
        """

        rv_match = self._re_rv.search(word)
        if not rv_match:
            return len(word)
        return rv_match.end()

    def _find_r2(self, word):
        """
        Searches for the R2 region.
        """

        r1_match = self._re_r1.search(word)
        if not r1_match:
            return len(word)
        r2_match = self._re_r1.search(word, r1_match.end())
        if not r2_match:
            return len(word)
        return r2_match.end()

    def _cut(self, word, ending, pos):
        """
        Tries to cut the specified ending after the specified position.
        """

        match = ending.search(word, pos)
        if match:
            try:
                ignore = match.group("ignore") or ""
            except IndexError:
                # No ignored characters in pattern.
                return True, word[:match.start()]
            else:
                # Do not cut ignored part.
                return True, word[:match.start() + len(ignore)]
        else:
            return False, word

    def _step_1(self, word, rv_pos):
        match, word = self._cut(word, self._re_perfective_gerund, rv_pos)
        if match:
            return word
        _, word = self._cut(word, self._re_reflexive, rv_pos)
        match, word = self._cut(word, self._re_adjective, rv_pos)
        if match:
            _, word = self._cut(word, self._re_participle, rv_pos)
            return word
        match, word = self._cut(word, self._re_verb, rv_pos)
        if match:
            return word
        _, word = self._cut(word, self._re_noun, rv_pos)
        return word

    def _step_2(self, word, rv_pos):
        _, word = self._cut(word, self._re_i, rv_pos)
        return word

    def _step_3(self, word, r2_pos):
        _, word = self._cut(word, self._re_derivational, r2_pos)
        return word

    def _step_4(self, word, rv_pos):
        _, word = self._cut(word, self._re_superlative, rv_pos)
        match, word = self._cut(word, self._re_nn, rv_pos)
        if not match:
            _, word = self._cut(word, self._re_, rv_pos)
        return word


class TestStemmer(unittest.TestCase):
    """
    Tests the stemmer.
    """

    _stemmer = Stemmer()

    def test_re_perfective_gerund_av(self):
        self.assertEqual(
            "ав",
            self._stemmer._re_perfective_gerund.search("слушав").group(),
        )

    def test_re_perfective_gerund_avshi(self):
        self.assertEqual(
            "авши",
            self._stemmer._re_perfective_gerund.search("сделавши").group(),
        )

    def test_re_perfective_gerund_avshis(self):
        self.assertEqual(
            "авшись",
            self._stemmer._re_perfective_gerund.search("испугавшись").group(),
        )

    def test_re_perfective_gerund_ivshis(self):
        self.assertEqual(
            "ившись",
            self._stemmer._re_perfective_gerund.search("нагуглившись").group(),
        )

    def test_re_adjective_emu(self):
        self.assertEqual(
            "ему",
            self._stemmer._re_adjective.search("читавшему").group(),
        )

    def test_re_participle_aem(self):
        self.assertEqual(
            "аем",
            self._stemmer._re_participle.search("воспринимаем").group(),
        )

    def test_re_participle_yvsh(self):
        self.assertEqual(
            "ывш",
            self._stemmer._re_participle.search("забывш").group(),
        )

    def test_re_reflexive_s(self):
        self.assertEqual(
            "сь",
            self._stemmer._re_reflexive.search("забывшись").group(),
        )

    def test_re_verb_aete(self):
        self.assertEqual(
            "аете",
            self._stemmer._re_verb.search("делаете").group(),
        )

    def test_re_verb_yla(self):
        self.assertEqual(
            "ыла",
            self._stemmer._re_verb.search("плыла").group(),
        )

    def test_re_noun_iiam(self):
        self.assertEqual(
            "иям",
            self._stemmer._re_noun.search("понятиям").group(),
        )

    def test_re_superlative_eishe(self):
        self.assertEqual(
            "ейше",
            self._stemmer._re_superlative.search("красивейше").group(),
        )

    def test_re_derivational_ost(self):
        self.assertEqual(
            "ость",
            self._stemmer._re_derivational.search("честность").group(),
        )

    def test_stem(self):
        """
        Uses http://snowball.tartarus.org/algorithms/russian/diffs.txt
        to test the stemmer.
        """

        with open("diffs.txt", "rt", encoding="utf-8") as diffs_file:
            diffs = diffs_file.readlines()
        for i, line in enumerate(diffs):
            word, stem = line.split()
            self.assertEqual(
                stem,
                self._stemmer.stem(word),
                "Diff in word: %s (%d/%d)" % (word, i + 1, len(diffs)),
            )


if __name__ == "__main__":
    unittest.main()

Удаление устаревших kernel'ов

Следующая команда выведет нам список всех kernel'ов, установленных в системе:

dpkg --get-selections | grep linux-image

Вывод будет выглядеть примерно так:

linux-image-3.5.0-17-generic                    install
linux-image-3.5.0-26-generic                    install
linux-image-3.5.0-27-generic                    install
linux-image-virtual                             install

Теперь можно удалить устаревшие kernel'ы:

sudo apt-get purge linux-image-3.5.0-17-generic

Несколько замечаний:

  1. Не удаляйте базовый linux image (в моем случае - linux-image-virtual).
  2. Не удаляйте kernel, который сейчас используется.
  3. Полезно не удалять 1-2 старых, заведомо работающих kernel'а - на всякий случай, если что-то пойдет не так.

Отладка базы данных SQLite на Android устройстве

Начиная с 8-го уровня API (Android 2.2), если приложение собрано с возможностью отладки, то в adb shell можно использовать команду run-as для выполнения команд от имени нужного пользователя или приложения.

А это значит, что можно запустить приложение прямо из Eclipse или IntelliJ IDEA, подключиться с помощью adb shell и выполнить следующие команды:

run-as package-name
cat /data/data/package-name/databases/database-name > /sdcard/database-name

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

Отключение растровых версий шрифтов в Ubuntu

В некоторые шрифты, например, Calibri, кроме векторной, включена еще и растровая версия этого шрифта для отрисовки на малых размерах символов. Почему-то по умолчанию, Ubuntu использует именно растр, и шрифты эти выглядят, мягко говоря, некрасиво.

Чтобы отключить использование растровых версий, создаем файлик ~/.fonts.conf со следующим содержанием:

<match target="font">
    <edit name="embeddedbitmap" mode="assign">
        <bool>false</bool>
    </edit>
</match>

После этого, скорее всего, понадобится сделать Log Off / Log On.

Теперь шрифты красивые, векторные и сглаженные.

Автоматические обновления в Ubuntu

Для автоматической установки обновлений на Ubuntu можно использовать пакет unattended-upgrades. По умолчанию он не установлен (по крайней мере, в 12.04.1 LTS), поэтому:

sudo apt-get install unattended-upgrades

Теперь можно настроить, какие обновления будут приходить к нам автоматически. Для этого редактируем файл /etc/apt/apt.conf.d/50unattended-upgrades:

// Automatically upgrade packages from these (origin:archive) pairs
Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}-security";
        "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};

Строки с двойными слешами пропускаются - это комментарии.

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

Unattended-Upgrade::Package-Blacklist {
//      "vim";
//      "libc6";
//      "libc6-dev";
//      "libc6-i686";
};

Частоту обновлений можно настроить в файле /etc/apt/apt.conf.d/10periodic:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";

Здесь:

  • APT::Periodic::Update-Package-Lists - частота обновления списков пакетов
  • APT::Periodic::Download-Upgradeable-Packages - частота загрузки пакетов
  • APT::Periodic::AutocleanInterval - частота очистки локального кэша пакетов
  • APT::Periodic::Unattended-Upgrade - частота установки обновлений

Все интервалы указываются в количестве дней.

Отключение верхнего регистра в меню Visual Studio 2012

Для тех, кто не воспринимает верхний регистр в главном меню Visual Studio: создайте в реестре ключ HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\General\SuppressUppercaseConversion типа REG_DWORD со значением 1.

Было:

Оригинальное меню

Стало:

Меню с отключенным верхним регистром

Импорт ключа при сборке в Visual Studio из защищенного паролем PFX-файла

Подписывать сборки ключом это хорошо, защищать приватный ключ паролем - тоже. Но может случиться так, что после checkout/clone репозитория Visual Studio откажется собирать проект со следующей ошибкой:

Cannot import the following key file: companyname.pfx. The key file may be password protected. To correct this, try to import the certificate again or manually install the certificate to the Strong Name CSP with the following key container name: VS_KEY_3E185446540E7F7A

Что, в общем логично: как расшифровать ключ - она не знает. Чтобы всё было хорошо, нужно явно импортировать ключ в указанный контейнер:

sn -i key.pfx VS_KEY_3E185446540E7F7A

Теперь IDE сможет использовать ключ из указанного контейнера, и сборка пройдёт нормально. Название контейнера здесь указано для примера, в вашем случае оно наверняка будет другим.

P.S. В некоторых случаях бывает полезно сначала удалить ключ перед его установкой:

sn -d VS_KEY_3E185446540E7F7A

Ограничение использования VPN только для внутренних ресурсов

После настройки VPN в стандартном клиенте Ubuntu, все обращения к сети стали ходить через этот VPN, хотя, по сути, VPN мне нужен только для обращения ко внутренним ресурсам сети.

Чтобы это не происходило, нужно выставить галочку Network Connections → VPN → Edit… → Routes… → Use this connection only for resources on its network.

Editing IPv4 routes for VPN

Блокировка перемещения mx:DataGridColumn

Хоть mx:DataGrid и не является рекомендуемым, в одной из работ у меня было требование использовать именно его. Кроме того, нужно было заблокировать перемещение самого первого столбца таблицы, его сортировку и изменение размера.

<mx:DataGridColumn dataField="key"
                   headerText="#"
                   width="0.025"
                   resizable="false"
                   draggable="false"
                   sortable="false"/>

И все бы хорошо, но если теперь взять и переместить любой другой столбец мышью перед первым, то этот самый первый сдвинется вправо и перестанет быть первым. :)

Поиски решения дали понять, что встроенными средствами исправить это никак не получится, но зато это можно обойти с помощью обработки события headerShift:

<mx:DataGrid headerShift="controller.DataGridHeaderShiftHandler(event)"/>

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

public function DataGridHeaderShiftHandler(event: IndexChangedEvent): void
{
    var dataGrid: DataGrid = DataGrid(event.target);
    
    if (event.newIndex == 0)
    {
        var newColumns: Array = dataGrid.columns.concat();
        
        newColumns[1] = dataGrid.columns[0];
        newColumns[0] = dataGrid.columns[1];
        
        dataGrid.columns = newColumns;
    }
}

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