Страницы

Поиск по вопросам

вторник, 28 мая 2019 г.

Работа с Firebase

Хочу задать вопрос по поводу Firebase, а именно сохранение данных в БД Firebase. Насколько я понимаю: что как только данные сохраняются в БД Firebase, то они сразу отправляются на сервер и Firebase обновляет данные на всех устройствах, у которых установлено данное приложение. Что происходит, когда пользователь находится оффлайн, все данные пропадают? и юзер не может больше пользоваться приложением? Как решаются конфликты? Например, пользователем на одном устройстве удалил какие-то данные будучи оффлайн, а другой пользователь вносил изменение в эти данные.


Ответ

Как только обновляются данные в FireBase (и если вы использовали ValueEventListener), то у пользователя, который в этот момент работает в приложении произойдет обновление и он это увидит. Когда пользователь находится в оффлайн, все данные продолжают сохраняться в Firebase (только пользователь об этом не знает). Пользователь может по прежнему пользоваться приложением даже в оффлайн, как сказано в документации. Если кто-то внес изменения в базу, то изменения произойдут сразу, а кто подключится из оффлайн, то есть станет онлайн, найдет нужную ветку и уже удалит эти данные. Так что другие пользователи не увидят ветку с этими данными из базы. П.С. что же у вас за данные, что пользователь их может удалить, а другой может их при этом менять? Может лучше сделать их личными - кто захотел удалил, поменял. А основные данные сделать доступными только для чтения большинству.

Обработать строку с помощью регулярного выражения на Python

Задача: нужно отбросить из начала данной строки все символы, не являющимися буквами, до первой встретившийся буквы. Исключительно используя регулярное выражение.
Например: s = "12. Привет мир 23 раза"
Должно остаться "Привет мир 23 раза"
Пробовал как то так
re.match(r'(?<=(\d|\.|\s)*)(.*)', s).group()
не получается


Ответ

Модуль регулярных выражений Python re не поддерживает блоков предварительного просмотра назад неопределенной длины. В (?<=(\d|\.|\s)*) длина совпадения неопределена, так как квантификатор * находит ноль и более (неизвестно сколько) символов.
Используйте
re.sub(r'^[^а-яА-ЯёЁ]+', '', s)
Демо
Подробности:
^ - начало строки [^а-яА-ЯёЁ]+ - 1 и более символов, отличных от русских букв. Если надо, можно включить и латинские - [^а-яА-ЯёЁa-zA-Z]+
Примечание
Символ ^ в разных контекстах может обозначать:
Буквальный символ ^ (caret):
Если он экранирован знаком \ (в любом месте регулярного выражения) Если он находится внутри символьного класса не в начальной позиции (т.е. [;!^]) (В некоторых других языках / библиотеках ещё может быть между \Q ... \E) Метасимвол начала строки/целого текста (в зависимости от модификатора или библиотеки регулярных выражений, в Python при использовании re.M / re.MULTILINE - позиция после знака перевода строки LF,
, если модификатор не указан, будет найдено только начало целого текста)
Если он не экранирован и не находится внутри символьного класса Метасимвол, инвертирующий символьный класс, т.е. [^.] найдёт все символы, отличные от точки.
ВНИМАНИЕ! [^^] находит любой символ, отличный от знака ^

Компилятор не поддерживает расширенную инициализацию

