illumium.org

Главная › Блоги › Блог kayo

Пробуем NixOS. Первые впечатления.

kayo — Пт, 24/04/2015 - 16:32

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

Введение

NixOS — уникальный дистрибутив. В общих словах, уникален он тем, что в нём решена проблема ада зависимостей (dependency hell). Если вы хорошо представляете суть этой проблемы, то введение можете смело пропустить.

Любая сколько-нибудь сложная программа, как правило, использует возможности множества библиотек через систему типов данных и вызовов спецификации API, что делает программу зависимой от этой спецификации. В свою очередь, библиотеки тоже могут зависеть от других библиотек подобным образом. Мы живём в реальном мире, а реальный мир развивается крайне не синхронно. В то время как одни программы и библиотеки часто не поспевают за развитием своих зависимостей, — другие требуют возможностей более новых версий API. Всё хорошо, покуда изменения сохраняют обратную совместимость, то есть новая спецификация API дополняет старую, но не изменяет её.

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

И такие ситуации очень часты, жаргонно они называются адом зависимостей (dependency hell). Сопровождающие дистрибутивов решают эту проблему путём создания разных экземпляров одной и той же библиотеки в виде обособленных пакетов с суффиксами в именах, например libjpeg62 и libjpeg8 для libjpeg веток 6.2 и 8 соответственно. Но такой подход имеет ряд недостатков и является скорее обходом проблемы, а не её решением. Когда в системе одновременно существуют разные версии одних и тех же библиотек, необходимо их как-то различать. libjpeg в нашем примере собрана в виде разделяемого объекта (shared object) с именем libjpeg.so, для различения версий этот файл переименован на этапе пакетизации в libjpeg.so.62 и libjpeg.so.8. С другой стороны необходимы разные наборы заголовочных файлов для сборки под разные версии API. Такое разделение создаёт проблемы при сборке (компиляции) и связывании (линковке). Возникает необходимость в вещах типа pkg-config и autotools которые генерируют соответствующие флаги для сборки и связывания программ с нужными версиями библиотек.

Ад зависимостей особенно актуален для динамично развивающихся компонентов для языков Python (PIP), JavaScript (NodeJS NPM), Haskell (Cabal Hackage), D (DUB). Дистрибутивы обычно существенно отстают от их развития и мы имеем ситуацию, когда пакеты из официальных репозиториев слишком старые и не подходят нам по этой причине. В системе Debian с которой я работаю уже очень давно, приходится устанавливать пакеты из веток testing и sid поверх stable, чтобы иметь актуальные версии. Но прямое обновление зачастую вызывает обновление других зависимостей, которые не хотелось бы трогать. Когда отставание было существенным, приходилось целиком сидеть на ветке sid. Но каждое обновление системы было довольно рискованным занятием, поскольку в ветке sid часто оказывались пакеты, работоспособность котрых в бою принципиально никем не проверялась. А откат пакетной базы (downgrade) сопряжен с рядом трудностей и в общем случае не всегда возможен, поскольку старые версии пакетов могли быть уже удалены из репозиториев.

NixOS

Подход  NixOS к управлению пакетами и конфигурированию в корне отличается от подхода, используемого в дистрибутивах традиционно. Каждый пакет устанавливается в своё собственное изолированное окружение. Таким образом, вполне нормально сосуществование в системе разных версий одного и того же пакета. Как написано на сайте дистрибутива, пакетный менеджер Nix реализует чисто функциональный подход к управлению пакетами и конфигурации.

Вся конфигурация системы описывается в файле /etc/nixos/configuration.nix на специально разработанном декларативном языке. Конфигуратор обрабатывает этот файл вместе с множеством других, содержащих описания пакетов и их конфигурации, в результате чего устанавливаются и настраиваются пакеты в системе. Разработчики заверяют, что с одним и тем же файлом конфигурации результат обновления системы будет тем же, что и результат установки с нуля.

Подготовка

