Страницы

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

воскресенье, 8 декабря 2019 г.

Ошибка Another git process seems to be running in this repository

#git


git add выдает такое:


  Another git process seems to be running in this repository, e.g.
  an editor opened by 'git commit'. 


Что делать?
    


Ответы

Ответ 1



Такое бывает, если прервать операцию с репозиторием "внезапно". Или какая то программа решила без Вашего ведома работать с репой. Если Вы не уверены, что какая то программа может работать с репой без Вашего ведома - перегрузите комп. В противном случае в репе найдите в папке .git файл index.lock и удалите его rm .git/index.lock

Ответ 2



Гит когда выполняет какую то команду блокирует себя же, чтобы паралельно ничего не делали с файлами. Если вы уверены что у вас нет паралельно ничего запущено тогда просто с папки .git удалите .lock файлы, если память не изменяет там должен быть index.lock файл.

Как запретить изменение переменной?

#java #классы #переменные #доступ #константа


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


Ответы

Ответ 1



Не припомню таких спецификаторов в языке Java. Но можно сделать, например, private поле с public getter() и НЕ public setter().

Ответ 2



Если нужен доступ в режиме readonly, то можно написать примерно так: public class Foo { private int bar; public int getBar() { return bar; } }

WPF: Как правильно с точки зрения концепции MVVM вызывать новое окно командой?

#c_sharp #wpf #xaml #mvvm


Без шаблона MVVM, вызов нового окна в приложениях WPF довольно прост: 

// Обработчик кнопки открытия другого окна

void OpenOtherWindow(object sender, RoutedEventArgs e) {
    OtherWindow otherWindow = new OtherWindow();
    otherWindow.ViewModel = "ViewModel"; 
    otherWindow.Show();
    otherWindow.ShowViewModel();
}

// Другое окно
public partial class OtherWindow : Window {
    public string ViewModel { get; set; }

        public OtherWindow(){
            InitializeComponent();
        }

        public void ShowViewModel(){
            MessageBox.Show(ViewModel);
        }
}


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

MainWindowView.xaml (Элемент View)


    



MainWindowView.xaml.cs

private void OpenOtherWindow_Executed(object sender, ExecutedRoutedEventArgs e) {
    OtherWindow otherWindow = new OtherWindow();
    otherWindow.ViewModel = "ViewModel"; 
    otherWindow.Show();
    otherWindow.ShowViewModel();
}


AutomationCommands.cs

public static RoutedCommand OpenList = new RoutedCommand("OpenOtherWindow", typeof(AutomationCommands),
new InputGestureCollection(){
        new KeyGesture(Key.N, ModifierKeys.Control)
});


Согласно концепции шаблона MVVM, в MainWindowView.xaml.cs особо логики быть не должно.
Какие альтернативные, более правильные с точки зрения MVVM подходы Вы можете преложить?



Обновление (Конкурс)

Несколько часов смотрел разные примеры по данной теме на разных языках. Все они либо
неполные, потому не получается довести их до рабочего приложения, либо слишком сложные,
а потому крайне трудны для понимания и адаптировать их под своё приложение, понимая
при этом что делаешь, невозможно без помощи более опытных wpf-разработчиков. Потому,
в данном конкурсе задача будет такая: 


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







Мы будем придерживаться паттерна MVVM, но в данном примере нам модель не нужна. Также
не уведен, нужна ли ViewModel но на всякий случай добавил соответствующие классы. Таким
образом организация файлом будет такая (папка Models присутствует, но она пустая):





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


Заготовки кода:

MainWindowView.xaml - элемент View главного окна 


    
        


Ответы

Ответ 1



Написано приложение, демонстрирующее открытие и закрытие окон с использованием паттерна MVVM. Так же, команды отвечающие за открытие окон привязаны на горячие клавиши (Ctrl-Y - открыть первое окно, Ctrl-Z - открыть второе окно) Код приложения находится в git https://github.com/bakulev/MVVM_OpenNewWindowMinimalExample Работоспособность приложения проверена. В коде использованы советы описанные в вопросе Сервис создания модальных и немодальных окон в контексте паттерна MVVM

Ответ 2



Очень хороший вопрос. Открытие новых окон — это сложный момент в рамках паттерна MVVM. Смотрите. С одной стороны, решение об открытии нового окна принадлежит уровню бизнес-логики, то есть, VM. С другой стороны, VM не имеет права ничего знать о View. Получается противоречие. Обычно это противоречие решают, создавая дополнительный сервис открытия окон, который настраивается в начале работы программы, и лежит между VM и View. С таким подходом VM-код создаёт VM-объект некоторого типа, и просит сервис обеспечить показ. Сервис проверяет тип объекта, создаёт окно нужного типа, и показывает его, установив переданный объект в качестве DataContext. Пример кода, реализующего этот подход, можно найти здесь (и посмотрите связанные вопросы). Вам ещё придётся организовывать логику, оповещающую сервис о закрытии окна (и, возможно, запрашивающую подтверждение этого в VM).

Ответ 3



Как вариант, можно воспользоваться классическим паттерном "Команда", как показано здесь. Тогда, в идеале, можно достичь того, что в представлении останется только инициализация модели представления.

как переименовать коммит в github?

#git #github #git_commit


Недавно начал ознакомление с git и github. Могу ли я переименовать commit, уже пропушеный
на гитхабе? Знаю, что для этого используют git commit --amend -m "Some info". Только
вот куда это вписывать? Долго рылся в интернете и не смог найти внятного объяснения.
Использую расширение для VS, также есть десктопная версия гитхаба. 


    


Ответы

Ответ 1



Для выполнения команд git используется так называемая «консоль» — интерпретатор команд на специальном языке. На Linux/Unix/OS X консоль работает с языками семейства Sh (sh, bash, zsh...), на Windows есть cmd.exe (cmd) и PowerShell (powershell), но вместе с Git ставится Git Bash – интерпретатор bash с базовым набором программ. Подробнее: Что означают такие понятия как: консоль, терминал, эмулятор терминала? Не всегда коммит можно переименовывать Пока коммит не попал на удаленный репозиторий, с ним можно делать что угодно. Ваш коммит уже попал на удаленный репозиторий, в ветку master. Если кто-то ещё использует этот репозиторий, переименовывать коммиты нельзя, потому что при переименовании фактически создается новый коммит. В вашем случае похоже, что вы работаете над учебным заданием в собственном репозитории, поэтому вреда не будет. Как переименовать коммит и отправить новое состояние на GitHub Предположим, что есть вот такая история коммитов. На локальном и удаленном сервере одна и та же история: локальный: A---B (master) удаленный: A---B (origin/master) Для переименования коммита действительно нужно выполнить команду. git commit --amend -m 'Новое сообщение' Стало после --amend: локальный: A---B2 (master) # совершенно другой коммит, хоть и с тем же содержимым) \ B # не удален, но больше не принадлежит ветке master. # можно восстановить через git reflog удаленный: A---B (origin/master) После этого придётся явным образом переписать ветку master на удаленном репозитории (на GitHub). Поскольку история коммитов разошлась, GitHub не примет изменения просто так, нужно добавить ключ --force: git push --force origin <имя ветки на удаленном репозитории> Было: локальный: A---B2 (master) \ B удаленный: A---B (origin/master) Стало после push --force: удаленный: A---B2 (origin/master) \ B # вообще недоступен, потому что у вас нет доступа к файловой системе гитхаба # уберется сборщиком мусора на сервере Осторожно: в общем случае команда push --force опасна, так как переписывает состояние ветки на удаленном репозитории и может привести к потерям. Например, если кто-то добавит свой коммит в ветку master, а потом вы переименуете свою ветку и сделаете push --force, то чужой коммит будет потерян. Было: локальный: A---B2 (master) \ B удаленный: A---B---С (origin/master) Стало: чужой коммит C потерян, автор идёт к вам с недобрыми намерениями удаленный: A---B2 (origin/master) \ B---С # недоступен

От чего зависит размер приложения после установки?

#android


Возникла довольно интересная ситуация, которую даже после некоторых поисков я не
смог объяснить сам себе. У меня есть приложение которое было создано при помощи студии
и имеет версию release а не debug. Размер установочного пакета - 1 МБ. Дальше это приложение
было установлено на два разных телефона, например - A (HTC Desire 820) и B (Huawei
Honor 8). 


Телефон A - 2 ГБ ОЗУ, Android 6, ПЗУ 16ГБ;
Телефон B - 4 ГБ ОЗУ, Android 8, ПЗУ 32ГБ;


После установки вот что мы можем увидеть из занимаемой памяти (ПЗУ):


A ~ 3 МБ;
B ~ 8 МБ;


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


Ответы

Ответ 1



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

Ответ 2



Так как марки телефонов умолчали, будем угадывать. Скорее всего на первом телефоне андроид в 32битном режиме, а на другом компиляция в 64 битный код. Обычно (обычно), 64битный код занимает приблизительно в два раза больше памяти. Что собственно и случилось.

Версии Java: платные - не платные, что вообще происходит?

#java #openjdk


Если я разрабатываю на Spring MVC web приложение, какую версию Java мне взять, для
проекта, который планируется запустить в интернет с целью заработка и чтобы не платить
при этом Oracle?

Раньше все было просто: качал последнюю версию и ни о чем не задумывался.

После продолжительного перерыва в Java я зашел по старинке на сайт, скачал последнюю
доступную версию Java, коей оказалась jdk 12.0.1. 

Но тут я начинаю узнавать, что есть какие-то сборки OpenJDK, Oracle JDK, что начиная
с 1.8 что-то поменялось. Oracle какое-то лицензирование ввело.

Можете кратко объяснить, какую взять версию Java для разработки сайта на Spring MVC,
на котором планируется зарабатывать на рекламе и возможно в отдаленном будушем на платных
подписках(т.е. планируется коммерческий продукт), чтобы при этом не заморачивать себе
голову с лицензированием?
    


Ответы

Ответ 1



Язык Java и виртуальная машина HotSpot - это open source. Есть абсолютно бесплатный OpenJDK в который контрибьютят множество других компаний, кроме Oracle - от небольших типа Excelsior JET до гигантов типа IBM. Oracle JDK собирается из исходного кода Open JDK. Они полностью идентичны. Деньги Oracle берёт за поддержку собственной сборки. Так же, как у Red Hat есть платная поддержка бесплатного Линукса. Если вам поддержка не нужна, используйте одну из множества бесплатных сборок OpenJDK и живите спокойно. Если вы компания класса MailRu Group, предоставляющая высоконагруженные сервисы 330 миллионам пользователей, и ваши специалисты каждую неделю находят баг в виртуальной машине, лучше использовать платный Oracle JDK. Подробное официальное заявление на эту тему можно прочитать здесь.

