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

Ubuntu, File Roller и крякозяблы в именах файлов

В Ubuntu для работы с RAR-архивами традиционно используются две программы: rar и unrar. Обе поддерживаются стандартным гномовским менеджером архивов - File Roller-ом. Первая, rar, предназначена для создания и распаковывания rar-архивов, но, к сожалению, не всегда справляется должным образом со второй задачей. В частности проблемы возникают при распаковке архивов созданных в Windows, где имена файлов/папок содержат русские буквы. Также, судя по постам в интернете, проблемы возникают и с зашифрованными архивами. Поэтому для распаковки, лучше всего воспользоваться программой unrar, вторым коммерческим продуктом создателя формата. Эта утилита прекрасно распаковывает rar-архивы, но, как следует из ее названия не предназначена для их создания. Для любителей всего свободного существует другая, но также несколько ограниченная версия распаковщика - unrar-free. Под свободной здесь понимается то, что проприетарный формат RAR и его основной закрытый функционал был исследован и реализован при помощи реверс-инжиниринга.


Для тех, кто, как я, предпочитает пользоваться графическим интерфейсом, в частности менеджером File Roller одновременное использование rar для упаковки и unrar для распаковки не представляется возможным. Если в системе установлен rar, наличие unrar просто игнорируется. Я даже глянул в исходники File Roller-а, чтобы убедиться в этом. Во всех местах, связанных с извлечением данных присутствует такой код:

if (have_rar ())
       fr_process_begin_command (comm->process, "rar");
else
       fr_process_begin_command (comm->process, "unrar");


Итог: Для приемлемой работы с RAR-архивами можно воспользоваться полумерой: установить unrar и удалить rar. Нужно лишь отказаться от создания RAR-архивов (в мире Linux это чуждый формат), в пользу другого, например zip.


суббота, 7 апреля 2012 г.

Меняем кодировку ID3 из cp1251 в Unicode. Ubuntu

Установка:
sudo apt-get install python-mutagen 

Создаем Id3v2 в кодировке utf8 из тега id3v1 и кодировки cp1251 для одного файла. Тег id3v1 удаляется:
mid3iconv -e CP1251 -d bad.mp3

То же, что и выше, но для всех файлов коллекции:
find /media/Music/ -iname "*.mp3" -print0 | xargs -0 mid3iconv -e CP1251 -d

Источник:

Вебсервер в Ubuntu в VirtualBox

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

У меня хост-система тоже Ubuntu (12.04 beta), но думаю, что это не играет какую-то важную роль, упомяну лишь, что VirtualBox 4.1.10 был установлен из репозиториев дистрибутива.

