Отладка Django-сайта на боевом сервере OpenShift

Ни в коем случае нельзя включать отладку на боевом сервере. Рекомендуется создать копию сервера, недоступного для пользователя.

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

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

Следующий код позволяет включать и отключать отладку на локальном сервере и на сервере Openshift. Код располагается в файле settings.py.

import os
ON_PAAS = 'OPENSHIFT_REPO_DIR' in os.environ
LOCAL_DEBUG = True
ENV_DEBUG = os.environ.get('DEBUG') == 'True'

DEBUG = (not ON_PAAS and LOCAL_DEBUG) or (ON_PAAS and ENV_DEBUG)

if ON_PAAS and DEBUG:
    print("Warning: debug mode!")

Переменная ON_PAAS равна True если код выполняется на сервере Openshift, иначе она равна False. Переменная LOCAL_DEBUG включает или отключает локальную отладку.

При отключении отладки на локальном сервере в список ALLOWED_HOSTS должна быть добавлена строка ‘localhost’.

ALLOWED_HOSTS = ['localhost']

Включить отладку на сервере Openshift можно если создать переменную окружения DEBUG со значением True.

Управлять переменными окружения на Openshift можно с помощью инструмента rhc. Следующие команды включают отладку на сервере Openshift.

rhc env set DEBUG=True -a test
rhc app stop -a test
rhc app start -a test

Где test — это имя приложения. Первая команда устанавливает переменную окружения, а две другие перезапускают приложение.

Отключить отладку можно следующими командами.

rhc env unset DEBUG -a test
rhc app stop -a test
rhc app start -a test

Вместо первой команды можно использовать следующую команду.

rhc env set DEBUG=False -a test

 

Библиотека на языке C для конвертации строк из кодировки UTF-8 в CP1251

Написал легкую библиотеку utf8_to_cp1251 для конвертации из UTF-8 в CP1251 для применения в программах для микроконтроллеров. Охватывает языки от С89 до C++.

Библиотека и ее описание опубликованы на Github.

Статические переменные вместо глобальных на Си/Си++

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

Есть простой способ избавиться от большинства глобальных переменных.

void fun(void) {
    static int A = 10;
    ...
}

Переменная A располагается в глобальной области памяти, но имеет локальную область видимости (в пределах функции fun). То есть переменная сохраняет свое значение между вызовами функции. Начальное значение переменной равно 10.

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

static int A = 10;

void setA(const int value) {
    A = value;
}

int getA(void) {
    return A;
}

Область видимости переменной A — только этот файл. Никаким способом к ней нельзя получить доступ из других файлов. Функции setA и getA позволяют получить и установить значение переменной.

Угол опрокидывания тела

ugol-oprokidivaniya.png

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

\alpha = arctg \left(\frac{X_M}{Y_M}\right)

Расчет на Питоне:

import math
Xm = 1.5
Ym = 2
math.degrees(math.atan(Xm / Ym))

Результат примерно 37°.

Публикация проекта в PyPI

PyPI — это хранилище пакетов Python.

Регистрируемся на сайте PyPI и на TestPyPI. Поле PGP Key ID заполнять необязательно. На TestPyPI регистрироваться не обязательно, это хранилище нужно только для тренировки, перед тем как опубликовать пакет в PyPI.

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

Добавляем в файл следующее содержимое.

[distutils]
index-servers =
    pypi
    testpypi

[pypi]
repository = https://pypi.python.org/pypi
username = Логин
password = Пароль

[testpypi]
repository = https://testpypi.python.org/pypi
username = Логин
password = Пароль

Вместо Логин и  Пароль указываем логин и пароль, использованные при регистрации на сайтах PyPI и TestPyPI.

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

  • example
    • example
      • __init__.py
      • foo.py
    • LICENSE.txt
    • MANIFEST.in
    • README.rst
    • setup.cfg
    • setup.py

Для большей наглядности приведу изображение.

pypi-dirs-and-files.png

Примечание: для проекта следует выбрать уникальное имя, которого нет в хранилище.

Для публикации проекта нужно заполнить файл setup.py, все остальные файлы могут быть пустыми.

Файл setup.py следует заполнить следующим образом.

from setuptools import setup, find_packages

