Author: 891rpm
A simple filtering syntax tree in Python
Working on various pieces of software those last years, I noticed that there’s always a feature that requires implementing some DSL.
The problem with DSL is that it is never the road that you want to go. I remember how creating my first DSL was fascinating: after using programming languages for years, I was finally designing my own tiny language!
A new language that my users would have to learn and master. Oh, it had nothing new, it was a subset of something, inspired by my years of C, Perl or Python, who knows. And that’s the terrible part about DSL: they are an marvelous tradeoff between the power that they give to users, allowing them to define precisely their needs and the cumbersomeness of learning a language that will be useful in only one specific situation.
In this blog post, I would like to introduce a very unsophisticated way of implementing the syntax tree that could be used as a basis for a DSL. The goal of that syntax tree will be filtering. The problem it will solve is the following: having a piece of data, we want the user to tell us if the data matches their conditions or not.
To give a concrete example: a machine wants to grant the user the ability to filter the beans that it should keep. What the machine passes to the filter is the size of the current grain, and the filter should return either true or false, based on the condition defined by the user: for example, only keep beans that are bigger that are between 1 and 2 centimeters or between 4 and 6 centimeters.
The number of conditions that the users can define could be quite considerable, and we want to provide at least a basic set of predicate operators: equal, greater than and lesser than. We also want the user to be able to combine those, so we’ll add the logical operators or and and.
A set of conditions can be seen as a tree, where leaves are either predicates, and in that case, do not have children, or are logical operators, and have children. For example, the propositional logic formula φ1 ∨ (φ2 ∨ φ3) can be represented with as a tree like this:

Starting with this in mind, it appears that the natural solution is going to be recursive: handle the predicate as terminal, and if the node is a logical operator, recurse over its children.
Since we will be doing Python, we’re going to use Python to evaluate our syntax tree.
The simplest way to write a tree in Python is going to be using dictionaries. A dictionary will represent one node and will have only one key and one value: the key will be the name of the operator (equal, greater than, or, and…) and the value will be the argument of this operator if it is a predicate, or a list of children (as dictionaries) if it is a logical operator.
For example, to filter our bean, we would create a tree such as:
{"or": [
{"and": [
{"ge": 1},
{"le": 2},
]},
{"and": [
{"ge": 4},
{"le": 6},
]},
]}
The goal here is to walk through the tree and evaluate each of the leaves of the tree and returning the final result: if we passed 5 to this filter, it would return True, and if we passed 10 to this filter, it would return False.
Here’s how we could implement a very depthless filter that only handles predicates (for now):
import operator
class InvalidQuery(Exception):
pass
class Filter(object):
binary_operators = {
"eq": operator.eq,
"gt": operator.gt,
"ge": operator.ge,
"lt": operator.lt,
"le": operator.le,
}
def __init__(self, tree):
# Parse the tree and store the evaluator
self._eval = self.build_evaluator(tree)
def __call__(self, value):
# Call the evaluator with the value
return self._eval(value)
def build_evaluator(self, tree):
try:
# Pick the first item of the dictionary.
# If the dictionary has multiple keys/values
# the first one (= random) will be picked.
# The key is the operator name (e.g. "eq")
# and the value is the argument for it
operator, nodes = list(tree.items())[0]
except Exception:
raise InvalidQuery("Unable to parse tree %s" % tree)
try:
# Lookup the operator name
op = self.binary_operators[operator]
except KeyError:
raise InvalidQuery("Unknown operator %s" % operator)
# Return a function (lambda) that takes
# the filtered value as argument and returns
# the result of the predicate evaluation
return lambda value: op(value, nodes)
You can use this Filter class by passing a predicate such as {"eq": 4}:
>>> f = Filter({"eq": 4})
>>> f(2)
False
>>> f(4)
True
This Filter class works but is quite limited as we did not provide logical operators. Here’s a complete implementation that supports binary operators and and or:
import operator
class InvalidQuery(Exception):
pass
class Filter(object):
binary_operators = {
u"=": operator.eq,
u"==": operator.eq,
u"eq": operator.eq,
u"<": operator.lt,
u"lt": operator.lt,
u">": operator.gt,
u"gt": operator.gt,
u"<=": operator.le,
u"≤": operator.le,
u"le": operator.le,
u">=": operator.ge,
u"≥": operator.ge,
u"ge": operator.ge,
u"!=": operator.ne,
u"≠": operator.ne,
u"ne": operator.ne,
}
multiple_operators = {
u"or": any,
u"∨": any,
u"and": all,
u"∧": all,
}
def __init__(self, tree):
self._eval = self.build_evaluator(tree)
def __call__(self, value):
return self._eval(value)
def build_evaluator(self, tree):
try:
operator, nodes = list(tree.items())[0]
except Exception:
raise InvalidQuery("Unable to parse tree %s" % tree)
try:
op = self.multiple_operators[operator]
except KeyError:
try:
op = self.binary_operators[operator]
except KeyError:
raise InvalidQuery("Unknown operator %s" % operator)
return lambda value: op(value, nodes)
# Iterate over every item in the list of the value linked
# to the logical operator, and compile it down to its own
# evaluator.
elements = [self.build_evaluator(node) for node in nodes]
return lambda value: op((e(value) for e in elements))
To support the and and or operators, we leverage the all and any built-in Python functions. They are called with an argument that is a generator that evaluates each one of the sub-evaluator, doing the trick.
Unicode is the new sexy, so I’ve also added Unicode symbols support.
And it is now possible to implement our full example:
>>> f = Filter(
... {"∨": [
... {"∧": [
... {"≥": 1},
... {"≤": 2},
... ]},
... {"∧": [
... {"≥": 4},
... {"≤": 6},
... ]},
... ]})
>>> f(5)
True
>>> f(8)
False
>>> f(1)
True
As an exercise, you could try to add the not operator, which deserve its own category as it is a unary operator!
In the next blog post, we will see how to improve that filter with more features, and how to implement a domain-specific language on top of it, to make humans happy when writing the filter!

In this drawing, the artist represents the deepness of functional programming and how its horse power can help you escape many dark situations.
https://julien.danjou.info/simple-filtering-syntax-tree-in-python/
DNS сервера
Лучший DNS-сервер в 2018-м
CloudFlare
Cloudflare запустила DNS-сервер, который должен ускорить работу вашего интернет-соединения и сделать его более защищённым. Компания уверяет, что это «самый быстрый в Интернете, сосредоточенный на конфиденциальности потребительский DNS-сервер». Одно из его преимуществ — то, что Cloudflare удаляет все записи о DNS-запросах в течение 24 часов.
Обычно интернет-провайдеры предоставляют собственные DNS-серверы, с помощью которых доменные имена превращаются в IP-адреса, распознаваемые роутерами. Зачастую такие серверы медленные и ненадёжные — в частности, они позволяют владельцу сети узнать, на какие сайты вы заходили.
Cloudflare вместе с Азиатско-Тихоокеанским сетевым информационным центром (Asia-Pacific Network Information Centre или APNIC) решила предложить собственный DNS-сервер под первичным и вторичным адресами 1.1.1.1 и 1.0.0.1. Ранее многие использовали 1.1.1.1 в качестве фиктивного адреса.
«Мы обратились к команде APNIC и рассказали, что хотим создать крайне быструю DNS-систему с упором на конфиденциальность, — рассказал генеральный директор Cloudflare Мэтью Принс (Matthew Prince). — Мы предложили сеть Cloudflare для изучения трафика, а взамен получили возможность использовать запоминающиеся IP-адреса в качестве DNS-адресов».
Продукт Cloudflare поддерживает DNS-over-TLS и DNS-over-HTTPS. Сервер работает с задержкой 14 мс, в то время как у OpenDNS этот показатель составляет 20 мс, а у Google DNS — 34 мс. Это делает DNS-сервер Cloudflare самым быстрым в мире.
- Протокол IPv4: 1.1.1.1 and 1.0.0.1
- Протокол IPv6: 2606:4700:4700::1111 and 2606:4700:4700::1001
Самые быстрые DNS сервера
В эту часть обзора мы включили сразу три сервиса: OpenDNS, GoogleDNS и Level3DNS, поскольку все они имеют сходные характеристики и среди них сложно выбрать лучшего.
Важно отметить, что перечисленные публичные службы DNS не используют шифрование. Напомним также, что ваш провайдер Интернета получает ваши персональные данные, и использование публичных DNS Вас от этого не спасет.
OpenDNS ( 208.67.222.222 и 208.67.220.220)
Сервис OpenDNS, также известный под названием Cisco Umbrella, является очень популярной службой DNS и умеет фильтровать контент по множеству параметров, в том числе блокирует сайты для взрослых, а также предоставляет защиту от кражи персональных данных.
У OpenDNS есть бесплатные и премиум тарифы, отличающиеся лишь в скорости соединения и в наличии функции добавления исключений, предназначенной для создания «заблокированной сетевой среды» (как ее называют в OpenDNS).
Наиболее привлекательной опцией у сервиса OpenDNS является возможность создания настраиваемых фильтров, которая позволяет самостоятельно фильтровать контент. Так что, если Вы хотите внедрить родительский контроль на уровне DNS, используйте OpenDNS.
Публичный Google DNS (8.8.8.8 и 8.8.4.4)
Google Public DNS пользуется большой популярностью. Хотя этот сервис работает достаточно быстро и располагает хорошей службой поддержки, у Google Public DNS есть один минус, и заключается он в сборе пользовательской статистики.
Ни для кого уже не секрет, что Google зарабатывает на рекламе и сборе данных пользователей, которые затем используются для выдачи соответствующих результатов по поисковым запросам.
Нельзя утверждать, что это является серьезным нарушением безопасности, поскольку GoogleDNS все же не имеет доступа к персональным данным пользователя, но все равно необходимо иметь в виду, что сбор данных ведется, а это потенциально может привести к раскрытию конфиденциальной информации.
На информационном сайте Гугл ДНС размещена документация, более подробно освещающая услуги и функции этого сервиса.
Level3DNS (4.2.2.1 и 4.2.2.2)
Level3DNS предоставляет широкую линейку продуктов, которые подойдут как для личных целей, так и для корпоративного сегмента.
Компания Level3 – это один из крупнейших провайдеров услуг Интернет, а значит, почти весь трафик проходит через их сервера. Level3 не берет плату за услуги DNS (просто потому, что это их работа), и, как следствие, этот сервис добрался до третьего места популярности в мире.
Как и в случае с ранее упомянутыми DNS-серверами, имейте в виду, что Level3 регистрирует все запросы, исходящие с вашего компьютера.
Самые конфиденциальные DNS сервера
По критерию анонимности мы отобрали DNS-сервисы, которые не проводят регистрацию запросов и при этом предлагают дополнительную защиту (блокировка рекламы, вредоносных программ) соединения.
DNS.Watch (84.200.69.80 и 84.200.70.40)
DNS.Watch – публичный DNS-сервис, который получил известность благодаря тому, что для его использования не требуется регистрация.
DNS.Watch предоставляет и IPV4, и IPv6 DNS-серверы общего пользования и поддерживает DNSSEC (обратите внимание, что в данном случае DNSSEC не означает «шифрование DNS», DNS запросы на этом сайте по-прежнему не зашифрованы).
На наш взгляд недостатки DNS.Watch кроются в скорости – при тестировании из России мы выявили длительную задержку (более 100 мс).
DNSCrypt
DNSCrypt предлагает поддержку шифрованных запросов DNS, но работает этот сервис только через собственное программное обеспечение, так что налету, просто настроив DNS-серверы на сетевой карте, начать работу не получится.
И вот почему:
DNSCrypt, в отличие от прочих сервисов, шифрует сделанные вами DNS-запросы, а не оставляет их в виде читаемого текста, который легко перехватить.
DNSCrypt поддерживает основные операционные системы, а также предоставляет прошивку для роутера. Инструкции по установке и настройке приведены на их сайте, прямо на главной странице.
Нельзя обойти вниманием еще одну интересную функцию, которая позволяет пользователю запустить собственный DNS-сервер – для кого-то она может оказаться полезной.
Comodo Secure DNS (8.26.56.26 и 8.20.247.20)
Comodo Secure DNS предоставляет за плату довольно много услуг, однако непосредственно сама служба DNS является бесплатной и, как утверждает сама компания, ее можно рекомендовать любому, особенно тем пользователям, которым нужен надежный, быстрый и безопасный интернет-серфинг.
Выбирайте DNS из перечисленных нами, но не забывайте, что разные сервисы предлагают разный функционал, и в своем обзоре мы не ранжировали сервисы по местам, не называли самый лучший DNS, однако все эти сервисы рекомендуются нами к использованию.
Deploy Django, Gunicorn, NGINX, PostgresQL using Docker
Lets not waste time and go to the following steps.
1. Let’s make an empty directory named myproject and add another folder inside name it src. src should contain the django project. For testing purpose lets put a simple django project inside named mydjango.
2. Let’s create a subdirectory inside myproject and name it config. Lets put a requirement.pip file inside config and write these line in it:
Django==1.10 gunicorn==19.6.0 psycopg2==2.6.2
3. Now let’s make a Dockerfile inside the myproject. This should contain the following lines:
FROM python:3.5 ENV PYTHONUNBUFFERED 1 RUN mkdir /config ADD /config/requirements.pip /config/ RUN pip install -r /config/requirements.pip RUN mkdir /src; WORKDIR /src
requirement.pip file in /config directory within the container and installing the packages from it.4. Let’s create a file called docker-compose.yml in myproject directory.
The docker-compose.yml file describes the services that make your app. Here we need a web service(Django+Gunicorn), A database(Postgres), and Proxy Server(Nginx). It also describes which Docker images these services will use, how they will link together, any volumes they might need mounted inside the containers. Finally, the docker-compose.yml file describes which ports these services expose. See the docker-compose.yml reference for more information on how this file works. Don’t forget to add docker-compose
to your python environment by running pip install docker-compose.
5. Let’s add the following configuration to the docker-compose.yml file:
version: '2'
services:
nginx:
image: nginx:latest
container_name: ng01
ports:
- "8000:8000"
volumes:
- ./src:/src
- ./config/nginx:/etc/nginx/conf.d
depends_on:
- web
web:
build: .
container_name: dg01
command: bash -c "python manage.py makemigrations && python manage.py migrate && gunicorn mydjango.wsgi -b 0.0.0.0:8000"
depends_on:
- db
volumes:
- ./src:/src
expose:
- "8000"
db:
image: postgres:latest
container_name: ps01
postgres and password is postgresweb container is build using project’s
Dockerfile. It mounts src directory into it and exposes port 8000. version is being used for which format to use to compose the docker file.nginx uses nginx’s latest image from dockerhub. This proxy server is accessible from port 8000. It mounts src and config directory.
6. Now let’s write a nginx configuration config file named mydjango.conf inside myproject‘s config folder and put it in a subdirectory named nginx.
upstream web {
ip_hash;
server web:8000;
}
# portal
server {
location / {
proxy_pass http://web/;
}
listen 8000;
server_name localhost;
}
── myproject
├── src
│ ├── mydjango
│ ├── manage.py
├── config
│ ├── requirements.pip
│ ├── nginx
│ ├── mydjango.conf
├── Dockerfile
└── docker-compose.yml
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
'PORT': 5432,
}
}
8. All is done. Now lets run docker-compose build in terminal within the project directory. It will build/rebuild(if necessary) all the containers. For first time running the containers, run docker-compose up -d. Lets go to browser and type: localhost:8000. We should see the django application up and running.
docker-compose stop. Re-running docker, use docker-compose start.10. For shell accessing.
#Nginx docker exec -ti nginx bash #Web docker exec -ti web bash #Database docker exec -ti db bash
#Nginx docker-compose logs nginx #Web docker-compose logs web #DB docker-compose logs db
(Thanks to Akimul Islam for the source)
Cheers!!
Update:
Serving django with gunicorn won’t allow you to serve static files with it. You need to serve static files seperately. You can follow this post: http://ruddra.com/2016/11/02/serve-static-files-by-nginx-from-django-using-docker/ for how to do serve static files using Nginx from docker.
Linux cgroups
Чтобы ограничить ресурсы с помощью cgroup не обязательно заводить отдельное окружение (lxc-контейнер). Достаточно завести свою группу, выставить ей нужные лимиты и приписать свой процесс туда.
Пример:
$ cgcreate -g memory:/myGroup $ echo $(( 500 * 1024 * 1024 )) > /sys/fs/cgroup/memory/myGroup/memory.limit_in_bytes $ echo $(( 5000 * 1024 * 1024 )) > /sys/fs/cgroup/memory/myGroup/memory.memsw.limit_in_bytes $ cgexec -g memory:myGroup myProgramm
Утилиты для работы входят в пакет libcgroup-tools (для CentOS). При желании таким же макаром можно прописать ограничения для системных пользователей или групп.
Собственно контейнера lxc по такому принципу и работают.
https://habrahabr.ru/post/266083/#comment_8560049
GPG и PGP
Создание своего ключа
Для того чтобы зашифровать или подписать файл с помощью GPG, нужно чтобы у вас был собственный ключ.
Создаем ключ:
~ $ gpg --gen-key
Далее нужно передать свой публичный ключ адресату или разместить его в публичном доступе на серверах с ключами.
~ $ gpg --armor --output pubkey.txt --export 'Your Name' ~ $ gpg --send-keys 'Your Name' --keyserver hkp://subkeys.pgp.net
Шифрование/расшифровка на локальном хосте
Теперь мы можем зашифровать/расшифровать файл с именем foo.txt на своем локальном хосте, — это выглядет так:
~ $ gpg --encrypt --recipient 'Your Name' foo.txt ~ $ gpg --output foo.txt --decrypt foo.txt.gpg
Шифрование файла для передачи адресату
gpg --search-keys 'myfriend@his.isp.com' --keyserver hkp://subkeys.pgp.net gpg --import key.asc gpg --list-keys gpg --encrypt --recipient 'myfriend@his.isp.net' foo.txt
Расшифровка
gpg --output foo.txt --decrypt foo.txt.gpg
Подписание файлов
gpg --verify crucial.tar.gz.asc crucial.tar.gz gpg --armor --detach-sign your-file.zip
Ссылки по теме
HDD SMART
Таблица расшифровки показаний SMART
| № | Имя атрибута | Описание |
| 01 | Raw Read Error Rate | Частота ошибок при чтении данных с диска, происхождение которых обусловлено аппаратной частью диска. |
| 02 | Throughput Performance | Общая производительность диска. Если значение атрибута уменьшается, то велика вероятность, что с диском есть проблемы. |
| 03 | Spin-Up Time | Время раскрутки пакета дисков из состояния покоя до рабочей скорости. |
| 04 | Start/Stop Count | Полное число запусков/остановок шпинделя. У дисков некоторых производителей (например, Seagate) — счётчик включения режима энергосбережения. В поле raw value хранится общее количество запусков/остановок диска. |
| 05 | Reallocated Sectors Count | Число операций переназначения секторов. Когда диск обнаруживает ошибку чтения/записи, он помечает сектор «переназначенным» и переносит данные в специально отведённую область. Вот почему на современных жёстких дисках нельзя увидеть bad-блоки — все они спрятаны в переназначенных секторах. Этот процесс называют remapping, а переназначенный сектор — remap. Чем больше значение, тем хуже состояние поверхности дисков. Поле raw value содержит общее количество переназначенных секторов. |
| 06 | Read Channel Margin | Запас канала чтения. Назначение этого атрибута не документировано. В современных накопителях не используется. |
| 07 | Seek Error Rate | Частота ошибок при позиционировании блока головок. Чем их больше, тем хуже состояние механики и/или поверхности жёсткого диска. |
| 08 | Seek Time Performance | Средняя производительность операции позиционирования магнитными головками. Если значение атрибута уменьшается, то велика вероятность проблем с механической частью. |
| 09 | Power-On Hours (POH) | Число часов (минут, секунд — в зависимости от производителя), проведённых во включенном состоянии. В качестве порогового значения для него выбирается паспортное время наработки на отказ (MTBF — mean time between failure). |
| 10 | Spin-Up Retry Count | Число повторных попыток раскрутки дисков до рабочей скорости в случае, если первая попытка была неудачной. Если значение атрибута увеличивается, то велика вероятность неполадок с механической частью. |
| 11 | Recalibration Retries | Количество повторов запросов рекалибровки в случае, если первая попытка была неудачной. Если значение атрибута увеличивается, то велика вероятность проблем с механической частью. |
| 12 | Device Power Cycle Count | Количество полных циклов включения-выключения диска. |
| 13 | Soft Read Error Rate | Число ошибок при чтении по вине программного обеспечения. |
| 184 | End-to-End error | Данный атрибут — часть технологии HP SMART IV, это означает, что после передачи через кэш памяти буфера данных паритет данных между хостом и жестким диском не совпадают. |
| 187 | Reported UNC Errors | Ошибки, которые не могли быть восстановлены, используя методы устранения ошибки аппаратными средствами. |
| 190 | Airflow Temperature (WDC) | Температура воздуха внутри корпуса жёсткого диска для дисков Western Digital. Для дисков Seagate рассчитывается по формуле (100 — HDA temperature). |
| 191 | G-sense error rate | Количество ошибок, возникающих в результате ударных нагрузок. |
| 192 | Power-off retract count | Число циклов выключений или аварийных отказов. |
| 193 | Load/Unload Cycle | Количество циклов перемещения блока магнитных головок в парковочную зону / в рабочее положение. |
| 194 | HDA temperature | Здесь хранятся показания встроенного термодатчика. |
| 195 | Hardware ECC Recovered | Число коррекции ошибок аппаратной частью диска (ошибок чтения, ошибок позиционирования, ошибок передачи по внешнему интерфейсу). |
| 196 | Reallocation Event Count | Число операций переназначения. В поле «raw value» атрибута хранится общее число попыток переноса информации с переназначенных секторов в резервную область. Учитываются как успешные, так и неуспешные попытки. |
| 197 | Current Pending Sector Count | В поле хранится число секторов, являющихся кандидатами на замену. Они не были ещё определены как плохие, но считывание с них отличается от чтения стабильного сектора, это так называемые подозрительные или нестабильные сектора. В случае успешного последующего прочтения сектора он исключается из числа кандидатов. В случае повторных ошибочных чтений накопитель пытается восстановить его и выполняет операцию переназначения. |
| 198 | Uncorrectable Sector Count | Число неисправимых ошибок при обращении к сектору. {Возможно, имелось в виду «число некорректируемых секторов», но никак не число самих ошибок!} В случае увеличения числа ошибок велика вероятность критических дефектов поверхности и/или механики накопителя. |
| 199 | UltraDMA CRC Error Count | Число ошибок, возникающих при передаче данных по внешнему интерфейсу. |
| 200 | Write Error Rate / Multi-Zone Error Rate |
Показывает общее количество ошибок, происходящих при записи сектора. Может служить показателем качества поверхности и механики накопителя. |
| 201 | Soft read error rate | Частота появления «программных» ошибок при чтении данных с диска. Данный параметр показывает частоту появления ошибок при операциях чтения с поверхности диска по вине программного обеспечения, а не аппаратной части накопителя. |
| 202 | Data Address Mark errors | Number of Data Address Mark (DAM) errors (or) vendor-specific. |
| 203 | Run out cancel | Количество ошибок ECC. |
| 204 | Soft ECC correction | Количество ошибок ECC, скорректированных программным способом. |
| 205 | Thermal asperity rate (TAR) | Number of thermal asperity errors. |
| 206 | Flying height | Высота между головкой и поверхностью диска. |
| 207 | Spin high current | Amount of high current used to spin up the drive. |
| 208 | Spin buzz | Number of buzz routines to spin up the drive. |
| 209 | Offline seek performance | Drive’s seek performance during offline operations. |
| 220 | Disk Shift | Дистанция смещения блока дисков относительно шпинделя. В основном возникает из-за удара или падения. Единица измерения неизвестна. |
| 221 | G-Sense Error Rate | Число ошибок, возникших из-за внешних нагрузок и ударов. Атрибут хранит показания встроенного датчика удара. |
| 222 | Loaded Hours | Время, проведённое блоком магнитных головок между выгрузкой из парковочной области в рабочую область диска и загрузкой блока обратно в парковочную область. |
| 223 | Load/Unload Retry Count | Количество новых попыток выгрузок/загрузок блока магнитных головок в/из парковочной области после неудачной попытки. |
| 224 | Load Friction | Величина силы трения блока магнитных головок при его выгрузке из парковочной области. |
| 226 | Load ‘In’-time | Время, за которое привод выгружает магнитные головки из парковочной области на рабочую поверхность диска. |
| 227 | Torque Amplification Count | Количество попыток скомпенсировать вращающий момент. |
| 228 | Power-Off Retract Cycle | Количество повторов автоматической парковки блока магнитных головок в результате выключения питания. |
| 230 | GMR Head Amplitude | Амплитуда «дрожания» (расстояние повторяющегося перемещения блока магнитных головок). |
| 231 | Temperature | Температура жёсткого диска. |
| 240 | Head flying hours | Время позиционирования головки. |
| 250 | Read error retry rate | Число ошибок во время чтения жёсткого диска. |
Webpack
- Устанавливаем Bootstrap и Jquery через Bower
$ bower install bootstrap jquery
- Устанавливаем необходимые плагины через npm
$ npm install webpack css-loader style-loader file-loader url-loader --save-dev
- Создаем webpack.config.js и app.js:
/*---- webpack.config.js ----*/ var webpack = require('webpack'), //путь к js файлам, у вас может быть другой path_src = 'src/js', ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { entry: path_src + '/app.js', devtool: '#source-map', resolve: { modulesDirectories: [ "." ], alias: { //ссылка на jquery lib jquery: "bower_components/jquery/dist/jquery.js" } }, output: { //папка куда он все выплюнет, находится в корне проекта path: 'dist', filename: 'bundle.js' }, module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }, { test: /\.png$/, loader: "url-loader?limit=100000" }, { test: /\.jpg$/, loader: "file-loader" }, { test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream' }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file' }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml' }, //webpack автоматически устранит зависимость bootstrap.js от jquery { test: /bower_components\/dist\/bootstrap\/js\//, loader: 'imports?jQuery=jquery' }, ] }, plugins: [ //чтобы в любом месте сразу писать через $ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }), new ExtractTextPlugin('bundle.css') ] };/*---- app.js ----*/ //подключаем bootstrap.css require('bower_components/bootstrap/dist/css/bootstrap.css'); //подключаем bootstrap.js require('bower_components/bootstrap/dist/js/bootstrap.js'); //подключаем файл стилей require('src/css/_main.scss'); - Запускаем команду «webpack«
- Подключаем получившиеся bundle к странице:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8"> <link href="dist/bundle.css" rel="stylesheet" /> </head> <body> <script src="dist/bundle.js"></script> </body> </html> - Проверяем и радуемся что все работает.
Установка NPM пакетов глобально без sudo
Node.js набирает огромную популярность. Одна из самых его замечательных особенностей — NPM пакеты или модули. По-умолчанию они устанавливаются локально, в директорию откуда вы запустили команду. Однако есть способ установки NPM пакетов глобально. Проблема в том что для этого вам нужно запускать команду установки пакетов с правами root пользователя.
К счастью эту проблему можно исправить простыми шагами.
1. Создание директории для глобальных пакетов
$ mkdir ~/.npm-packages
2. Указать где будут находиться пакеты с помощью .bashrc
$ NPM_PACKAGES="${HOME}/.npm-packages"
3. Указать npm где вы собираетесь хранить глобальные пакеты
Для этого откройте файл ~/.npmrc с помощью текстового редактора и вставьте следующую строку:
prefix=${HOME}/.npm-packages
4. Убедитесь, что Node.js будет знать где находятся пакеты
Откройте опять ~/.bashrc с помощью текстового редактора и вставьте следующие строки:
NODE_PATH="$NPM_PACKAGES/lib/node_modules:$NODE_PATH"
PATH="$NPM_PACKAGES/bin:$PATH"
unset MANPATH
MANPATH="$NPM_PACKAGES/share/man:$(manpath)"
Если все предыдущие шаги вам кажутся слишком сложными, то можете воспользоваться скриптом npm-g_nosudo, он все предыдущие шаги делает автоматически.
How to monitor traffic at Cisco router using Netflow
By default Cisco IOS doesn’t provide any traffic monitoring tools like iftop or iptraff available in Linux. While there are lots of proprietary solutions for this purpose including Cisco Netflow Collection, you are free to choose nfdump and nfsen open source software to monitor traffic of one or many Cisco routers and get detailed monitoring data through your Linux command line or as graphs at absolutely no cost.
Below is beginner’s guide that helps to quickly deploy netflow collector and visualizer under Linux and impress everybody by cute and descriptive graphs like these:
It is highly recommended to look through Netflow basics to get brief understanding of how it works before configuring anything. For example, here is Cisco’s document that gives complete information about Netflow. In a few words to get started you should enable netflow exporting on Cisco router and point it to netflow collector running under Linux. Exported data will contain complete information about all packets the router has received/sent so nfdump and nfsen working under Linux will collect it and visualize to present you the graph like above example.
Cisco Router Setup
1. Enable flow export on ALL Cisco router’s interfaces that send and receive some traffic, here is an example:
Router1# configure terminal Router1(config)#interface FastEthernet 0/0 Router1(config-if)#ip route-cache flow input Router1(config-if)#interface FastEthernet 0/1 Router1(config-if)#ip route-cache flow input ...
2. Setup netflow export:
Router1# configure terminal Router1(config)#ip flow-export source FastEthernet0/0 Router1(config)#ip flow-export source FastEthernet0/1 Router1(config)#ip flow-export version 5 Router1(config)#ip flow-export destination 1.1.1.1 23456
Where 1.1.1.1 is IP address of Linux host where you plan to collect and analyze netflow data. 23456 is port number of netflow collector running on Linux.
Linux Setup
1. Download and install nfdump.
cd /usr/src/ wget http://sourceforge.net/projects/nfdump/files/stable/nfdump-1.6.2/nfdump-1.6.2.tar.gz/download tar -xvzf nfdump-1.6.2.tar.gz cd nfdump-1.6.2 ./configure --prefix=/ --enable-nfprofile make make install
2. Download and install nfsen.
It requires web server with php module and RRD so make sure you have the corresponding packages installed. I hope you’re running httpd with php already so below are rrd/perl related packages installation hints only.
Fedora/Centos/Redhat users should type this:
yum install rrdtool rrdtool-devel rrdutils perl-rrdtool
Ubuntu/Debian:
aptitude install rrdtool librrd2-dev librrd-dev librrd4 librrds-perl librrdp-perl
If you run some exotic Linux distribution just install everything that is related to rrd + perl.
At last, nfsen installation:
cd /usr/src/ wget http://sourceforge.net/projects/nfsen/files/stable/nfsen-1.3.5/nfsen-1.3.5.tar.gz/download tar -xvzf nfsen-1.3.5.tar.gz cd nfsen-1.3.5 cp etc/nfsen-dist.conf etc/nfsen.conf
In order to continue you should edit file etc/nfsen.conf to specify where to install nfsen, web server’s username, its document root directory etc. That file is commented so there shouldn’t be serious problems with it.
One of the major sections of nfsen.conf is ‘Netflow sources’, it should contain exactly the same port number(s) you’ve configured Cisco with — recall ‘ip flow-export …’ line where we’ve specified port 23456. E.g.
%sources = (
'Router1' => { 'port' => '23456', 'col' => '#0000ff', 'type' => 'netflow' },
);
Now it’s time to finish the installation:
./install.pl etc/nfsen.conf
In case of success you’ll see corresponding notification after which you will have to start nfsen daemon to get the ball rolling:
/path/to/nfsen/bin/nfsen start
From this point nfdump started collecting netflow data exported by Cisco router and nfsen is hardly working to visualize it — just open web browser and go to http://linux_web_server/nfsen/nfsen.php to make sure. If you see empty graphs just wait for a while to let nfsen to collect enough data to visualize it.
That’s it!