1. Веб-сервер - Ubuntu 10.04 LTS, новая установка.
2. Установка LAMP через Synaptic-Пакет-менеджер (Меню Edit=>установка пакетов по задачам=>LAMP server.
3. После установки заменил режим сети в VirtualBox с NAT на Bridged networking
4. Для создания нескольких виртуальных хостов на одном сервере использовал следующие руководства:
    - http://blog.axshavan.ru/2010/11/lamp-ubuntu.html
    - http://ubuntuforums.org/showthread.php?t=794248
    - http://wiki.ubuntuusers.de/Apache/Virtual_Hosts
    - http://barrierefrei.e-workers.de/know_virtual.php
    - ftp://ftp.ua.openwall.com/pub/docs/mirrors/pm4u.opennet.ru/apache.htm

- Скопировал файла /etc/apache2/sites-available/default в ту же папку
- Новый файл переименовал во что-то вроде этого “mysites” и отредактировал следующим образом:
<VirtualHost *:80>
  ServerName mysites 
  #ServerAlias можно указать альтернативные имена хоста
  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/mysites/
  <Directory />
    Options FollowSymLinks
    AllowOverride None
  </Directory>
  <Directory /var/www/mysites>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride None
    Order allow,deny
    allow from all
  </Directory>
  ErrorLog /var/log/apache2/error.log
  # Possible values include: debug, info, notice, warn, error, crit,
  # alert, emerg.
  LogLevel warn
  CustomLog /var/log/apache2/access.log combined
</VirtualHost>


* This source code was highlighted with Source Code Highlighter.


- Создал папку “/var/www/mysites/” и в ней index-файл (html, php...)
- Прописал новый хост в файле “/etc/hosts”
    127.0.0.1     mysites

- Для активации виртуального хоста выполнил команду: “sudo a2ensite”, после ввода пароля спросит какой файл подключить.

На заметку:
Для деактивации хоста можно использовать смежную команду: sudo a2dissite
Активированные хосты можно узнать по содержимому папки “/etc/apache2/sites-enabled”

- Для вступления изменений в силу: “sudo /etc/init.d/apache2 reload”, можно и перезапустить apache: “sudo /etc/init.d/apache2 restart”
- Локальную страницу можно вызвать задав в браузере имя сервера, в примере это “mysites”

5. Описанным в 4-ом пункте образом можно создать множество виртуальных хостов, но снаружи (моя главная система, в которой запущена виртуальная машина) будет видна только дефольтная страница. Ее можно использовать для показа каталога доступных страниц, например так:

<html><body><h1>It works!</h1>
<p>This is the default web page for this server.</p>
<p>The web server software is running but no content has been added, yet.</p>
<p/>
<p><a href="/mysites/">mysites</a></p>
<p><a href="/xxx/">xxx</a></p>
</body></html>


* This source code was highlighted with Source Code Highlighter.


Все!

воскресенье, 19 февраля 2012 г.

Отменяемая асинхронная операция при помощи Task Parallel Library .NET 4

Недавно в одной WinForms программе мне понадобилось воспользоваться асинхронными операции, чтобы не блокировать графический интерфейс во время длительных расчетов. Это можно реализовать, конечно же, очень многими способами, от “ручного” программирования потоков (Threads) до использования таких конструкций как BackgroundWorker. Но мне захотелось (наконец-то!) попробовать новые библиотеки для параллельного программирования появившиеся в .NET 4 версии.

Итак, основные требования: длительная операция запускается пользователем, не должна блокировать графический интерфейс, должна быть отменяемой, результаты расчета отображаются на главной форме. Существенным облегчением было то, что одновременно могла быть запущена только одна операция.

Вот что у меня получилось:


    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    using System.Threading.Tasks;

    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            private void startButton_Click(object sender, EventArgs e)
            {
                StopCalcIfRun();
                BeginCalc();
            }

            private void stopButton_Click(object sender, EventArgs e)
            {
                StopCalcIfRun();
            }

            // --------------------------------------

            class CalcResult
            {
                public int IntResult;
            }

            // объект задачи одновременно является флагом, нулевое значение которого указывает на то, запущена ли операция
            volatile Task calcTask = null;

            void StopCalcIfRun()
            {
                Task task = calcTask;

                if (task != null)
                {
                    // извлекаем CancellationTokenSource для отмены операции
                    CancellationTokenSource ts = (CancellationTokenSource)task.AsyncState;
                    ts.Cancel();

                    try
                    {
                        task.Wait();
                    }
                    catch (AggregateException e)
                    {
                        // Если e.InnerExceptions содержит исключение TaskCanceledException,
                        // то это указывает на "успешную" отмену задачи, а не на сбой
                    }
                }
            }

            void BeginCalc()
            {
                TaskScheduler uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

                CancellationTokenSource tockenSource = new CancellationTokenSource();
                CancellationToken tocken = tockenSource.Token;

                // Создаем и запускаем длительную операцию.
                // Вниманине, tockenSource "закрепляется" за задачей как State Object, и используется для ее отмены в StopCalcIfRun методе
                calcTask = Task.Factory.StartNew((xxx) =>
                {
                    try
                    {
                        // уже отменили задачу?
                        tocken.ThrowIfCancellationRequested(); // *** Отмена задачи ***
                        CalcResult result = new CalcResult();

                        // длительные вычисления
                        result.IntResult++;
                        System.Threading.Thread.Sleep(1000);
                     
                        if (tocken.IsCancellationRequested) { // *** Отмена задачи ***
                            // ... освобождаем ресурсы
                            tocken.ThrowIfCancellationRequested();
                        }

                        // продолжаем длительные вычисления
                        result.IntResult++;
                        System.Threading.Thread.Sleep(1000);
                     
                        if (tocken.IsCancellationRequested) { // *** Отмена задачи ***
                            // ... освобождаем ресурсы
                            tocken.ThrowIfCancellationRequested();
                        }
                     
                        return result;
                    }
                    finally
                    {
                        calcTask = null;
                    }
                }, tockenSource, tocken);

                // Это продолжение будет вызвано в случае возникновения исключения (см. TaskContinuationOptions).
                // Исключение TaskCanceledException отменяющее задачу является корректным завершением задачи
                // и к таким исключениям не относится!
                calcTask.ContinueWith((ant) =>
                {
                     MessageBox.Show(ant.Exception.InnerException.ToString());
                }
                    , System.Threading.CancellationToken.None
                    , TaskContinuationOptions.OnlyOnFaulted
                    , uiTaskScheduler);

                // Продолжение если задача отменяется.
                // ant.Result есть null, не стоит к нему обращатся
                calcTask.ContinueWith((ant) =>
                {
                    resultTextBox.Text += "Canceled;";
                }
                    , System.Threading.CancellationToken.None
                    , TaskContinuationOptions.OnlyOnCanceled
                    , uiTaskScheduler);

                // Полное завершение задачи => отображаем результаты
                calcTask.ContinueWith((ant) =>
                {
                    resultTextBox.Text += ant.Result.IntResult + ";";
                }
                    , System.Threading.CancellationToken.None
                    , TaskContinuationOptions.OnlyOnRanToCompletion
                    , uiTaskScheduler);
            }
        }
    }