Ответ 2



OpenJDK - абсолютно бесплатен, но его надо обновлять каждые 6 месяцев в сентябре и марте (выходят новые версии).

C++, более одного объявления в выражении инициализации цикла for

#cpp #for #инициализация #объявление #выражение


Существует ли в C++ способ объявить в выражении инициализации цикла for несколько
переменных разного типа?

Например:

for (size_t s = 0, float f = 0.f; ; ) {}

    


Ответы

Ответ 1



Начиная с С++17 у вас есть вариант с structured binding for (auto [s, f] = std::make_tuple(0, 0.0); ; ) { // Работаем с `s` и `f` } А до появления structured binding были лишь трюки вроде for (struct { size_t s = 0; float f = 0.f; } sf; ; ) { // Работаем с `sf.s` и `sf.f` } или for (struct { size_t s; float f; } sf = { 0 }; ; ) { // Работаем с `sf.s` и `sf.f` } Такой трюк не используется особенно широко, но тем не менее доступен со времен С.

Как по клику изменить текст, используя css?

#css #css3 #sass #less


Получил интересное задание, но уже сломал голову, как его выполнить, без js. Звучит
оно так - 

"Дан фрагмент html, для которого нужо написать стили css, допускается less или sass.
Результат должен быть как на картинке. Круг, а внутри цифра 4. При клике цифра должна
уменшаться на-1. Если кликнуть по кружку когда в нём находится цифра 1, то цифра сбрасывается
до 4 - необходимо описать такой внешний вид и поведение, используя только стили. html-менять
нельзя, применять другие языки тоже нельзя.

http://prntscr.com/okb9zt ссылка на пример"

html 

css, который я для этого уже написал .radius{ position: absolute; padding: 20px; margin: 5px; border: 3px solid black; border-radius: 50px; } .num{ position: relative; top: 19px; left: 24px; }


Ответы

Ответ 1



Такое можно вытворять ради спортивного интереса, но это издевательство над CSS, в реальном коде не надо так!)) Оставил чекбоксы, чтобы было видно, что происходит. Можно было не трогать четверку лейбела, и добавить еще три before-after, но так показалось нагляднее. .num::before { content: "4"; } .radius::before { content: "3"; } .num::after { content: "2"; } .radius::after { content: "1"; } #check1:not(:checked) + #check2:not(:checked) ~ .num { display: block;} #check1:not(:checked) + #check2:not(:checked) ~ .num::before { display: block;} #check1:not(:checked) + #check2:checked ~ .radius { display: block;} #check1:not(:checked) + #check2:checked ~ .radius::before { display: block;} #check1:checked + #check2:checked ~ .num { display: block;} #check1:checked + #check2:checked ~ .num::after { display: block;} #check1:checked + #check2:not(:checked) ~ .radius { display: block;} #check1:checked + #check2:not(:checked) ~ .radius::after { display: block;} /* Ага, можно оставить один { display: block }, а все селекторы разделить запятыми. */ label { display: none; position: relative; /* Чтобы абсолютные before и after не выходили за рамки элемента */ color: transparent; /* текст самого лейбела - прозрачный, чтобы не заморачиваться */ width: 30px; height: 30px; border: 1px solid #999; border-radius: 50%; font-size: 20px; font-family: "Helvetica"; cursor: pointer; user-select: none; } .num::before, .num::after, .radius::before, .radius::after { display: none; position: absolute; color: black; top: 5px; width: 100%; text-align: center; }
P.s. А возможных комбинаций n! ))) Будет 3 чекбокса - можно сделать 6 "переключений". 4 штуки = 24, 5 штук - уже 120 !)

Ответ 2



Хоть и не в тему, но вот подобное на z-index, без javascript: Изначальный вариант был длиннее и неинтереснее, ищите его в истории правок, если угодно. Новый, улучшенный вариант: button:focus + button {z-index: 4} button:nth-child(1) {z-index: 3} button:nth-child(2) {z-index: 2} button:nth-child(3) {z-index: 1} button { background: radial-gradient(#fff 57%,#000 61%,#000 67%,#fff 71%); padding: 0 12px; position: absolute; font-size: 40px; outline: none; border: none; }

Какие есть алгоритмы шифрования изображений, устойчивые к трансформации?

#фурье #fft #изображения #wavelet #шифрование


Какие есть алгоритмы шифрования изображений, устойчивые к изменению размера изображения,
поворотам на углы, кратные 90 градусам?
Т.е. зашифровал исходное изображение - оно на себя не похоже, набор узоров, загрузил
на фотохостинг, где его в т.ч. уменьшили. Взял уменьшенный вариант, и тем же ключом
расшифровал в уменьшенную копию исходной картинки. Есть такие решения?
В идеале — вообще зашифровали - распечатали - сфотографировали на мобильник распечатку
- дешифровали в исходное, пусть такого же уменьшенного разрешения и плюс искажения
перспективы. Т.е. решение, не привязанное жестко к пикселам, и к точным значениям цветов/яркостей.
Upd. как шаг к анонимности интернетов в эпоху тотального контроля государств и корпораций,
имеет смысл добиваться такого вида зашифрованного изображения, что автоматическими
методами сложно провести его связь с исходником. Т.е. например, гистограмма зашифрованного
никак не должна кореллировать с гистограммой исходника. Например, если порезать картинку
на блоки и переставить их местами, гистограмма никак не изменится. Если канал инвертнуть,
гистограмма его просто отзеркалится. Поэтому, повторю, интересно услышать тех, кто
работал с FFT (быстрое преобразование Фурье) и вейвлетами.    


Ответы

Ответ 1



UPD [2013-02-07] Новый алгоритм «Chan» Не оставляет меня в покое эта тема. Написал новый алгоритм шифрования. Алгоритм работает очень долго, посему просьба не тестировать на больших картинках и набраться терпения: кнопки «Encrypt» и «Decrypt» понимают с первого раза, не стреляйте в них очередью. Примеры: Оригинал Зашифрованное изображение Расшифрованное изображение Расшифрованное с неверным паролем Основан на преобразовании цветов пикселей, но работает весьма неплохо, на мой взгляд. Недостатки: шифрование слишком слабое; перебо́ров за 10–20 можно подобрать такой пароль, который даст представление о содержании изображения (хотя цвета могут быть искажены) JPEG-компрессия сказывается на расшифрованном изображении (появляется рябь), поэтому на тестовой странице я выдаю результат в PNG очень много коллизий ключей очень медленно, необходимо оптимизировать Положительные черты: устойчивость к любым трансформациям (кроме цвета), будь то поворот/разворот или даже посторонние данные, например: Исходное: зашифрованная ранее картинка находится на нормальной (к примеру, фото плаката с изображением зашифрованной фотографии) Расшифрованное: зашифрованная картинка «распаковалась» Есть идея добавить свойство (bool) loseless, в зависимости от которого алгоритм и, соответственно, результат, будет меняться: при loseless = on – будет работать как сейчас; при loseless = off – шифрование будет значительно надежнее, но с потерей двух цветов: 0xFFFFFF станет 0xFFFFFE, а 0x000000 – 0x000001 (то есть, и в зашифрованном и в дешифрованном абс. белый и абс. черный будут отсутствовать). Или можно не заморачиваться и прописать loseless = off как единственный вариант. @sergiks, а у тебя как дела с этой задачей? ----------------------------------------------------------------------------------------- UPD [2013-01-30] Новая версия алгоритма «мозаика» Доделал вот прототип: http://image.lotoflot.com/mosaic_crypt.php Выдерживает повороты кратные 90 град., но с изменением размера беда: очень сильные искажения после дешифровки. Удачный пример Оригинал Зашифрованное изображение Расшифрованное изображение Лавина хорошая благодаря md5. Ключ внутри функции раскладывается на составляющие, каждый из которых хешируется. Для нормальной работы нужен массивный набор данных (а не 2-3 символа), поэтому решил не изобретать и подключить md5. Параметр Pieces определяет, на сколько кусков в обоих направлениях (X, Y) будет порезана картинка. Чем больше значение, тем больше блоков. Обычно лучше устанавливать значение в диапазоне 10—30 для картинок размера 300—2000 px. Я как-то давно на PHP начал писать класс-прослойку для GD. Так вот эти функции шифровки/дешифровки я запихнул в класс расширения этой прослойки, так что код будет слегка запутанным. Но если все же заинтересует, могу поделиться.

Ответ 2



Конкретных алгоритмов не скажу, но наверняка они есть. Наверное надо копать в сторону именно графической шифровки, к примеру поставить точки которые организуют квадрат чтобы уйти от зависимости от ориентации картинки, и внутри этого генерировать данные которые представляют исходную картинку. самое тупое - например точка 2x2 или 3x3 - 1, нет такой точки - 0. Можно наверное более сложно придумать - яркая точка начала, от неё рисовать примитивы - линия под углом - определённый набор битов (например угол задаётся исходным куском битов, цвет каждой следующей линии - следующая пачка данных) ну и т.д. Ваша задача - графически представить нужные вам данные - как - простор для фантазии. Так же можно использовать тупо набор известных вам однозначно обратимых фильтрах (сдвиги, повороты и т.д.) которые Вы применяете в определённом порядке, а для расшифровки - в обратном (например картинку сдвигает на 10 пикселов, поворачиваете на 15 градусов, сдвигаете на 3 пиксела вниз, инвертируете цвета, сдвигаете цвета на 20, меняете каналы местами и т.д.).

Ответ 3



Я бы посоветовал копать в сторону стеганографических трюков с изображениями, когда модифицируется наименее значимый бит (LSB) пикселя или что-то подобное. Обзор некоторых из таких методов здесь Наиболее перспективный для вас метод на мой взгляд это redundant pattern encoding, то есть когда шифровка размещается не по всему изображению, а дублируется в нескольких частях (pattern), так что при обрезке изображения останутся кодированные куски из которых можно будет восстановить сообщение. Теперь рассмотрим способ восстановления исходного шифросообщения после изменения размера изображения (паттерна). Здесь может помочь один из алгоритмов избыточного кодирования, например метод Хамминга или что-то подобное. Благо таких способов довольно много, надо просто задаться процентом сколько бит надо уметь восстанавливать из потерянных - это чуть ли не целая отрасль математики.

Ответ 4



Почему вы так быстро отказались от шифрование данных каждого пикселя независимо друг от друга? Изменения размеров и артефакты сжатия такому методу не страшны. Я, обдумывая ту же идею, склонен предполагать, что можно найти достаточно устойчивый (к взлому) шифр. Но так как в области криптографии моих знаний ноль, с этим вопросом я и пришёл сюда.

Что лучше, выделить много памяти или много указателей на память?

#графы #память #указатели #cpp


Есть задача, нужно создать взвешенный граф в виде матрицы смежности. Нужен int-массив,
который будет одновременно означать и связь и ее "цену". Ну так вот, весь прикол в
том, что (в реале) не все элементы будут связаны друг с другом, а значит некоторый
объем памяти лежать без дела => умнее будет создать массив указателей, и те элементы
которые не используются будут = NULL, т.е. память занимать не будет...Но опять же я
занимаю много памяти под адреса. Что же лучше? Вообще, указатели же имеет "вес"?    


Ответы

Ответ 1



У Кнута в первом томе есть пример, как можно хранить такие матрицы, достаточно экономно и с возможностью быстро индексировать. Для хранения одного элемента используется структура struct Node { int row; // это и следующее поле можно и исключить int col; // ниже будет описана замена. Node * next; Node * bottom; Data data; // а это одно (или несколько полей), где собственно хранятся данные. } Поэтому получается, что на каждый элемент нужно два дополнительных указателя (8-16 байт) и, возможно, ещё 4-8-16 байт для ускорения работы (и возможно отладки). Индексы также не обязательно хранить в int. Вполне может оказаться, что short может оказаться достаточным. Данные хранятся следующем виде. Каждая нода хранит ссылку на следующую ноду в строке и следующую ноду в столбце. Если в данной строке/столбце больше правее/ниже нет нод, то хранится ссылка на самую верхнюю/левую, то есть, зацикливаем. Если данных 4 байта, и система 32 битная, то уже при заполнении менее, чем на треть, уже будет выигрыш. Как работать с такой матрицей Заводим один вектор, который будет хранить указатели на списки строк. Что бы найти какой-то элемент по индексу, нужно просто в векторе взять нужную строку, а потом просто пройтись по элементам до нахождения нужного. Если нужно посчитать сумму по строке - также не сложно - просто нужно получить строку и суммировать элементы. Нулевых нет, но они не меняют картины. Но если размерности матрицы большие ( к примеру 100000 на 100000), то есть смысл просто сделать список всех существующий строк и столбцов. Подсуммировав все, получаем такое struct Node { int row; int col; Node * next; Node * bottom; Data data; // а это одно (или несколько полей), где собственно хранятся данные. } std::list rows; std::list cols; // дальше алгоритмы словесные. Node * get(int i, int j) { // Пройтись циклом по rows до нужной строки. // Если такой строки нет, значит элемент нулевой // иначе проходим по строке (используя указатель next), ищем нужный элемент. } // Добавление элемента. void add(Node * n) { // Находим нужную строку. Если строки в списке rows нет, нужно вставить. // добавляем этот элемент в эту строку. // если строка есть, то проходим циклом, что бы найти место вставки, // поправляем два указателя // аналогичное проделываем с столбцами. } // удаление аналогично. Возможно я немного модифицировал идею Кнута, поэтому настойчиво рекомендую взять его книгу и поискать (думаю легко по заголовкам найдется, первый том). Также в книге рекомендуется создать свой пул объектов, если предполагается, что данные будут часто модифицироваться. Ещё раз напомню, данный алгоритм будет очень эффективным, если кол-во элементов значительно ( в сотни раз) меньше общей вместимости матрицы.

Ответ 2



Два стандартных представления связей в графе это 1) матрица, где элемент (i,j) указывает есть ли связь между i-ой и j-ой вершинами и 2) массив списков, где i-ый элемент массива содержит список связный с ним вершин. Если связи (i,j) в графе нет, то в i-ом списке не будет элемента j. Оба подхода имеют плюсы и минусы. Плюс второго подхода в экономии памяти.

Ответ 3



Это называется сильно разреженными матрицами, рассматривалось, к примеру, Кнутом. Есть давнишняя книжка Писанецки строго на эту тему

Ответ 4



Просто создайте указатель на указатель ;) **

Найти суммарный размер всех регулярных файлов в каталоге, рекурсивно обходя все подкаталоги

#linux #файловая_система


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

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

1) Можно ли как-то решить исходную задачу средствами bash (команда ls и так далее)? 

2) Какие могут быть "крайние" случаи, на которых программу стоит протестировать?
Ну кроме пустого каталога.
    


Ответы

Ответ 1



Чтобы подсчитать суммарный размер обычных файлов (S_ISREG) в заданном дереве директорий, пропуская все symlinks, на Питоне: #!/usr/bin/env python3 import os from contextlib import suppress def get_tree_size_scandir(path): """Return total size of all regular files in directory tree at *path*.""" size = 0 for entry in os.scandir(path): with suppress(OSError): # ignore errors for entry & its children if entry.is_dir(follow_symlinks=False): # directory size += get_tree_size_scandir(entry) elif entry.is_file(follow_symlinks=False): # regular file size += entry.stat(follow_symlinks=False).st_size return size if __name__ == "__main__": import sys print(get_tree_size_scandir(sys.argv[1])) Пример: $ ./get-tree-size /usr 7217750930 Вывод показывает, что общий размер всех обычных файлов в /usr директории, около 7 GB. Python, listdir() Для проверки, я реализовал get_tree_size(), не используя os.scandir(): #!/usr/bin/env python3 import os import stat from contextlib import suppress _dir_flags = os.O_RDONLY def get_tree_size_listdir_fd(fd): """Return total size of all regular files in directory tree at *fd*.""" size = 0 for name in os.listdir(fd): with suppress(OSError): # ignore errors for entry & its children st = os.lstat(name, dir_fd=fd) # don't follow symlinks if stat.S_ISDIR(st.st_mode): # directory top_fd = os.open(name, _dir_flags, dir_fd=fd) try: size += get_tree_size_listdir_fd(top_fd) finally: os.close(top_fd) elif stat.S_ISREG(st.st_mode): # regular file size += st.st_size return size if __name__ == "__main__": import sys print(get_tree_size_listdir_fd(os.open(sys.argv[1], _dir_flags))) Результаты одинаковые в данном случае, но в общем случае они могут отличаться (например, os.listdir() возвращает список (сразу все имена), а os.scandir() возвращает итератор, поэтому os.scandir() может учесть больше имен, а os.listdir() пропустит всю директорию, если произойдёт ошибка c получением хотя бы одного имени в директории). Код для примеров адаптирован из Python issue: PEP 471 implementation: os.scandir() directory scanning function. Внимание: размер файла и занимаемое место на диске могут отличаться. Bash, du 1) Можно ли как-то решить исходную задачу средствами bash (команда ls и так далее)? Можно, конечно, но результаты могут немного отличаться (см. тестовые случаи). Если нужны точные результаты, то несложно написать программу, с точным необходимым поведением как показывают примеры кода на Питоне выше. du -bs . возвращает значение, которое превышает суммарные размеры файлов, например: $ ls -l total 8 -rw-rw-r-- 1 me me 820 Oct 25 22:59 get_tree_size_fd.py -rw-rw-r-- 1 me me 631 Oct 25 23:07 get_tree_size_scandir.py Суммарный размер: 820 + 631 == 1451: $ python3 get_tree_size_fd.py . 1451 что ожидаемо (Питон возвращает правильный результат), но du возвращает неверный результат: $ du -bs . 5547 . -b опция уже включает в себя --apparent-size (то есть результат уже не отражает занимаемое место на диске -- как и хотелось). @avp упомянул: du считает также размеры всех каталогов, которые они занимают на диске. Что подтверждается экспериментами: $ mkdir dir # создаём пустую директорию $ python3 get_tree_size_fd.py . # результат ожидаемо не изменился 1451 $ du -bs . 9643 . Результат для du стал больше, что согласуется c комментарием @avp. Если выключить --apparent-size, то du возвращает занимаемое место на диске: $ du -s -B1 . 16384 . Что ещё больше отличается от суммарного размера файлов. 2) Какие могут быть "крайние" случаи, на которых программу стоит протестировать? Ну кроме пустого каталога. Потестировать имена файлов, директорий, начинающихся на точку (.zshrc, .ssh). Потестировать на директории со специальными файлами, например, /dev директория может содержать /dev/sda файл, который не является обычным файлом (это диск -- блочное устройство S_ISBLK) или FIFO (S_ISFIFO) (можно создать командой: mkfifo /tmp/named_pipe). Или потестировать на директориях с нечитаемыми записями, например, из-за недостатка прав доступа (командой chmod можно подготовить). И, конечно, потестировать на директориях, содержащих символические ссылки (S_ISLNK), которые ссылаются как на обычные файлы так и на другие директории. Для проверки надёжности, можно сгенерировать глубоко-вложенные директории с именами записей разной длины, состоящих из произвольных байтов (всё кроме слэша / и нулевого байта '\0', если локальная система не вносит своих ограничений). С, nftw() Для сравнения, можно посмотреть на примеры кода на С/С++. Для рекурсивного обхода дерева директорий, можно nftw() использовать: #define _XOPEN_SOURCE 500 #include #include #include #include int main(int argc, char* argv[]) { if (argc > 2) { fputs("Usage: get-tree-size []\n", stderr); exit(2); } int flags = FTW_PHYS; // do not follow symlinks int nopenfd = 100; // maximum number of directories that nftw() may hold // open simultaneously uintmax_t size = 0; int visit_path(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) // nested function -- gcc extension { if (typeflag == FTW_F) // regular file size += sb->st_size; return 0; // continue }; const char *dirpath = (argc == 2) ? argv[1] : "."; // default is the current working directory if (nftw(dirpath, visit_path, nopenfd, flags)) exit(1); return printf("%" PRIuMAX "\n", size) < 0; } Пример: $ gcc get-tree-size-ftw.c && ./a.out Чтобы передать дополнительные переменные (size) в visit_path() обратный вызов, gcc позволяет использовать вложенные функции. В общем случае, для более тонкого контроля обхода дерева директорий, к примеру, чтобы пропустить всё внутри .git и других подобных директорий, есть fts_open() API, добавив fnmatch() API, можно реализовать аналог команды: $ find -name .git -prune -o -type f -name \*.txt -print С, readdir() При желании, можно руками с помощью readdir() рекурсивный обход директории выполнить: #define _XOPEN_SOURCE 700 #include #include #include #include #include #include static uintmax_t get_tree_size_readdir(int dirfd) { DIR *dirp; if (!(dirp = fdopendir(dirfd))) return 0; //NOTE: ignore errors from open,openat,fdopendir here uintmax_t size = 0; for (struct dirent* entry; (entry = readdir(dirp)); ) { // skip ".", ".." entries size_t namelen = strlen(entry->d_name); if (entry->d_name[0] == '.' // 1 <= namelen <= NAME_MAX && (namelen == 1 || (entry->d_name[1] == '.' && namelen == 2))) continue; struct stat statbuf; if(fstatat(dirfd, entry->d_name, &statbuf, AT_SYMLINK_NOFOLLOW)) continue; //NOTE: ignore errors if (S_ISREG(statbuf.st_mode)) // count size of regular files only size += statbuf.st_size; else if (S_ISDIR(statbuf.st_mode)) { // count the size in subdirectories int fd = openat(dirfd, entry->d_name, O_RDONLY); size += get_tree_size_readdir(fd); //NOTE: if nested deeply; it may exceed `ulimit -n` close(fd); } } //NOTE: ignore readdir() errors closedir(dirp); //NOTE: let the caller to invoke rewinddir() if necessary return size; } директория задаётся с помощью dirfd это позволяет избежать каждый раз от корня все пути просматривать, так как entry->d_name содержит только последнюю часть пути. В противном случае пришлось бы создавать путь от входной (с которой вызов начался) директории каждый раз, прежде чем путь в stat() передать специальные имена "." и ".." явно пропускаются используется AT_SYMLINK_NOFOLLOW, чтобы не следовать по символическим ссылкам, чтобы получить информацию о самой записи (entry) ошибки по индивидуальным записям явно игнорируются #include #include int main(int argc, char* argv[]) { if (argc > 2) { fputs("Usage: get-tree-size []\n", stderr); exit(2); } const char *dirpath = (argc == 2) ? argv[1] : "."; // default is the current working directory return printf("%" PRIuMAX "\n", get_tree_size_readdir(open(dirpath, O_RDONLY))) < 0; } Пример: $ gcc get-tree-size-readdir.c && ./a.out С++, В C++ рекурсивно обойти дерево директорий можно используя библиотеку: #include #include #include namespace fs = std::experimental::filesystem; int main(int argc, char* argv[]) { if (argc > 2) { std::cerr << "Usage: get-tree-size []\n"; std::exit(2); } uintmax_t size = 0; fs::path dirpath = (argc == 2) ? argv[1] : fs::current_path(); for (auto&& entry : fs::recursive_directory_iterator( dirpath, fs::directory_options::skip_permission_denied)) { std::error_code ignore_error; if (fs::is_regular_file(fs::symlink_status(entry, ignore_error))) { size += fs::file_size(entry); } } std::cout << size << '\n'; } символические ссылки, указывающие как на директории так и на обычные файлы пропускаются "." и ".." записи также пропускаются ошибки доступа и ошибки при чтении статуса файла игнорируются, но цикл может исключения выбрасывать в случае других ошибок. Пример: $ g++ -std=c++11 *.cc -lstdc++fs && ./a.out (для ). В С++17 можно просто #include использовать. Библиотека также доступна как #include : $ sudo apt-get install libboost-{file,}system-dev # install Boost on Ubuntu $ g++ -std=c++11 *.cc -lboost_{file,}system && ./a.out Все варианты кода для подсчёта суммарного размера выдают один и тот же результат в обычных случаях, но возможны отличия, когда исключительные ситуации по разному обрабатываются. Производительность ограничивается скоростью диска. Если мета-данные уже закэшированы в памяти, то вариант с медленнее, чем nftw() и readdir(), которые похоже себя ведут. код только немного медленнее кода на Питоне.

