Страницы

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

понедельник, 12 ноября 2018 г.

Asp.Net MVC 5 или Web Api 2.0

Я совсем запутался... Asp.Net MVC - создание веб-приложений, Web Api - сервисов. Не могли бы вы объяснить для каких задач пишутся сервисы, а для каких веб приложения? Насколько я понимаю, если у нас клиент планируется не только веб, но еще, например, WPF-приложение, мобильное, то выбор должен пасть в сторону сервисов.
Конкретно для моего случая: имеется некое десктопное приложение еще на WinWorms. Хочется его перевести в веб. И встает логичный вопрос что использовать: Asp.Net Web Api + AngularJs или Asp.Net MVC?
Буду благодарен за любую информацию.


Ответ

Бакэнд для AngularJs можно написать хоть на ASP.NET MVC, хоть на Asp.Net Web Api, хоть на WCF (да, WCF тоже умеет делать REST-сервисы). Основная разница между ними в следующем:
ASP.NET MVC подходит для генерации страниц на стороне сервера (но не мешает работать и клиентским фреймворкам). Выбрав связку Angular.js + Web Api, вы навсегда ограничите себя исключительно клиентской генерацией страниц, приобретя заодно возможные проблемы с индексацией поисковиками. Взамен - у вашего сайта автоматически появится API, которое можно сделать публичным.
Думаю, начать надо с выяснения ответов на следующие вопросы:
Сколько человек будут работать над проектом и какие технологии им знакомы? Насколько само ваше веб-приложение укладывается в концепцию HTTP? Оно будет состоять из набора отдельных динамически генерируемых страниц или из одной (или нескольких) страниц, содержащих формы, контролы и экраны?
Пример приложения первого вида - Википедия. Пример приложения второго вида - Gmail.
2а. Предполагается ли, что страница никогда не будет обновляться полностью?
2б. Сможет ли пользователь открыть одновременно 2 части вашего приложения в одной вкладке? (+ ко второму виду)
2в. Понадобится ли пользователю делиться ссылкой с другими или ставить ссылку в закладки? (+ к первому виду) Нужно ли вам публичное API?

После регистрации как правильно хранить данные пользователя

Здравствуйте, после регистрации пользователя в приложении, как правильно хранить пароль пользователя?
Если sharedpreferences - это наилучший вариант, можете объяснить почему, и можно ли взломать, и получить данные пользователя?


Ответ

данные типа String хранятся в SharedPreferences в явном виде, практически в текстовом файле. Получить к нему доступ и прочитать эти данные - не очень сложная задача.
Для предотвращения доступа к данным используйте шифрование. Как Core Java (пакеты crypto и security), так и фреймворк Android (класс AccountManger к примеру) предоставляют достаточно инструментов (классов) для надежного шифрования информации. Способ же сохранения зашифрованных данных отходит на второй план - это может быть БД, преференсы, файл и тп., как удобнее для конкретной задачи (например БД оправдана при хранении нескольких однотипных данных и слишком избыточна для только одного логина-пароля).

ListView, конец списка

Как определить что список ListView прокручен до конца?


Ответ

listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE && (listView.getLastVisiblePosition() - listView.getHeaderViewsCount() - listView.getFooterViewsCount()) >= (adapter.getCount() - 1)) {
// Now your listview has hit the bottom } }
@Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
} });

Для чего делать do {} while (0)?

Уже не раз замечаю подобный код
#if FUSE_TRACE #define TRACE(x...) fprintf(stderr,x) #else #define TRACE(x...) do {} while (0) #endif
Почему именно так, а не
#if FUSE_TRACE #define TRACE(x...) fprintf(stderr,x) #else #define TRACE(x...) #endif
Насколько я понял do {} while (0) транслируется в NOP инструкцию, но зачем она здесь?


Ответ

Макросы - вещь достаточно тонкая. Представьте ситуацию, кто-то написал код (пример условный) (но лучше так не пишете именно из-за этого).
for (int i = 0;i < 10; i++) TRACE("ok"), s+=i; do_any();
Здесь всё будет корректно работать. В релиз режиме если мы будем использовать как вы предлагаете
#define TRACE(x...)
Произойдёт следующее, код преобразуется в
if (something) , s+=i; do_any();
И он не скомпилируется.
Так же не скомпилируется
expr? TRACE("y") : TRACE("n");
Однако, и с использованием макроса #define TRACE(x...) do {} while (0) есть аналогичные проблемы. Я лично использую следующий макрос в таких целях:
#define TRACE(x...) ((void)0)
Либо же использую отдельную функцию (а не макрос) для вывода логов.

Каждая картинка отдельно или спрайт?

Возьмём самый распространенный вариант - смайлики. Их очень много (~1500) и отображаются все одновременно, как лучше их выводить?
На сервер храниться одна большая картинка (спрайт) где все смайлики расположены друг за другом, у клиента в css расписаны расположение каждого смайлика (background-image и background-position) и в html документе с помощью class распознаются смайлики. На сервер хранится каждая картинка смайлика отдельно, у клиента в css расписаны путь до каждого смайлика (background-image) и в html документе с помощью class распознаются смайлики. На сервер хранятся изображения отдельно, у клиента только в html документе написаны путь до смайликов (img[src]).
И какие картинки лучше использовать svg или png?
Возможно вы предложите ещё более правильный вариант, пожалуйста расскажите максимально подробно, почему именно так?

Второй вопрос заключается в генерации этого списка смайликов, как лучше его генерировать?
Сгенерировать заранее и хранить на сервере в виде шаблона/html документа и подгружать его через ajax и вставлять в html страницу, когда это нужно. Хранить html код в JS коде, в виде строки и вставлять когда это нужно. Генерировать html код из заранее составленного массива хранящийся в js коде. Генерировать код из массива хранящейся на сервер и полученного через ajax.
Так же прошу рассказывать максимально подробно.
Под правильным вариантом подразумевается не только правильно по написанию кода, но и по быстроте загрузки смайликов и нагрузки на обе стороны (сервер и клиент).


Ответ

Куда проще пожертвовать загрузкой одним спрайтом на N Mb, чем открывать 1500 соединений. Спрайт после первой загрузки в кэш и тяжёлое неудобство исчезнет. В HTTP2 попроще в этом вопросе, но настроить сервер грамотно нужно для выигрыша скорости. Выходит для спрайта лучше юзать одну картинку с background-position и классами. Какой формат лучше - вопрос достаточно сложный, сильно зависящий от конкретной ситуации и предпочтений, для спрайтов лично я обычно использую png - разумный баланс качества/размера.

Генерировать как картинку, которую прописать background-image, браузер сам подтянет, JS вообще не нужен.
Use the grunt-spritesmith, Luke!
P. S. Инлайнить в css - это зарядить револьвер и поднести к ноге: поддержка сложнее, код распухает, кэшировать картинки нельзя (можно файлы стилей, конечно, но их может автоматически генерировать сервер, выгоды мало). Однажды я попробовал и отказался.

Какой существует алгоритм для объединения точек в области?

Есть область с кучей разбросанных точек, нам нужно объединить в области те точки, которые находятся на расстоянии меньше определенной константы друг от друга.
Как-то вот так:


Ответ

написал свой велосипед на javascript, может кому еще пригодится

Вывод:
матрица расстояний
0,64,34,23,57,17,7,49,35,61,28 64,0,30,41,7,47,57,113,28,3,35 34,30,0,11,23,17,27,83,1,27,6 23,41,11,0,34,6,16,72,13,38,6 57,7,23,34,0,40,49,106,21,4,28 17,47,17,6,40,0,10,66,18,44,11 7,57,27,16,49,10,0,57,28,54,21 49,113,83,72,106,66,57,0,85,110,78 35,28,1,13,21,18,28,85,0,25,7 61,3,27,38,4,44,54,110,25,0,33 28,35,6,6,28,11,21,78,7,33,0
матрица близости
0,6,5,3,10,2,8,7,4,9,1 1,9,4,8,2,10,3,5,6,0,7 2,8,10,3,5,4,9,6,1,0,7 3,5,10,2,8,6,0,4,9,1,7 4,9,1,8,2,10,3,5,6,0,7 5,3,6,10,0,2,8,4,9,1,7 6,0,5,3,10,2,8,4,9,7,1 7,0,6,5,3,10,2,8,4,9,1 8,2,10,3,5,4,9,6,1,0,7 9,1,4,8,2,10,3,5,6,0,7 10,3,2,8,5,6,0,4,9,1,7
матрица кластеров
0,6 1,9,4 2,8,10,3,5 7

Восстановить файлы и каталоги после rm -r

Как восстановить удалённые файлы и каталоги в дистрибутиве debian gnu/linux?


Ответ

программы для восстановления (из одноимённых пакетов): testdisk, extundelete (только для файловых систем ext), foremost, scalpel
возможно, некоторые из них и позволяют работать с примонтированными файловыми системами, но безопаснее, конечно, этого не делать. и восстанавливать удалённые файлы безопаснее в другую файловую систему (примонтированную).
т.е., если удалённые файлы находились, например, в корневой файловой системе, то проще всего воспользоваться каким-нибудь live-cd/dvd/usb (к примеру, systemrescuecd), загрузившись с него.
инструкции по использованию перечисленных программ можно почитать, например, здесь: http://help.ubuntu.ru/wiki/восстановление_данных

Как в NavigationView в header установить текст?

У меня есть вот такой NavigationView

Вот такой код:




и вот такой header





Мне нужно в этот header в поле для имени user поставить его имя, а в поле для email поставить соответственно email
Я понимаю, что все стандартно и нужно найти по id view с которым хочешь работать и установить в него TextView.
Но когда я нахожу view и ставлю text, то вылетает ошибка, что такого view еще нет. Это логично т.к. NavigationView еще не открыт...
Так вот вопрос. Как отследить что NavigationView уже открыт и только после этого устанавливать text в view?
Если я в onCreate() нахожу и устанавливаю текст
TextView tvName = (TextView) findViewById(R.id.tvName); TextView textEmail = (TextView) findViewById(R.id.textEmail);
tvName.setText("test"); textEmail.setText("test");
то получаю такую ошибку в строке tvName.setText("test");
FATAL EXCEPTION: main Process: com.example.android.camera2basic, PID: 32152 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.camera2basic/com.example.android.camera2basic.activities.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
Если применять такой подход, то ошибки нет, но текст остается таким как по умолчанию
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); RelativeLayout headerView = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.nav_header_mainsecond, null); TextView tvName = (TextView) headerView.findViewById(R.id.tvName); TextView textEmail = (TextView) headerView.findViewById(R.id.textEmail); tvName.setText("name"); textEmail.setText("email");