setup(
    name='example',
    version='0.0.1',
    description='Короткое описание',
    packages=find_packages(),
    author='Имя автора',
    author_email='Почта@автора',
    url='http://Сайт проекта',
)

В файле лучше использовать только латиницу.

Чтобы собрать пакет, в папке, где содержится файл setup.py (папке проекта), выполняем следующую команду .

python setup.py sdist

После этого в папке проекта появятся папки dist и example.egg-info.

pypi-dirs-and-files-after-build.png

Устанавливаем программу twine, которая позволит разместить пакет в хранилище, следующей командой.

pip install twine

Зарегистрируем пакет в тестовом хранилище TestPyPI следующей командой.

twine register -r testpypi dist/example-0.0.1.tar.gz

С помощью опции -r задается хранилище, которое было указано в файле .pypirc.

Загрузим пакет в хранилище следующей командой.

twine upload -r testpypi dist/example-0.0.1.tar.gz

Пакет появится в списке пакетов на сайте хранилища.

testpypi-your-packages.png

За более подробной информацией следует обратится к официальному руководству.

Иллюстрация: Ноты для пианино

Скачать иллюстрацию в формате PDF.

Noty_dlya_pianino

Лист А4 разделен на две половины формата А5, чтобы лист А4 можно было сложить пополам. На левой половине нотоносец с басовым ключем, на правой — со скрипичным.

Обозначения

  • ск — субконтроктава,
  • к — контроктава,
  • Б — большая октава,
  • м — малая октава,
  • 1 — первая октава,
  • 2 — вторая октава,
  • 3 — третья октава,
  • 4 — четвертая октава,
  • 5 — пятая октава.

Техническая информация

Проект доступен на Github, чтобы любой желающий мог поправить под свои нужды.

Иллюстрация выполнена в LibreOffice Draw 5.1.4.

Печать HTML-документа в Qt 5.8

23 января 2017 года вышла Qt версии 5.8, в которой появилась поддержка печати полноценных HTML-документов.

До этого возможность напечатать документ тоже была. Можно было:

  • Использовать метод QTextDocument::Print(). Но приходилось ограничиваться небольшими возможностями HTML и CSS.
  • Использовать метод QWebFrame::print(), который существовал пока не вышла Qt 5.6. Потом в Qt был окончательно заменен веб-движок и поддержка печати пропала.
  • Использовать печать в PDF с помощью метода QWebEnginePage::printToPdf(), который появился в Qt 5.7. Но печать в PDF — это не печать через принтер.
  • Вывести видимую часть страницы на печать методом QWebEngineView->render(). Но это плохой обходной путь, так как не вся страница будет выведена на печать и потребуется отобразить страницу.

В Qt 5.8 появился метод QWebEnginePage::print(), который выводит на печать HTML-документы без отрисовки в окне и поддерживает современные возможности HTML, CSS и JavaScript.

Следующий код выводит HTML-документ на принтер.

#include <QDebug>
#include <QPrinter>
#include <QPrintDialog>
#include <QPrinterInfo>
#include <QWebEnginePage>

void MainWindow::on_printButton_clicked()
{
    QPrinter * printer = new QPrinter();

    QPrintDialog printDialog(printer, this);
    if (printDialog.exec() != QDialog::Accepted) {
        return;
    }

    QWebEnginePage * page = new QWebEnginePage;

    page->setHtml("<html><body>Привет<body/></html>");

    connect(page, &QWebEnginePage::loadFinished, [page, printer] (bool ok) {
        if (!ok) {
            qDebug() << "Загрузка документа провалилась."; delete page; delete printer; return; } page->print(printer, [page, printer](bool ok) {
            if (ok) {
                qDebug() << "Документ напечатан.";
            }
            else {
                qDebug() << "Печать документа провалилась.";
            }

            delete page;
            delete printer;
        });
    });
}

В файле проекта (*.pro) нужно подключить два модуля с помощью следующей строчки.

QT += printsupport webenginewidgets

В коде используются лямбда-выражения, которые появились в C++11. Это конструкции вида: «[…] (…) {…}», анонимные функции внутри функций. В Qt 5.8 по умолчанию включен C++11.

Класс QWebEnginePage обрабатывает, отрисовывает и печатает документы асинхронно с основным кодом программы, поэтому код в лямбда-функциях выполняется уже после того, как завершится метод on_printButton_clicked().