Ответ 2



du -s /your/path/* Где /your/path/ - путь к папке. Размер указывается в килобайтах. Если нужно в байтах, то: du -sb /your/path/*

Как на яндекс карте показать районы города?

#javascript #веб_программирование #yandex_maps_api #яндекс #карты


Есть задача показать административные районы города на яндекс картах. 
При этом каждый район должен иметь свой цвет и прозрачность.
Например, здесь отображается один район города:
на Яндекс Карте

Нужно показать все( или несколько) районы(ов) города и иметь возможность задать им
цвет и прозрачность через API.
Подскажите, как это можно сделать?

UPD1. Есть идея сделать районы в виде полигонов. Тогда можно будет править их как
угодно. Но нужны координаты границ районов. Карта яндекса откуда же берет эти данные.
Вот как их получить?  

UPD2. Получен официальный ответ от тех поддержки Яндекс Карт.
"Средствами АПИ Яндекс карт сделать это нельзя". Так что испольуем OSM.
    


Ответы

Ответ 1



Общий план действий такой: ymaps.ready(function() { // 0. Создаем карту, например так: var map, regionName = "Краснодар, Западный округ", center = [38.943216, 45.033266], zoom = 11; map = new ymaps.Map('yamap', { center: center, zoom: zoom, controls: [] }); // 1. Запрашиваем через геокодер район (у Яндекса этой возможности пока нет, придется пользоваться OSM) var url = "http://nominatim.openstreetmap.org/search"; $.getJSON(url, {q: regionName, format: "json", polygon_geojson: 1}) .then(function (data) { $.each(data, function(ix, place) { if ("relation" == place.osm_type) { // 2. Создаем полигон с нужными координатами var p = new ymaps.Polygon(place.geojson.coordinates); // 3. Добавляем полигон на карту map.geoObjects.add(p); } }); }, function (err) { console.log(err); }); }); Этап 1, в качестве примера, приведен с использованием jQuery. Этап 2 скрывает небольшую проблему. OSM возвращает координаты в порядке (долгота, широта), Яндекс работает по-умолчанию с порядком (широта, долгота). Чтобы это поменять нужно указать порядок при подключении API Также на этапе 2 можно добавить "по вкусу" цвет фона, обводку, прозрачность и многое другое см. Polygon

Как скачать пакет с nuget.org и извлечь из него сборки?

#net #nuget


В ответах и документации часто вижу следующее:  


подключите к проекту пакет ...  
скачайте пакет ...  
Install-Package ...  


Моя IDE не поддерживает работу с nuget.org.
Как скачать пакет вручную и как извлечь из него сборки? 
    


Ответы

Ответ 1



Например, требуется пакет Newtonsoft.Json (версия 7.0.1). Чтобы скачать его с nuget.org, надо перейти по ссылке https://www.nuget.org/api/v2/package/Newtonsoft.Json/7.0.1 Полученный файл newtonsoft.json.7.0.1.nupkg - это zip-архив. Например, в Windows Explorer его можно переименовать, заменить .nupkg на .zip, и открыть. В \lib находятся \net20, \net35, и т.д. Если для вашего проекта требуется сборка для .NET 4.5, то в \net45 находится соответствующий файл Newtonsoft.Json.dll

Ответ 2



Официальный метод, судя по всему, такой: Если ещё нет в системе, скачать https://www.nuget.org/nuget.exe и поместить где угодно (лучше в %PATH%). Им можно пользоваться. Например: D:\Test\NugetTest\3rdparty>..\nuget.exe install rx-main Attempting to resolve dependency 'Rx-Interfaces (= 2.2.5)'. Attempting to resolve dependency 'Rx-Core (= 2.2.5)'. Attempting to resolve dependency 'Rx-Linq (= 2.2.5)'. Attempting to resolve dependency 'Rx-PlatformServices (= 2.2.5)'. Installing 'Rx-Interfaces 2.2.5'. Successfully installed 'Rx-Interfaces 2.2.5'. Installing 'Rx-Core 2.2.5'. Successfully installed 'Rx-Core 2.2.5'. Installing 'Rx-Linq 2.2.5'. Successfully installed 'Rx-Linq 2.2.5'. Installing 'Rx-PlatformServices 2.2.5'. Successfully installed 'Rx-PlatformServices 2.2.5'. Installing 'Rx-Main 2.2.5'. Successfully installed 'Rx-Main 2.2.5'. При таком методе у вас появятся к каталоге 3rdparty подкаталоги, соответствующие инсталлированным пакетам. Добавить их в ваш проект вам придётся самостоятельно: nuget не знает из коробки, как добавиться в вашу структуру проекта. Литература: Nuget command line reference Installing NuGet packages directly from the command line

Проверить на PHP введенное число на соответствие 1, 10, 100, …, 10 000 000

#php


Как математически проверить пользовательский ввод: соответствует ли число одному
из заданной последовательности: 1, 10, 100, ..., 10 000 000 на PHP. Проверить с помощью
preg_match() - не проблема, но как-то не правильно проверять числа функцией, предназначенной
для проверки строк.

if (!preg_match('/^10{0,7}$/', $_GET['insert_number'])) {
    echo 'число должно быть 1, 10, 100, 1000 и т.д.';
}


Как назвать последовательность чисел 1, 10, ..., чтобы сообщение об ошибке было более
информативным?
    


Ответы

Ответ 1



Всего 8 вариантов, отчего бы не захардкодить? =) in_array($userInput, [1,10,100,1000,10000,100000,1000000,10000000]); Ещё странный вариант: смотреть на валидные числа как на двоичные – там ведь только единицы и нули допустимы, длиной не более байта (8 позиций). function is10x($userInput) { $input = trim($userInput); // убрать пробелы по краям и считать строкой $binStr = sprintf('%b', intval($input,2)); // перевести в двоичное число и в строку единиц и нулей if( $binStr !== $input) return FALSE; // должно пережить двойной перевод без потерь return array_sum(str_split($binStr)) === 1; // должно содержать только одну 1 } Тесты Сообщение: «Число должно начинаться с единицы и, кроме неё, может содержать только нули»

Ответ 2



Можно проверить через логарифм, но при этом нужно учитывать что функции log() и log10() всегда возвращают число типа float. Можно применить такой хак: $y = 10; $x = pow((string)log10($y),1); результат работы log10() перегоняем в строку и скармливаем функции pow(), которая выдает int или float в зависимости от полученного результата if (is_float($x) || $y < 1) echo "Число не удовлетворяет условию"; var_dump($x);

Ответ 3



Написал на Java, т.к не пользуюсь PHP //Проверка на то, является ли число одной из степеней 10: public boolean is10(int n) { if(n==1) return true; else if(n<1) return false; return n%10==0 && is10(n/10); } Ну и попытался конвертировать на PHP: function is10($n): boolean { if ($n == 1) { return true; } elseif ($n < 1) { return false; } return $n % 10 == 0 && is10($n / 10); }

Ответ 4



нельзя ли сделать простым циклом? так как максимальное число 10 000 000 // Функция проверки цисла function proveritChislo($number){ // Если число больше 1 можно работать while ( $number > 1 ) { // Если не заканчивается на 0, значит не правильно $ostatok = $number % 10; if ($ostatok != 0) { return FALSE; } // убираем последний 0 $number = ($number - $ostatok) / 10; } return $number == 1; }

Ответ 5



$test="1".str_repeat("0",strlen($input)-1); if($test % $unput != 0) echo "Ошибка бла-бла-бла";

Что такое AIDL и для чего он нужен?

#java #android #android_sdk #android_service


Что такое AIDL и для чего он нужен? Понятно, что он связан с сервисами, но что конкретно
он делает мне не понятно. Как я понял из документации AIDL нужен для взаимодействия
сервисов (возможно, что я не прав). Приведите, пожалуйста, пример использования и код. 
    


Ответы

Ответ 1



AIDL В буквальном переводе – язык описания интерфейсов Android. Используется для описания композиции и декомпозиции Java объектов в примитивы ОС для непосредственно передачи между процесами. AIDL файлы очень похожи на стандартные интерфейсы в java за исключением: Импортировать нужно даже те aidl файлы, которые находятся в том же пакете. Ключевое слово oneway в декларации void метода означает что метод будет вызван асинхронно (клиент не дожидается его выполнения). Использовать можно только примитивы, String, List и Parcelable классы, объявленные в других aidl файлах. С помощью AIDL автоматически генерируется java код для генерации stub’ов. Подробнее: тут

В чём опасность использования for .. in для объекта или массива?

#javascript #javascript_faq


В чём опасность использования for .. in для объекта или массива?
    


Ответы

Ответ 1



Как написано в mdn Проход по массиву и for...in Замечание: for...in не следует использовать для Array, где важен порядок индексов. Индексы массива - перечисляемые свойства с целочисленными именами, а в остальном аналогичны свойствам объектов. Нет гарантии, что for...in будет возвращать индексы в нужном порядке и вернёт все перечисляемые свойства, включая имеющие не целочисленные имена и наследуемые. Поэтому порядок прохода зависит от реализации, проход по массиву может не произойти в правильном порядке. Следовательно лучше с числовыми индексами использовать циклы for, Array.prototype.forEach() или for...of, когда проходим по массивам, где важен порядок доступа к свойствам.

Ответ 2



Для объекта: Перебираются все ключи, в том числе унаследованные: var obj = {a: 9}; Object.prototype.myAwfulThing = 8; for (var key in obj) { console.log(key); } При этом унаследованное свойство может быть добавлено какой-то библиотекой. Поэтому рекомендуется делать проверку на наличие свойства в самом объекте: var obj = {a: 9}; Object.prototype.myAwfulThing = 8; for (var key in obj) { if (obj.hasOwnProperty(key)) { console.log(key); } } Даже если ты на 100% уверен, что унаследованных свойств нет, библиотеками никакими не пользуешься и всё замечательно работает, браузер-то об этом не знает. Браузер оптимизирует только случай, когда есть проверка на hasOwnProperty. Что-то этот пункт не захотел подтверждаться экспериментально. Для массива: Будут перебираться не только индексы, но и другие свойства. Если вместо массива окажется массивоподобный объект, то может попасться свойство length. Если подключены полифилы для массивов (что весьма вероятно), в браузерах, не умеющих делать скрытые свойства, в перебор попадут все эти функции. Перебираются только индексы, которые есть в массиве. Если элемент массива удалялся через delete, либо добавление в массив происходило по индексу после его конца, то отсутствующие индексы будут пропущены. Но порядок перебираемых индексов будет верным. var a = [undefined, , 4]; a[7] = undefined; for (var i in a) { // 0 2 7 console.log(i); } Перебор массива через for in по производительности уступает нормальному циклу в десятки раз. ES6 Для перебора элементов массива (значений, не индексов!) ES6 вводит цикл for of: var a = [undefined, , 4]; a[7] = undefined; for (var x of a) { console.log(x); } 2 раза выводится undefined, затем 4 и ещё 5 раз undefined.

Аналог Photoshop для Ubuntu

#ubuntu #веб_дизайн #photoshop #поиск_программ


Какой есть аналог Photoshop для Ubuntu, главное чтоб мог открывать psd и работать
с слоями. Сейчас использую в качестве альтернативы assets.adobe.com, но с 28,06 самая
главная функция Extract отключится
    


Ответы

Ответ 1



Аналогом фотошопа на Ubuntu является GIMP. Само собой, что к некоторым вещам нужно привыкнуть: чего-то в нем нет, что-то сделано иначе. Но это не фотошоп - это аналогичная программа. Как и Ubuntu - это не Windows - сравнивать бессмысленно. P.S.: Как бессмысленно сравнение и по цене.

Ответ 2



Есть пакет GIMP Photoshop Tweaks (под лицензией GPLv3), он допиливает gimp до состояния фотошопа: интерфейс, горячие клавиши и расположение окон и вкладок. Я особой разницы не заметил, все как в cs6 только бесплатно и работает шустрее.

Ответ 3



Gimp полностью всё умеет из того, что Вам нужно. По интерфейсу - очень похож на Photoshop. Всегда есть много мануалов и видео уроков/подсказок

Ответ 4



Можно поставить VirtualBox, а на него винду и фотошоп. По идее, если комп современный, то снижения производительности вы не заметите при работе с виртуалкой....

Ответ 5



Поставьте фотошоп на wine и будет вам счастье

Сколько потоков нужно для чтения файлов с диска?

#java #многопоточность #файлы


Имеется 400,000 xml-файлов. Вес большей части не превышает 2КБ. Java-приложение должно
считать их с диска, обработать (сейчас используется stax парсер) и загрузить в различные
коллекции.

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



Дополнено:

@Arhad @KoVadim @Monk если запускать программу впервые (т.е. warmup'a нет), то у
меня этот процесс занимает аж целый час, на других машинах - не больше 15 минут. После
нескольких запусков у меня тоже где-то 15 минут обработка занимает. Вчера попробовал
forkjoinpool (каждая папка уходит в отдельный тред) и fixedthreadpool (просто скидываю
подряд все файлы в виде runnable-тасков) - толку ноль.

Выставлял 4 нити (столько ядер у процессора). Может можно как-то увеличить количество
единоразовой подачи информации с диска в память, файлы ведь дефрагментированы, должны
подряд идти непосредственно на носителе, если я правильно понимаю.

По поводу разделения логики: думал об этом в самом начале. Но вряд ли это можно применить
к stax парсеру.
    


Ответы

Ответ 1



Если кратко, то универсального ответа на данный вопрос не существует. Вооружитесь профилировщиком и ищите максимум производительности среди различного количества одновременно открываемых файлов. Дело в том, что: с одной стороны, HDD и SSD не могут быть опрошены одновременно в несколько потоков, даже если эти потоки принадлежат разным процессам; но с другой стороны, операционная система как правило делает чтение на упреждение в буфер, размещаемый в незанятой области ОЗУ. Однако предсказать удачность подобного кэширования практически невозможно из-за совокупности огромного количества постоянно меняющихся факторов.

Ответ 2



Разделяйте логику. Грузите в одном потоке файлы, в другом - обрабатывайте загруженные. Диск не будет простаивать, пока идёт обработка, как если бы вы работали в одном потоке, но и не будет пытаться в несколько потоков загружать файлы, что редко дает толк без низкоуровневой обработки.

Ответ 3



Много потоков какбы и не есть хорошо. 1 поток тоже не есть хорошо. У вас должна быть реализована нейкая системка, типо нейкая пара потоков читает(тоесть ожидает пока операционная система не предоставит данные с жесткого) 2.а вторая пара уже работает с парой данных которые предоставили из 1 потока. (но у вас еще декодинг да, думаю его в первую пару прикрепить).

Ключевое слово inline

#cpp


Почему библиотечные функции часто имеют спецификатор inline, а в "обычном" коде его
не встретишь?
    


Ответы

Ответ 1



Спецификатор inline не означает, что функция будет встроена в точке вызова вместо реального вызова. Такими оптимизациями на текущий момент заведует компилятор и только он, он может встроить или не встроить любую функцию, без всякой связи с наличием или отсутствием inline. Реальный смысл inline такой: сообщить компоновщику, что функции с одним именем, которые он видит в разных единицах трансляции — это одна и та же функция, и не нужно выдавать ошибку множественного определения. Таким образом, при помощи inline вы можете определять функцию в header'е. Заметьте, что методы классов, определённые внутри класса, имеют (неявный) inline. Библиотечные функции содержат inline для того, чтобы можно было не определять тело функции в cpp-файле, при этом библиотека таким образом сможет вовсе не содержать файлов с имплементацией.

Ответ 2



Наверное, зависит от того, чей код смотрите. Я довольно часто пишу static inline ..., когда хочу показать (прежде всего другим программистам, для компилятора inline совсем необязательное слово, просто hint), что из соображений эффективности, желал бы видеть этот код вставляемым по месту использования (аналогично коду, определяемому в #define), но одновременно хотел бы, чтобы он был свободен от побочных эффектов расширения аргументов макро (из общих соображений возможных вариантов вызова).

Ответ 3



Определитель inline указывает компилятору, чтобы тот вставлял код функции в место, откуда она вызывается. Например inline int quadrat(int x) { return x*x; } int main() { int y = quadrat(2); return 0; } Этот код будет скомпилирован в: int main() { int y = 2*2; return 0; } Как правило, указать функции определитель inline можно, только если тело функции определено в заголовочном файле (.h). Если тело функции определено в файле .c, то компилятор проигнорирует этот определитель, и функция будет скомпилирована как обычная.

Принудительный вызов base C#

#c_sharp #ооп #наследование


Какая в  C# есть возможность для принудительного вызова функции базового класса 
в функции наследника

Пример:

class A
{
    public virtual void F(){...}
}

class B : A
{
    public override void F()
    {
       base.F();//<--- должна быть эта строка! Иначе ,
                //выкинуть ошибку, к примеру. 
        ...
    }
}


Спасибо!
    


Ответы

Ответ 1



Можно сделать так: порядок вызова определяем в родителе, а наследников обязуем переопределить их часть. Если эта часть необязательная, то можно ослабить условие, и сделать метод virtual вместо abstract. class A { public void F() { // базовый код FInternal(); } protected abstract void FInternal(); // более мягкий вариант //protected virtual void FInternal() //{ //} } class B : A { protected override void FInternal() { ... } }

Ответ 2



Наследованием вы не добьетесь. Сделайте из базового класса сервис, которому передавайте клиентский класс, чтобы он находился под управлением сервиса: interface IClient() { void F(); } class Service : IClient { public void Execute(IClient c) { F(); c.F(); } public void F() { ... } };

jQuery: удалить все внутренние тэги, кроме одного указанного

#javascript #html #jquery


Как можно с помощью jQuery удалить все тэги внутри контейнера, кроме одного указанного?
Например, как можно удалить из тэга с классом .container всё, кроме div.main?



header
main
aside


Ответы

Ответ 1



$('.container').children().not('.main').remove();
header
main
aside


Ответ 2



css вариант .container *:not(.main){ display: none; }
header
main
aside


Как сделать рваные края в ImageMagick?

#imagemagick


Нужно сделать рваные края на картинке, пример есть тут. Но сделать надо в ImageMagick
и независимо от того, какого размера изображение. Подскажите, как это можно реализовать.
    


Ответы

Ответ 1



1. bordereffects Эффект, который понадобился ув-му автору вопроса, например, в Greenshot называется Torn edge. Его можно добиться и при помощи нативных команд ImageMagick, см. пример на официальном сайте (к сожалению, он там только один). Однако писать придётся многовато. На мой взгляд, намного проще использовать скрипт для ImageMagick, называемый bordereffects. Да, на сайте с bordereffects присутствует огромное количество бесплатных скриптов — Fred's ImageMagick Scripts — упрощающих работу с ImageMagick. У пользователей Windows могут возникнуть проблемы с использованием скриптов, поскольку все они написаны под Linux/macOS. Как у меня получилось запустить bordereffects, см. в разделе 3. 2. Демонстрация 1. Ограничения в демонстрационных примерах демонстрируется простой запуск команд в Cygwin терминале, в примерах преобразование происходит только для одного изображения. 2. Torn edge Исходный файл SashaQueen.jpg: Эффект Torn edge в файле SashaMagic.jpg: bordereffects -s 25 -d 1 -c 10 -g 1 -p 1 SashaQueen.jpg SashaMagic.jpg Оптимальные значения опций различны в зависимости от размеров изображений. 3. Примеры опций bordereffects Значения опций, кроме той, о которой идёт речь, остаются такими же, как в примере с Torn edge. -d — density. При больших значениях (в примере -d 50) изображения будут выглядеть так: -g — granularity. При больших значениях (в примере -g 50) изображения будут выглядеть так: -c — curviness. При небольших значениях (в примере -с 1) изображения будут выглядеть так: Подробные описания команд и больше примеров смотрите на сайте bordereffects. 3. Запуск Fred's ImageMagick Scripts в Windows В Cygwin на примере bordereffects. Для остальных скриптов действия примерно те же. 1. Программно-аппаратное окружение Протестировано лично на Windows 10 64-bit Enterprise LTSB EN, ImageMagick 7.0.4-3 Q16 x64 2017-01-07, Cygwin 2.6.1, cyg-get 1.2.1. Для запуска в 64-битных Windows можно использовать и Bash для Windows, однако в Windows LTSB на момент написания данного сообщения Bash не поддерживается. 2. Установка и настройка Устанавливаем Cygwin и cyg-get. Скачиваем bordereffects с официального сайта в папку, которая есть в пользовательской переменной PATH или же добавляем папку с bordereffects в пользовательскую переменную PATH — это удобно делать через Rapid Environment Editor. Открываем файл bordereffects в любом продвинутом текстовом редакторе → делаем, включив поиск/замену регулярными выражениями замену \bconvert\b — magick, поскольку в Windows есть нативная команда convert, → делаем замену \bidentify\b — magick identify → сохраняем файл. 3. Работа в Cygwin Открываем терминал Cygwin — для запуска команд Cygwin нужен специализированный терминал, обычной консолью Windows не обойтись; я запускаю его ярлыком Cygwin64 Terminal из Wox. В терминале Cygwin перемещаемся в папку, где лежат изображения, которые необходимо преобразовать, → проверяем, что всё работает, запуском команды bordereffects, например, bordereffects SashaQueen.jpg SashaMagic.jpg. Если в консоли появляются сообщения, что какая-то команда из скрипта bordereffects не запускается, в предпочтительном для Вас терминале для Windows (уже не в терминале Cygwin) набираем команду cyg-get. Синтаксис: cyg-get firstpackage secondpackage thirdpackage. Например, после запуска bordereffects выяснилось, что у меня отсутствовала утилита bc → установил её командой cyg-get bc. При установке bc вручную с сайта GnuWin у меня возникали баги, связанные с этим интерпретатором, поэтому рекомендовал бы устанавливать недостающие команды через пакетный менеджер cyg-get.

Разница во времени на Java

#java #время #временная_зона


Как задать 2 даты и посмотреть сколько времени между ними прошло.   

Например: 

01.01.2000 10:10:10
02.03.2005 20:10:20


и получить в ответ: 1 день 2 месяца 5 лет 10 часов 0 минут 10 секунд  

И потом понадобится сортировка от самого большого времени к самому маленькому.
Пишу на Java 7.
    


Ответы

Ответ 1



Это легко сделать с помощью org.joda.time.Period private static String strDiff(DateTime from, DateTime to) { Period period = new Period(from, to, PeriodType.yearMonthDayTime()); return period.getYears() + "y " + period.getMonths() + "m " + period.getDays() + "d " + period.getHours() + "h " + period.getMinutes() + "min " + period.getSeconds() + "s" + ""; } public static void main(String[] args) { DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"); DateTime start = formatter.parseDateTime("2017-04-03 03:00:00"); DateTime end = formatter.parseDateTime("2017-04-11 03:00:00"); System.out.println(strDiff(start, end)); }

Ответ 2



Создайте два Date, потом возьмите из них время в миллисекундах и узнаете разницу. Затем парсите.

Почему при шифровании TLS используются именно простые числа?

#алгоритм #безопасность #ssl #шифрование #криптография


Почему при шифровании TLS, да и вообще в криптографии используются именно простые
числа? Почему бы не использовать любые? 
    


Ответы

Ответ 1



Одна причина в том, что легко умножить 2 большие простые числа, например 393050634124102232869567034555427371542904833 * 170141183460469231731687303715884105727 дает сразу 66874100049762646240147492397977579549553083399872470020691839934725993584071278591 (Python, < 0.2 секунд), no обратное сделать (разложить большое число на простые числа) практически не возможно - нет общего достаточно быстрого алгоритма (см. Алгоритмы факторизации.) Вообще это работа на несколько лет даже для супер компьютеров.

Ответ 2



TLS допускает использование различных протоколов шифрования и обмена ключей. Разные протоколы используют простые числа по совершенно различным причинам: RSA Один из самых популярных протоколов шифрования, RSA, основывается на том, что задача факторизации числа - разложение составного числа на простые множители (скорее всего), не разрешима с полиномиальной сложностью на обычных компьютерах (но разрешима за полиномиальное время на квантовых, криптоапокалипсис грядет). Т.е. если у вас есть два огромных простых числа p и q, то тот, кто знает только n = p * q, проведет достаточно много времени, пытаясь разложить n обратно на p и q. Естественно, есть оговорки, позволяющие отсечь известные субэкспоненциальные алгоритмы, например, p и q должны отличатся порядком хотя бы на пару разрядов, но в общем случае можно считать что большие p и q сделают решение задачи факторизации n дико долгим. При этом, найти два больших простых числа - достаточно легко. Так что использование больших простых чисел - это способ получить огромное и тяжело факторизируемое составное число. RSA описывает подбор/генерацию чисел e, d, n, таких, что для любого значения m будет справедливо: Способ генерации предполагает выбор n = p * q, e = 65,537 (или любому другому небольшому числу). Т.е. они находятся быстро. Пара (n, e) - это публичный ключ. Доказано, что если взять в качесте d результат решения уравнения ed = 1(mod ϕ(n)), то тройка (e, d, n) будет отвечать требованию выше. ϕ(n) - это функция Эйлера - равная количеству натуральных чисел, меньших n и взаимно простых с ним. Для ее нахождения нужно факторизовать n. Т.е. если вы знаете только (n, e), то поиск d решением этого уравнения займет вечность. Но при этом φ(p) = p − 1, φ(q) = q − 1. И для простых p и q: φ(n) = φ(pq) = (p − 1) * (q − 1). Так что вы берете два больших простых числа, быстро вычисляете φ(n) и n, получаете d из уравнения выше. Простые числа и φ(n) выбрасываете и никому не показываете. (n, d) - это ваш приватный ключ, и узнать его, зная только (n, e), ни у кого не получится за разумное время. После этого любой, у кого есть ваш публичный ключ может зашифровать для вас сообщение: А вот расшифровать его можете только вы: Из взаимозаменяемости e и d и одинаковости для шагов для шифрации/дешифрации следует второй способ применения RSA - только вы можете зашифровать известный текст так, что расшифровать его можно будет только с помощью публичного ключа. Если вы допишете к концу сообщения его чексумму, зашифрованную приватным ключом (получив при этом "электронную подпись"), то любой может посчитать ту же чексумму, "расшифровать" подпись, и сравнить два значения. Если они совпадут - значит сообщение дошло без изменений, и отправили его именно вы. Diffie-Hellman Протокол обмена ключами DH полагается не на сложность факторизации, а на сложность решения задачи дискретного логарифмирования. Он основан на том, что нельзя быстро вычислить ключ зная только ga, gb, g и p. Но при этом он легко позволяет сторонам вычислить этот общий ключ, переслав по открытому каналу ga, gb, если одна сторона придумает свое секретное a, а вторая - свое секретное b. Elliptic Curve Diffie-Hellman Даже основы эллиптической криптографии в один пост SO не влезут, так что стоит только упомянуть, что ECDHE так же полагается не на сложность факторизации, а на сложность решения задачи дискретного логарифмирования. Для задачи дискретного логарифмирования есть субэкспоненциальный алгоритм Полига-Хеллмана, позволяющий свести решение проблемы для n точек к подзадачам для множителей n - p1, p2, p3, p4. Соответственно, количество точек кривой выбирают таким, чтобы оно делилось на какое-то большое простое число p, сравнимое по длине с n. Т.е. простые числа в ECDHE используются только косвенно, в качестве "ограничителя простоты". Из этих же соображений значения p, g в DH накладываются соответствующие ограничения.

Ответ 3



На самом деле ничего суперсложного здесь нет. 1) TLS базируется на асимметричной криптографии, в каковой есть понятие приватного и публичного ключей 2) Если не вдаваться в математические тонкости асимметричной криптографии, навроде теоремы Эйлера, Ферма, Галуа и проч. мастодонтов то эти ключи (например, в алгоритме RSA) вычисляется на основе целых числе p, q (необязательно кстати и простых): PublicKey={e(p,q), p*q} //e(p,q) - некая целочисленная функция (публичная экспонента) PrivateKey={d(p,q), p*q) //d(p,q) - также некая целочисленная функция (приватная экспонента) грубо говоря, если знать эти 2 числа p, q то можно вычислить ключи. Теперь внимание, атакующему всегда известно их произведение p*q - из публичного ключа, который как явствует из его названия известен всем. 3) То есть чтобы дешифровать надо просто разложить некое число n на 2 множителя p, q. Задача называется факторизацией - алгоритмов масса, но в целом все очень печально (с точки зрения скорости). 4) Подходим к самому главному - ради чего весь цирк с конями и затевался: зачем требуется, чтобы p, q были простыми? Здесь есть 2 ответа: Функции e(p, q) и d(p, q) - работают не со всеми числами, то есть если подать им на вход непростое число, то функции могут не дать ничего. Зато если p, q простые то функции работают безупречно. Для усложнения факторизации n: разложение большого числа на простые сомножители усложняется с ростом длины числа как n*log(n), то есть вы раскладываете 1024 битовое число, то сложность грубо говоря будет 1024*2^1024, но если число вдруг окажется четным то его сложность составит уже 512*2^1023 - то есть вычислительная сложность упадет в 4 раза - соответственно простота гарантирует увеличение вычислительной сложности.

Ответ 4



Кажется разобрался с этой темой. На примере Диффи-Хеллмана. Чтобы найти ключ K, нужно решить уравнение K=g^a*b mod p, где "g", "p" - известно. Произведение простых чисел (очень больших) действительно сложно подобрать. И нужно использовать именно простые числа потому что нет базы данных среди больших простых чисел (а базы данных нет потому что нереально перебрать такие большие цифры), иначе бы это сильно ускорило решение задачи, как и со всеми числами. Но это в теории, а на практике серьезные взломщики вряд ли будут перебирать произведение 2-ух простых чисел. Т.к. чтобы найти секретный ключ K, можно решить и другое уравнение, которое тоже равно секретному ключу. K=B^a mod p, где "p" известно, а "B" можно перехватить (т.к. эта информация в незащищенном видео передается по сети). И тогда уже останется подобрать только "a". А если учесть, что "a" - как минимум нечетное и огромное (порядка 10^100) - отбросить на конце четные и диапазон слишком маленьких чисел. Хотя даже при всем при этом "a" замучаешься подбирать)

Ответ 5



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

Почему не вызывается конструктор копии?

#cpp


Имею такой код

#include 

using namespace std;

class Unit{
    int a_;
    char* pch_;
    public:
    Unit(){ cout << "Simple constr" << endl;}
    Unit(int r) : a_(r), pch_(new char[100]){ cout << "Constr " << endl;}
    Unit(const Unit& ){ cout << "Constr copy " << endl;}
    ~Unit(){
        delete [] pch_;
        cout << "Destr" << endl;
    }
};

int main(){
    Unit a = 20;
    return 0;
}


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

Почему не так:
1. Вызывается конструктор с параметром: Unit(20).
2. Происходит присваивание в объект который не был создан - это копирование. Вызывается
конструктор копирования. Как раз rvalue можно передать по const T&.
3. Деструктор для rvalue.
4. Деструктор для a.
    


Ответы

Ответ 1



В "классическом" С++ (С++98) ваша инициализация копированием (copy-initialization) Unit a = 20; действительно концептуально означала именно Unit a = Unit(20); с применением конструктора конверсии Unit::Unit(int) и затем конструктора копирования Unit::Unit(const Unit &). Однако даже в "классическом" С++ компилятору было разрешено исключать формирование промежуточного временного объекта и оптимизировать код до прямой инициализации (direct-initialization) Unit a(20); т.е. исключать вызов конструктора копирования даже если конструктор копирования обладал побочными эффектами. Эта оптимизация называется copy elision. (Даже при выполнении copy elision наличие доступного конструктора копирования все равно требовалось.) Начиная с С++17 в языке появилась гарантированная copy elision, при котором ваша инициализация гарантированно трактуется как Unit a(20); без требования наличия конструктора копирования. Т.е. в любом случае, ожидать тут обязательного вызова конструктора копирования вы не должны (и не должны были никогда). В "классическом" С++ конструктор копирования тут мог быть вызван, но не более того. В вашем конкретном случае инициализация копированием (copy-initialization) ведет себя идентично прямой инициализации (direct-initialization), но в общем случае существенные различия между этими формами инициализации сохраняются и в С++17. Например struct A { A(int) {} }; struct B { operator int() const { return 0; } }; int main() { B b; A a1(b); // Все в порядке A a2 = b; // Ошибка } P.S. Никакого "присваивания" тут, конечно, нет и в помине.

Ответ 2



Пусть наличие = не вводит в вас в заблуждение, форма записи Unit a = 20; называется copy initialization она полностью аналогична записи Unit a(20);, за тем исключением, что не допускает вызова explicit конструктора. Начиная с C++11 вместо них следует использовать list initialization Unit a{20};. Начиная с С++17 добиться вызова конструктора копирования / перемещения при создании временного объекта больше невозможно, т.е. Unit foo(void) { return Unit{Unit{20}}; } Unit a{Unit{foo()}}; Приведет к вызову только одного конструктора.

Ответ 3



Потому что Unit a = 20; это по сути то же, что и Unit a(20); просто другая форма записи. Т.е. вызывается конструктор Unit(int r). А при выходе из main - деструктор.

Почему wait/notify/notifyAll методы определены в классе Object, а не в классе Thread?

#java #многопоточность


Почему wait/notify/notifyAll методы определены в классе Object, а не в классе Thread?
    


Ответы

Ответ 1



На самом деле интересный вопрос. В java объекты могут выступать в роли mutex'ов, т.е. участвовать в процессе разграничения доступа к ресурсам между различными потоками. С помощью synchronized блока и методов wait, notify, notifyAll. Соответственно, доступ к этому объекту должен быть для всех потоков, желающих получить монопольное право на ресурс. Отсюда и вытекает ответ на ваш вопрос - почему эти методы не находятся в классе Thread. Если бы это было так, другим потокам пришлось бы хранить информацию о других потоках (ожидающих доступ к ресурсу) и самостоятельно, заниматься их пробуждением, в момент освобождения ресурса, что согласитесь не очень удобно 🙂

Ответ 2



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

Анимация знака радиационной безопасности

#javascript #html #css #css3 #svg




Мне необходимо анимировать знак радиационной безопасности. 
Анимация должна быть реализована с помощью прорисовки контуров знака с последующим
заполнением цветом. 

Для анимации я перерисовал картинку знака в формате *.png  в формат *.svg. 

Ниже код: 




  
  
    
      
	 	  
      
     
	 
	  	  
    
  





Для реализации анимации допустимы:  анимации css3, smil svg, Javascript

Очень хотелось бы получить несколько ответов, с разнообразными техниками выполнения.
    


Ответы

Ответ 1



Вариант с Первый шаг: Сначала узнаем длину stroke: После поместим в каждый патч stroke-dashoffset & stroke-dasharray Второй шаг: Далее делаем сам внутри & : Анимация закрашивания: P.S. Будет срабатывать только тогда, когда первая анимация закончится, begin="strokeTap.end" Третий шаг: Также поместим в : * { padding: 0; margin: 0; } .wrapper { display: flex; justify-content: center; align-items: center; }


Ответ 2



Вариант на CSS: * { padding: 0; margin: 0; } .wrapper { display: flex; justify-content: center; align-items: center; } #mainCircle { fill: #fff; stroke: black; stroke-dashoffset: 1424; stroke-dasharray: 1424; animation: main-circle 2s cubic-bezier(0.6, 0.05, 0.795, 0.035) forwards; } #sector { fill: #fff; stroke-dashoffset: 1467; stroke-dasharray: 1467; animation: stroke 4s cubic-bezier(0.95, 0.05, 0.795, 0.035) forwards; } #smallCircle { fill: #fff; stroke-dashoffset: 356; stroke-dasharray: 356; animation: stroke-small 4s cubic-bezier(0.95, 0.05, 0.795, 0.035) forwards; } @keyframes main-circle { to { fill: #F8F73F; stroke-dashoffset: 0; } } @keyframes stroke { from { stroke-dashoffset: 1467; } to { fill: black; stroke-dashoffset: 0; } } @keyframes stroke-small { from { stroke-dashoffset: 356; } to { fill: black; stroke-dashoffset: 0; } }


Бесплатная библиотека для работы с *.DOCX

#c_sharp #net #поиск_библиотек #docx


Посоветуйте бесплатную и хорошо документированную библиотеку для работы с *.DOCX.

Знаю, что есть OpenXML, но что есть в природе удобного помимо него?

Например, для Excel есть удобная EpPlus.
    


Ответы

Ответ 1



DocX Git Exp: DocX doc= DocX.Create(filePath); Paragraph p1 = template.InsertParagraph(); p1.AppendLine("This line contains a ").Append("bold").Bold().Append(" word."); p1.AppendLine("Here is example with question mark?"); p1.AppendLine(); p1.AppendLine("Can you help me figure it out?"); p1.AppendLine(); Очень проста в использовании.

Ответ 2



Есть такая open-source С++ библиотека DocxFactory для генерации DOCX документов. Для неё в том числе есть обертка для C#. Прикладываю ссылку на туториал. Судя по документации, основной функционал работы она поддерживает(сам не пробовал использовать на проектах). В документации имеются куски примеров по работе с DOCX. Также ссылка на github-проект. Если требуется, можно попробовать создать какой-то экзампел.

Ответ 3



Microsoft.Office.Interop.Word Как известно, Microsoft Word является COM-объектом, т.е. спроектирован таким образом, что позволяет другим программам подключаться к себе и управлять им. Программно можно проделать практически все операции, которые мы делаем вручную в Word: создать новый документ, внести в него правки, сохранить его и т.п. Но для ее работы требуется лицензия MS Office на каждом клиентском компьютере. Кроме того, MS Office загружается в фоновом режиме, вследствие чего занимает определенное количество оперативной памяти и загружает большое количество файлов и DLL. Приложения MS Office были разработаны как приложения для пользовательского интерфейса, и поэтому Microsoft.Office.Interop.Word работает очень медленно. Microsoft не рекомендует использовать Office Automation (или любой Office Interop) на сервере. DocumentFormat.OpenXml Open XML SDK предоставляет инструменты для работы с документами Office Word, Excel и PowerPoint. Он поддерживает такие сценарии, как заполнение содержимого в файлах Word из источника данных XML, разделение (измельчение) файла Word или PowerPoint на несколько файлов и объединение нескольких файлов Word, поиск и замена контента с использованием регулярных выражений. Но при присвоении некоторого стиля, в свойствах предоставляется только идентификатор предоставленого стиля, а сам стиль описывается отдельно в файле style.xml. В результате необходимости регулярного сопоставления ID стиля с контейнером style.xml для получения характеристик стилей абзацев, возрастает сложность программного использования библиотеки. link Spire.Doc Spire.Doc для .NET - это полностью независимая библиотека классов .NET Word, специально созданная для разработчиков, которая позволяет быстро генерировать, открывать, писать, редактировать и сохранять документы Word не требует установки в систему каждого пользователя MS Office, то есть возможность полностью независимой от него работы; объемная документация с примерами и пояснениями. Работать с библиотекой достатосно удобно. Однако полная версия Spire.Doc не является бесплатной, а бесплатная версия, FreeSpire.Doc, имеет определенные ограничения (например обработка не более 500 абзацев и 25 таблиц). link

Получить из одного IEnumerable три за один обход

#c_sharp #linq


В некотором отчёте нужно отобразить три "кучки" покупателей (условно назовём их "золотыми",
"серебряными" и "бронзовыми"):


кто сделал покупки на сумму свыше 100 000 рублей, 
свыше 50 000 рублей (но не добрал до 100 тыс.),
свыше 10 тыс рублей (и не набрал 50 тыс.).


У меня есть некоторый IEnumerable, где в CustomerDto лежат Id клиента и его имя,
а также есть поле хранящее сумму покупок - Amount.

В принципе, я могу три раза вырезать нужные мне данные через Where:

var report = new CustomersDto
{
    Gold   = allCustomers.Where(x => x.Amount > 100000),
    Silver = allCustomers.Where(x => x.Amount >  50000 && x.Amount < 100000),
    Bronze = allCustomers.Where(x => x.Amount >  10000 && x.Amount <  50000),
};


Но мне стало любопытно: а можно ли сразу за один обход allCustomers получить нужные
мне данные?

Т.е. что-то вроде:

CustomersDto report = allCustomers.Something(
    x => x.Amount > 100000,
    x => x.Amount >  50000 && x.Amount < 100000,
    x => x.Amount >  10000 && x.Amount <  50000);


Такое возможно?
    


Ответы

Ответ 1



Используя только IEnumerable такого трюка сделать не получится. Но этого можно достичь используя IObservable и Rx.NET (оно же System.Reactive). Сначала нужно превратить allCustomers в IObservable: var source = allCustomers.ToObservable().Publish(); Метод Publish используется для того, чтобы избежать многократного обхода исходной последовательности. Теперь, если свойства класса CustomersDto имеют подходящий тип, можно поступить вот так: var report = new CustomersDto { Gold = source.Where(x => x.Amount > 100000).ToListObservable(), Silver = source.Where(x => x.Amount > 50000 && x.Amount < 100000).ToListObservable(), Bronze = source.Where(x => x.Amount > 10000 && x.Amount < 50000).ToListObservable(), }; source.Connect(); Если же их тип - конкретный класс вроде List, придется сделать чуть сложнее: var report = new CustomersDto { Gold = new List(), Silver = new List(), Bronze = new List() }; source.Where(x => x.Amount > 100000).Subscribe(report.Gold.Add); source.Where(x => x.Amount > 50000 && x.Amount < 100000).Subscribe(report.Silver.Add); source.Where(x => x.Amount > 10000 && x.Amount < 50000).Subscribe(report.Bronze.Add); source.Connect();

Ответ 2



Можно исхитриться и все же получить из одного IEnumerable три таковых) Моя идея состоит в том, чтобы использовать стандартный GroupBy. Приступим: 0) Опишем структуру покупателя, которую будем использовать: public class Customer { public ulong ID { get; private set; } public string Name { get; private set; } public double Amount { get; private set; } public Customer(ulong ID, string Name, double Amount) { this.ID = ID; this.Name = Name; this.Amount = Amount; } public override string ToString() => $"{ID}: {Name} - {Amount}руб."; } 1) Опишу вспомогательный enum: public enum CustomerType { // < 10k None, // >= 10k && < 50k Bronze, // >= 50k && < 100k Silver, // >= 100k Gold } 2) Напишем метод-расширение (я исхожу из того, что Вы не можете по каким-то причинам менять изначального класса. В противном случае Вы можете прямо в нем создать аналогичное свойство)): public static class CustomerHelper { // Получим тип покупателя, исходя из его счета: public static CustomerType GetCustomerType(this Customer Customer) => (CustomerType)(Customer.Amount < 10000 ? 0 : Customer.Amount < 50000 ? 1 : Customer.Amount < 100000 ? 2 : 3); } 3) Опишем структуру класса CustomersDto: public class CustomersDto { public IEnumerable Bronze { get; set; } public IEnumerable Silver { get; set; } public IEnumerable Gold { get; set; } public CustomersDto() { Bronze = new Customer[0]; Silver = new Customer[0]; Gold = new Customer[0]; } public CustomersDto(IEnumerable Customers) : this() { // Сгруппируем покупателей по типу и избавимся от тех, кто недобрал 10к var grouped = Customers.GroupBy(x => x.GetCustomerType()).Where(x => x.Key != CustomerType.None); // Установим нужные поля foreach (var group in grouped) SetCustomers(group.Key, group.Select(x => x)); } public void SetCustomers(CustomerType Type, IEnumerable Customers) { switch (Type) { case CustomerType.Bronze: Bronze = Customers; break; case CustomerType.Silver: Silver = Customers; break; case CustomerType.Gold: Gold = Customers; break; default: break; } } } 4) Протестируем: // Тестовые покупатели Customer[] allCustomers = new[] { new Customer(0, "Vasya", 5000), new Customer(1, "Petya", 11000), new Customer(2, "Vanya", 14500), new Customer(3, "Stepan", 50000), new Customer(4, "Kir", 57000), new Customer(5, "AK", 100000) }; // Инициализируем наш класс CustomersDto dto = new CustomersDto(allCustomers); // Выведем результат: Console.WriteLine("Bronze:"); foreach (Customer bronze in dto.Bronze) Console.WriteLine(bronze); Console.WriteLine("\nSilver:"); foreach (Customer silver in dto.Silver) Console.WriteLine(silver); Console.WriteLine("\nGold:"); foreach (Customer gold in dto.Gold) Console.WriteLine(gold); И получим такой вот вывод: Bronze: 1: Petya - 11000руб.2: Vanya - 14500руб. Silver:3: Stepan - 50000руб.4: Kir - 57000руб. Gold:5: AK - 100000руб. Собственно, все как надо) К слову, сначала я хотел сделать так: // Сгруппируем -> Уберем тех, у кого меньше 10к -> Отсортируем по ключу -> Оставим лишь IEnumerable> var grouped = Customers.GroupBy(x => x.GetCustomerType()).Where(x => x.Key != CustomerType.None).OrderBy(x => x.Key).Select(x => x.Select(y => y)); Bronze = grouped.ElementAt(0); Silver = grouped.ElementAt(1); Gold = grouped.ElementAt(2); Тогда в grouped действительно будет лежать 3 IEnumerable> при текущем наборе данных Но потом я вспомнил, что какой-то из групп может и вовсе не быть, так что доступ по индексу - плохая идея) Можно, конечно, извратиться с Union и пустыми IGrouping, но это уже какой-то мазохизм...) Если Вам будет интересно - допишу и этот вариант. Тогда решение будет полностью соответствовать задаче: получить 3 коллекции из одной)

Ответ 3



Вот также через группировку. var groups = new List<(Func,int)> { ( a => a > 100000, 0), ( a => 50000 < a && a < 100000, 1), ( a => a < 50000, 2) }; var split = customers.GroupBy(c => groups.First(g => g.Item1(c.Amount)).Item2) .OrderBy(g => g.Key) .ToList(); Далее можно достать по индексу или превратить в словарь. ИМХО. Все это все равно немного муторнее, чем шлепнуть 3 раза Where

Ответ 4



Можно попробовать Aggregate: var report = allCustomers.Aggregate(new CustomersDto { Gold = new List(), Silver = new List(), Bronze = new List() }, (dto, cust) => { if (cust.Amount > 100000) dto.Gold.Add(cust); else if (cust.Amount > 50000) dto.Silver.Add(cust); else if (cust.Amount > 10000) dto.Bronze.Add(cust); return dto; }); При условии, что class CustomersDto { public List Gold { get; set; } public List Silver { get; set; } public List Bronze { get; set; } }