Пробовать новую для нас систему будем, как водится, в виртуальной машине. Я использую менеджер виртуальных машин libvirtd, но с не меньшим успехом можно воспользоваться qemu/kvm.

Первое, что необходимо сделать, скачать подходящий для вас live-образ дистрибутива с официального сайта. Я выбрал ISO образ минимального инсталляционного CD диска под архитектуру x86_64.

Затем создадим образ диска формата qcow2 размера 10G средствами qemu-img:

qemu-img create -f qcow2 rootfs-x86_64.qcow2 10G

В virt-manager:

create_image_rootfs.png

Затем подключаем установочный ISO образ и стартуем виртуальную машину через virt-manager или kvm:

kvm -m 1024M \
-cdrom nixos-minimal-14.12.501.2635bde-x86_64-linux.iso \
-drive file=rootfs-x86_64.qcow2,if=virtio \
-net nic,model=virtio -net user

После загрузки установочного CD имеем следующее:

start-virt-nixos.png

Теперь необходимо залогиниться под пользователем root без пароля. Как говорит подсказка, руководство по установке и настройке доступно в 8-й виртуальной консоли. Если ставим на реальной машине и поблизости нет других машин с сетью, то оно будет весьма кстати.

Установка

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

Установка по ssh

Сделаем маленькое отступление. Мне привычнее выполнять установку по ssh, поэтому я сконфигурировал ssh сервер для входа пользователем root. Для этого надо добавить следующую секцию в файл /etc/nixos/configuration.nix:

{ config, pkgs, ... }:

{
  imports = [ <nixos/modules/installer/cd-dvd/installation-cd-minimal.nix> ];

  # Добавленная секция, разрешающая запуск ssh сервера и вход суперпользователя с паролем
  services.openssh = {
    enable = true;
    permitRootLogin = "yes";
  };
}

Теперь применим конфигурацию и установим пароль суперпользователя:

nixos-rebuild switch
passwd

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

# Запускаем
start sshd

# проверяем, что запустился
status sshd

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

Разбивка диска

Я решил использовать менеджер виртуальных томов LVM для корневой файловой системы и таблицу разделов GPT. Виртуальное блочное устройство для размещения наших разделов в системе распознано как /dev/vda. Воспользуемся утилитой gdisk для разбивки:

[root@nixos:~]# gdisk /dev/vda 
GPT fdisk (gdisk) version 0.8.8

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.

Command (? for help): ?
b	back up GPT data to a file
c	change a partition's name
d	delete a partition
i	show detailed information on a partition
l	list known partition types
n	add a new partition
o	create a new empty GUID partition table (GPT)
p	print the partition table
q	quit without saving changes
r	recovery and transformation options (experts only)
s	sort partitions
t	change a partition's type code
v	verify disk
w	write table to disk and exit
x	extra functionality (experts only)
?	print this menu

# создаём новую таблицу разделов GPT

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): Y

# создаём раздел для системного загрузчика grub2
# 4 мегабайта должно хватить
# но не забываем выставить правильный тип ef02