Ответ

Вам надо:
Получить NavigationView
NavigationView nv = ...;
Получить разметку его Header
View header = nv.getHeaderView(0);
Найти нужные поля и с ними что-то сделать
TextView tv = (TextView)header.findViewById(...);

Событие клика на ссылку

Здравствуйте. При клике на ссылку появляются пункты меню, и если после этого кликнуть в любое место экрана (кроме ссылки которая активирует меню) - меню пропадает.
Каким образом сделать чтоб меню пропадало еще и при повторном клике на эту же ссылку?
.menu { display: none; padding: 3px; } .menu a { display: block; margin: 1px; padding: 10px; } .active_menu { display: block; } .active_menu:focus ~ .menu, .active_menu:active ~ .menu, .menu:hover { display: block; } Развернуть меню



Ответ

.menu { display: none; } .menu a { display: block; margin: 1px; padding: 10px; } .active_menu input:checked + .menu { display: block; }


Передача параметров в компонент, создаваемый в react-router

Использую библиотеку react-router для навигации в SPA на базе React. Само приложение имеет вид:
application.jsx
import React from 'react'; import { Router, Route, browserHistory } from 'react-router'; import Home from './home.jsx';
export default React.createClass({ render() { // Объект пользователя. Здесь не важно, откуда именно он берется. const user = {name: 'FooBarBaz'};
return ( ); } });
home.jsx
import React from 'react';
export default React.createClass({ render() { return (

You are {this.props.user.name}
); } });
Вопрос заключается в том, как именно пробросить объект пользователя (user) компоненту Home?

Использую react-router@2.4.1 и react@15.1.0


Ответ