Имеется такой код:
int main() { double d {4.5}; int x {d}; }
Прочитал, что в новой версии С++11 есть поддержка на запрет сужающих преобразований при инициализации. Но компилятор ошибки не выдает, хотя должен (ибо я пытаюсь double в int преобразовать с синтаксисом новой версии инициализации (с помощью фигурных скобок), которая как раз запрещает подобные небезопасные преобразования.
IDE - DevC++ 5.11 Компилятор - TDM-GCC 4.9.2.
Вопрос: Так почему нет поддержки этой новой инициализации? Компилятор новый же, его вместе со средой скачал недавно вот.


Ответ

Стандарт С++ не обязывает реализацию языка выдавать именно "ошибку компиляции" для случаев когда в стандарте написано что код ошибочен. (Однако при этом не должно ломается SFINAE, иначе это уже баг компилятора).
Компилятор g++ в некоторых случаях ограничивается предупреждением:
double d = 4.5; int x{d}; // предупреждение в g++ int y{4.5}; // ошибка в g++
Впрочем этого достаточно, т.к. рекомендуется компилировать код с -Wall -pedantic -Werror
Что касается стандарта, то int x{d}; это несомненно неправильный код. В разделе [dcl.init.list] есть аналогичный пример

Из текстового файла в строки C#

Допустим есть текстовый файл, в котором в каждой строке лежит слово и последовательность цифр. Как мне поместить в одну строку только слова, а в другую - только цифры?
Пример файла:
testText0 1 2 3 4 testText1 2 4


Ответ

Кроме решений в лоб всегда остаётся вариант использования регулярных выражений.
using System.Text.RegularExpressions; ........ var Lines = File.ReadAllLines("MyFileName.txt"); var RegEx = new Regex(@"^([a-zA-Z]+)([\d\s]+)$"); var Words = new List(); var Digits = new List();
foreach (var Line in Lines){ var Matches = RegEx.Match(Line); Words.Add(Matches.Groups[1].ToString()); Digits.Add(Matches.Groups[2].ToString()); }
Этот подход хорош еще и тем, что он автоматически валидирует входные данные.
Проверить регулярные выражения можно тут.

Как сделать простой сервер на Python работающий как автономно, так и через apache?

Необходимо создать простой одностраничный сайт для тестовых целей. На странице необходимо иметь возможность делать AJAX запросы к серверу. Пожалуйста, подскажите, каким образом реализовать самым простым и быстрым способом инфраструктуру сервера? Необходимо учитывать, что сервер будет запускаться как на локальной машине не техническим специалистом, так и на общем тестовом сервере. На локальной машине не технического специалиста нет какого–либо специального ПО. На сервере используется apache2, а также настроено окружение для django–проектов.


Ответ

Самым простым способом реализовать указанное будет использование встроенного python HTTP–сервера на локальной машине и простого WSGI–приложения на сервере. При создании структуры проекта необходимо учитывать, что при работе через WSGI статические файлы лучше отдавать напрямую через apache.
Предлагаемая структура проекта будет следующей
server.py static/ | - index.html | - m/ | - styles.css | - scripts.js | - img/
В этом случае, мы сможем одинаково работать с файлами проекта. В html/css коде ссылки на статические файлы будут выглядеть следующим образом
/m/scripts.js
Конфигурация apache
ServerAdmin webmaster@mysite.ru DocumentRoot "/path/to/my/site/root/" ServerName mysite.ru
WSGIApplicationGroup %{GLOBAL} WSGIDaemonProcess mysite WSGIProcessGroup mysite WSGIScriptAlias / /path/to/my/site/root/server.py
Alias /m/ /path/to/my/site/root/static/m/
Order deny,allow Allow from all
ErrorLog "/var/log/apache2/mysite_error.log" LogLevel warn CustomLog "/var/log/apache2/mysite_warning.log" combined

В конфигурационном файле для сервера мы казали, где находится наш WSGI скрипт (WSGIScriptAlias / /path/to/my/site/root/server.py). Предлагается использовать тот же скрипт и для локального сервера. Также мы добавили псевдоним для /m/ (Alias /m/ /path/to/my/site/root/static/m/). Таким образом, все что остается – сделать папку static рабочей директорией для локального сервера, а apache автоматически сам будет обрабатывать ссылки на файлы.
import SimpleHTTPServer import SocketServer import os import sys
PORT = 8000 AJAX_ENPOINT_URL = "/ajax/endpoint" DOCUMENT_ROOT = "/path/to/my/site/root/"
# Обработчик локального сервера. class CustomHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): # Обрабатываем GET–запрос к серверу. # Если запрос к приходит по известному нам URL, формируем ответ. # Если мы не знаем URL, предлагаем стандартной библиотеки обработать его. def do_GET(self): if self.path == AJAX_ENPOINT_URL: self.send_response(200) self.send_header('Content-type','application/json') self.end_headers() self.wfile.write("My ajax response") return else: SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
if __name__ == "__main__": os.chdir("./static/") httpd = SocketServer.TCPServer(("", PORT), CustomHandler) print "Serving at port", PORT httpd.serve_forever() quit()
def get_index(): f = open(DOCUMENT_ROOT +'/static/index.html', 'r') data = f.read() f.close() return data
def application(environ, start_response): output = "" status = "200 OK" content_type = "text/plain" path = environ.get('PATH_INFO', None)
if path == "/" or path == "index.html": output = get_index() content_type = 'text/html' elif path == AJAX_ENPOINT_URL: content_type = 'application/json' output = "My Ajax response"
if output == "": status = "404 Not Found" output = "Not Found"
response_headers = [('Content-type', content_type), ('Content-Length', str(len(output)))] start_response(status, response_headers) return [output]
Для запуска сервера на локальной машине, достаточно перейти в корень проекта и выполнить команду
python server.py
В случае запуска на сервер, необходимо добавить конфигурацию apache в папку конфигураций и перезапустить его.

Не работает русская клавиатурная раскладка в сочетаниях горячих клавиш Sublime Text 3

Установил плагин Markdown Editing, синтаксис Markdown GFM. Хочу обернуть текст в код или квадратные скобки. Когда нахожусь в английской клавиатурной раскладке, проблем не возникает:

Но когда раскладка русская, я уже не могу обернуть текст:

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


Ответ

1. Суть проблемы
Откроем консоль: Ctrl+` (машинописный обратный апостроф, символ расположен на той же клавише, где кириллическая «ё») → вводим в открывшееся поле sublime.log_input(True). Нажмём сначала Ctrl+k в английской раскладке, затем Ctrl+л в русской. Посмотрим, что выведется в консоли:
key evt: control+k key evt: control+k
Если с системой нет проблем, результат должен быть аналогичным. А теперь нажмём k в английской, потом л в русской.
chr evt: k (0x6b) chr evt: л (0x43b)
Sublime Text воспринимает k и л как разные символы, если они нажимаются не вместе со служебными клавишами. Если используется двойное нажатие хоткеев, Ctrl+k,k и Ctrl+л,л Sublime Text также видит по-разному.
Т.е. когда в качестве шортката используется одинарный символ, чтобы результат в русской раскладке был таким же, как в английской, придётся раскладку переключать. Так что если будете сами задавать сочетание для команды, без использования служебных клавиш, продублируйте запись и для русской раскладки, пример:
// Предпросмотр вики-страницы в плагине Mediawiker { "keys": ["ctrl+7", "p"], "command": "mediawiker_preview" }, { "keys": ["ctrl+7", "з"], "command": "mediawiker_preview" },

2. Попытки урегулирования проблемы с разработчиками
Заявка в issue tracker Sublime Text висит долгое время, её приоритет обозначен как «minor». Есть предложение использовать в качестве идентификатора клавиши keycode вместо keysym, но по состоянию на сентябрь 2016 оно не реализовано на практике. Разработчик плагинов отказался принимать мой pull request, добавляющий хоткеи для русской раскладки.
Значит, придётся настраивать Sublime Text для русской раскладки самостоятельно.

3. Решение
На примере плагина BetterFindBuffer.
Устанавливаем плагин PackageResourceViewer: Ctrl+Shift+P → PackageResourseViewer:Open Resourse (благодаря fuzzy поиску достаточно набрать просто prvor) → MarkdownEditing → Default.sublime-keymap (иногда Default(ваша операционная система).sublime-keymap) → в открывшемся файле ищем шорткаты, состоящие из одного символа, которого в русской раскладке нет или же он расположен на другой клавише. Пример:
{ "keys": ["o"], "command": "find_in_files_open_file", "context": [ { "key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] },
Заменяем o на соответствующую ей в русской раскладке букву, это щ
{ "keys": ["щ"], "command": "find_in_files_open_file", "context": [ { "key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] },
Preferences → Key Bindings - User → вставляем в открывшийся файл код с буквой щ. Проделываем данное действие со всеми шорткатами без служебных клавиш, где это необходимо.
После того, как произвели действия, проверьте, всё ли работает нормально. Пример: в Preferences → Key Bindings - Default есть такой код:
{ "keys": ["\""], "command": "insert_snippet", "args": {"contents": "\"$0\""}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|>|$)", "match_all": true }, { "key": "preceding_text", "operator": "not_regex_contains", "operand": "[\"a-zA-Z0-9_]$", "match_all": true }, { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.double - punctuation.definition.string.end", "match_all": true } ] },
(\" — символ "кавычки-ёлочки". Для использования кавычки как литерала в JSON-файлах требуется её экранировать.)
Вы вставили в свой кеймап:
{ "keys": ["э"], "command": "insert_snippet", "args": {"contents": "\"$0\""}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|>|$)", "match_all": true }, { "key": "preceding_text", "operator": "not_regex_contains", "operand": "[\"a-zA-Z0-9_]$", "match_all": true }, { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.double - punctuation.definition.string.end", "match_all": true } ] },
Но теперь когда вы просто вводите букву э, вводятся двойные кавычки. Код с буквой э не нужен, удаляем его из нашего файла. Проверяем — буква э пишется теперь нормально. Если после ваших действий с назначением команд клавишам русской раскладки символы русской раскладки заработают неправильно, значит, скорее всего, вы вставили лишнее, подлежащее удалению.

4. Поддержка русской раскладки для дефолтных хоткеев без служебных клавиш
Можно добавлять строки ниже в файл, открывающийся после Preferences → Key Bindings - User, сразу после установки Sublime Text, чтобы не приходилось переключаться при оборачивании текста в различные виды кавычек и скобок, а также при использовании Vintage Mode. Проверял, ошибок возникнуть не должно.
Обёртка текста в скобки и кавычки
// // // Дефолтные сочетания в русской раскладке клавиатуры // // // Выделение {фигурными скобками} { "keys": ["Х"], "command": "wrap_block", "args": {"begin": "{", "end": "}"}, "context": [ { "key": "indented_block", "match_all": true }, { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, { "key": "following_text", "operator": "regex_match", "operand": "^$", "match_all": true }, ] }, { "keys": ["Х"], "command": "insert_snippet", "args": {"contents": "{${0:$SELECTION}}"}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true } ] }, { "keys": ["Ъ"], "command": "move", "args": {"by": "characters", "forward": true}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^\\}", "match_all": true } ] }, // Выделение "кавычками-ёлочками" { "keys": ["Э"], "command": "insert_snippet", "args": {"contents": "\"${0:$SELECTION}\""}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true } ] }, { "keys": ["Э"], "command": "move", "args": {"by": "characters", "forward": true}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^\"", "match_all": true }, { "key": "selector", "operator": "not_equal", "operand": "punctuation.definition.string.begin", "match_all": true }, { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.double - punctuation.definition.string.end", "match_all": true }, ] }, // Выделение 'одинарными кавычками' { "keys": ["э"], "command": "insert_snippet", "args": {"contents": "'${0:$SELECTION}'"}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true } ] }, { "keys": ["э"], "command": "move", "args": {"by": "characters", "forward": true}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^'", "match_all": true }, { "key": "selector", "operator": "not_equal", "operand": "punctuation.definition.string.begin", "match_all": true }, { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.single - punctuation.definition.string.end", "match_all": true }, ] }, // Выделение [квадратными скобками] { "keys": ["х"], "command": "insert_snippet", "args": {"contents": "[$SELECTION]$0"}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, { "keys": ["х"], "command": "insert_snippet", "args": {"contents": "[${0:$SELECTION}]"}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true } ] }, { "keys": ["ъ"], "command": "move", "args": {"by": "characters", "forward": true}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^\\]", "match_all": true } ] },
Vintage Mode
Вставляем отсюда, (на всякий случай архивная копия, также см. ответ

5. Поддержка русской раскладки в некоторых плагинах
Чтобы не мучились настраивать русскую раскладку для этих плагинов самостоятельно, готовый код:
BetterFindBuffer
// BetterFindBuffer, русская раскладка { "keys": ["щ"], "command": "find_in_files_open_file", "context": [ { "key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] }, { "keys": ["ф"], "command": "find_in_files_open_all_files", "context": [ { "key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] }, { "keys": ["т"], "command": "find_in_files_jump_file", "context": [ { "key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] }, { "keys": ["з"], "command": "find_in_files_jump_file", "args": { "forward": false }, "context": [ { "key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] }, { "keys": ["о"], "command": "find_in_files_jump_match", "context": [ { "key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] }, { "keys": ["л"], "command": "find_in_files_jump_match", "args": { "forward": false }, "context": [ { "key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] }, { "keys": ["а"], "command": "bfb_fold_and_move_to_next_file", "context": [ {"key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] }, { "keys": [","], "command": "bfb_toggle_popup_help", "context": [ {"key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] },
Markmon
// Markmon, русская раскладка { "keys": ["ctrl+k", "ь"], "command": "markmon_toggle", "args": { "enable": true } },
MarkdownEditing
// MarkdownEditing, русская раскладка { "keys": ["ё"], "command": "insert_snippet", "args": {"contents": "`${0:$SELECTION}`"}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, { "keys": ["ё"], "command": "run_macro_file", "args": {"file": "Packages/MarkdownEditing/macros/Skip Closing Character.sublime-macro"}, "context": [ { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "^`", "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true } ] }, { "keys": ["Ё"], "command": "insert_snippet", "args": {"contents": "~~${0:$SELECTION}~~"}, "context": [ { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true }, { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, { "keys": ["№"], "command": "insert_snippet", "args": {"contents": "#${0: ${SELECTION/(^ | $)//g} }#"}, "context": [ { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "preceding_text", "operator": "not_regex_contains", "operand": "#{6}", "match_all": true }, { "key": "setting.mde.match_header_hashes", "operator": "equal", "operand": true }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, { "keys": ["№"], "command": "insert_snippet", "args": {"contents": "#${0: ${SELECTION/(^ | $)//g}}"}, "context": [ { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "preceding_text", "operator": "not_regex_contains", "operand": "#{6}", "match_all": true }, { "key": "setting.mde.match_header_hashes", "operator": "equal", "operand": false }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, { "keys": ["№"], "command": "run_macro_file", "args": {"file": "Packages/MarkdownEditing/macros/Padded Headline.sublime-macro"}, "context": [ { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "preceding_text", "operator": "regex_contains", "operand": "#{6}", "match_all": true }, { "key": "following_text", "operator": "regex_contains", "operand": "#+", "match_all": true }, { "key": "setting.mde.match_header_hashes", "operator": "equal", "operand": true }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, { "keys": ["№"], "command": "run_macro_file", "args": {"file": "Packages/MarkdownEditing/macros/Padded Headline.sublime-macro"}, "context": [ { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "preceding_text", "operator": "regex_contains", "operand": "#{6}", "match_all": true }, { "key": "setting.mde.match_header_hashes", "operator": "equal", "operand": false }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ] }, { "keys": ["Ю"], "command": "run_macro_file", "args": {"file": "Packages/MarkdownEditing/macros/Convert to Blockquote.sublime-macro"}, "context": [ { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }, { "key": "selector", "operator": "equal", "operand": "text.html.markdown", "match_all": true }, { "key": "selector", "operator": "not_equal", "operand": "markup.raw", "match_all": true } ]

Как в Atom заставить разворачиваться конструкцию emmet-а “div.class” по табуляции в php файлах?

Дело в том, что в html файлах отрабатывает: div.some-class преобразовывается в

при нажатии табуляции, когда курсор стоит в конце конструкции, а в php файлах такая система не работает. Как заставить это работать в php файлах?


Ответ

В конфигурации горячих клавиш Emmet по умолчанию про Tab написано следующее:

'atom-text-editor[data-grammar="text html basic"]:not([mini]), atom-text-editor[data-grammar~="erb"]:not([mini]), atom-text-editor[data-grammar~="jade"]:not([mini]), atom-text-editor[data-grammar~="css"]:not([mini]), atom-text-editor[data-grammar~="stylus"]:not([mini]), atom-text-editor[data-grammar~="sass"]:not([mini]), atom-text-editor[data-grammar~="scss"]:not([mini])': 'tab': 'emmet:expand-abbreviation-with-tab'
(Этот селектор пугает ровно до того момента, пока не начнёте смотреть его по секциям, разделённым запятыми: после этого он сразу приобретает смысл)
Чтобы получить этот кусок конфигурации, откройте настройки, Keybindings, наберите в поиске expand-abbreviation и нажмите кнопку напротив tab. Соответствующий кусок конфигурации будет скопирован в буфер обмена.
Формат основан на CSON: как JSON, но с ароматом CoffeeScript
В этом же окне наверху есть ссылка your keymap file. Нажав на неё, вы попадёте в файл конфигурации собственных горячих клавиш. Вставьте туда скопированный кусочек.
Как видно, он имеет формат:
'селектор': 'кнопка': 'команда'
Чтобы указать его действие в PHP-файлах, нужно написать соответствующий селектор. Следуя примерам из настроек по умолчанию, например, такой:
atom-text-editor[data-grammar="text html php"]:not([mini])
(Применимость селекторов можно проверить, открыв DevTools и найдя в DOM узел с редактором, в котором вы хотите, чтобы горячая клавиша действовала. Посмотрите на селектор, на узел, и попробуйте выполнить сопоставление в уме.)
Получится что-то такое:
'atom-text-editor[data-grammar="text html php"]:not([mini])': 'tab': 'emmet:expand-abbreviation-with-tab'
Сохраняйте, пробуйте.

Невозможно создать новую ветвь в git-репозитории в среде NetBeans

Нажимаю "Группа" — "Ветвь" — "Создать", при любом имени ветви пишет "Ветвь с этим именем уже существует"


Ответ

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

Leaflet координаты

Подскажите, как я могу получить координаты углов каждого тайла?
var layers = { Streets: L.mapbox.tileLayer('mapbox.streets'), }; layers.Streets.on('tileload', function (e) { ... как-то получить координаты углов загрузившегося тайла ... });
Версия leaflet 0.7.7. Благодарю!


Ответ

В обработчик события tileload передается объект {tile: ... , url: ... }. Элемент tile является HTML элементом с некоторыми допольнительными параметрами. Один из них _leaflet_pos - отступ в пикселах от левого верхнего угла видимой части карты (поскольку параметр начинается с подчеркивания, подразумевается что он приватный, его не будет в документации и он запросто может называться в другой версии иначе или вообще отсутствовать). Также эти значения можно увидеть в параметре inline-стиля transform. Чтобы перевести пикселы в координаты, можно воспользоваться методом layerPointToLatLng. Например так:
layers.Streets.on('tileload', function (e) { console.log(mymap.layerPointToLatLng(e.tile._leaflet_pos)); });
См также:
Исходник L.TileLayer

Не работает MySQL из PHP

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

второй документ
'; echo 'Title' . mysql_result($result,$j,'title') . '
'; echo 'Category' . mysql_result($result,$j,'category') . '
'; echo 'Year' . mysql_result($result,$j,'year') . '
'; echo 'ISBN' . mysql_result($result,$j,'isbn') . '
'; } ?>


Ответ

У вас код кривой, в этом вся проблема, давайте разберемся.
Тут не хватает знака указания переменной $
if (!db_server) //меняем на if (!$db_server)
В die, принимается всего один параметр, Вы передаете 2 параметра, запятую заменяем точкой
die("невозможно подключиться к базе данных: " , mysql_error()); //Меняем на die("невозможно подключиться к базе данных: " . mysql_error());
Корректный код второго файла:
require_once 'login.php'; $db_server = mysql_connect($db_hostname, $db_username, $db_password); if (!$db_server) die("невозможно подключиться к базе данных: " . mysql_error()); mysql_select_db($db_database) or die("невозможно подключиться к базе данных: " . mysql_error()); $query = 'select * from class'; $result = mysql_query($query); if (!$result) die("невозможно подключиться к базе данных: " . mysql_error()); $rows = mysql_num_rows($result); for ($j = 0 ; $j < $rows; ++$j) { echo 'Author' . mysql_result($result,$j,'autor') . '
'; echo 'Title' . mysql_result($result,$j,'title') . '
'; echo 'Category' . mysql_result($result,$j,'category') . '
'; echo 'Year' . mysql_result($result,$j,'year') . '
'; echo 'ISBN' . mysql_result($result,$j,'isbn') . '
'; }
Если вы используете версию PHP 7, тогда у вас не будет работать данный код. Расширение mysql отключено, Вам требуется писать будет код с использованием библиотеки PDO или mysqli, иначе получите ошибку
Uncaught Error: Call to undefined function mysql_connect()
А также обязательно смотрите лог ошибок сервера, чтобы точнее понять проблему. Для разработки можете включить вывод ошибок в браузер (не делать это не продакшене, даже под дулом пистолета)
error_reporting(E_ALL); ini_set('display_errors', 'on');

Изменение стилей

Доброго времени суток коллеги, вопрос такой: Как изменить стиль элемента при нажатии на другой элемент?

Пример: У меня есть вот такая кнопка

GOOGLE
Как при нажатии на кнопку первая буква меняла цвет на красный(к примеру)?


Ответ

Еще как вариант
a { text-decoration: none; display: block; width: 10rem; height: 5rem; line-height: 5rem; background: #111; color: #fff; border-radius: 4px; text-align: center; letter-spacing: 4px; font-family: sans-serif; text-transform: uppercase; font-size: 1.5rem; } a:first-letter { color: cornflowerblue; } a:focus:first-letter{ color: tomato; } GOOGLE

Цикл добавляет только последний проход и затирает предыдущие

Есть два массива
dataArr = [[1,2,3], [4,5,6], [7,8,9]]; colors = ['red','green','blue'];
И функция, в которую они идут в качестве аргументов.
function makeDataArrays(dataObj,colors) { var a = {}; var b = []; for (var i=0; inewArr = makeDataArrays(dataArr, colors);
В итоге функция вернет массив объектов. Все объекты будут одинаковы и равны последней итерации.
Почему? Как исправить?


Ответ

Объекты в массиве у вас не просто равны, это - один и тот же объект
Создавайте новый объект на каждой итерации - и будет вам счастье

(Android) Перезапуск метода при появлении интернета на устройстве

Добрый день! В onCreate методе выполняется запрос данных с удаленного сервера (использую PostResponseAsyncTask). В случае, если на устройстве недоступно или отсутствует подключение к интернету, пользователю выводится соответствующее сообщение. Но хочется, чтобы приложение самостоятельно выполнило действия, описанные в onCreate, при появлении интернет соединения. Как это лучше реализовать?
public class cityActivity extends Activity { private ArrayList cityList; private ListView lvCity; FunDapter adapter;
public void get_cityList() { lvCity = (ListView) findViewById(R.id.list); PostResponseAsyncTask taskRead = new PostResponseAsyncTask(cityActivity.this, new AsyncResponse() { @Override public void processFinish(String s) { if (s == "") { Toast.makeText(cityActivity.this, "Проверьте подключение к интернету!", Toast.LENGTH_LONG).show(); } cityList = new JsonConverter().toArrayList(s, city.class);
BindDictionary dict = new BindDictionary(); dict.addStringField(R.id.tvCity, new StringExtractor() { @Override public String getStringValue(city cityOption, int position) { return cityOption.city_option; } });
adapter = new FunDapter<>(cityActivity.this, cityList, R.layout.layout_city, dict); lvCity.setAdapter(adapter); initTextFilter(adapter);
} }); taskRead.setLoadingMessage("Загружаю список городов"); taskRead.execute("example.com");
AdapterView.OnItemClickListener itemListener = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View v, int position, long id) { TextView tvCity = (TextView)v.findViewById(R.id.tvCity); String cityOption = tvCity.getText().toString();
Intent intent = new Intent(cityActivity.this, sferaActivity.class);
// в ключ username пихаем текст из первого текстового поля intent.putExtra("cityOption",cityOption); startActivity(intent);
} }; lvCity.setOnItemClickListener(itemListener); } ...
Класс NetworkChangeReciever:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager;
public class NetworkChangeReceiver extends BroadcastReceiver {
@Override public void onReceive(final Context context, final Intent intent) { final ConnectivityManager connMgr = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo wifi = connMgr .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobile = connMgr .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (wifi.isAvailable() || mobile.isAvailable()) { // Do something
} } }


Ответ

Вам нужен BroadcastReceiver который будет слушать состояние сети. и когда она есть можете выполнять нужные вам действия.
public class NetworkChangeReceiver extends BroadcastReceiver {
@Override public void onReceive(final Context context, final Intent intent) { final ConnectivityManager connMgr = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo wifi = connMgr .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobile = connMgr .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (wifi.isAvailable() || mobile.isAvailable()) { // Do something
Log.d("Network Available ", "Flag No 1"); } } }
и интент фильтр

Ну и зарегестрировать его можно либо в activity либо Manifest.xml в теле тега

UPD:
Регистрируем в Активити:
public class cityActivity extends Activity { private ArrayList cityList; private ListView lvCity; FunDapter adapter;
private String BROADCAST_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
IntentFilter intentFilter = new IntentFilter(BROADCAST_ACTION);
BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) { case BROADCAST_ACTION:
final ConnectivityManager connMgr = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo wifi = connMgr .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobile = connMgr .getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (wifi.isAvailable() || mobile.isAvailable()) { get_cityList();
Log.d("Network Available ", "Flag No 1"); } break; } } };
@Override protected void onCreate(Bundle savedInstanceState) { //...
registerReceiver(receiver,IntentFilter); }
@Override protected void onResume() { super.onResume(); registerReceiver(receiver,IntentFilter); } @Override protected void onPause() { unregisterReceiver(receiver); }
public void get_cityList() { lvCity = (ListView) findViewById(R.id.list); PostResponseAsyncTask taskRead = new PostResponseAsyncTask(cityActivity.this, new AsyncResponse() { @Override public void processFinish(String s) { if (s == "") { Toast.makeText(cityActivity.this, "Проверьте подключение к интернету!", Toast.LENGTH_LONG).show(); } cityList = new JsonConverter().toArrayList(s, city.class);
BindDictionary dict = new BindDictionary(); dict.addStringField(R.id.tvCity, new StringExtractor() { @Override public String getStringValue(city cityOption, int position) { return cityOption.city_option; } });
adapter = new FunDapter<>(cityActivity.this, cityList, R.layout.layout_city, dict); lvCity.setAdapter(adapter); initTextFilter(adapter);
} }); taskRead.setLoadingMessage("Загружаю список городов"); taskRead.execute("http://remont.qwerq.ru/app/city_list.php");
//...

Как открыть div блок на всю страницу?

Как открыть div блок .conteiner на всю страницу, как на данном сайте, под кодом до вопроса "Развернуть фрагмент" ?
https://jsfiddle.net/p7cc1uys/
$("#button").click(function() { //alert("Проверка"); }); * { margin: 0px; padding: 0px; } html, body { min-height: 100%; } body { background: #ddd; } .conteiner { background: #F3EFE1; overflow: auto; width: 200px; height: 200px; margin: 0 auto; margin-top: 40px; position: relative; -webkit-box-shadow: inset 0px 0px 9px 2px rgba(0, 0, 0, 0.32); -moz-box-shadow: inset 0px 0px 9px 2px rgba(0, 0, 0, 0.32); box-shadow: inset 0px 0px 9px 2px rgba(0, 0, 0, 0.32); } #button { float: right; width: 80px; cursor: pointer; text-align: center; padding: 4px 13px; border: solid 1px #004F72; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; font: 12px Verdana, Geneva, sans-serif; font-weight: bold; color: #E5FFFF; background-color: #3BA4C7; background-image: linear-gradient(top, #3BA4C7 0%, #1982A5 100%); -webkit-box-shadow: 0px 0px 2px #bababa, inset 0px 0px 1px #ffffff; -moz-box-shadow: 0px 0px 2px #bababa, inset 0px 0px 1px #ffffff; box-shadow: 0px 0px 2px #bababa, inset 0px 0px 1px #ffffff; }

Развернуть


Ответ

Еще один вариант
$(".button").click(function() { var parent = $(this).parents()[0]; //получаем родительський элемент var width = $(parent).width(); //узнаем ширину родительського блока $(parent).toggleClass("full"); //добавляем/убираем класс где блок во весь екран if(width=='200'){ //если ширина равна 200 $(parent).children('.button').text('Свернуть'); //если истина то надпись "Свернуть" } else { $(parent).children('.button').text('Развернуть');//если ложь то надпись "Свернуть" } }); /* блок во весь екран */ .full { width: 100% !important; height: 100% !important; position: absolute !important; margin-top: 0px !important; z-index: 99999 !important; } * { margin: 0px; padding: 0px; } html, body { min-height: 100%; } body { background: #ddd; } .conteiner { background: #F3EFE1; overflow: auto; width: 200px; height: 200px; margin: 0 auto; margin-top: 40px; position: relative; -webkit-box-shadow: inset 0px 0px 9px 2px rgba(0, 0, 0, 0.32); -moz-box-shadow: inset 0px 0px 9px 2px rgba(0, 0, 0, 0.32); box-shadow: inset 0px 0px 9px 2px rgba(0, 0, 0, 0.32); } .button { float: right; width: 80px; cursor: pointer; text-align: center; padding: 4px 13px; border: solid 1px #004F72; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; font: 12px Verdana, Geneva, sans-serif; font-weight: bold; color: #E5FFFF; background-color: #3BA4C7; background-image: linear-gradient(top, #3BA4C7 0%, #1982A5 100%); -webkit-box-shadow: 0px 0px 2px #bababa, inset 0px 0px 1px #ffffff; -moz-box-shadow: 0px 0px 2px #bababa, inset 0px 0px 1px #ffffff; box-shadow: 0px 0px 2px #bababa, inset 0px 0px 1px #ffffff; }

Развернуть

Можно ли на чистом HTML и CSS сделать несколько блоков одинаковой, но переменной длины внутри родителя?

Можно ли на чистом HTML и CSS добиться того, чтобы блоки имели одинаковую ширину внутри родителя, но растягивались/сужались по мере растяжения/сужения родительского блока?

Другими словами, ширина каждого из n блоков внутри контейнера без учёта отсупов равна ParentWidth/n для любых ширин родителя Parent Width
Если это невозможно на чистом HTML и CSS - так и ответьте и на этом вопрос закроем; JS-решения пока не требуются.


Ответ

вариант с display: table
+
table-layout: fixed - таблица делится на колонки равной ширины. Для корректной работы этого значения обязательно должна быть задана ширина таблицы.
*{ padding: 0; margin: 0; box-sizing: border-box; } .b{ display: table; width: 100%; table-layout: fixed; height: 150px; } .b-item{ display: table-cell; vertical-align: top; border: 2px solid #ccc; }

Другими словами, ширина каждого из n блоков внутри контейнера без учёта отсупов равна ParentWidth/n для любых ширин родителя Parent Width.
Другими словами, ширина каждого из n блоков внутри контейнера без учёта отсупов равна ParentWidth/n для любых ширин родителя Parent Width.Другими словами, ширина каждого из n блоков внутри контейнера без учёта отсупов равна ParentWidth/n для любых ширин родителя Parent Width.
Другими словами, ширина каждого из n блоков внутри контейнера без учёта отсупов равна ParentWidth/n для любых ширин родителя Parent Width. Другими словами, ширина каждого из n блоков внутри контейнера без учёта отсупов равна ParentWidth/n для любых ширин родителя Parent Width. Другими словами, ширина каждого из n блоков внутри контейнера без учёта отсупов равна ParentWidth/n для любых ширин родителя Parent Width.

Определение вызывающего родителя

Функция_А вызывает функцию_Б.
Подскажите пожалуйста, можно ли как-то находясь внутри функции_Б определить какая функция её вызвала?
И ещё интересует другая ситуация, а если вместо функции_А например просто скрипт, можно ли как-то определить это, чтобы например показало "main".


Ответ

Обычно, для этого получают стек вызова при помощи функции debug_backtrace(). Первый элемент будет содержать информацию о текущей функции, второй - об непосредственно родителе. Например:
"; $funcs = debug_backtrace(); echo "Parent: ". $funcs[1]['function']; }
function a($str) { b($str); }
a('Hello world!');
Результат
From b: Hello world! Parent: a

Имплементация интерфейса с generic type

Помогите с реализацией интерфейса. Допустим у нас есть интерфейс
public interface Sorter> { void sort(List list); }
и я хочу создать класс, который будет реализовывать этот интерфейс используя genec types. Я пробовала так:
public class SorterImpl> implements Sorter { public void sort(List list){ boolean erijuht1 = true; boolean erijuht2 = true; for(int a=0; a list.get(a+1)){ erijuht1 = false; } if(list.get(a) < list.get(a+1)){ erijuht2 = false; } } } }
Проблема в том, что последний класс не хочет сравнивать объекты между собой. Как мне реализовать данный интерфейс так, что бы класс был и с generic type, и мог сравнивать объекты?


Ответ

Вы не можете в данной функции сравнивать два объекта таким образом, так как не понятно какой из них считать большим, а какой меньшим (и равным). list.get() возвращает Вам объект класса T, наследуемый от Comparable. Значит мы можем использовать вызывать все методы этого класса, а в данном случае compareTo (возвращает 1,0 или -1). Осталось добавить код для перемены мест в случае если "больший" имеет меньший индекс. Вот что получилось:
public class SorterImpl> implements Sorter { public void sort(List list) { // boolean erijuht1 = true; // boolean erijuht2 = true; for (int j = 0; j < list.size() - 1; j++) for (int a = 0; a < list.size() - j - 1; a++) { if (list.get(a).compareTo(list.get(a + 1)) > 0) { // erijuht1 = false; } else { // erijuht2 = false; T temp = list.get(a + 1); list.set(a + 1, list.get(a)); list.set(a, temp); } } } //Тестируем public static void main(String[] args) { List ar = new ArrayList() { { add(2); add(3); add(5); add(8); add(2); } }; SorterImpl s = new SorterImpl(); s.sort(ar); for (int i = 0; i < ar.size(); i++) { System.out.print(ar.get(i).toString() + " "); }
}
}
Результат:
8 5 3 2 2

php, перфекционизм

Есть бэкенд на PHP, обслуживающий разные запросы и возвращающие json.
Точка входа(упрощенно):
try { switch ($method) { case 'login': $call = new Login($data); break; case 'list': $call = new List($data); break; default: $call = new WrongMethod($data); } $out = ['r' => $call(),'n' => (string)Error::OK,'e' => '']; } catch (Error $e) { $out = [ 'r' => $call::defaultResult())), 'n' => (string)$e->getCode(), 'e' => $e->getMessage() ]; } print_r(json_encode($out, JSON_UNESCAPED_UNICODE), false);
Уже увидели ошибку? ;)
Проблема: $call::defaultResult() - в блоке catch объект $call не определен.
Все классы пуляют Error extends Exception и реализуют интерфейс
interface Call { public function __construct(array $data); public function __invoke(); public static function defaultResult(); }
defaultResult нужен потому, что _invoke может вернуть скаляр, обычный массив либо ассоциативный массив и если при ошибке использовать значение какого-то одного типа, то фронт споткнется на десериализации. То есть мне нужно гарантированно получить в блоке catch такую же структуру поля 'r', как и в блоке try
Я вижу два варианта решения:
Вынести из конструктора все, что может бросить исключение. Такой подход не нравится тем, что у меня в конструкторах исключительно проверка входных данных на валидность и их приведение в случае необходимости. ИМХО этому функционалу самое место в конструкторе. Перейти на тёмную сторону и сделать как-то так:
(Этот вариант мне вообще не нравится. Прям вызывает дискомфорт и потерю аппетита.)
function getMethodClass($method) { switch ($method) { case 'login': return "Login"; case 'list': return "GetList"; default: return "WrongMethod"; } } $className = $callsNameSpace."\\" . getMethodClass($method); try { $call = new $className($data); ... } catch (Error $e) { $out = ['r' => call_user_func(array($className, 'defaultResult')), ... }
Внимание, вопрос!
Может я не прав относительно своих фобий и первый(или второй) вариант вполне себе хорош?
Может я заработался и не вижу простого и очевидного решения? Такого чтоб и работало нормально и с души не воротило?
UPD PHP 5.6


Ответ

Вы забыли о еще одном очень-очень важном моменте. В первом вашем варианте конструкция:
$call::defaultResult()
невалидна (как минимум, идеологически). Фактически вы пытаетесь вызвать метод класса у экземпляра, что лишено смысла.
С учетом этого, второй ваш вариант намного лучше. Хотя я немного причесал бы его (в примере ниже использую PHP 5.5+):
$map = [ 'login' => Login::class, 'list' => List::class, ]; $class_name = isset($map[$method]) ? $map[$method] : WrongMethod::class;
try { $call = new $class_name($data); // ... } catch (Error $e) { $out = ['r' => $class_name::defaultResult()]; }
Замечание:
Для ошибок валидации входных данных в PHP традиционно используется \InvalidArgumentException и его подклассы. А \Error - это специальный класс ошибок введенный в PHP7. Возможно стоит немного изменить имя вашего класса исключений, чтобы повысить читаемость кода и избежать двусмысленности после перехода на PHP7.

Экспорт модели в .xlsx соблюдая SOLID

В БД есть таблица результатов тестирования по русскому языку и математике (SubjectCode=2)
dbo.Result
Во второй таблице находятся просто сведения о школах:
dbo.School

Таких результатов бывает 40.000-70.000. Нужно на выходе получить для каждого тестируемого вот такой отчет в pdf-файле

Мое решение:
Создал Excel-шаблон; Беру данные из базы и заношу их в этот xlsx-шаблон; Сохраняю этот шаблон в pdf-файл; И так для каждого ученика.

LearnerReport.cs
namespace so16092016.Models { public class LearnerReport { public string SNS { get; set; } //Surname Name SecondName public string SchoolName { get; set; } public string ClassName { get; set; } public int TestResult5 { get; set; } } }
Program.cs
using Excel = Microsoft.Office.Interop.Excel;
namespace so16092016 { class Program { static void Main(string[] args) { resultsEntities context = new resultsEntities(); ResultsRepository resultsRepository = new ResultsRepository(context); var ma_results = resultsRepository.GetTList().Where(x => x.SubjectCode == 2); //получить результаты по математике
Excel.Application app = new Excel.Application(); app.DisplayAlerts = false; Excel.Workbook book_template = app.Workbooks.Open(@"шаблон_отчета.xlsx"); Excel._Worksheet sheet_template = book_template.Sheets["отчет"];
foreach(var ob in ma_results) { //1. Создаем объкт LearnerReport из БД LearnerReport report = new LearnerReport { SNS = $"{ob.surname} {ob.name} {ob.SecondName}", SchoolName = ob.SchoolName, ClassName = ob.ClassName, TestResult5 = ob.TestResult5 };
//2. Экспорт объкта LearnerReport в шаблон xlsx sheet_template.Range["C4"].Value2 = report.SNS; sheet_template.Range["C5"].Value2 = report.SchoolName; sheet_template.Range["C6"].Value2 = report.ClassName; sheet_template.Range["C9"].Value2 = report.TestResult5;
//3. Сохраняем полученный файл в .pdf на рабочем столе string file_name = $@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\{report.SNS}.pdf"; sheet_template.ExportAsFixedFormat(Excel.XlFixedFormatType.xlTypePDF, file_name); }
book_template.Close(0); book_template = null; app.Quit(); app = null; } } }
Необходимо: Приложение работает и дает необходимый результат. Но вы наверное видите, что оно далеко от ООП (SOLID) и как результат очень трудно его "допиливать" и масштабировать. Помогите правильно спроектировать данный механизм формирования подобных отчетов:
логика экспорта модели в .xlsx должна быть у самой модели или необходимо создать отдельный класс-менеджер для этого? какие должны быть модели? как правильно создавать модель-отчета на основе объектов БД? какой порождающий паттерн здесь больше подходит?


Ответ

Конкретно в вашем случай нет необходимость, применять какие либо паттерны, т.к. у вас довольно простая программа и паттерны добавят лишь ненужную сложность (применять паттерны ради паттернов плохая практика). Паттерны сгодятся если вы пишите большие Enterprise приложения, где необходима гибкость и масштабируемость.
Если я правильно понял, то вы хотите отрефакторить программу.
1) Из кода я не понял что вы используете для получения данных из БД, но посоветовал бы использовать какую нибудь ORM, например Entity Framework 6
Создать DbContext и использовать его в репозиториях ResultsRepository и SchoolRepository Все выборки засунуть в соответствующий репозиторий например
class ResultsRepository { // возвращает все результаты public IEnumerable GetResults()
// возвращает все результаты по заданому предмету. public IEnumerable GetResults(Subject subject)
// возвращает все результаты для заданой школы. public IEnumerable GetResults(int idSchool)
// возвращает все результаты для заданой школы по заданому предмету. public IEnumerable GetResults(int idSchool, Subject subject) }
class SchoolRepository { // возвращает список всех школ. public IEnumerable GetSchools() }
2) Модель данных приблизительно выглядит так
class Result { [Key] public Guid Id { get; set; }
public string Surname { get; set; } public string Name { get; set; } public string SecondName { get; set; }
[NotMapped] public string SNS => $"{Surname} {Name} {SecondName}";
public School School { get; set; }
public string ClassName { get; set; }
public Subject Subject { get; set; }
public int TestResult5 { get; set; } }
class School { [Key] public int Id { get; set; } public string Name { get; set; } }
enum Subject { RussianLanguage = 1, Mathematics = 2 }
3) Можно создать отдельный класс для работы отчётами
class LearnerReportManager { public Excel._Worksheet CreateReport(Result result)
public SaveReport(Excel._Worksheet reportWorksheet, string fileName) }
4) Для формирования Excel отчёта луче используйте EPPlus или более крутой File Formats от Syncfusion (у них есть бесплатная версия). вы так не будите зависеть от установленного MS Office.
5) Если кол. формируемых отчетов за раз от 40 до 70 тыс., то было бы не плохо добавить многопоточное создание отчетов, это существенно уменьшит время создания отчётов.

Как повернуть стрелку?

Собственно не могу понять, как её повернуть так, чтобы она была вверх? Менял transform, но не могу понять, как он работает. Добивался нужного результата когда указывал больше 100% в transform-origin, но это, как я понимаю, не совсем правильное решение.
.prev { position: relative; } .prev:before, .prev:after { content: ''; display: block; height: 8px; width: 32px; background: #4a275c; border-radius: 5px; } .prev:before { transform-origin: 50% 100%; -webkit-transform: rotate(-45deg); -ms-transform: rotate(-45deg); transform: rotate(-45deg); } .prev:after { transform-origin: 0% 100%; -webkit-transform: rotate(45deg); -ms-transform: rotate(45deg); transform: rotate(45deg); }



Ответ

Поворот линий:
Располагаем линии абсолютно, чтобы и before, и after распогались друг на друге; Исходя из высоты блоков в 8px предполагаем, что линии у нас - толщиной в 4px и начинаются они не с 0 0, а с 4px 4px. Корректируем transform-origin Смещаем обе линии ближе к середине блока, и поворачиваем - одну на 45 градусов (правую), другую на 135 градусов (левую).
Код:
.prev { display: inline-block; height: 26px; position: relative; width: 44px; } .prev:before, .prev:after { background: #4a275c; border-radius: 5px; content: ''; display: block; height: 8px; position: absolute; transform-origin: 4px 4px; width: 32px; } .prev:before { transform: translate(18px, 0) rotate(45deg); } .prev:after { transform: translate(18px, 0) rotate(135deg); }


Или посмотреть код на jsfiddle

Связи в Объектно Орентированном Программировании c#

Всем привет:) Друзья, подскажите пожалуйста, если Я передаю ссылку на объект в метод, какая это связь?
public void Method(MyClass my) // какая связь? { //.. }
Если можно скиньте ссылки!
Композиция - всё ясно.
public class ElectricEngine { }
public class Car { ElectricEngine engine; public Car() { engine = new ElectricEngine(); } }
Агрегация
public abstract class Engine { }
public class Car { Engine engine; public Car(Engine eng) { engine = eng; } }
Ассоциация
class Team {
} class Player { public Team Team { get; set; } }
Наследование и реализация - тоже не вызывают проблем)


Ответ

Это зависимость.

Вообще, я не встречал четкого определения для связи "Зависимость", но во многх источниках под ней подразумевают два случая.
Параметер в методе
public void Method(MyClass my) { // ... }
Создание локальной переменной
public void Method() { MyClass my = new MyClass(); // ... }
Если брать UML, то в нем определены еще конкретные зависимости: call, create, use и т.п.

Почему CHECK не работает в MySQL?

mysql> create table t (x int check (x>0)); Query OK, 0 rows affected (0.44 sec)
mysql> insert into t value (-1); Query OK, 1 row affected (0.08 sec)
mysql> create table t1(x int, constraint namec check (x>0)); Query OK, 0 rows affected (0.28 sec)
mysql> insert into t1 value (-1); Query OK, 1 row affected (0.06 sec)
Почему я не получаю никаких ошибок/предупреждений о том, что добавляемое мной значение в таблицу не удовлетворяет CHECK?


Ответ

Потому что MySQL игнорирует это объявление. Он не поддерживает таких ограничений.
The CHECK clause is parsed but ignored by all storage engines. — MySQL Reference Manual по CREATE TABLE
Вместо них предлагается использовать триггеры.

Это перевод ответа на вопрос CHECK constraint in MySQL is not working на StackOverflow.
См. также аналогичный вопрос на DBA.SE: check constraint does not work?

Как корректно указать дополнительный путь для gcc?

Я новичек в этом. Я использую Linux и gcc в bash
Имеется:
p1.c:
int func() { return 1889; } func.h:
#ifndef ONCE #define ONCE int func(); #endif p2.c:
#include #include
int main() { int a = func(); printf("%d",a); return 0; }
func.h я специально переместил в другую папку. В *.bashrc* дописал export PATH="$PATH:/root/deleteme/spec"
# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/root/deleteme/spec

# gcc p?.c
вывод:
p2.c:2:18: fatal error: func.h: No such file or directory #include ^ compilation terminated.
Заработало при указании gcc -I.
Почему не работает через переменную окружения? Хочется разобраться как это работает. Спасибо :)


Ответ

Переменная окружения $PATH, содержащая пути где исполняемые файлы (скрипты, программы) лежат, не имеет отношения к путям, в которых gcc ищет заголовочные файлы (*.h).
Есть директории по умолчанию такие как /usr/include, например, используемые для библиотек, установленных из *-dev системных пакетов.
Распространенный способ указать свои пути к заголовочным файлам это использовать -I опцию. Если хочется, можно определить соответствующие переменные окружения (CPATH, etc). Если использовать "func.h", а не , то func.h сперва ищется в директории с текущим файлом (p2.c). Существуют и другие (менее используемые) опции, контролирующие как заголовки ищутся

Где хранить единичные данные в Django

Где хранить единичные данные в Django v1.10.1 и Python v3.5, например:
Названия сайта, Номер телефона, Логотип, Описание.
И необходимо изменять через админку.


Ответ

Решил данную задачу средствами django-solo, пример:
models.py:
# models.py
from django.db import models from solo.models import SingletonModel
class SiteConfiguration(SingletonModel): site_name = models.CharField(max_length=255, default='Имя сайта ') maintenance_mode = models.BooleanField(default=False)
def __unicode__(self): return u"Конфигурация Сайта"
class Meta: verbose_name = "Конфигурация Сайта"
admin.py:
# admin.py
from django.contrib import admin from solo.admin import SingletonModelAdmin from config.models import SiteConfiguration
admin.site.register(SiteConfiguration, SingletonModelAdmin)
views.py:
# views.py
from django.shortcuts import render_to_response from config.models import SiteConfiguration
def main(request): ConfSiteConfiguration = SiteConfiguration.objects.all() return render_to_response('index.html', {'config': ConfSiteConfiguration})
template:
{% load solo_tags %} {% get_solo 'config.SiteConfiguration' as site_config %} {{ site_config.site_name }} {{ site_config.maintenance_mode }}
Код в примере взял из документации django-solo

SystemInfo как улучшить код?

Проблема в том что выходит слишком много foreach, как всё это можно сократить?
private static string pcCPU; private static string pcGPU; private static string pcLocalIP; private static string pcExternalIP; private static string pcAntivirus;
string savePath = @"C:\Sys.txt"; using (FileStream file = new FileStream(savePath, FileMode.Append)) { using (StreamWriter twf = new StreamWriter(file, Encoding.UTF8)) { foreach (ManagementBaseObject avResult in avsearcher.Get()) { pcAntivirus = "& " + (avResult.GetPropertyValue("displayName")).ToString(); pcAntivirus = (pcAntivirus.StartsWith("& ")) ? pcAntivirus.Substring(1) : pcAntivirus; twf.WriteLine(" антивирус: " + pcAntivirus); } foreach (ManagementObject gr in gs.Get()) { foreach (PropertyData pty in gr.Properties) { if (pty.Name == "Description") { pcGPU += pty.Value.ToString(); twf.WriteLine(" Видеоадаптер: " + pcGPU); } } } foreach (ManagementObject gob in sar.Get()) { twf.WriteLine(" Модель компьютера: " + gob["Manufacturer"] + gob["Model"]); } } }
P.S: Я вот попробовал так сделать, но тут не получается:
1 - Выводит ошибку Invalid Class
2 - в twf нельзя записать WriteALLtext, можно только Write
StringBuilder sb = new StringBuilder(); foreach (ManagementBaseObject avResult in avsearcher.Get()) { Sb.Append(" антивирус: ").Append(pcAntivirus).Append("
"); } foreach (ManagementObject gr in gs.Get()) { foreach (PropertyData pty in gr.Properties) { if (pty.Name == "Description") { Sb.Append(" Видеоадаптер: ").Append(pcGPU).Append(pty.Value.ToString()).Append("
");; } } } foreach (ManagementObject gob in sar.Get()) { Sb.Append(" Модель компьютера: ").Append(gob["Manufacturer"]).Append(gob["Model"]).Append("
");; } twf.Write(sb.ToString());
А вот ошибка: На просторах интернета нашёл интересный код: с использованием List
Информация о системе


Ответ

Например, вы можете отделить получение данных от их вывода.
// зачем вам странный трюк с "& "? var avNames = avsearcher.Get() .Cast() .Select(av => (string)av["displayName"]) .ToList();
var graphicCardList = gs.Get() .Cast() .Select(mo => (string)mo["Description"]) .ToList();
var computerInfoList = sar.Get() .Cast() .Select(gob => (string)gob["Manufacturer"] + gob["Model"]) .ToList();
И теперь запись:
File.AppendAllLines( savePath, avNames.Select(s => $" Антивирус: {s}"), Encoding.UTF8);
File.AppendAllLines( savePath, graphicCardList.Select(s => $" Видеоадаптер: {s}"), Encoding.UTF8);
File.AppendAllLines( savePath, computerInfoList.Select(s => $" Модель компьютера: {s}"), Encoding.UTF8);
Циклы не нужны вовсе.

Выбор БД для проекта с сложной структурой данных

Начал делать проект на Django. Имеются следующие данные в JSON (привожу часть структуры, остальное повторяется):
[{"name": "Hydrogen", "atomic_number": 1, "symbol": "H", "thermal": {"absolute_boiling_point": { "value": 234, "unit": "K"}, "heat_of_vaporization": { "value": {"p": 4, "M": 0.452, "n": 10}, "unit": "kJ/mol"}}}]
Для наглядности:

Видно, что структура довольно сложная и многократно вложенная.
Элемент обладает свойствами без группы (типа, Name, symbol, atomic_number, которых около десяти и они являются общими для всех элементов) и группами свойств (групп имеется несколько десятков, в каждую из которых входит также несколько десятков свойств).
Как видно значение свойств может быть представлено строкой, десятичным число и инженерной записью (для которой используется три числа - мантисса, основание, степень)
Возникла проблема - я не могу описать эту структуру через реляционную БД проекта (postgresql), не могу установить связи.
Подойдет мне реляционная БД? Или следует обратить внимание на noSQL решения? Правильные я выбрал инструменты для реализации проекта?
Создал модели для элемента
class Element(models.Model): class Meta: verbose_name = 'Element' verbose_name_plural = 'Elements' name = models.CharField(verbose_name="Name", max_length=255, blank=True, null=True) symbol = models.CharField(verbose_name="Symbol", max_length=255, blank=True, null=True)
Различных форм записи
class ScientificNotation(models.Model): class Meta: verbose_name = 'Scientific Notation' significand = models.FloatField(verbose_name="Significand", blank=True, null=True) base = models.IntegerField(verbose_name="Base", blank=True, null=True) exponent = models.IntegerField(verbose_name="Exponent", blank=True, null=True) unit = models.CharField(verbose_name="Unit", max_length=255, blank=True, null=True)
class DecimalNotation(models.Model): class Meta: verbose_name = 'Decimal Notation' value = models.FloatField(verbose_name="Value", blank=True, null=True) unit = models.CharField(verbose_name="Unit", max_length=255, blank=True, null=True)
Группы свойств. С этой моделью и возникает проблема.
class ThermalProperties(models.Model): class Meta: verbose_name = 'Thermal properties' verbose_name_plural = 'Thermal properties' element = OneToOneField(Element) melting_point = ForeignKey(ScientificNotation) boiling_point = ForeignKey(ScientificNotation) heat_of_vaporization = ForeignKey(DecimalNotation)
Я не могу ссылаться на одну и ту же модель (в конкретном примере ScientificNotation)
ERRORS: table.ThermalProperties.boiling_point: (fields.E304) Reverse accessor for 'ThermalProperties.boiling_point' clashes with reverse accessor for 'ThermalProperties.melting_point'. HINT: Add or change a related_name argument to the definition for 'ThermalProperties.boiling_point' or 'ThermalProperties.melting_point'.
И продублирую вопрос здесь, если кто-то дочитал. Подойдет мне реляционная БД? Правильные я выбрал инструменты для реализации проекта?


Ответ

Хороший вопрос, я даже рад пожертвовать час на написание ответа :)
Как бы не громко звучал заголовок, но эта структура больше простая, чем сложная.
Реляционная структура
Почти любую структуру можно описать в реляционной базе данных, хоть она и будет достаточно жетской
Прошу заметить, что в реляционных базах данных тоже есть патерны проектирования, и давайте попробуем сначала реализовать один из правильных патернов, называющихся Class Table Inheritance. Он гарантирует размещение разных элементов в разных таблицах, в которых они должны находится:
element - структура для элементов
name atomic_number symbol element_thermal - структура для параметров
atomic_number type unit element_thermal_mol - структура для параметров mol/kg
atomic_number p M n element_thermal_value - структура для обычных параметров
atomic_number value
Здесь в зависимости от unit'а требуется выбирать таблицу, которую нужно будет делать JOIN. Мы здесь используем подход разделения данных на таблицы, который полностью соответствует реляционной структуре и ее правилам, но с каждым новым типом и данными Вам придется добавлять новую таблицу и усложнять сохранения и бизнес логику.
Ок. Попробуем подход Entity-Attributes-Values (EAV), его часто называют анти-паттерном проектирования из-за отсутствия контроля типа, контроля данных, размещения данных в одной таблице и т.д и вообще это выворачивание реляционной структуры наизнанку, но сам подход на небольших данных достаточно хорошо себя проявляет.
element - структура для элементов
name atomic_number symbol element_thermal - структура для параметров
atomic_number type unit element_thermal_values - структура для всех параметров
atomic_number parameter_type value
По сути, здесь все свои значения параметров вы храните в element_thermal_values записывая в parameter_type название параметра (INT, P, M, N), после чего делайте JOIN этой таблицы и получаете все параметры и обрабатываете их, запрос на получение данных всегда один, но естественно контроль должен быть обеспечен на уровне кода.
На маленьком проекте не будет разницы в том, что вы выберете, второй вариант просто проще, первый правильнее.
Да по сути, можно вообще не создавать отдельную таблицу, а просто запихнуть данные в value в виде json, просто с ними нельзя будет работать и как-то выполнять запросы, поэтому этот подход не всегда правильный, хотя базы типа PostgreSQL позволяют производить какие-то операции на уровне JSON.
NoSQL (Неструктурированные базы)
Хотите использовать noSQL, используйте. Никто Вас в этом не ограничивает и ваша структура, в некоторой степени являющейся динамичной, будет подходить для MongoDB, когда вы будете использовать все прелести документ-ориентированного подхода. Сам ваш элемент выглядит как документ.
Если у данных нет связей или их очень мало с другими данными, то в целом NoSQL (MongoDB) отличный выбор для вашей задачи и сможет упростить в некоторой степени работу с данными.
В целом размер кода будет примерно одинаковый, т.к. обработчики на value при выводе или процессинге все равно придется писать.
Вывод
Я рекомендую Вам попробовать несколько подходов, начните с нового MongoDB, потом попробуйте грамотное наследование в реляционных таблицах, сравните плюсы и минусы тех или иных реализаций и посмотрите что подходит для вас, опыта меньше не станет.
MongoDB заинтересует Вас тем, что это база данных по сути в которой данные хранятся в виде доступном приложению (JSON) и изменяемой структурой данных, которая тоже имеет плюсы и минусы, из плюсов конечно еще масштабируемость.
Старый подход на SQL отлично решает вопросы построения систем, где нужна целостность данных, соблюдение ACID, тяжелые запросы на объединение с многими таблицами.
В двух подходах есть минусы и плюсы, в своем случае, если бы я писал систему которая содержала периодическую таблицу и мне хотелось бы пощупать новые технологии, я бы взял MongoDB и познал бы Map-Reduce и т.д.

Мы часто используем Mongo для данных, чью структуру тяжело предусмотреть, например логирование в виде истории действий пользователя с различными типами параметров, конечно было бы хорошо запихнуть это в MySQL, но желания создавать отдельную таблицу под определенные данные просто нет, а использование подхода EAV на большом объеме данных просто уничтожает всю производительность, в MongoDB же есть хорошая масштабируемость и изменяемая структура данных, поэтому плюсы перевешивают минусы.

TypeError: __init__() takes 2 positional arguments but 3 were given в Django

Есть вот такая система моделей
class NormalTag(models.Model): caption = models.CharField(max_length=1024, unique=True, blank=False, default=None) def __init__(self, caption): super().__init__() self.caption = caption
def __str__(self): return self.caption
class Tag(models.Model): caption = models.CharField(max_length=1024)
def __init__(self, caption): super().__init__() self.caption = caption self.set_normaltag()
def normalize(self): return self.caption.lower().replace(" ",'').replace("\"",'')
def set_normaltag(self): try: normaltag = self.get_normaltag() except NormalTag.DoesNotExist: normaltag = NormalTag(self.normalize()) normaltag.save()
def get_normaltag(self): return NormalTag.objects.get(caption=self.normalize())
def __str__(self): return self.caption
При вызове из шелла выдает ошибку:
[env]user ~/path/to/project > python manage.py shell Python 3.5.2 (default, Jul 5 2016, 12:43:10) [GCC 5.4.0 20160609] on linux Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from home.models import NormalTag, Tag >>> t = Tag("ПроВеРка ТэГа") Traceback (most recent call last): File "", line 1, in File "/home/path/to/project/home/models.py", line 28, in __init__ self.set_normaltag() File "/home/path/to/project/home/models.py", line 35, in set_normaltag normaltag = self.get_normaltag() File "/home/path/to/project/home/models.py", line 41, in get_normaltag return NormalTag.objects.get(caption=self.normalize()) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py", line 379, in get num = len(clone) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py", line 238, in __len__ self._fetch_all() File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py", line 1087, in _fetch_all self._result_cache = list(self.iterator()) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/query.py", line 66, in __iter__ obj = model_cls.from_db(db, init_list, row[model_fields_start:model_fields_end]) File "/home/path/to/env/lib/python3.5/site-packages/django/db/models/base.py", line 565, in from_db new = cls(*values) TypeError: __init__() takes 2 positional arguments but 3 were given
Так и не понял, откуда она берется.


Ответ

В джанге много чего происходит магическим образом. То есть во фреймворке не всё соотвествует питону, хотя и написано на нём.
В данном случае вы передали позиционный аргумент в модель, а при создании моделей нужно передавать только именованные аргументы.
В вашем случае нужно было написать:
t = Tag(caption="ПроВеРка ТэГа")
И да, в моделях переопределять метод __init__ надо с осторожностью, если нужно добавить какие-то дополнительные действия во время создания модели, то лучше использовать метод менеджера модели create(), он создан специально для этого.

Элемент управления типа UpDown

В WinForms есть стандартный контрол NumericUpDown

Хочется получить такой же, но без поля ввода. Т.е. по сути нужны только кнопки вверх/вниз. Понятно, что можно сляпать свой из двух кнопок и с изображением стрелок, но хотелось бы унификации со стандартным, чтобы на разных машинах или при смене настроек интерфейса пользователя мой контрол и стандартный выглядели единообразно.
Какие шаги следует предпринять для достижения нужного эффекта?


Ответ

Попробуйте унаследоваться от предка NumericUpDown: UpDownBase и лимитировать размер контрола размером области кнопок:
using System.Windows.Forms; using System.Reflection; using System.Drawing;
public class UpDownControl : UpDownBase { private readonly Control upDownButtons;
public UpDownControl() { // Достаем internal свойство UpDownButtonsInternal var prop = GetType().GetProperty("UpDownButtonsInternal", BindingFlags.NonPublic | BindingFlags.Instance); if (prop != null) upDownButtons = (Control)prop.GetValue(this, null); }
protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); int gapWidth = Width - upDownButtons.Right + 1; // Либо const int gapWidth = 2; Size = new Size(upDownButtons.Width + gapWidth, upDownButtons.Height); }
public override void DownButton() { }
public override void UpButton() { }
protected override void UpdateEditText() { } }
События нажатий на кнопки будут прилетать в методы DownButton и UpButton соответственно.

Почему вызов плагина jquery-validate происходит со второго раза?

Пытаюсь сделать валидацию формы с помощью плагина jquery-validate
// Callback forms (function(){ var app = { init: function(){ this.setUpListeners(); }, setUpListeners: function(){ $(document).on('submit', 'form', this.submitForm); $(document).on('keyup', 'input', this.removeError); }, submitForm: function(e){ e.preventDefault(); var form = $(this), btnSubmit = form.find('[type="submit"]'); if(app.validateForm(form) === false) return false; btnSubmit.addClass('disabled'); var str = form.serialize(); $.ajax({ url: 'contacts.php', type: 'post', data: str }).done(function(msg){ if(msg === "OK"){ var res = "

Well done! You successfully read this important alert message.
"; $(".fancybox").html(res); setTimeout(function(){ $.fancybox.close(); }, 2000) console.log('ok'); $(".fancybox").fancybox().trigger('click'); }else { $(".fancybox").html(msg); $(".fancybox").fancybox().trigger('click'); } }).always(function(){ btnSubmit.removeAttr('disabled', ''); }); }, validateForm: function(form){ var inputs = form.find('input'), valid = true; form.validate({ invalidHandler: function(event, validator){ var errors = validator.numberOfInvalids(); if (errors) { valid = false; } else { console.log('valide'); } validator.focusInvalid(); } }); return valid; }, removeError: function(){ var $this = $(this), formGroup = $this.closest('.form-group'); formGroup.removeClass('has-danger'); } } app.init(); })(); if($(".modalbox").length){ $(".modalbox").fancybox({ fitToView : false, autoSize : false, closeClick : false, maxWidth : 502, maxHeight : 444, prevEffect : 'none', nextEffect : 'none', padding : 0, margin : 50, closeBtn : false, helpers : { overlay : { css : { 'background' : 'rgba(0, 0, 0, 0.72)' } }, } }); } .callback-modal { display: none; } JS Bin
Но не могу понять, почему срабатывает проверка, только со второго раза? Возможно кто-то работал с данным плагином.
Как можно исправить модуль, чтобы плагин срабатывал и срабатывал как положено (если поля не заполнены, форма не отправляется отображаются error поля, если все в порядке, то отправляются данные)?


Ответ

В данном случае происходит неверное использование плагина. Перед тем как использовать что-то, это что-то надо инициализировать.
По аналогии, рассчитывать, что сработает this.submitForm при отправке формы, не вызвав app.init

Далее, сама инициализация, выполнена не совсем корректна.
В документации к плагину можно увидеть, что свойство invalidHandler нужно для выполнения своего кода в случае если валидация не прошла. В коде в вопросе, в этом методе идет выставление переменной valid, которая в коде используется для определения того, прошла валидация или нет.
Вместо это нужно было использовать метод form, который как раз возвращает результат проверки, без дополнительных переменных.
В итоге метод validateForm: function(form){ можно удалить и заменить его использование на одну строку
form.validate().form()
В этом случае плагин не будет инициализирован дважды и более раз, ввиду наличия проверки внутри самого плагина.
Пример:
// Callback forms (function() { var app = { init: function() { this.setUpListeners(); }, setUpListeners: function() { $(document).on('submit', 'form', this.submitForm); $(document).on('keyup', 'input', this.removeError); }, submitForm: function(e) { e.preventDefault(); var form = $(this), btnSubmit = form.find('[type="submit"]'); if (form.validate().form() === false) return false; btnSubmit.addClass('disabled'); var str = form.serialize(); $.ajax({ url: 'contacts.php', type: 'post', data: str }).done(function(msg) { if (msg === "OK") { var res = "

Well done! You successfully read this important alert message.
"; $(".fancybox").html(res); setTimeout(function() { $.fancybox.close(); }, 2000) console.log('ok'); $(".fancybox").fancybox().trigger('click'); } else { $(".fancybox").html(msg); $(".fancybox").fancybox().trigger('click'); } }).always(function() { btnSubmit.removeAttr('disabled', ''); }); }, removeError: function() { var $this = $(this), formGroup = $this.closest('.form-group'); formGroup.removeClass('has-danger'); } } app.init(); })(); if ($(".modalbox").length) { $(".modalbox").fancybox({ fitToView: false, autoSize: false, closeClick: false, maxWidth: 502, maxHeight: 444, prevEffect: 'none', nextEffect: 'none', padding: 0, margin: 50, closeBtn: false, helpers: { overlay: { css: { 'background': 'rgba(0, 0, 0, 0.72)' } }, } }); } .callback-modal { display: none; }

RabbitMQ ест память

Запущен сервер на Python с использованием RabbitMQ. Через некоторое время (около месяца) вот процесс съедает всю память и очереди останавливаются. Вот этот процесс:
29431 rabbitmq 20 0 4330792 1,992g 4596 S 12,6 12,7 792:49.90 beam.smp
После убиства процесса все становится хорошо.
Судя по beam.smp, работает виртуальная машина erlang. Но почему она не освобождает память - непонятно.


Ответ

Разобрался с вопросом. Дело было в том, что раббит написан на erlang. В прекрасном языке erlang сборщик мусора в виртуальной машине работает по старым и не особо эффективным алгоритмам. Он начинает чистить память только когда она заканчивается. Однако есть способы указать явно когда он запускается.
Таким образом, через настройки RabbitMQ можно достучаться до виртуальной машины Erlang. Для этого необходимо создать (если его нет) файл /etc/rabbitmq/rabbitmq.config (Debian, Ubuntu). В нем можно указать процент от общей памяти или конкретное количество, сообщающее когда следует запускать сборщик мусора. Следует помнить, что учитывается не оперативная память, а виртуальная(!). Я сделал 20% от общей виртуальной памяти так:
[{rabbit, [{vm_memory_high_watermark, 0.2}]}].
Моя проблема заключалась в том, что значение по умолчанию 0.4, а это слишком много для нагруженного сервера в production...
Убедиться в том, что предел потребляемой виртуальной памяти не превышает норму можно командой sudo rabbitmqctl status. Нужный параметр: vm_memory_limit

Отслеживание бездействия Python

Добрый день! Подскажите, пожалуйста, как можно реализовать выполнение функции на Python в консольном приложении по таймауту?
Смысл в следующем: Есть консольное приложение, которое идет своим чередом и периодически требует от пользователя каких-либо действий. В случае же, если пользователь проявляет бездействие в течение определенного времени, необходимо выполнить определенную функцию.
Из того, что есть: Функция для отслеживания времени (Пример):
StartTime = time.time() // В теле программе отслеживаем время последнего действия TimeOut = 2000 def countTime(): CurTime = time.time() // текущее время If CurTime > (StartTime+TimeOut): // проверяем разницу между текущим временем и последним действием, сравниваем с таймаутом print SomeFunction() // выполняем необходимую функцию
Но я не имею никаких предположений, как запускать функцию проверки времени параллельно (асинхронно?) выполнению основного алгоритма программы.
Заранее спасибо!


Ответ

если пользователь проявляет бездействие в течение определенного времени, необходимо выполнить определенную функцию.
Общий подход: запланировать выполнение функции на определённое время и при любой активности пользователя переносить запуск на более позднее время.
Чтобы просто запланировать выполнение функции func через 5 секунд в Питоне, не блокируя основной поток:
import threading
timer = threading.Timer(5, func) timer.start()
Если timer.cancel() (отмена) не вызвать, то через 5 секунд будет вызвана func() в фоновом потоке.
Чтобы адаптировать для вашей задачи, необходимо метод restart() добавить, который запустит отсчёт заново, при любой активности пользователя. Этот подход достаточно распространён, чтобы своё имя заработать: Watchdog timer — букв. «сторожевой пёс»
watchdog = WatchdogTimer(timeout, func, daemon=True) watchdog.start() # ... здесь программа что-то делает # и перезапускает отсчёт при любой активности пользователя watchdog.restart()
# в конце отменяем вызов func совсем или просто из программы выходим watchdog.cancel()
где WatchdogTimer класс определён здесь
Вот пример кода, где Питон-скрипт завершается, если пользователь не активен больше заданного времени в X (на Unix)

Необязательно потоки использовать, например, в программе, использующей asyncio
async def watchdog(loop, last_activity_time, timeout, func, *args): "Run *func(*args)* if more than *timeout* seconds since *last_activity_time*." while (loop.time() - last_activity_time()) < timeout: await asyncio.sleep(1) return func(*args)
Цель данной реализации—простота: пока разница между текущим временем (loop.time()) и записанным временем последней активности пользователя (last_activity_time()) меньше заданного значения (timeout), спим. В противном случае вызываем заданную функцию (func). Можно придумать решение, которое не использует asyncio.sleep(1)
Пример использования:
#!/usr/bin/env python3 import asyncio import random
loop = asyncio.get_event_loop() user = {'last_activity': loop.time()} asyncio.ensure_future(watchdog(loop, lambda: user['last_activity'], 5, print, 'idle')) async def simulate_activity(): for i in range(20): print(i) if random.random() < .1: user['last_activity'] = loop.time() # user have done something now await asyncio.sleep(1) loop.run_until_complete(simulate_activity())
Программа печатает idle, если пользователь, имитированный с помощью random в simulate_activity() coroutine, слишком долго не показывает активности.