Command (? for help): n
Partition number (1-128, default 1): 
First sector (34-20971486, default = 2048) or {+-}size{KMGTP}:   
Last sector (2048-20971486, default = 20971486) or {+-}size{KMGTP}: +4M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): L
0700 Microsoft basic data  0c01 Microsoft reserved    2700 Windows RE          
4100 PowerPC PReP boot     4200 Windows LDM data      4201 Windows LDM metadata
7501 IBM GPFS              7f00 ChromeOS kernel       7f01 ChromeOS root       
7f02 ChromeOS reserved     8200 Linux swap            8300 Linux filesystem    
8301 Linux reserved        8302 Linux /home           8400 Intel Rapid Start   
8e00 Linux LVM             a500 FreeBSD disklabel     a501 FreeBSD boot        
a502 FreeBSD swap          a503 FreeBSD UFS           a504 FreeBSD ZFS         
a505 FreeBSD Vinum/RAID    a580 Midnight BSD data     a581 Midnight BSD boot   
a582 Midnight BSD swap     a583 Midnight BSD UFS      a584 Midnight BSD ZFS    
a585 Midnight BSD Vinum    a800 Apple UFS             a901 NetBSD swap         
a902 NetBSD FFS            a903 NetBSD LFS            a904 NetBSD concatenated 
a905 NetBSD encrypted      a906 NetBSD RAID           ab00 Apple boot          
af00 Apple HFS/HFS+        af01 Apple RAID            af02 Apple RAID offline  
af03 Apple label           af04 AppleTV recovery      af05 Apple Core Storage  
be00 Solaris boot          bf00 Solaris root          bf01 Solaris /usr & Mac Z
bf02 Solaris swap          bf03 Solaris backup        bf04 Solaris /var        
bf05 Solaris /home         bf06 Solaris alternate se  bf07 Solaris Reserved 1  
bf08 Solaris Reserved 2    bf09 Solaris Reserved 3    bf0a Solaris Reserved 4  
bf0b Solaris Reserved 5    c001 HP-UX data            c002 HP-UX service       
ea00 Freedesktop $BOOT     eb00 Haiku BFS             ed00 Sony system partitio
ef00 EFI System            ef01 MBR partition scheme  ef02 BIOS boot partition 
Press the <Enter> key to see more codes: 
fb00 VMWare VMFS           fb01 VMWare reserved       fc00 VMWare kcore crash p
fd00 Linux RAID            
Hex code or GUID (L to show codes, Enter = 8300): ef02
Changed type of partition to 'BIOS boot partition'

# создаём раздел для менеджера томов LVM
# используя всё оставшееся место

Command (? for help): n
Partition number (2-128, default 2): 
First sector (34-20971486, default = 10240) or {+-}size{KMGTP}: 
Last sector (10240-20971486, default = 20971486) or {+-}size{KMGTP}: 
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 8e00
Changed type of partition to 'Linux LVM'

# применяем изменения

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/vda.
The operation has completed successfully.

Теперь оприходуем физический том в LVM:

# создаём физический том
[root@nixos:~]# pvcreate /dev/vda2 
  Physical volume "/dev/vda2" successfully created

# создаём группу томов с именем nixos
[root@nixos:~]# vgcreate nixos /dev/vda2
  Volume group "nixos" successfully created

# создаём логический том с именем root в группе nixos
[root@nixos:~]# lvcreate --extents 100%FREE --name root nixos
  Logical volume "root" created

# я сразу расширил его до 100%

Теперь можно отформатировать наш том и смонтировать для дальнейшей установки на него системы:

[root@nixos:~]# mkfs.ext4 /dev/nixos/root 
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 2619392 4k blocks and 655360 inodes
Filesystem UUID: 010ef059-a9dc-4416-a4df-e1f7a2cedbda
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done 


[root@nixos:~]# mount /dev/nixos/root /mnt

Установка системы

Осталось установить NixOS на свежесозданный раздел:

# сгенерируем начальную конфигурацию
# опцией root мы указали куда смонтирован корневой каталог

[root@nixos:~]# nixos-generate-config --root /mnt
writing /mnt/etc/nixos/hardware-configuration.nix...
writing /mnt/etc/nixos/configuration.nix...

Теперь необходимо подшаманить файл /etc/nixos/configuration.nix в /mnt. Как минимум нужно правильно указать устройство для установки начального загрузчика grub2:

# раскомментируем строку и укажем правильное имя устройства
boot.loader.grub.device = "/dev/vda";

Затем я включил сервер ssh, и добавил пользователя kayo, чтобы после установки можно было сразу логиниться в систему:

# раскомментируем строку
services.openssh.enable = true;

# и добавим секцию
users.extraUsers.kayo = {
  isNormalUser = true;
  uid = 1000;
  # я одмин ^_^
  extraGroups = [
    "wheel"
  ];
};

Потом я хотел бы, чтобы в новой системе уже были установлены некоторые программы:

# раскомментируем секцию и добавим нужные программы
environment.systemPackages = with pkgs; [
  wget
  htop
  screen
];

Всё, наконец-то можно делать бутстрэпинг:

[root@nixos:~]# nixos-install 
building the system configuration...

# затем побежит установка

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

Продвинутый вариант установки

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

  • Загрузить конфигурацию в git репозиторий на один из хостингов вроде github.com или bitbucket.org
  • В установочной системе установить пакет git
  • Превратить каталог /etc/nixos в полноценный репозиторий git
  • Добавить ссылку на удалённый репозиторий
  • Затянуть содержимое удалённого репозитория
  • Установить систему с использованием конфига из репозитория

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

Итак, делаем следующее:

# Устанавливаем пакет git
[root@nixos:~]$ nix-env -i git

# Переходим в каталог с конфигом
[root@nixos:~]$ cd /mnt/etc/nixos

# Создаём репозиторий
[root@nixos:/mnt/etc/nixos]$ git init
Initialized empty Git repository in /mnt/etc/nixos/.git/

# Добавляем ссылку на внешний апстрим
[root@nixos:/mnt/etc/nixos]$ git remote add origin git@bitbucket.org:kayo/nixos-config

# Генерируем rsa ключи для доступа к git
# если репозиторий публичный и доступен по HTTP
# можно обойтись и без этого
[root@nixos:/mnt/etc/nixos]$ ssh-keygen

# Передаём публичный ключ хостеру репозитория
# нам потребуется доступ на чтение по нему
# обычно это называют ключи для деплоя
[root@nixos:/mnt/etc/nixos]$ cat ~/.ssh/id_rsa.pub

# Не забудем потом скопировать ключи в корневую
# файловую систему устанавливаемой системы

# Переименовываем имеющийся конфиг
# чтобы избежать конфликта
[root@nixos:/mnt/etc/nixos]$ mv configuration.nix configuration.nix~orig

# Затягиваем контент из внешнего репозитория
[root@nixos:/mnt/etc/nixos]$ git pull origin master
From bitbucket.org:kayo/nixos-config
 * branch            master     -> FETCH_HEAD

# Устанавливаем в качестве апстрима удалённую ветку master
[root@nixos:/mnt/etc/nixos]$ git branch --set-upstream-to=origin/master master
Branch master set up to track remote branch master from origin.

# Запускаем установку
[root@nixos:/mnt/etc/nixos]$ nixos-install

Это работает, я гарантирую это :)

Настройка и использование

Как мы уже видели при установке, вся настройка производится путём редактирования файла /etc/nixos/configuration.nix. Чтобы изменения вступили в силу, нужно вызвать утилиту nixos-rebuild <действие>. Существует несколько вариантов действий:

  1. switch — соберёт и применит новую конфигурацию и сделает её загружаемой по-умолчанию. При этом предыдущие конфигурации по прежнему будут доступны из меню загрузки.
  2. boot — соберёт новую конфигурацию и сделает её загружаемой по умолчанию, но не применит её.
  3. test — соберёт и применит новую конфигурацию, но не сделает её загружаемой.
  4. build — только соберёт конфигурацию. Можно использовать для выявления ошибок  сборки и установки.
  5. dry-build — показывает какие пути в хранилище будут задействованы в операции сборки, но не выполняет сборку.
  6. dry-activate — делает сборку но вместо активации показывает какие изменения будут произведены в процессе активации.
  7. build-vm — собирает виртуальную машину для проверки работоспособности конфигурации до применения на реальной машине. В результате будет создано изолированное окружение, так что если что-то пойдёт не так, ваши реальные файлы не пострадают, но без лишнего оверхеда в виде образов дисков.

Не бедно, правда? Таких возможностей я не встречал в других дистрибутивах. Так как же NixOS достигает всего этого? Давайте разбираться.

Во первых, как уже было сказано выше, каждый пакет существует в своём персональном окружении. На практике это реализовано вот как: пакеты живут в своих поддиректориях директории /nix/store. С помощью символьных ссылок пакетный менеджер Nix слинковывает зависимости пакетов из других директорий, так, чтобы программы могли запускаться и работать. Ад зависимостей забыт как страшный сон, программы всегда будут иметь правильно настроенные зависимости.

Одна из причин моего интереса к NixOS заключалась в том, что пакеты из Npm и Hackage актуальных версий доступны в репозитории пакетов Nix. Как оказалось, в NixOS имеются инструменты автоматического конвертирования Npm2Nix и Cabal2Nix и другие подобные им.

Управление пакетами

Инструментарий Nix позволяет делать вещи, которые мы всегда считали преступными и незаслуженно осуждали. Например, теперь обычные пользователи могут устанавливать пакеты из репозитория. В традиционных дистрибутивах сие занятие весьма опасное, поскольку в них пакеты устанавливаются глобально для всей системы. В NixOS же управление пакетами отделена от настройки рабочих окружений. Другими словами, окружение уровня системы никак не будет затронуто, когда пользователь установит нужный ему пакет. Установленные пользователем пакеты будут доступны только ему и тем пользователям, кто тоже установил их, при этом не будет никакого дублирования, если версии пакетов одинаковые.

Вот как обычный пользователь может установить и удалить программы:

# Получить список доступных пакетов можно так:
nix-env -qa '.*'
# (как видим, тут можно регекспы)

# Получаем доступные версии нужной нам программы для редактирования configuration.nix
nix-env -qa emacs

# Устанавливаем хороший годный, кхм, текстовый редактор
nix-env -i emacs

# Удаляем другой текстовый, кхм, редактор
nix-env -e vim

# Просмотрим список установленных нами пакетов
nix-env -q

Ставить и удалять программы глобально для всей системы можно через /etc/nixos/configuration.nix как мы уже делали при установке.

Может возникнуть вполне закономерен вопрос: а что происходит с хранилищем пакетов при удалении и обновлении пакетов? Происходит то, что ничего не происходит. Покуда существуют конфигурации, ссылающиеся на старые версии пакетов, они так и будут оставаться в системе нетронутыми. Это сделано, чтобы всегда иметь возможность откатиться на предыдущие конфигурации, если при очередном обновлении что-то сломалось.

Но имеющийся инструментарий позволяет чистить систему от ненужных конфигураций и старых версий пакетов:

# Удаляем все не текущие генерации
nix-env --delete-generations old

# Или можем удалить все старее прошлой недели
nix-env --delete-generations 7d

# Удаляем неиспользуемые пакеты из хранилища навсегда
nix-collect-garbage

Или глобально для всех профилей это же можно сделать так (разумеется от рута):

# Удалить все не текущие
nix-collect-garbage --delete-old

# Или всё старше недели
nix-collect-garbage --delete-older-than 7d

Конфигурирование

NisOS предлагает функциональный декларативный подход к конфигурированию системы. Традиционные файлы конфигурации unix вычисляются по правилам, разработанным сопровождающими пакетов. NixOS, конечно, пока довольно молодой дистрибутив и далеко не всегда вас устроит гибкость предлагаемых правил. Однако, даже если сопровождающие не предусмотрели гибкости, всегда можно переопределить их правила своими. Здесь же мы не будем углубляться в дебри декларативного языка менеджера пакетов Nix, а рассмотрим базовые возможности настройки.

Существует полезная утилита nixos-option, которая позволяет исследовать возможности конфигурации, например так:

[kayo@nixos:~]$ nixos-option 
This attribute set contains:
assertions
boot
containers
ec2
environment
fileSystems
fonts
gnu
gtkPlugins
hardware
i18n
ids
jobs
kde
krb5
lib
meta
nesting
networking
nix
nixpkgs
passthru
power
powerManagement
programs
qtPlugins
security
services
sound
swapDevices
system
systemd
time
uim
users
virtualisation
warnings
zramSwap

Без аргументов команда возвращает список всех настроек в корне. Предположим, что мы хотим настроить сервис sshd. Настройки сервисов, очевидно, живут в группе services, посмотрим, какие сервисы нам доступны для настройки:

[kayo@nixos:~]$ nixos-option services
This attribute set contains:
…
openssh
…

(вывод был сокращён)

Где-то в длинном списке затесалось заветное название сервиса openssh. Теперь посмотрим, что мы можем настроить:

[kayo@nixos:~]$ nixos-option services.openssh
This attribute set contains:
allowSFTP
authorizedKeysFiles
challengeResponseAuthentication
enable
extraConfig
forwardX11
gatewayPorts
hostKeys
knownHosts
listenAddresses
passwordAuthentication
permitRootLogin
ports
startWhenNeeded

Не все возможности но наиболее часто используемые есть. Посмотрим, как настроена аутентификация по паролю:

[kayo@nixos:~]$ nixos-option services.openssh.passwordAuthentication
Value:
true

Default:
true

Description:

Specifies whether password authentication is allowed.

Declared by:
  "/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix"

Defined by:
  "/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix"

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

# После строки
services.openssh.enable = true;
# Добавим строку
services.openssh.passwordAuthentication = false;

# Или уберём эти строки и запишем конфигурацию
# в более удобоваримой форме в виде секций
services = {
  openssh = {
    enable = true;
    passwordAuthentication = false;
  };
};

Теперь проверим, изменилось ли значение:

[kayo@nixos:~]$ nixos-option services.openssh.passwordAuthentication
Value:
false

Default:
true

Description:

Specifies whether password authentication is allowed.

Declared by:
  "/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix"

Defined by:
  "/etc/nixos/configuration.nix"

Как видим, Value стало false. Команда nixos-option ориентируется на значение в файле конфигурации, даже если конфигурация ещё не была применена.

Чтобы изменения вступили в силу, вызовем команду nixos-rebuild с соответствующим действием в зависимости от того, что мы желаем получить, как было описано выше.

На этом наше погружение в сий уникальный дистрибутив NixOS подходит к концу. Надеюсь, вам понравилось. Все свободны, спасибо за внимание ;)

  • Системное администрирование
  • gnu
  • linux
  • nixos
  • systemd
  • дистрибутивы
  • Бортовой журнал Иллюмиума

Ну и как оно! Впечатления

Гость (не проверено) — Вс, 07/05/2017 - 07:53

Ну и как оно! Впечатления есть? Для десктопного варианта можно использовать?

  • ответить

Использую на лэптопе

kayo — Ср, 02/08/2017 - 17:27
Использую на лэптопе
We used to be in Love…
  • ответить

Отправить комментарий

Содержимое этого поля является приватным и не будет отображаться публично.
  • Доступные HTML теги: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Syntax highlight code surrounded by the {syntaxhighlighter SPEC}...{/syntaxhighlighter} tags, where SPEC is a Syntaxhighlighter options string or "class="OPTIONS" title="the title".

Подробнее о форматировании

CAPTCHA
Этот вопрос задается для того, чтобы выяснить, являетесь ли Вы человеком или представляете из себя автоматическую спам-рассылку.
  ___   ____            ____    _____ __        __
|_ _| | _ \ _ _ | __ ) |__ / \ \ / /
| | | |_) | | | | | | _ \ / / \ \ /\ / /
| | | _ < | |_| | | |_) | / /_ \ V V /
|___| |_| \_\ \__, | |____/ /____| \_/\_/
|___/
Введите код, изображенный в стиле ASCII-арт.
RSS-материал

Навигация

  • Подшивки
  • Фотоальбомы

«Иллюмиум» на якоре.

Работает на Drupal, система с открытым исходным кодом.

(L) 2010, Illumium.Org. All rights reversed ^_~