Надо внимательно следить за удалением объектов, чтобы не возникло утечки памяти и ошибки сегментации, особенно при печати нескольких документов в цикле. Объект принтера может быть одним, а выводимых на печать документов несколько. Тогда объект принтера надо удалять, после печати последнего документа, и не забывать, что печать происходит асинхронно. То есть функция print() завершается еще до вывода документа на печать.

Но и у этого способа печати есть огромный недостаток. К сожалению модуль Qt WebEngine, в который входит класс QWebEnginePage, недоступен при сборке проекта с помощью MinGW в Виндовс. Собрать проект в Виндовс можно только с помощью Visual Studio.

Обмен файлами между компьютерами через USB

Скачать статью в PDF.

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

Суть такова, соединяем два переходника USB-UART и передаем файлы по протоколу ZMODEM.

Читать далее Обмен файлами между компьютерами через USB

Российские правообладатели

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

Сегодня (спустя почти 3 года) мне позвонили и попросили удалить руководства. Я убрал ссылки из статьи и добавил надпись «Удалено по просьбе правообладателя.».

Российская проблема в том, что никто не хочет делиться документацией на приборы и электронные комплектующие, пока ты их не купишь. Наверное, поэтому их мало кто покупает. Я чаще всего ищу аналог, у которого есть техническое описание, а тех кто скрытничает, посылаю лесом. Как вообще можно покупать кота в мешке?

Однажды, был в командировке на электростанции, и мне надо было воспользоваться прибором конкурентов. Мне нужно было руководство, чтобы понять, как прибор работает. Бумажное я найти не смог, а производитель специально не публикует руководства на сайте. Я сделал запрос у производителя, но мне даже не ответили. Как потом выяснилось, они спалили, что я из конкурирующей организации и просто посмеялись надо мной. А мне нужно было работать, время поджимало. В общем, задачу я решил, но меня эта ситуация взбесила. Производитель подвел не только меня, но и электростанцию.

С зарубежной документацией почти никогда не бывает проблем, она в открытом доступе, подробна и понятна. У нас же, если кто-то и публикует документацию, то сделана она плохо. Я думаю, это одна из причин почему Россия в жопе.

Справочник. Переходные процессы в электрических цепях

1 Заряд конденсатора

1.1 Схема

Заряд конденсатора.png

С точки зрения протекающих процессов обе схемы одинаковы.

Предполагается, что перед коммутацией ключа S, конденсатор полностью разряжен, то есть на нем напряжение 0 В.

1.2 Формулы

Параметр Формула Строчная формула
Постоянная времени \tau=R\cdot C tau=R*C
Ток i=\dfrac{E}{R}\cdot e^{-\tfrac{t}{R\cdot C}} i=E/R*exp(-t/(R*C))
Напряжение на конденсаторе u_{c}=E\cdot\left(1-e^{-\tfrac{t}{R\cdot C}}\right) u_C=E*(1-exp(-t/(R * C)))
Напряжение на резисторе u_{R}=E\cdot e^{-\tfrac{t}{R\cdot C}} u_R=E*exp(-t/(R*C))
Мощность на резисторе p_{R}=\dfrac{E^{2}}{R}\cdot e^{-\tfrac{2t}{R\cdot C}} p_R=E^2/R*exp(-2*t/(R*C))

1.3 Начальное и конечное состояние

Параметры Значение при t = 0 Значение при t = \infty
Ток \tfrac{E}{R} 0
Напряжение на конденсаторе 0 E
Напряжение на резисторе E 0
Мощность на резисторе \tfrac{E^2}{R} 0

1.4 Графики

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

Ток.png

Напряжение на конденсаторе.png

Напряжение на резисторе.png

Мощность на резисторе.png

2 Разряд конденсатора

Если такое изложение переходных процессов вызовет интерес, то я продолжу статью.

Создание предыдущего раздела про заряд конденсатора заняло целый день, больше 10 часов. Параллельно статье я делаю PDF-версию в которой все схемы, формулы и графики в векторном формате, то есть документ можно масштабировать без потери качества. PDF-версию и все исходники планирую выложить в открытый доступ.

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

3 «Заряд» катушки индуктивности

4 «Разряд» катушки индуктивности

5 Заряд конденсатора с нагурзкой

6 RLC-цепь

7 Разряд конденсатора на катушку индуктивности