Ресурсы:

Threading in C#, Joseph Albahari
http://www.albahari.com/threading/part5.aspx

Перевод части статьи Джозефа Албахари (Joseph Albahari) от Sergey Teplyakov
http://sergeyteplyakov.blogspot.com/2010/09/52.html

Все дело в SynchronizationContext [RU. MSDN Magazine]
http://msdn.microsoft.com/ru-ru/magazine/gg598924.aspx

Отмена задач [RU. MSDN Статья]
http://msdn.microsoft.com/ru-ru/library/dd997396.aspx

суббота, 28 января 2012 г.

Visual Studio 2010 Color Schema. Моя темная цветовая схема

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

Редакотор c# кода:


XAML:


XML:


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

Скачать схему

понедельник, 23 января 2012 г.

Visual Studio. Поиск русских букв в коде

Иногда, когда я пишу прототипы или набрасываю код, то снабжаю его на скорую русскими комментариями. В конечном продукте заметок на русском быть не должно, и я, прорабатывая результат, стараюсь от них избавится. Что бы не пропустить ни одного использую стандартный поиск (Ctrl+F) с regex выражением “[а-яА-ЯёЁ]”.

воскресенье, 22 января 2012 г.

MS SQL. Выборка данных без учета диакритических знаков

Встала задача находить записи в базе данных, которые содержали диакритические знаки без указания этих знаков. Например, если представить, что в базе находится фирма “Télécöm”, хотелось бы находить ее по значению “Telecom”. В результаты наших запросов эти значения не попадали.

Проблема таилась в сортировке, которая использовалась в базе данных по умолчанию: Latin1_General_ci_AS. Эта сортировка с суффиксом “_AS” различает символы с диакритическими знаками, так что 'a' и 'ấ' это не одно и то же. Сортировка с суффиксом “_AI”, ей в противоположность, считает эти символы идентичными. Подробнее о сортировках можно почитать здесь.

Итак, проблему решили путем применения сортировки Latin1_General_ci_AI на выбираемые колонки при помощи оператора COLLATE:

SELECT ID, Company
FROM Companies
WHERE (Company LIKE N'Telecom' COLLATE Latin1_General_ci_AI)

В заключении хочу добавить, что сортировка вообще определяется MS SQL Server-ом на нескольких уровнях: от уровня сервера, через уровень базы, затем через уровень столбца, до уровня выражений. Мы применили уровень выражения, но можно было бы, конечно, использовать и другие уровни.