Реакт позволяет использовать чистые функции в качестве компонентов. Это дает вам возможность обернуть компонент Home добавив туда любые свойства.
Код приложения может выглядеть, например, так:
import React from 'react'; import { Router, Route, browserHistory } from 'react-router'; import Home from './home.jsx';
export default React.createClass({ render() { const user = {name: 'FooBarBaz'};
// Это всего лишь обертка для компонента Home, позволяющая передавать // дополнительные параметры через замыкание. const WrappedHome = function(props) { // Конструкция "{...props}" нужна, чтобы не потерять // параметры, переданные от компонента Route return (); };
// Обратите внимание на замену "Home" на "WrappedHome" в параметре // "component". return ( ); } });

Деструкторы в php - какой в них смысл?

Начал изучение магических методов PHP. С большинством все понятно. Но вот __destruct(), я не могу понять практическое применение его именно в PHP. В каких случаях он нужен вообще? Время жизни объектов же крайне не большое. Какая практическая польза?
Всем спасибо за ответы. Конкретно определить самый правильный не могу. Много интересных вещей написано в комментариях.


Ответ

Деструктор позволяет вашим объектам предоставлять гарантии по управлению ресурсами. В деструкторе вы можете написать логику, которая так или иначе - во время сборки мусора или при выключении VM - будет выполнена, и не оставит ваше приложение в неконсистентном состоянии. Сама логика может быть произвольной - чаще всего в пример приводят файл, который необходимо закрыть. Клиентский код может забыть это сделать, и тогда работу за него произведет деструктор. В качестве более интересного примера можно привести ссылочную систему: например, в системе есть кэш с коротким временем жизни, который самоуничтожается после того, как последний клиент отключился. В этом случае в деструкторе клиента такого кэша должна выполняться логика дерегистрации, чтобы кэш вовремя смог освободить оперативную память.
При этом все нельзя забывать, что машина, на которой выполняется код, ненадежна и может упасть прямо посередине какой-либо транзакции - в этом случае код в деструкторе не выполнится.

Как можно программно обновлять своё приложение на android?

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


Ответ

Стандартными средствами и без рута - никак.
Обычно это происходит так: вы выкладываете новую версию приложения в маркет, девайс юзера через маркет по расписанию (силами маркета, т.е. без вашего участия) проверяет все установленные приложения на предмет наличия обновлений и, если у юзера поставлены соответствующие настройки в маркете, маркет сам установит обновление

Согласно en-SO, если у вы программно скачаете новый apk, у коего версия больше версии текущего и идентичные пакет и сертификат, то вы можете запустить системный Intent на обновление приложения так:
Intent intent = new Intent(Intent.ACTION_VIEW); Uri uri = Uri.fromFile(new File(pathToApk)); intent.setDataAndType(uri, "application/vnd.android.package-archive"); startActivity(intent);
Далее юзер должен будет, по идее, подтвердить установку обновления.

Если девайс рутован, то можно вот так запустить установку apk через систему без участия юзера:
public static void installNewApk() { try { Runtime.getRuntime().exec(new String[] {"su", "-c", "pm install -r /mnt/internal/Download/fp.apk"}); } catch (IOException e) { System.out.println(e.toString()); System.out.println("no root"); } }

Реализовать же логику запуска этого интента/команды можно примерно так:
При первом запуске приложения запишите во внутренние ресурсы (sharedPrefereneces) номер версии. С к-л переодичностью проверяйте есть ли у вас где-то на к-л сервере новая версия. Если да - скачивайте apk и по завершении запускайте интент/команду.

Переместить unique_ptr из vector в deque

Необходимо перенести объект типа std::unique_ptr из вектора в дек.
Пример кода
using UPtr = std::unique_ptr;
std::deque d; std::vector v;
for (int i = 0; i < 5; ++i) { v.emplace_back(new int(i)); }
for (const auto& item : v) { d.emplace_front(std::move(item)); }
Но неожиданно возникает ошибка компиляции:
error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete]' { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } ^ In file included from /usr/include/c++/5/memory:81:0, from prog.cpp:4: /usr/include/c++/5/bits/unique_ptr.h:356:7: note: declared here unique_ptr(const unique_ptr&) = delete;
Насколько я понимаю, должен использоваться перемещающий конструктор, а не копирующий, но этого не происходит.


Ответ

Проблема оказалась в квалификаторе const В цикле
for (const auto& item : v) { d.emplace_front(std::move(item)); }
переменная item имеет тип const std::unique_ptr&, соответственно при вызове std::move получаем тип const std::unique_ptr&&. Перемещающего конструктора, который бы принимал этот тип, нет, поэтому компилятор использует копирующий конструктор, что и приводит к ошибке.

Похожая ошибка рассмотрена у Скотта Мейерса в книге "Эффективный и современный C++" в разделе 5.1.

Положение символа `^` в регулярном выражении

Простой вроде вопрос. Что означает регулярка "a^b" и можно ли ее найти в какой либо строке?
import re p = re.compile("a^b") p.search("ab") --> None p.search("a^b") --> None p.search("a
b") --> None
Если такое выражение действительно не соответствует никакой строке (действительно, как может символ a встретиться до начала проверяемой строки), то почему оно вообще компилируется?
Или, перефразируя, меняется ли смысл символа ^/$ в зависимости от его положения в регулярном выражении (не внутри квадратных скобок)? Если нет, то почему?
Вопрос безотносительно ЯП, python просто примера ради.


Ответ

^ означает "начало строки" вне зависимости от того, в какой части выражения встретилось. Так же как и $ - конец "строки". Но вот "начал" и "концов" в "строке" может быть несколько. Возьмем пример (на питоне, так на питоне):
import re p=re.compile("a.*^b",re.M+re.S) p.search("abc
abcd") --> None p.search("abc
bcd") --> <_sre.SRE_Match object; span=(0, 5), match='abc
b'>
При компиляции выражения указаны флаги: re.S заставляет соответствовать любым символам, включая перевод каретки. re.M заставляет рассматривать "строку", как "многострочную" - т.е. ^ начинает соответствовать не только началу данных, но и точке после любого перевода каретки. Вот мы и получили, что "a" встретился до начала строки.
Флаги можно задавать не только вторым параметром compile, но и внутри самой регулярки, конструкциями вроде (?sm). Думаю разработчикам регулярок влом проводить такой глубокий анализ (Есть флаги, нет, а когда они начали действовать), ради выдачи ошибок вроде "начала строки тут быть не может". Собственно по этому никто и не рискует рассматривать ^ и $ по разному, в зависимости от положения (кроме случаев с квадратными скобками, конечно).
Пример на regexp101.com

Дочерний блок шире родительского блока с ограниченной шириной. Как сделать?

Имеется колонка с текстом. На странице она одна и занимает примерно 70% от всей ширины страницы. Расположена по-центру.
Внутри текст и некоторые другие элементы, включая изображения. Нужно сделать так, чтобы изображения занимали, скажем, 90% от ширины всей страницы.
Тут все дело вот в чем.
Использовать position: absolute не получится, потому как часть текста не будет видна, ибо будет находиться за картинкой. Просто указать ширину равную, скажем, 180% для изображения тоже нельзя, иначе результат будет примерно следующий. Также стоит учесть, что изображения могут быть разные по ширине. Из этого следует, что нужно сделать следующее: более мелкие изображения, которые не дотягивают до ширины колонки, нужно растягивать так, чтобы они занимали 100% ширины род. элемента. А те, что шире нужно растягивать так, чтобы занимали не более 90% от ширины всей страницы. Грубо говоря все это дело должно выглядеть примерно так:
img { min-width: 100%; /* от ширины родителя */ max-width: 90%; /* от ширины всей страницы */ }
Как подобное можно реализовать? Допускается обрамлять img в div'ы и другие теги.
Вспомнил об еще одном не подходящем способе: вариант обрамления всего содержимого кроме картинок в дополнительный тег и придание ему margin или padding. Этот вариант не подходит как минимум по двум причинам: задача заключается в том, чтобы разрешить картинке быть на всю (почти) ширину страницы, оставаясь при этом по-центру, а не сместить все кроме картинок, чтобы они казались растянутыми (1). И использование дополнительных тегов (что будет крайне неудобно делать каждый раз) (2).


Ответ

Достаточно использовать относительные единицы измерения.
body { background-color: #eee; } .container { background-color: #fff; max-width: 70%; margin: 0 auto; padding: 10px; /* Для красоты */ } img { display: block; transform: translateX(-50%); margin-left: 50%; max-width: 90vw; min-width: 100%; }

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam optio quasi sapiente labore enim nisi sit, facere adipisci corrupti distinctio. Fuga eos in debitis, recusandae rerum minus nulla sint doloribus ducimus dolore non, repellendus, ullam quia. Molestiae enim ratione eaque?

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit nemo sit qui dolorem, minima quibusdam. Cumque aperiam sint odio culpa totam alias explicabo suscipit voluptates officiis adipisci temporibus, amet ipsum, vero voluptatibus consequatur rerum, aut ullam. Sequi iusto, similique. Quis eaque, veritatis sapiente ea amet, veniam neque voluptatem repellendus possimus laboriosam quasi nam aliquam ullam similique, expedita. Quo aliquam molestias ratione nemo pariatur sed velit, sint nulla tempore eveniet maiores nesciunt explicabo quas! Nesciunt, reprehenderit! Soluta voluptatibus perferendis quod nam.

Demo 1

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Pariatur a saepe eveniet similique laudantium non aut delectus, facere libero ut vitae, enim tempore magnam eligendi adipisci cum minus. Eius doloremque molestias, dolores consequatur hic! Culpa eveniet, velit nam dolor dignissimos!

Demo 2

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam optio quasi sapiente labore enim nisi sit, facere adipisci corrupti distinctio. Fuga eos in debitis, recusandae rerum minus nulla sint doloribus ducimus dolore non, repellendus, ullam quia. Molestiae enim ratione eaque?

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit nemo sit qui dolorem, minima quibusdam. Cumque aperiam sint odio culpa totam alias explicabo suscipit voluptates officiis adipisci temporibus, amet ipsum, vero voluptatibus consequatur rerum, aut ullam. Sequi iusto, similique. Quis eaque, veritatis sapiente ea amet, veniam neque voluptatem repellendus possimus laboriosam quasi nam aliquam ullam similique, expedita. Quo aliquam molestias ratione nemo pariatur sed velit, sint nulla tempore eveniet maiores nesciunt explicabo quas! Nesciunt, reprehenderit! Soluta voluptatibus perferendis quod nam.

Demo 3

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam optio quasi sapiente labore enim nisi sit, facere adipisci corrupti distinctio. Fuga eos in debitis, recusandae rerum minus nulla sint doloribus ducimus dolore non, repellendus, ullam quia. Molestiae enim ratione eaque?

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit nemo sit qui dolorem, minima quibusdam. Cumque aperiam sint odio culpa totam alias explicabo suscipit voluptates officiis adipisci temporibus, amet ipsum, vero voluptatibus consequatur rerum, aut ullam. Sequi iusto, similique. Quis eaque, veritatis sapiente ea amet, veniam neque voluptatem repellendus possimus laboriosam quasi nam aliquam ullam similique, expedita. Quo aliquam molestias ratione nemo pariatur sed velit, sint nulla tempore eveniet maiores nesciunt explicabo quas! Nesciunt, reprehenderit! Soluta voluptatibus perferendis quod nam.


Разверните пример на всю страницу. Так лучше видно, что картинки 90% шириной.

Расположение методов в многопоточном приложении

При изучении многопоточности в Java столкнулся с непонятным для меня явлением при перестановке двух методов местами внутри одного блока if
Ниже пример, в котором запускаются 10 потоков (ссылка на пример кода в GitHub). Их задача в порядке возрастания Id произвести некую работу, в данном случае вывести сообщение, содержащее Id потока и значение переменной в вспомогательном классе.
Пример содержит три класса:
Класс Main. В нем в цикле создается 10 экземпляров класса ThreadExample, которые, в свою очередь являются элементами массива. Id первого экземпляра потока, до его старта заносится в переменную вспомогательного класса. После этого поочередно в цикле вызывается метод start всех потоков.
package lan.example.thread_example;
public class Main {
static HelperSingletonBillPugh INSTANCE_TEST_THREAD = HelperSingletonBillPugh.getInstance(); static ThreadExample[] myThreads = new ThreadExample[10]; static final int COUNT = 10;
public static void main(String[] args) {
for (int i = 0; i < COUNT; i++) { myThreads[i] = new ThreadExample(); if (i == 0) { INSTANCE_TEST_THREAD.setCurentThreadId(myThreads[i].getId()); } myThreads[i].start(); } } }
Класс HelperSingletonBillPugh. Это вспомогательный хелпер класс, реализованрый по типу синглетона способом Била Пью. Вроде такой тип реализации синглетона считается потокобезопасным. Класс содержит переменную curentThreadId типа long с Id потока и публичные методы setCurentThreadId(long threadId), getCurentThreadId(), incremenCurentThreadId() для изменения, чтения и инкремента значения этой переменной.
package lan.example.thread_example;
public class HelperSingletonBillPugh {
private HelperSingletonBillPugh() { }
private static class SingletonHandler { private static final HelperSingletonBillPugh INSTANCE = new HelperSingletonBillPugh(); }
public static HelperSingletonBillPugh getInstance() { return SingletonHandler.INSTANCE; }
private long curentThreadId = 0L; // Id потока, который должен выполнить вывод сообщения
public long getCurentThreadId() { return this.curentThreadId; }
public void setCurentThreadId(long threadId) { this.curentThreadId = threadId; }
public void incremenCurentThreadId() { this.curentThreadId++; } }
Класс ThreadExample. Класс наследник Thread. В нем вечный цикл, с паузами и постоянным сравнением значения getId() потока с переменной curentThreadId экземпляра вспомогательного класса HelperSingletonBillPugh. Если равенство выполняется, то выводится сообщение, переменная curentThreadId увеличивается на 1 и поток завершает работу.
package lan.example.thread_example;
public final class ThreadExample extends Thread {
static HelperSingletonBillPugh INSTANCE_TEST_THREAD = HelperSingletonBillPugh.getInstance();
@Override public void run() {
while (true) {
if (INSTANCE_TEST_THREAD.getCurentThreadId() == this.getId()) {
// Раскомментируй следующую строку //INSTANCE_TEST_THREAD.incremenCurentThreadId(); System.out.println("Print " + this.getName() + " ### ID:" + this.getId() + " ### getCurentThreadId: " + INSTANCE_TEST_THREAD.getCurentThreadId());
// Закоментируй следующую строку INSTANCE_TEST_THREAD.incremenCurentThreadId();
break; } } } }
В данном примере кода сообщения выводятся последовательно и потоки завершают свою работу, все стабильно от запуска к запуску, вот такой вывод:
Print Thread-1 ### ID:11 ### getCurentThreadId: 11 Print Thread-2 ### ID:12 ### getCurentThreadId: 12 Print Thread-3 ### ID:13 ### getCurentThreadId: 13 Print Thread-4 ### ID:14 ### getCurentThreadId: 14 Print Thread-5 ### ID:15 ### getCurentThreadId: 15 Print Thread-6 ### ID:16 ### getCurentThreadId: 16 Print Thread-7 ### ID:17 ### getCurentThreadId: 17 Print Thread-8 ### ID:18 ### getCurentThreadId: 18 Print Thread-9 ### ID:19 ### getCurentThreadId: 19 Print Thread-10 ### ID:20 ### getCurentThreadId: 20
Но стоит только переставить местами метод INSTANCE_TEST_THREAD.incremenCurentThreadId() и метод System.out.println() (в коде помечено где убрать и добавить коммент) и результат становится не стабильным и для меня не понятным, хотя перестановка осуществляется внутри блока if. Если быть точнее, то он не всегда стабильный, то есть, несколько запусков может пройти вполне корректно. Вот вывод одного из запусков после перестановки методов местами:
Print Thread-1 ### ID:11 ### getCurentThreadId: 12 Print Thread-2 ### ID:12 ### getCurentThreadId: 15 Print Thread-6 ### ID:16 ### getCurentThreadId: 17 Print Thread-5 ### ID:15 ### getCurentThreadId: 16 Print Thread-4 ### ID:14 ### getCurentThreadId: 15 Print Thread-7 ### ID:17 ### getCurentThreadId: 21 Print Thread-3 ### ID:13 ### getCurentThreadId: 21 Print Thread-8 ### ID:18 ### getCurentThreadId: 21 Print Thread-9 ### ID:19 ### getCurentThreadId: 21 Print Thread-10 ### ID:20 ### getCurentThreadId: 21
Из примера видно, что потоки выводят сообщения хаотично и значение переменной getCurentThreadId временами отличается от Id текущего потока более чем на 1. Что-же происходит при изменении местами двух этих методов? Дело в том, что когда System.out.println() находится перед INSTANCE_TEST_THREAD.incremenCurentThreadId(), то у меня нет ни одного непредсказуемого результата. Можно ли считать это стабильной работой или все-таки эта стабильность обманчива и при неких обстоятельствах пример отработает не корректно?
P/S. На всякий случай уточню. Я немного имею представление про Java Memory Model, оператор volatile, блок synchronize, про кэши данных и атомарность, правда глубоких знаний пока нет, но добиться гарантированной стабильной работы примера скорее всего смогу. Интересует именно понимание того, какие-такие серьезные изменения происходят при перестановки местами этих двух методов, так влияющие на результат работы примера. И, как следствие, можно ли считать стабильной работу примера в первом случае и почему? Проверял пример на разных операционных системах (Linux Mint 32 и 64 bit, Windows 10 64 bit), но правда только с Oracle JDK.


Ответ

Дело в том, что операция инкремента не является атомарной, а состоит из двух операций: чтения текущего значения и записи увеличенного значения. Если развернуть ее, то цикл в первом сценарии будет выглядеть так:
while (...) { <чтение id> // вывод на консоль <чтение id> // инкремент, шаг 1 <запись id> // инкремент, шаг 2 }
Такое расположение операций вкупе с хитрым условием while по сути служит локом, дающим доступ к телу цикла только одному потоку. Сначала только первый поток заходит внутрь цикла, а остальные просто прокручивают его ("блокируются"). Когда первый поток записывает увеличенный id и выходит из цикла, то уже он начинает прокручивать цикл ("блокируется"), а второй поток заходит внутрь. И так по очереди для всех потоков. Именно за счет инкремента все потоки получают этот доступ последовательно, согласно своим номерам. Важным здесь является то, что запись id по сути освобождает "лок" текущего потока и "разрешает" выполнение другого потока. Пока она идет последней в теле цикла, проблем не возникает.
Во втором сценарии цикл выглядит следующим образом:
while (...) { <чтение id> // инкремент, шаг 1 <запись id> // инкремент, шаг 2 <чтение id> // вывод на консоль }
Теперь мы видим, что "лок" освобождается чуть раньше. К чему это может привести? К тому, что между записью id и вторым чтением id могут начать исполняться другие потоки, поскольку "лок" свободен и доступ к телу цикла может получить другой поток. Т.е. возникает классическая гонка, в результате которой может происходить следующее:
поток на втором чтении id может получить уже обновленное значение (это объясняет, например, почему Thread-2 выводит 15, а не 13) вывод в консоль может перепутаться из-за того, что другие потоки "встревают" сразу после записи id
while (...) { <чтение id> // инкремент, шаг 1 <запись id> // инкремент, шаг 2 <возможное исполнение других потоков> <чтение id> // вывод на консоль (потенциально уже нового значения) }
Сценарий выполнения для приведенного вами в вопросе лога может выглядеть так:
все потоки начинают выполнение все потоки кроме потока 1 "блокируются" на условии while поток 1 читает id (=11) поток 1 увеличивает id (=12) поток 2 "разблокируется" поток 2 читает id (=12) поток 1 читает id и выводит на консоль (=12) поток 1 "засыпает" поток 2 увеличивает id (=13) поток 3 "разблокируется" поток 3 читает id (=13) поток 3 увеличивает id (=14) поток 4 "разблокируется" поток 4 читает id (=14) поток 4 увеличивает id (=15) поток 2 читает id и выводит на консоль (=15) поток 2 "засыпает" поток 5 "разблокируется" поток 5 читает id (=15) поток 5 увеличивает id (=16) поток 6 "разблокируется" поток 6 читает id (=16) поток 6 увеличивает id (=17) поток 6 читает id и выводит на консоль (=17) поток 6 "засыпает"
...и так далее

Генерация случайной ASCII строки

Генерирую ASCII-строку следующим образом:
def buildblock(size): out_str = '' for i in range(0, size): a = random.randint(65,90) out_str += chr(a) return(out_str)
Но в таком случае генерируются символы только верхнего регистра. Например, FGLKJDSDH. А как сделать так, чтобы генерировались строки и нижнего и верхнего регистра одновременно? По типу YjhmrdVDgm


Ответ

Как-то так:
import random import string
def buildblock(size): return ''.join(random.choice(string.ascii_letters) for _ in range(size))
Можно добавить ещё и цифры:
import random import string
def buildblock(size): return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(size))
Действующий код

Передача сообщений между потоками - C#

Есть у меня простой класс-логгер:
static class Logger { public delegate void Message(string msg);
static public event Message OnMessage;
static public void SendMessage(string msg) { OnMessage?.Invoke(msg); } }
Я из любых мест приложения отправляю ему сообщения по типу: Logger.SendMessage("Получена команда на запуск");
При загрузке window (WPF) я подписываюсь на события логгера и вывожу лог в textbox
Пока приложение было однопоточным всё отлично работало, но теперь методы отлажены и надо всё распараллелить (идет обращение к 40 БД на разных хостах поэтому всё хорошо параллелится)
Но теперь возникла проблема - при попытке прочитать отправленное сообщение из другого потока возникает Exception
"Вызывающий поток не может получить доступ к данному объекту, так как владельцем этого объекта является другой поток."
Как это грамотно и с малой кровью исправить?


Ответ

Смотрите.
Проблема в том, что события доставляются в том потоке, который отправляет события. Поэтому у вас подписчики событий получают событие каждый раз в разных потоках. Если подписчик — UI-код, который просто выводит текст в UI, то при приходе сообщения из неглавного потока происходит проблема.
Есть несколько путей починки вашего кода.
Можно привязать логгер к главному потоку. При этом сообщения будут доставляться только в главном потоке, и соответственно UI-код будет всегда работать «как надо».
static class Logger { static Lazy dispatcher = new Lazy(() => Application.Current.Dispatcher);
public delegate void Message(string msg);
static public event Message OnMessage;
static public void SendMessage(string msg) { if (dispatcher.Value.CheckAccess()) OnMessage?.Invoke(msg); else dispatcher.Value.InvokeAsync(() => OnMessage?.Invoke(msg)); } }
Это, наверное, не самое лучшее архитектурное решение, т. к. при этом логгер получается зависимым от WPF, то есть модель получает зависимость от VM (что не позволит использовать её повторно в других программах). Зато этот метод решает задачу наиболее просто: другие переделки при этом не нужны. Можно считать логгер не привязанным ни к какому потоку, тогда UI-код должен проверять, в каком потоке он запущен, и при необходимости пользоваться Dispatcher.InvokeAsync
Logger.OnMessage += s => { if (Dispatcher.CheckAccess()) LogContainer.Text += (s + "
"); else Dispatcher.InvokeAsync(() => LogContainer.Text += (s + "
")); };
Это более правильный подход, но здесь придётся потенциально править все места, где происходит подписка на сообщения от логгера. Впрочем, такое место в программе, судя по всему, одно. Вы можете использовать модные в этом сезоне Reactive Extensions, и переписать ваш класс на них:
using System.Reactive.Linq; using System.Reactive.Subjects;
static class Logger { static ISubject subject = Subject.Synchronize(new Subject()); public static IObservable Messages => subject; static public void SendMessage(string msg) => subject.OnNext(msg); }
Подписка при этом выглядит так:
Logger.Messages.ObserveOnDispatcher().Subscribe(s => LogContainer.Text += (s + "
"));
Максимальная гибкость, LINQ на сообщениях, доставка в произвольный поток, навесные плюшки наподобие подавления слишком частых или повторяющихся сообщений поставляется в комплекте, бонусом ощущение собственной крутости, функциональности и трендовости. Минус — вам придётся-таки разобраться с этим самым Rx (муа-ха-ха!). Или это можно считать плюсом, да. (Think positive.)
Не забудьте подключить из nuget System.Reactive.Core, System.Reactive.Interfaces, System.Reactive.Linq и System.Reactive.Windows.Threading

PHP - Запись в файл в многопользовательском режиме

Записываю протокол событий вот таким скриптом:
"); flock($file,3); fclose($file); ?>
Но возникает вопрос: Что будет, если вызовов будет слишком много и со всех сторон? Не выйдет ли, что пока я залочил файл в одном вызове скрипта, другой тоже попытался, ругнулся и ничего не записал? Как предусмотреть это в коде?


Ответ

Функция flock() создает для файла флаг, указывающий на то, что с файлом идет работа. При этом другой скрипт или другая программа, умеющая распознавать подобный флаг, сделает соответствующие выводы и содержимого файла не нарушит.
По умолчанию, данная функция будет ждать получения эксклюзивной блокировки на запись, это поведение можно изменить с помощью параметра LOCK_NB. Если у Вас будет многопоточная запись в файл, то каждый следующий запрос просто будет дольше выполняться из-за наличия блокировки.
Кстати, весь ваш код можно перенести в одну конструкцию:
file_put_contents('track.log', "$trnum \t" . date("Y-m-d h:ia") ."
", LOCK_EX | FILE_APPEND);

Yield и потоки и все все все

Оператор yield
class UserCollection { public static IEnumerable Power() { yield return "Hello world!"; } }
Оператор yield из .Net Reflector - перенесенный в рялии C# и Visual Studio
class UserCollection { public static IEnumerable Power() { return new ClassPower(-2); }
private sealed class ClassPower : IEnumerable, IEnumerator, IEnumerator, IDisposable { // Поля. private int state; private object current; private int initialThreadId;
// Конструктор. public ClassPower(int state) { this.state = state; this.initialThreadId = Thread.CurrentThread.ManagedThreadId; }
//private bool IEnumerator.MoveNext() // Так в Рефлекторе bool IEnumerator.MoveNext() { switch (this.state) { case 0: this.state = -1; this.current = "Hello world!"; this.state = 1; return true;
case 1: this.state = -1; break; } return false; }
IEnumerator IEnumerable.GetEnumerator() { if ((Thread.CurrentThread.ManagedThreadId == this.initialThreadId) && (this.state == -2)) { this.state = 0; return this; } return new UserCollection.ClassPower(0); }
IEnumerator IEnumerable.GetEnumerator() { // Так в Рефлекторе //return this.System.Collections.Generic.IEnumerable.GetEnumerator();
return (this as IEnumerable).GetEnumerator(); }
void IEnumerator.Reset() { throw new NotSupportedException(); }
void IDisposable.Dispose() { }
// Свойства. object IEnumerator.Current { get { return this.current; } }
object IEnumerator.Current { get { return this.current; } } } }
Меня интересует строка и как ее комментирует автор
this.initialThreadId = Thread.CurrentThread.ManagedThreadId;
данная строка свидетельствует о синхронизации и доступа к этой коллекции как к разделяемому ресурсу. Почему именно при работе с yield коллекция воспринимается как разделяемый ресурс и нужна вообще в принципе работа с потоками?
См. рисунок как я понял работу оператора yield и может т.к это в эту коробку все операторы yield помещают свое значение , то может поэтому нужна работа с потоками?


Ответ

Обратите внимание на функцию IEnumerable.GetEnumerator()
Данный объект реализует как IEnumerable, так и IEnumerator. Состояние -2 означает, что объект «свежий», только что вернулся из вызова функции Power, и его энумерация ещё не начиналась. В этой ситуации, когда тут же вызывается GetEnumerator в том же потоке (а это происходит в подавляющем большинстве случаев: например, при вызове foreach (var x in Power())), то из соображений эффективности можно вернуть этот же объект (т. к. он служит и энумератором тоже).
Но если энумерация уже прошла, внутреннее состояние объекта может быть испорчено, для этого случая возвращают новый объект. Точно так же если энумерация производится в другом потоке, то чтобы избежать необходимости синхронизации, лучше создать новый объект.
Остановимся специально на последнем пункте. Если вдруг IEnumerable уйдёт в другой поток, и оттуда буден вызван метод GetEnumerator(), и одновременно в основном потоке будет тоже вызван этот же метод, то без проверки thread id может случиться так, что оба потока пройдут одновременно проверку this.state == -2, и получат один и тот же объект! В результате при энумерации они будут мешать друг другу. В этом случае мы даём «выиграть» тому же потоку, который создал объект.
Таким образом, это специальная оптимизация для обычного случая (выделение только одного объекта); «необычные» случаи использования проходят более сложным путём.

Подробнее по теме: Jon Skeet, C# in Depth. Iterator block implementation details: auto-generated state machines

Определение свойства, по которому нужно произвести фильтр

Здравствуйте. Возник очень тяжелый вопрос с которым я никогда не сталкивался. мне нужно создать метод, который поймет по какому свойству нужно сделать фильтр. Т.е., допустим у меня есть класс
public class User { public string Name {get; set;} public string Nick {get; set;} }
И мне нужно вытащить из базы некоторых пользователей но критерий заранее не известен, в запросе Name или Nick могут быть null.
В данный момент это выглядит примерно так:
//это часть когда находится в классе user IQarable query ... тут создается query и передается в метод ниже ...
if (!string.IsNullOrEmpty(Name)) { query = query.Where(x => x.VenueName.Contains(Venue)); }
if (!string.IsNullOrEmpty(Nick)) { query = query.Where(x => x.City.Contains(City));
} //и так далее
Внутри блоков If есть еще кое какая проверка, вот поэтому я пытаюсь это вынести в 1 метод, но не в этом суть.
Я пытаюсь сделать метод, который принимает query и свойство в виде строки, по которому нужно выполнить Where(...), что бы это выглядело так
if (!string.IsNullOrEmpty(Name)) { query = SearchMethod(query, "Name", "Jhon"); }
Я не могу представить как мне заменить выражение Where(x => x./*тут свойство, которое каким-то образом определено*/.Contais("SearchingValue")) что-то другое, что может вычислить свойство по которому я веду поиск, и подставить его в это выражение. По рефлексии я смог получить только само свойство.
Type t = this.GetType(); PropertyInfo prop = t.GetProperty("EventName");
Прошу вашей помощи в решении этой проблемы.


Ответ

Отфильтровать IQueryable по Func нельзя. (У вас получится IEnumerable.) Для сохранения IQueryable вам придётся строить Expression (и кажется, вручную). Вот документация
Для вашего случая, если нужно сравнивать значение с константой, можно сделать так (не тестировал, возможны вылеты в рантайме):
IQueryable Filter(IQueryable original, Expression> еxtractor, V value) { return original.Where(ProjectionEquals(еxtractor, value)); }
Expression> ProjectionEquals(Expression> еxtractor, V value) { var body = Expression.Equal(еxtractor.Body, Expression.Constant(value)); return Expression.Lambda>(body, еxtractor.Parameters[0]); }
Пользоваться так:
query = Filter(query, x => x.Name, "Jhon");
Внутри Filter можно накрутить, понятно, более сложную логику.

Если всё же очень хочется потерять проверки на этапе компиляции и передавать имена свойств как строки, можно так:
IQueryable Filter(IQueryable original, string propName, V value) { return original.Where(PropertyEquals(propName, value)); }
Expression> PropertyEquals(string propName, V value) { var parameter = Expression.Parameter(typeof(T), "t"); var left = Expression.PropertyOrField(parameter, propName); var body = Expression.Equal(left, Expression.Constant(value)); return Expression.Lambda>(body, parameter); }
и пользоваться так:
query = Filter(query, "Name", "Jhon");
Понятна схема?

Для примера, если вам нужно Contains
Expression> GetContains(string propName, string value) { var parameter = Expression.Parameter(typeof(T), "t"); var prop = Expression.Property(parameter, propName); var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); var valueAsExpr = Expression.Constant(value, typeof(string)); var contains = Expression.Call(propOrField, containsMethod, valueAsExpr); return Expression.Lambda>(contains, parameter); }

Как подсказывает в комментарии @Pavel Mayorov, последнюю функцию можно переписать проще:
Expression> GetContains(string propName, string value) { var parameter = Expression.Parameter(typeof(T), "t"); var prop = Expression.Property(parameter, propName); var valueAsExpr = Expression.Constant(value, typeof(string)); var contains = Expression.Call(prop, "Contains", null, valueAsExpr); return Expression.Lambda>(contains, parameter); }

Возможные причины появления Debug Error - R6025 pure virtual function call

Моя программа завершает своё выполнение с ошибкой:
R6025 pure virtual function call.
Как вообще такое возможно, чтобы была вызвана чисто виртуальная функция? Экземпляр абстрактного класса не может быть создан. Если функция виртуальная, то используется позднее связывание, т.е. вызываться должна функция по типу объекта, а не по типу ссылки. Т.е. чисто виртуальная функция не может быть вызвана. Что мне делать?


Ответ

В ответе @AnT было объяснено, как может получиться такая ошибка. (Это вызов виртуальной функции, прямо или косвенно, в конструкторе или деструкторе.)
Теперь вопрос в том, что делать.
Для начала, попробуйте воспроизвести проблему под отладчиком. Microsoft советует заменить абстрактный метод на вызов DebugBreak, или запустить из-под отладчика и установить точки останова на _purecall в PureVirt.c. Но у меня проблема отловилась в Visual Studio 2015 и без этих заклинаний.
Вы увидите в стеке, какой именно абстрактный метод вы вызываете, и поискав по стеку конструктор или деструктор объекта данного класса, найдёте ошибочный вызов. Помните, что это вполне может быть косвенный вызов, через другие функции.
Если вам в конструкторе реально понадобился виртуальный метод, возможно, ваш конструктор делает слишком много. Может быть, имеет смысл вынести функциональность, требующую виртуальной функции, в отдельный метод, а конструктор закрыть, и конструировать класс через статическую фабричную функцию.
Ещё одной причиной данной ошибки может служить вызов функции по указателю на уже умерший объект. Если деструктор объекта отработал, то при условии, что память, занимаемая объектом, никем не затёрта, при попытке вызова метода по мёртвому указателю будет также выполнен чисто виртуальный метод (эта ситуация аналогична вызову метода в деструкторе), с понятными последствиями. Так что если в вашем стеке нету конструктора/деструктора, всё куда хуже: у вас умер указатель.

Выполнив восходящее преобразование от производного в базовый класс метод не переопределился

Выполнив восходящее преобразование от производного в базовый класс метод не переопределился? Почему не вызвался метод nasvai() базового класса?
class BasicClass { void nasvai() { System.out.println("Basic_Nasvai"); } }
class SubBasic extends BasicClass { @Override void nasvai() { System.out.println("Nasvai"); } }
class P231Exc20 { public static void main (String[] args) { SubBasic sb = new SubBasic(); sb.nasvai(); BasicClass bc = sb; bc.nasvai(); } }
Вывод:
Nasvai Nasvai


Ответ

А он и не должен был переопределяться. В Java (в отличии от С++ к примеру) все функции делаются виртуальными (virtual) и для поиска функции, которую необходимо вызвать, используется специальная таблица (VMT) которая (упрощённо) каждому объекту при создании ставит в соответствие его тип (по конструктору). И исходя из типа вызывает нужную функцию. При преобразовании типа сохраняется запись в VMT и соответственно происходит вызов функции исходя из типа созданного объекта а не связанной с ним переменной.

Как получить путь относительно базового каталога в C#?

В проекте на WinForms имеется набор отчетов, расположенных в папке и её подпапках, например:
D:\Shared\Common\BaseReports\Main.rpt D:\Shared\Common\BaseReports\Main_new.rpt D:\Shared\Common\BaseReports\2015\Payments.rpt D:\Shared\Common\BaseReports\2016\Payments.rpt
и т.д. Само приложение может располагаться где угодно, а путь к отчетам в нём указывается через переменную string reportPath = "D:\\Shared\\Common\\BaseReports";
В дальнейшем пусть путь к конкретному отчету задается с использованием базовой папки, например, так: string someReport = reportPath + "\\2015\\Payment.rpt";
Как получить список папок и файлов, находящихся внутри D:\Shared\Common\BaseReports\ в виде:
Main.rpt Main_new.rpt 2015\Payments.rpt 2016\Payments.rpt
... ?
Да, про string.Replace() [string relativePath = someReport.Replace(reportPath, "");] знаю, но может быть есть способ лучше? Спасибо!


Ответ

Как то так.
var baseDir = new DirectoryInfo("H:\\...\\Reports"); foreach(var file in baseDir.EnumerateFiles("*.rpt",SearchOption.AllDirectories)) { Console.WriteLine(file.FullName.Replace(baseDir.FullName + Path.DirectorySeparatorChar, string.Empty)); }
Работает с любой глубиной вложенных папок. Минимум должен быть доступ на чтение для файлов и папок, в противном случае будет исключение, но если это пользовательская папка и программа может писать туда отчеты с правами пользователя, то проблем с доступом быть не должно (диверсия пользователя не в счет). Выводит правильные системные слеши в путях. Работает быстрее чем с использованием Directory.GetFiles()

Как сверстать расположение фото?


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


Ответ

Набросал верстку.
.container { width: 600px; height: 600px; border: 1px solid; } .flex { display: flex; } .mini-width { min-width: 150px; } .mini-height { min-height: 150px; } .column { flex-direction: column; } .padding { padding: 6px; } .fs { flex: 1; } .pseudo-img { width: 100%; height: 100%; background: red; }


Исходник codepen

Построение кривых Безье SVG

В SVG есть встроенная функция построения кривых Безье 2-ой и 3-ей степени, т.е. только по трем и четырем точкам. Нужно строить по произвольному кол-ву точек.
Можно было бы строить кривую произвольной степени, но это не эффективно, и слишком долго, мне надо строить почти мгновенно.
Поэтому хотелось бы объединить несколько кривых второй степени в одну большую.
Как это сделать? Желательно с готовым кодом.
P.S. Пишу векторную рисовалку в академических целях


Ответ

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

Для соединения двух кривых к конечной точке первой кривой присоединяется начальная точка второй кривой. В этом случае координаты начальной точки второй кривой не указываются.

Для гарантированного получения гладкого, без изломов соединения двух кривых применяется команда – (T) или (t) (для относительных координат).

Далее можно присоединять сколько угодно кривых Безье. Примеры кода взяты здесь

Как правильно оборвать соединение TcpClient

В клиентском ПО в отдельном потоке идет работа с сервером. Программа в отдельном Task отправляет файл и ждет пока сервер обработает и пришлет ответ. Если пользователь хочет закрыть соединение tcpClient.Close() то в Task выбросится исключение. Как корректно в данной ситуации закрывать соединение?


Ответ

Не дело подставлять подножку своему коду, убивая объект, с которым другой поток ведёт работу. Передайте сигнал о необходимости окончания работы в работающий Task (например, через CancellationToken), и пусть этот Task сам закроет свой TcpClient

Order of volatile access is undefined in this statement

Имеются две volatile-переменные:
volatile uint32_t a; volatile uint32_t b;
Они объявлены как volatile, потому что могут измениться как в основной программе, так и в обработчике прерывания, так и устройствами на системной шине (такими как DMA). Если обе переменные участвуют в одном выражении, например:
uint32_t c = a + b;
то компилятор выдаёт предупреждение Order of volatile access is undefined in this statement. Как я понимаю, это означает, что неизвестно, какая переменная первой загрузится в регистр общего назначения, и возможна такая ситуация, когда переменная a загрузилась в регистр, сработало прерывание, изменило это переменную, а основная программа продолжает работать со старым значением. Некоторые источники рекомендую в таких ситуациях разбивать выражение на части, например:
uint32_t c = a; c += b;
но на мой взгляд, так мы лишь затыкаем компилятор, а не устраняем причину проблемы.
А теперь собственно вопрос. В программе обработчики прерываний постоянно периодически изменяют volatile-переменные, а основная программа выполняет математические преобразования. Как только пришло новое значение переменной, старое уже неинтересно. Можно ли в этом случае игнорировать предупреждение компилятора? Есть ли у этого предупреждения другие источники, о которых я не догадываюсь?


Ответ

В языке С порядок доступа к volatile объектам, наряду с вызовами функций ввода-вывода, является частью наблюдаемого поведения (observable behavior) программы. Поэтому данное предупреждение просто выглядит как предупреждение от педантичного компилятора, который говорит, что наблюдаемое поведение программы в данном случае однозначно не определено.
Компилятор прав - оно действительно не определено однозначно. Но компилятор, разумеется, не знает, какие грани наблюдаемого поведения являются действительно важными для специфики вашей программы, а какие нет, и выдает абстрактное педантичное предупреждение.
Если в данном случае для вас порядок доступа к этим переменным действительно важен, тогда предупреждение вполне оправданно. Если же вы не видите проблем с любым возможным порядком доступа, то перепишите код чисто ради устранения предупреждения от компилятора.
Понятно, что в описанной вами ситуации, при модификации a и b из независимых линий исполнения (потоки, прерывания и т.п.) и при отсутствии какой-либо синхронизации, будет наблюдаться выраженный data race. А уж смертелен ли этот data race для вашего приложения - вам виднее. Если вы захотите избавиться от этого data race, то тут одним подавлением предупреждений не обойдешься - придется организовывать ту или иную форму синхронизации доступа к этой паре.

Как подружить C++ и C# через COM наиболее простым способом?

Все рецепты использования COM включают в себя создание библиотеки типов, ее регистрацию в реестре, регистрацию в реестре сервера...
В DLL-ке при этом надо создавать фабрику объектов.
Если есть исполнимый файл на C# и DLL на C++ - можно ли обойтись безо всех этих шагов и просто загрузить dll-ку?


Ответ

Да, можно. Технология COM не требует для своего использования какой бы то ни было регистрации в реестре!
Все перечисленные в вопросе шаги нужны для уменьшения связности модулей. Если вам эти шаги не подходят, не нужны или вам просто лень их делать - их можно пропустить.
Вот работающий минимальный пример.
C#
using System; using System.Runtime.InteropServices;
[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface ICallback { void execute(); }
class Program : ICallback { static void Main(string[] args) { SetCallbacks(new Program()); }
[DllImport("mylib", CallingConvention=CallingConvention.StdCall)] static extern void SetCallbacks(ICallback callback);
void ICallback.execute() { Console.WriteLine("Hello, world!"); } }
С++
#include "windows.h"
interface ICallback : IUnknown { virtual HRESULT __stdcall execute() = 0; };
extern "C" __declspec(dllexport) void __stdcall SetCallbacks(ICallback *cb) { cb->execute(); }

В примере выше интерфейсы на двух языках были составлены независимо. В принципе, это является двойной работой - поэтому имеет смысл составить интерфейс только 1 раз, после чего его импортировать.
Если интерфейс составляется в C++-проекте на языке IDL - то достаточно потом подключить библиотеку типов в C#-проект как зависимость. Регистрировать ее при этом не обязательно!
Если интерфейс составляется в C#-проекте, то надо обязательно поставить ему кроме перечисленных выше атрибут Guid и сделать его публичным. После этого можно вытащить библиотеку типов через tlbexp и подключить в C++-проект. Регистрировать библиотеку типов в реестре, опять-таки, не требуется.

Как быть если остаток от деления не помещается в беззнаковый тип?

У меня есть два беззнаковых числа и требуется найти остаток от деления суммы этих чисел на третье, также беззнаковое число. Как это сделать аккуратно, если учитывать, что сумма двух беззнаковых вообще говоря не обязана влезать в тип по размеру (т.е. возможно переполнение)


Ответ

Алгоритм может быть такой. Берете остатки от деления каждого делимого на делитель. Затем берете разницу между делителем и одним из остатков. Вычитаете эту разницу из второго остатка, если она превосходит второй остаток, или складываете остатки, если они меньше в сумме делителя и получаете окончательный остаток.
Пусть имеются два беззнаковых числа x и y и делитель d. Тогда остаток r от деления x + y на d можно вычислить так.
r1 = x % d; r2 = y % d;
r = r1 < ( d - r2 ) ? r1 + r2 : r1 - ( d - r2 );
Вот пример функции для типа unsigned int на C/C++
unsigned int remainder(unsigned int x, unsigned int y, unsigned int d) { unsigned int r1 = x % d; unsigned int r2 = y % d;
return r1 < (d - r2) ? r1 + r2 : r1 - (d - r2); }

Странная магия оптимизатора MSSQL

Есть временная таблица следующего вида:

CREATE TABLE #1 ( num1 FLOAT ,num2 FLOAT ) INSERT INTO #1 SELECT 0 ,0 INSERT INTO #1 SELECT 0 ,1 INSERT INTO #1 SELECT 1 ,0 INSERT INTO #1 SELECT 1 ,1
Выполняю следующий запрос и он валится с ошибкой:
SELECT * FROM #1 a WHERE ( a.num1 > 0 AND a.num2 = 0 ) OR ( a.num1 > 0 AND a.num2 > 0 AND a.num1 / a.num2 >= 2 ) OR ( a.num1 >= 0 AND a.num2 < 0 )
Divide by zero error encountered.
Покурил справку, там написано, что операция деления выполняется раньше всех логических операций. Ок, теперь стало понятно, почему валится с ошибкой. Но потом я убираю знак "=" из последнего условия и все работает:
SELECT * FROM #1 a WHERE ( a.num1 > 0 AND a.num2 = 0 ) OR ( a.num1 > 0 AND a.num2 > 0 AND a.num1 / a.num2 >= 2 ) OR ( a.num1 > 0 AND a.num2 < 0 )
Посмотрел план выполнения запроса: Судя по плану выполнения запроса, должна была снова возникнуть ошибка деления на ноль. Но этого не произошло. Проверял на Microsoft SQL Server-е версии 2005 и 2012. Проблема такая везде присутствует. В Teradata первый запрос отрабатывает без проблем.
Мой вопрос не в том, как переписать запрос, чтобы все заработало, а ПОЧЕМУ оно так работает. Почему, когда во втором запросе я убираю знак "=" запрос отрабатывает без проблем?


Ответ

По-видимому дело вот в чём.
Посмотрите план выполнения (XML). Когда вы убираете =, то предикат оптимизируется в (отредактировано для краткости)
num1 > 0 num2 = 0 num1 / num2 >= 2 AND num2 > 0 num2 < 0
т.е.
a.num1 > 0 AND ( a.num2 = 0 OR a.num1 / a.num2 >= 2 AND a.num2 > 0 OR a.num2 < 0 )
Строки данных (0, 0) и (0, 1) отсекаются по условию a.num1 > 0. Строки (1, 0) и (1, 1) ему удовлетворяет, но (1, 0) проходит по условию a.num2 = 0 (до деления не доходит). Строка (1, 1) не проходит ни по одному условию OR.
Для сравнения, в неизменённом запросе предикат (также отредактировано для краткости), взятый из оценочного плана запроса, выглядит так:
num1 > 0 AND num2 = 0 num1/num2 >= 2 AND num1 > 0 AND num2 > 0 num1 >= 0 AND num2 < 0

Семантика работы/хранения статики в CLR

Известно, что статика не привязана к объекту (экземпляру), а хранится в типе объекта (!), и соответственна эта статика (в виде полей/методов и т.д.), будет существовать в едином экземпляре для всех созданных объектов типа.
Другими словами, все созданные объекты !статического класса будут ссылаться на единственную версию этих статических методов/полей.
На фоне этого, возникает вопрос, а как лучше всего использовать статику, ведь объекты с модификатором static не подлежат сборке мусора, т.к. хранятся в типе объекта (который в свою очередь связан с доменом приложения, и будет существовать до конца жизненного цикла приложения).
Стоит ли избегать статические коллекции/массивы, которые работают с большим кол-вом данных (или же стоит, но нужно будет их "чистить вручную")?
Что является дурным тонном по использованию статики?
Или же можно использовать статику в таком же количестве, как и экземплярные варианты?


Ответ

Я думаю, что стоит руководствоваться не «физическими» особенностями хранения, а семантикой, смыслом ваших данных.
Если у вас какой-либо метод или данные относится ко всем экземплярам класса, то этот метод/данные следует объявлять статическими. Если же у вас, например, экземпляр существует в единственном числе в системе, то следует объявлять его синглтоном.
Это должно быть главным соображением, влияющим на то, как именно вы объявляете ваши данные. Если в вашей программе по её смыслу данные являются статическими, объявляйте их статическими. Если они по своей сути являются экземпляром, объявляйте их данными экземпляра.
Пример: цвет автомашины, выпускаемой концерном Генри Форда — чёрный. Значит, это статические данные:
class FordCar { public static readonly Color = Colors.Black; }
В моей компании есть на текущий момент только одна машина. Но это всё равно конкретный экземпляр. Значит, это синглтон
class OurCompanyCar { private OurCompanyCar() { } public static OurCompanyCar() Instance { get { return lazy.Value; } }
private static readonly Lazy lazy = new Lazy(() => new OurCompanyCar()); }

Обоснование необходимости повторного вызова функции jQuery, когда объект уже создан

Допустим, мы хотим повесить обработчик события на кнопку
var messagesBtn = $("#menu_btn-messages");
В переменную messagesBtn у нас уже записан объект jQuery, и по идее теперь мы можем вызывать методы этого обекта:
messagesBtn.on('click', function(){ ... });
Тем не менее, насколько я видел в примерах, пишут:
$(messagesBtn).on('click', function(){ ... });
Получается, мы рекурсивно вызываем $($("#menu_btn-messages")). Прокомментируйте, пожалуйста, это явление.


Ответ

Когда вы пишете var messagesBtn = $("#menu_btn-messages"), вы записываете результат выполнения функции $() в переменную messagesBtn. В этой переменной хранится состояние элемента на момент присваивания переменной. Зачем так делают? Ну, на то есть как минимум 2 причины.
Первая и главная причина - это оптимизация. Такой процесс, кажется, называется кэшированием селекторов, но я могу ошибаться. Короче говоря, при каждом вызове функции $() происходят какие-то вычисления, которые тратят ресурсы (поиск элемента, построение jQuery-объекта и т.п.). Чтобы эти ресурсы лишний раз не тратить, объекты jQuery (и не только их - с обычными элементами DOM на ванильном JavaScript делают то же самое) часто помещают в переменные. Вот два теста:
Первый:
var iterations = 1000000; console.time('Function #1'); for (var i = 0; i < iterations; i++) { $('body').attr('title', 'test'); $('body').attr('title', 'foo'); $('body').attr('title', 'baz'); } console.timeEnd('Function #1');
Второй:
var iterations = 1000000; console.time('Function #1'); for (var i = 0; i < iterations; i++) { var $body = $('body'); $body.attr('title', 'test'); $body.attr('title', 'foo'); $body.attr('title', 'baz'); } console.timeEnd('Function #1');
Лично у меня первый тест выполнялся медленнее второго в 2 раза на Chrome 55.0.2883.87 m (64-bit) для Windows 10.
На самом деле, подобное кэширование не очень-то и сильно влияет на производительность в реальных условиях. Разница в скорости, конечно, в 2 раза, но обычный вызов функции $() выполняется слишком быстро, и если во всем сценарии у вас парочка вызовов, то разницу вы не заметите. Но кэширование нужно использовать, если вы работаете с jQuery из событий, которые выполняются невероятно часто. Например, событие скролла или событие ресайза окна браузера. Было бы неплохо приучить себя постоянно писать с использованием переменных.
Вторая причина, почему так делают - это читаемость кода и удобство его поддержки. Для лучшей читаемости рекомендуется переменные, содержащие jQuery-объект, именовать с символом доллара в начале (чтобы обозначить, что в переменной находится jQuery-объект), как во втором тесте, и давать имя, основанное не на имени класса или ID, а на значении (назначении) элемента. Таким образом, вы можете изменить имя селектора лишь в одном месте и не бояться, что вы где-то что-то забыли.
Что происходит, когда вы передаете jQuery-объект в функцию $(), например $($("#menu_btn-messages"))? Да ничего интересного и необычного. Разработчики jQuery таким образом лишь предотвратили возможные путаницы в коде. Но так делать не рекомендуется - это лишняя трата ресурсов.

как в python одной строкой преобразовать многомерный список строк в многомерный список чисел?

есть список вида
[['4', '45120'], ['52520', '52', '445', '778'], ['5785699', '789', '550000', '7'], ['89952', '8753', '7878', '8'], ['8', '8', '8', '8', '8', '255', '16']]
как преобразовать все строки в числа одной командой?


Ответ

для данного конкретного массива:
In [89]: [list(map(int, x)) for x in lst] Out[89]: [[4, 45120], [52520, 52, 445, 778], [5785699, 789, 550000, 7], [89952, 8753, 7878, 8], [8, 8, 8, 8, 8, 255, 16]]
PS это решение не будет работать если будет более глубокая вложенность - для таких случаев можно воспользоваться рекурсивной функцией

Почему нельзя использовать в Generics?

Я хочу ограничить тип, передаваемый в метод, в качестве параметра снизу:
public void fill(T list) {}
Но IDEA мне подчеркивает, что так делать нельзя.
Хотя когда я делаю такое же ограничение сверху вот так:
public void fill(T list) {}
То всё нормально работает.
В чем разница? Почему сверху я ограничение выставить могу, а такое же снизу выставить не получается? Как мне добиться нужного эффекта, используя именно , а не ?


Ответ

Если мы пишем , то тип T у нас может быть любым в иерархии наследования класса Number. Притом, что мы об этих классах не знаем ничего, кроме как того, что они наследуются от Object. Соотвественно, вызвать какие то методы напрямую у объекта типа T у нас не получится.
Ситуация с противоположная. Мы все еще понятия не имеем какой это класс T, но абсолютно точно знаем, что у него есть методы, которые определены в классе Number, т.к. класс наледуется от Number.
Следовательно, конструкция вида является бессмысленной. Основной профит ее использования, это применение с параметризированными классами, например List

Вывод одной строки на каждое имя с учетом метки

Есть таблица stuff_id с полями id и name Есть таблица stuff_phone с полями id, phone, preference
У одного сотрудника может быть несколько телефонов. У одного из его телефонов может быть предпочтение, в таком случае для этого телефона в поле preference стоит какая-то метка, скажем, 'p'
Нужен запрос, который выводит информацию в виде "имя - номер" для всех сотрудников, причём для каждого сотрудника нужно вывести только один номер, и если у него есть номер с предпочтением, то именно этот, в противном случае любой его.
Как написать такой запрос?
UPD: Для связи таблиц используется поле id. Можно считать поле preference битовым - не суть. Хотелось бы какое-то стандартное ANSI решение, которое работало бы везде, а так всё равно на какой реализации. Главное - суть вопроса, а не нюансы. Как сделать такое объединение таблиц, чтобы имени ставился в соответствие один номер из множества?


Ответ

Можно подзапросом в поле:
SELECT stuff_id.Id, stuff_id.name, (select top 1 stuff_phone.phone from stuff_phone where stuffid = stuff_id.Id order by stuff_phone.preference) phone FROM stuff_id
(для MSSQL работать будет)
Для MySQL и других СУБД, поддерживающих LIMIT, вместо top
SELECT stuff_id.Id, stuff_id.name, (select stuff_phone.phone from stuff_phone where stuffid = stuff_id.Id order by stuff_phone.preference limit 1) phone FROM stuff_id
Раз уж затронута тема первая строка из выборки, то приведу как звучит это в разных субд:
MSSQL,SYBASE,db2: select top 1 stuff_phone.phone from stuff_phone where stuffid = stuff_id.Id informix,firebird select first 1 stuff_phone.phone from stuff_phone where stuffid=stuff_id.Id oracle <12 select stuff_phone.phone from stuff_phone where stuffid = stuff_id.Id and rownum=1 oracle 12 select stuff_phone.phone from stuff_phone where stuffid = stuff_id.Id fetch first 1 rows only MySql select stuff_phone.phone from stuff_phone where stuffid = stuff_id.Id limit 1

Лучший способ для смены букв “А” и “Б” местами

Есть функция, которая принимает аргумент в виде строки, состоящей из "А", "а", "Б" и "б".
Каждая "Б" должна быть заменена на "А", каждая "А" на "Б" и так же с нижним регистром.
Пример:
>> swap('ААббББаа') 'ББааААбб'
Написал такой слабенький код, но рабочий:
def swap(text): new_text = [] for c in text: if c == 'а': new_text.append('б') elif c == 'б': new_text.append('а') elif c == 'А': new_text.append('Б') elif c == 'Б': new_text.append('А') return ''.join(new_text)
Вопрос: как можно решить эту задачу по другому? Чтобы код был короче и/или быстрее.


Ответ

Если важна скорость обработки, то рекомендую воспользоваться translate
trantab = str.maketrans('АБаб', 'БАба') text = 'ААббББаа' print(text.translate(trantab))
Результат:
ББааААбб

Преобразование огромных чисел

Преобразую значения из string в long long
val = atoll(a[i].c_str());
Как защититься от Васи Пупкина, который записал число, которое большее максимального (9223372036854775807)? Нужно приравнивать val к 0.
Программа ошибок не выдаёт, однако наличие такой недоработки меня напрягает.


Ответ

Ну, как вариант - использовать stoll и перехватывать исключения...
int main(int argc, const char * argv[]) { string s; cin >> s; long long l; try { l = stoll(s); } catch(out_of_range&) { l = 0; } catch(invalid_argument&) { l = -1; } cout << "s = " << s << endl; cout << "l = " << l << endl; }

В чем принципиальная разница между call/apply и почему код так работает?

Всем привет. Разрешите задать нубский вопрос по CALL/APPLY, может кто-то разжуёт Как следует из многих туториалов и учебников call отличается от apply тем, что в apply аргументом можно передать массив. А в call нет.
var object = { "arr": ["Первый элемент",2,3,4,5], "func": function() { function awayFromMe(arr){ console.log(arr); } awayFromMe.call (this, this.arr); awayFromMe.apply(this, this.arr); } }; object.func();
То-есть я рассчитывал что call ничего не даст, a apply отработает, но вопреки моим ожиданиям call дал вывод массива:["Первый элемент", 2, 3, 4, 5] apply дал вывод только первого элемента: "Первый элемент"
Почему так происходит?


Ответ

Путём проб и ошибок, мне кажется я уловил тонкий смысл различия между call/apply и хотел бы им с Вами поделиться, может ещё будет такой(-ая) же как я. Итак, допустим, у нас есть простая заданная функция, которая возвращает сумму двух чисел:
function sumTwoNumb(a, b){ return a + b; }
Код крайне простой, мы передаём два аргумента в параметры функции, а она возвращает сумму. И допустим, нам надо вызвать эту функцию для двух элементов некоего массива.

Если мы вызовем её как: sumTwoNumb.call(null, [100,150]), то получится так, что первый параметр a получит аргументом весь массив [100,150], а второй параметр, b не получит ничего и станет, соответственно, undefined. И в итоге функция вернёт результат сложения [100,150]+undefined, а это равно 100,150undefined

А если мы её вызовем так: sumTwoNumb.apply(null, [100,150]), то при входе в функцию первый параметр a получит нулевой элемент массива = 100, а второй параметр получит первый элемент массива = 150 и в итоге функция вернёт результат сложения 100 + 150, то есть верный.
Уважаемые профессионалы, если я не прав, поправьте. Надеюсь, кому-то пригодится.

Есть ли в python ограничения на длину регулярных выражений?

У меня есть очень длинные регулярные выражения с большим количеством групп внутри. Например,такие
((ab+)|(qwe[rty]?)|(hjk.*)|(mmm)|(ppp)|(sss))? ((ooo[0-9]?)|(ddd)|(ggg)|(jjj))kk? zzz
только длиной в 1-2 тысячи символов и с 100-200 групп и подгрупп. Есть ли в python какие-то ограничения на длину регулярного выражения? На количество групп в нем? Еще какие-то нюансы? Или же ограничений нет вообще, и все зависит только от мощности процессора?
Пока кажется, что я не могу использовать регулярные выражения длиной более 1000 символов и/или с более, чем 100 группами.


Ответ

Судя по этому тикету в Python до версии 3.5 есть ограничение в 100 групп (capturing groups).
https://bugs.python.org/file36654/re_maxgroups.patch
-``(?P=name)`` - A backreference to a named group; it matches whatever text was matched by the - earlier group named *name*. +``(?P=name)``, ``(?P=number)`` + A backreference to a group; it matches whatever text was matched by the + earlier group named *name* or numbered *number*. + + .. versionchanged:: 3.5 + Added support of group numbers.
``(?#...)`` A comment; the contents of the parentheses are simply ignored. diff -r 8a2755f6ae96 Lib/sre_compile.py --- a/Lib/sre_compile.py Thu Sep 18 19:45:04 2014 +0300 +++ b/Lib/sre_compile.py Thu Sep 18 23:27:28 2014 +0300 @@ -470,12 +470,6 @@ def compile(p, flags=0):
# print code
- # XXX: get rid of this limitation! - if p.pattern.groups > 100: - raise AssertionError( - "sorry, but this version only supports 100 named groups" - ) - # map in either direction groupindex = p.pattern.groupdict indexgroup = [None] * p.pattern.groups
Я бы все-таки посоветовал бы вам открыть новый вопрос и описать вашу задачу с примерами входного и "выходного" текста / данных - возможно существует более элегантное решение...

Использование std::find_if не для поиска

Сразу прощу прощения за такое туманное название, не знаю как в двух словах описать задачу.
Допустим у нас есть некий класс, выполняющий какую-то работу:
class Worker{ public: bool doWork(int arg); };
Метод doWork возвращает true если работа выполнена успешно. Нужно чтобы кто-то из имеющихся работников выполнил работу. Для этого хочу воспользоваться std::find_if
struct DoWork{ int arg; explicit DoWork(int arg): arg(arg) {} bool operator()(Worker &worker) const{ return worker.doWork(arg); } };
std::vector workers; //... std::find_if(workers.begin(), workers.end(), DoWork(42));
Идея такая. Алгоритм будет перебирать работников до тех пор пока один не выполнит работу или они не закончатся. Но меня терзают смутные сомнения что так делать можно. Нет ли здесь неопределенного поведения? Будет ли этот код всегда одинаково работать на разных реализациях stl?


Ответ

В требованиях к предикатам, передаваемым в std::find_if, указано, что параметр предиката не обязательно должен быть константной ссылкой, но тем не менее при этом предикату запрещается модифицировать передаваемый в него объект.
25.1 General [algorithms.general] 4 For purposes of determining the existence of data races, algorithms shall not modify objects referenced through an iterator argument unless the specification requires such modification.
Для алгоритм std::find_if как раз таки такого разрешения не дается (в отличие, скажем, от std::for_each). Как формально определяется модифицирующая операция я навскидку не скажу, но если ваша функция DoWork модифицирует элемент контейнера, то есть вероятность, что так делать формально нельзя.
Дополнительно далее там же
8 The Predicate parameter is used whenever an algorithm expects a function object (20.9) that, when applied to the result of dereferencing the corresponding iterator, returns a value testable as true. [...] The function object pred shall not apply any non-constant function through the dereferenced iterator.
Параметром std::find_if как раз является Predicate pred, т.е. эта часть уже однозначно запрещает ваш вариант, если DoWork является неконстантным членом класса Worker. Опять же, в этом определении есть свои дыры, но идея, я думаю, ясна.
Навскидку, конечно, трудно представить себе, что тут может пойти не так, если реализация специально не заточена на злостное вредительство и ловлю нарушителей стандарта...

Определить закрыта ли камера или нет (C++)

Рабочее приложение сотрудника (клиент) транслирует веб-камеру. Нужно определять не заклеена ли камера и не заблокирована ли она какой-то программой. С последним просто: в этом случае все кадры будут одинаковые - просто несколько раз сравнивается следующий кадр с предыдущим. А вот с заклеенной камерой беда. Текущий алгоритм проверяет кадры по размеру, но, как выяснилось, иногда размер кадра с закрытой камеры может быть больше реального изображения с не закрытой камеры. Вот примеры закрытых камер:
Бумажка (11 111 байт) Палец (10 541 байт) Плотная ткань (22 659 байт !!!)
Как видно, по размеру кадра судить бессмысленно - нормальный кадр выходит 17-20 кб, а на третьем фото аж 22 кб при закрытой камере. Определять лица тоже не вариант, так как сотрудник может отойти - не выключать же ему приложение за это. А вот если он закрыл камеру, программа должна прекратить работу.
Как провести более точный анализ заклеенных камер при помощи OpenCV?


Ответ

В комментариях говорили про ПФ. Но, я думаю, что это излишнее. Легко можно обойтись и без этого, более простыми методами. Я рассмотрю 3 изображения. 2 из них Ваши. Ещё одно -- из сети.



Очевидно, что изображения, представляющие собой закрытую камеру -- есть однотонные изображения, на которых преобладают оттенки из определённого цветового диапазона. Для того, чтобы это продемонстрировать, можно привести в пример гистограммы (распределение частот интенсивностей). Сразу оговорюсь, что предварительно все изображения я привожу к градации серого. Делаю это стандартным методом (питон). В принципе, он везде, как правило, реализовывается одинаково

На гистограмме частот для пальца наблюдается всплеск частот вблизи нуля. Далее, более яркие интенсивности отсутствуют. Уже отсюда можно сделать вывод, что в нашей гистограмме много нулевых значений. Аналогичную гистограмму можно привести и для листка бумаги:

Если мы рассмотрим лицо, то нулевые значения гистограммы отсутствуют:

Таким образом, возможным решением будет являться следующая метрика:

Данная метрика рассматривает все точки гистограммы, значения которых нулевые и нормирует их (делит на возможное количество точек). Очевидно, что коль скоро данное отношение близко к 1, то мы находимся в условиях открытой камеры. В противном случае мы находимся в условиях с закрытой камерой. Для того, чтобы понять, что есть 1, а что нет, нужно смотреть на все данные (все изображения), которые у Вас имеются и на основе них делать вывод. Для этого необходимо, вероятно, посмотреть на дисперсию и мат. ождание ненулевых значений гистограммы. Т.е. на числители для всех изображений закрытой камеры. Для них выбрать, например среднюю дисперсию.

Замечу, что можно произвести более глубокий анализ. Например, отчётливо видно, что у нас есть круглый объект -- палец. Бумажка же, вероятно, плотно прижата ладонью к экрану:

Здесь мне отчётливо видится ладонь.
К сожалению, openCV я знаю плохо, но вот на питоне скрипт накидал:
import matplotlib.pyplot as plt from scipy import fftpack, ndimage import matplotlib.image as mpimg import numpy as np
img = mpimg.imread(pathToImage)
imgplot = plt.imshow(img) plt.show() lum_img = img[:,:,0] imgplot = plt.imshow(lum_img) plt.colorbar() plt.show() y = np.histogram(lum_img, bins = range(0, 257)) plt.plot(np.array(range(0, 256)), y[0]) plt.show() fft = fftpack.fft(img) plt.imshow(abs(fft)) plt.show() lum_fft = fft[:,:,0] y = np.histogram(lum_fft, bins = range(0, 257)) plt.plot(np.array(range(0, 256)), y[0]) plt.show()
Но я полагаю, что его не составит труда перенести на нужный Вам язык, с использованием нужной либы. В коде также строится гистограмма для ПФ и само преобразование Фурье. Так что можно пронаблюдать, какие картинки возникают при этом. Кроме того, призываю заметить, что гистограмма для ПФ не несёт дополнительной информации при беглом осмотре.
Преобразование Фурье для картинки с пальцем и гистограмма для преобразования Фурье для картинки с пальцем: