Страницы

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

понедельник, 11 февраля 2019 г.

Как работает Arrays.toList (E … a)?

Есть код:
List c1 = new ArrayList<>( Arrays.asList(new Integer(1394), new Integer(52837)) ); List c2 = Arrays.asList(new Integer[c1.size()]);
Как мы вообще присваиваем c2 значение? На что мы ссылаемся, если Array.asList(T... a) возвращает List ? Я даже не понимаю, что это за странный тип возвращаемого значения. Мораль в том, что возвращается некоторый List, но List — это интерфейс. Значит, мы получим ссылку на объект, для которого определено действие .add(E o); Но почему-то вызов c2.add в данном случае вызывает ошибку. Почему так?


Ответ

Arrays.asList - возвращает список фиксированного размера. Поэтому нельзя ни добавлять, ни удалять. Чтобы как-то манипулировать элементами, придется оборачивать в новый список без фиксированного размера:
// List c2 = new ArrayList(Arrays.asList(new Integer[c1.size()])); List c2 = new LinkedList(Arrays.asList(new Integer[c1.size()]));

Если углубиться:
Во внутренностях метод Arrays.asList возвращает следующее:
return new ArrayList<>(a);
но(!!!) возвращает он ArrayList не тот, который находится в пакетеjava.util.ArrayList а тот, который определен как внутренний класс внутри самого java.util.Arrays;. Выглядит он так:
private static class ArrayList extends AbstractList implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; //.... и т.д. реализация }
Как видим, эта внутренняя реализация наследуется от AbstractList, в котором по дефолту определены некоторые методы в таком виде
public boolean add(E e) { add(size(), e); return true; }
public void add(int index, E element) { throw new UnsupportedOperationException(); }
public E remove(int index) { throw new UnsupportedOperationException(); }
Вот и получается, что вроде как вернули ArrayList, но на самом деле не тот лист, который ожидали (java.util.ArrayList), а эмуляцию.

О том, что такое и List стоит прочитать материалы на тему generics или обобщений. Тема очень широкая.

IntelliSense для ViewModel в редакторе XAML Visual Studio

При разработке WPF MVVM приложения у нас в разметке XAML повсеместно используется Binding, как получить удобство разработки в виде подсказок IntelliSense при вводе названий свойств из VM? Ведь, если мы ошибемся хотя бы в одном символе, привязка работать не будет, поэтому приходится часто переключаться между файлами проекта и копировать имена (а если VM собрана в библиотеку и исходника вообще у нас нет?).
Причем если в разметке указать что-то типа:

(и собрать проект) то IntelliSense начинает помогать. Но я ведь хочу быть хорошим разработчиком и, по рекомендациям, такую зависимость делать не хочу (и мне это в общем-то понятно).
Какие вы знаете и/или используете способы для включения подсказок в такой ситуации (есть ли они вообще)?


Ответ

Решение удалось найти самостоятельно. Подсмотрел здесь: https://stackoverflow.com/questions/29394295/intellisense-for-data-binding-not-working
Выглядит оно так:
т.е. в XAML должно быть подключено пространство имен xmlns:d="http://schemas.microsoft.com/expression/blend/2008" (оно подключено по умолчанию при создании нового окна) и тогда можно воспользоваться фичей: d:DataContext="{d:DesignInstance Type=local:MainVM}", при этом если указать параметр IsDesignTimeCreatable=True, то студия будет пытаться создать экземпляр указанной VM прямо во время работы в дизайнере и наполнять форму реальными данными (что иногда может замедлить работу дизайнера или даже повалить его)

Обработка нажатия по пункту контекстного меню - WinAPI

Создал приложение, свернул в панель задач. Создал контекстное меню из одного пункта, оно успешно вызывается по ПКМ. Теперь, хотелось бы обработать нажатие по пункту меню. Вот код, но он не срабатывает:
case TREY_MESSAGE: // своя константа { switch (lParam) { case WM_RBUTTONUP: { // Извлекаю координаты курсора мыши GetCursorPos(&pt); // т.к. координаты не передаются в функцию, берём напрямую // Отображаем меню TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
return 0; } case WM_LBUTTONUP: { // щёлчек левой кнопкой мышки
return 0; } case WM_COMMAND: { // отладчик здесь не останавливается MessageBoxA(hwnd, "test", "test", MB_OK); if (LOWORD(wParam) == MENU_EXIT) // MENU_EXIT - идентификатор пункта меню PostMessage(hwnd, WM_CLOSE, lParam, wParam); return 0; } default: return 0; } }
Блоки WM_RBUTTONUP, WM_LBUTTONUP(этот для теста) обрабатываются, а вот в WM_COMMAND упорно не заходит. Как лечить?


Ответ

Вы ищете сообщение WM_COMMAND не там, куда операционная система может его отправить. WM_COMMAND — это полноценное сообщение, код которого хранится в параметре Msg. Вы же пытаетесь работать с ним как с кодом, пересылаемым в рамках TREY_MESSAGE, ища его в lParam (подобно кодам уведомлений в WM_NOTIFY). WM_COMMAND проверяется внутри case-ветки, работающей с TREY_MESSAGE, хотя это равноправные сообщения.

Как изменить сообщение самого первого коммита?

Есть репозиторий, в нём три последовательных коммита.
Как мне изменить сообщение изначального, первого коммита?
git rebase -i HEAD~2 приводит к редактированию только двух последних.


Ответ

Очень просто. Опустить конкретный коммит и добавить опцию --root
git rebase -i --root
Так среди коммитов в запросе интерактивного ребейза окажется и самое начало.

Почему стоит отказываться от HttpUrlConnection?

Был сегодня на интервью.Ответил на все вопросы ,но вот на один они сказали ответ не правилен .Было задание подключиться к web-services ну и там по апи сделать разные дейтсвия.Всё окей только отметили что для этого я использовал HttpUrlConnection и сказали лучше найти ей альтернативу .Ясное дело я не смог у них спросить почему)Так вот, чем плох HttpUrlConnection и что посоветуете в замен.И почему


Ответ

Я бы не стал за использование HttpUrlConnection бить по рукам. Просто это более низкоуровневый механизм. Вам необходимо заботиться о многих вещах самому:
Необходимо оборачивать это дело в AsycnTask Хендлить случаи со сворачиванием игры. Обрабатывать повороты экрана. Писать кеш свой.
Тот же Retrofit из коробки будет быстрее, так как там встроенный механизм кеша.
Поэтому и рекомендуют volley/retrofit использовать. Уменьшается вероятность ошибки, меньше кода писать. Код читабельней и т.п.
Но, опять же, лично я бы не стал за ответ с использованием HttpUrlConnection минус ставить.

WPF создание ресурса с несколькими параметрами

У меня на окне располагается 9 StackPanel, я делаю для них анимацию смены цвета при наведении мыши

У каждой панели разный цвет и соответственно менять тоже нужно разный цвет, а писать 9 раз этот код для каждой панели, ну понимаете... Можно ли как то создать ресурс с параметрами (входным и выходным цветом)?


Ответ

Можно, но неочевидным образом.
К сожалению, в анимации невозможно использовать не Binding, не DynamicResource, поэтому придётся пойти обходным путём.
Идея такова: будем вместо цвета анимировать число от 0.0 до 1.0 и обратно, а цвет фона вычислим из начального и конечного цветов через конвертер.
Реализуем!
Итак, для начала конвертер, который будет интерполировать цвета. Он очень простой. Идея одолжена здесь
class ColorInterpolationConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object p, CultureInfo ci) { if (values.Contains(DependencyProperty.UnsetValue)) return Binding.DoNothing; Color from = (Color)values[0]; Color to = (Color)values[1]; double ratio = (double)values[2]; return from + (to - from) * (float)ratio; }
public object[] ConvertBack(object value, Type[] targetTypes, object p, CultureInfo ci) { throw new NotImplementedException(); } }
Теперь, нам нужно задать начальный и конечный цвет. Это должны быть, по идее, attached property. Так же нам нужно attached property для текущего значения соотношения между начальным и конечным цветами, которое мы будем анимировать. Определяем их во вспомогательном классе:
static class ColorExtensions { #region attached property double Ratio public static double GetRatio(DependencyObject obj) => (double)obj.GetValue(RatioProperty);
public static void SetRatio(DependencyObject obj, double value) => obj.SetValue(RatioProperty, value);
public static readonly DependencyProperty RatioProperty = DependencyProperty.RegisterAttached( "Ratio", typeof(double), typeof(ColorExtensions)); #endregion
#region attached property Color BaseColor public static Color GetBaseColor(DependencyObject obj) => (Color)obj.GetValue(BaseColorProperty);
public static void SetBaseColor(DependencyObject obj, Color value) => obj.SetValue(BaseColorProperty, value);
public static readonly DependencyProperty BaseColorProperty = DependencyProperty.RegisterAttached( "BaseColor", typeof(Color), typeof(ColorExtensions)); #endregion
#region attached property Color HoverColor public static Color GetHoverColor(DependencyObject obj) => (Color)obj.GetValue(HoverColorProperty);
public static void SetHoverColor(DependencyObject obj, Color value) => obj.SetValue(HoverColorProperty, value);
public static readonly DependencyProperty HoverColorProperty = DependencyProperty.RegisterAttached( "HoverColor", typeof(Color), typeof(ColorExtensions)); #endregion }
Окей, теперь сам стиль.

Используем:

Результат:

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

Метод System.exit(0)

Я поместила вызов метода System.exit(0) в onBackPressed
@Override public void onBackPressed() { super.onBackPressed(); System.exit(0); }
и после нажатия на клавишу BACK (из первого активити), судя по логам, вызываются следующие методы обратного вызова:
onCreate onStart onResume onBackPressed
После этого я запускаю приложение снова (неважно как - вызовом из списка запущенных приложением, или тапом по иконке приложения на домашнем экране), и вижу, что следующим вызывается метод OnCreate, минуя методы onStop и onDestroy. Каким образом завершается активность без вызова методов onStop и onDestroy? Убивается процесс, в котором запущено приложение?


Ответ

Вызов System.exit(0) перезапускает приложение, выкидывая последнюю activity.
Например, если из ActivityA открыта ActivityB, в которой делается вызов System.exit(0), то приложение будет убито и сразу же перезапущено с ActivityA.
Источник: Difference between finish() and System.exit(0)

Как отсортировать int[] со своим компаратором?

Массив Integerов сортируется, а вот с массивом intов что-то не получается:
https://ideone.com/tXfCql
class Ideone { public static void main (String[] args) throws java.lang.Exception { Integer a[] = {1,2,3,4,5,6,7}; int b[] = {1,2,3,4,5,6,7};
Arrays.sort(a, (x,y) -> y-x); //Arrays.sort(b, (x,y) -> y-x);
System.out.println(Arrays.toString(a)); System.out.println(Arrays.toString(b)); } }
Если раскомментировать сортировку массива b, то будет ошибка
Main.java:11: error: no suitable method found for sort(int[],(x,y)->y - x) Arrays.sort(b, (x,y) -> y-x); ^ method Arrays.sort(T#1[],Comparator) is not applicable (inference variable T#1 has incompatible bounds equality constraints: int upper bounds: Object) method Arrays.sort(T#2[],int,int,Comparator) is not applicable (cannot infer type-variable(s) T#2 (actual and formal argument lists differ in length)) where T#1,T#2 are type-variables: T#1 extends Object declared in method sort(T#1[],Comparator) T#2 extends Object declared in method sort(T#2[],int,int,Comparator) Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output 1 error
Как его правильно отсортировать с кастомным компаратором?


Ответ

Массив Integerов сортируется, а вот с массивом intов что-то не получается
И правильно, что не получается, так как дженерики (коим является Comparator) не параметризуются примитивами, а автобоксинг для массивов не работает.
Как отсортировать int[] со своим компаратором?
Так, как хотите Вы (непосредственно с помощью Arrays.sort(...)) -- никак, но есть множество альтернативных решений, которые перечислены в соседнем ответе

Несколько моделей для 1 контроллера и представления

Пишу на asp.net mvc.
В одном view должна быть целая куча записываемых и показываемых данных, по-этому мне было бы очень удобно разделить модель на много маленьких моделей по категориям, что бы было легче ориентироваться их полях.
Однако так как это надо сделать все в одном view, которое может иметь только одну модель, такой способ не прокатит.
Как можно это реализовать иначе?


Ответ

В таких случаях (сложное представление состоит из множества блоков) обычно во вьюхе делают partial view с отдельными маленькими модельками.

Как динамически сформировать выражение типа Expression для сервиса?

Имеется модель EF
public class OrderDbModel { public bool IsPayed { get; set; }
public string Name { get; set; }
public DateTime Created { get; set; }
public bool IsDeleted { get; set; } }
Ей соответствует доменная модель:
public class Order { public bool IsPayed { get; set; }
public string Name { get; set; } }
Чтобы получить список доменных моделей заказов из сервиса в слое бизнес-логики приложения, предполагается использование следующего класса-фильтра
public class OrderFilter { public bool GetUnpayed { get; set; }
public IEnumerable Names { get; set; } }
Для получения списка доменных моделей по фильтру создан сервис, который использует репозиторий:
public class OrderService { private readonly IOrderRepository _repository;
public OrderService(IOrderRepository repository) { _repository = repository; }
public IEnumerable GetFilteredOrders(OrderFilter filter) { // как динамически сформировать выражение??? Expression> filterExpression = null;
var orders = _repository.Get(filterExpression);
return Mapper.Map, IEnumerable>(orders); } }
Собственно, сам вопрос - в комментариях в коде сервиса. Не получается динамически сформировать filterExpression. Крайне интересен пример кода для данного конкретного случая с подробным описанием. Имеются ли какие-то библиотеки, которые позволяют это сделать с наименьшими трудозатратами?
PS: .NET Framework 4.6, C# 6.
Пример значений: для OrderFilter со значениями { GetUnpayed = false, Names = new List { "Foo", "Bar" } } должно плучиться выражение o => o.IsPayed && (o.Name == "Foo") || o.Name == "Bar")


Ответ

И так, вам нужен способ комбинировать выражения. Проще всего это сделать через операцию бета-редукции (т.е. подстановки фактического параметра на место формального).
Для этого понадобится вот такой простейший визитор (visitor, "посетитель"):
class Reducer : ExpressionVisitor { private readonly IDictionary arguments;
public Reducer(IDictionary arguments) { this.arguments = arguments; }
protected override Expression VisitParameter(ParameterExpression node) { Expression result; if (arguments.TryGetValue(node, out result)) return result; return base.VisitParameter(node); } }
Даже если вы не сталкивались с классом ExpressionVisitor ранее - тут все просто. Класс Reducer заменяет в выражении параметры (объекты класса ParameterExpression ) на соответствующие им во входном словаре, если находит их там. Остальные узлы выражения он не трогает.
Теперь можно определить операцию подстановки. Тут все просто: формируем словарь параметров и передаем его классу Reducer после чего прогоняем через Reducer тело лямбда-функции:
public static Expression BetaReduce(this LambdaExpression expr, params Expression[] args) { Debug.Assert(expr.Parameters.Count == args.Length); var mapping = new Dictionary(); for (int i=0; iНу а теперь через операцию BetaReduce уже можно выражать полезные комбинаторы для выражений. Например, комбинатор And:
public static Expression> And(params Expression>[] items) => And(items.AsEnumerable()); public static Expression> And(IEnumerable>> items) { var p = Expression.Parameter(typeof(T)); var body = items.Select(item => item.BetaReduce(p)).Aggregate(Expression.AndAlso); return Expression.Lambda>(body, p); }
Или комбинатор Or:
public static Expression> Or(params Expression>[] items) => Or(items.AsEnumerable()); public static Expression> Or(IEnumerable>> items) { var p = Expression.Parameter(typeof(T)); var body = items.Select(item => item.BetaReduce(p)).Aggregate(Expression.OrElse); return Expression.Lambda>(body, p); }
Теперь вам ничего не помешает сложить все ваши условия в список, после чего объединить их все через And:
var conditions = new List>>();
if (filter.GetUnpayed) conditions.Add(x => !x.IsPayed); ...
var filterExpression = ExpressionUtils.And(conditions);

Если же вам не нравится работать с выражениями в "сыром" виде, можете попробовать библиотеку LinqKit

TextBlock с подсветкой текста

Столкнулся с необходимостью выделения фрагмента текста в TextBlock, а именно определённых ключевых слов по которым были отфильтрованы элементы ListBox , этот текстовый блок собственно и содержащие
XAML, мой ваиант


Вариант XAML, рекомендованный VladD, не создаёт коллекцию HighlightRulesCollection (хотя казалось бы даже отрабатывает конвертер)
Используется компонент написанный нашим соотечественником с открытым исходным Компонент
Описание компонента
Закомментированный код это старый TexBlock без выделения
Новый компонент HighlightTextBlock прекрасно выделяет текст если использовать статический ресурс, как в примере, но когда я пытаюсь его привязать к текущему тексту он не может найти это поле :( , я новенький в WPF помогите разобраться с
HightlightedText="{Binding Path=title, Converter={StaticResource getFilter}}"
Изначально вопрос звучал как верно привязать это свойство к title ? Мне дали совет по реструктуризации XAML, через ресурсы , но это не работает т.к. не создаётся HighlightRulesCollection и выделение не работает.
В ходе обсуждения было высказано предположение что следует несколько модифицировать сам компонент и поместить коллекцию HighlighRule (также) в визуальное дерево. Тогда будет автоматически наследоваться DataContext и по идее будет работать привязка через ElementName.
Подскажите как это можно реализовать? или может кто то внесёт правки в исходный код компонента ?
Альтернативный вариант , подскажите, как реализовать такого рода функционал другими методами ?
структура DataContext
public ObservableCollection Procedures { set; get; } public CollectionViewSource ProceduresView { set; get; } = new CollectionViewSource();
....
Procedures = new ObservableCollection();
ProceduresView.Filter += Procedures_Filter; ProceduresView.Source = Procedures;
....
public class Procedure : ObservableObject { .... public String title { get; set; } .... } ....
// Просто фильтрация
void Procedures_Filter(object sender, FilterEventArgs e) { Procedure procedure = (Procedure) e.Item; Boolean flag = false; if (!string.IsNullOrEmpty(filter)) { Setting.Filter sfilter = new Setting.Filter(); sfilter.type = "искать везде"; sfilter.text = filter; ObservableCollection arr = new ObservableCollection(); arr.Add(sfilter); if (Utils.AssignedProcedureFromFilter(procedure, arr)) flag = true; } else flag = true; e.Accepted = flag; }
Видео с описанием проблемы
Упрощённый проект эмитирующий мой функционал


Ответ

Нашёл работающее решение своей задачи
public class SearchHightlightTextBlock : TextBlock { public SearchHightlightTextBlock() : base() { }
public String SearchText { get { return (String)GetValue(SearchTextProperty); } set { SetValue(SearchTextProperty, value); } }
private static void OnDataChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) { TextBlock tb = (TextBlock)source;
if (tb.Text.Length == 0) return;
string textUpper = tb.Text.ToUpper(); String toFind = ((String)e.NewValue).ToUpper(); int firstIndex = textUpper.IndexOf(toFind); String firstStr = ""; String foundStr = ""; if (firstIndex != -1) { firstStr = tb.Text.Substring(0, firstIndex); foundStr = tb.Text.Substring(firstIndex, toFind.Length); } String endStr = tb.Text.Substring(firstIndex + toFind.Length, tb.Text.Length - (firstIndex + toFind.Length));
tb.Inlines.Clear(); tb.FontSize = 16; var run = new Run(); run.Text = firstStr; tb.Inlines.Add(run); run = new Run(); run.Background = Brushes.Yellow; run.Text = foundStr; tb.Inlines.Add(run); run = new Run(); run.Text = endStr;
tb.Inlines.Add(run); }
public static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register("SearchText", typeof(String), typeof(SearchHightlightTextBlock), new FrameworkPropertyMetadata(null, OnDataChanged)); }
Использовать вот так

Не совсем элегантное решение , но работает привязка и все дела :)

Что такое висячие указатели, в чем их опасность?

Почему появляются проблемы подобного рода ?


Ответ

char* f() { char s[100]; // страшное вычисление s return s; }
Представили? вызываем char * s = f();. Нормально? вроде бы да.
Но когда мы начнем использовать этот указатель - тот char s[100]; из функции давно может быть перезаписан чем-то другим (эта память выделяется в стеке только на время работы функции). И мы получаем висячий указатель - т.е. он есть и даже куда-то указывает... Только там может быть что угодно.
Или -
s = malloc(...); .... free(s);
Значение s остается - free его не меняет, но указывает оно на память, которая освобождена, может быть выделена заново, перезаписана... или, например, еще раз удалена.
Так понятнее?

Помощь с указателями

Всем привет, дошел до темы указателей, честно говоря, тема неприятная, поэтому сразу к вам вопросы, товарищи.
1)
char *lo = "12345"; char *plo = lo; // вот так можно, это понятно // но почему можно так? char **plo = lo; или так char **plo = *lo;
2) Что тут происходит и почему так можно делать?
main() { char *lo = "12345"; fun(lo); }
// так void fun(char s[]){ // немного не понимаю, почему так делается printf("%s", s); }
// или так void fun(char *s){ // так понимаю printf("%s", s); }
//можно и так void fun(char **s){ // так тоже не понимаю printf("%s", s); }
//тоже не проблема void fun(char **s[]){ // ну а это вообще факинг щит какой-то printf("%s", s); }
А главное все варианты работают...
3) main() {
char *err[] = { "Cannot Open File
", "Read Error
", "Write Error
", "Media Failure
" }; fun(err); }
void fun(char *s[]){ printf("%s", s[0]); }
Понимаю, если бы написали
void fun(char **s){ printf("%s", s[0]); }
Но почему char *s[] работает, я не понимаю. Главное, если в main так попробую написать
main(){ *perr[] = err; }
то работать не будет...
Спасите... заранее благодарю, хотя бы за то, что прочитаете. Шлю флюиды добра тем, кто ответит


Ответ

Для начала давайте разделим понятие "работает" на "работает и все ок", "компилируется и вроде работает", "компилируется, но происходит что то странное".
Второе, разделим с и с++. Многие считают, что с является подмножеством с++. Но это далеко не так. На данный момент, это языки, которые имеют просто много общего.
Начнем с самого главного, которое справедливо для с/с++
a[b] == b[a] == *(a+b)
То есть, эти все три выражения эквивалентны. Когда в следующий раз увидите 1[a] - не пугайтесь, это нормально, хоть и не очень применимо для продакшн кода.
Отсюдова второе следствие, если закрыть глаза на некоторые особенности, то массив это и есть указатель. И в большинстве случаев *a == a[]
Теперь разберем примеры.
char *lo = "12345";
в си - это почти ок. В с++ это плохо, так как "12345" - это const char*. А присваивание с потерей константности это плохо.
char *plo = lo; // вот так можно, это понятно
конечно можно - char* и char*
// но почему можно так? char **plo = lo;
а так как бы нельзя. И с++ будет ругаться, потому что с одной стороны char** , а с другой char*. Но для с это два указателя и он закрывает на это глаза.
или так char **plo = *lo;
Опять же, для с++ компилятора тут ужас - попытка присвоить типу char** значение типа char Но на низком уровне все ок. Указатель это просто int, char - это просто то, что может быть приведено. Компилятор си доверяет человеку.
Поехали дальше.
main() { char *lo = "12345"; fun(lo); }
по поводу типа я уже писал. там явно не хватает const.
// так void fun(char s[]){ // немного не понимаю, почему так делается printf("%s", s); }
char[] это просто массив. А массив это указатель.
// или так void fun(char *s){ // так понимаю printf("%s", s); }
//можно и так void fun(char **s){ // так тоже не понимаю printf("%s", s); }
тут формально все ок. Потому что printf будет трактовать s как char*. как я сказал выше, char*, char** это все просто int. Вызывающая функция сохранила адрес, а printf его извлек.
//тоже не проблема void fun(char **s[]){ // ну а это вообще факинг щит какой-то printf("%s", s); }
Здесь снова никаких "проблем". char** s[] - это просто char*** и снова тот же int. Пример сводится к предыдущему.
поэтому, и пример ещё ниже - char* s[] это char** s
main(){ *perr[] = err; }
а вот это точно не будет работать - код не валидный, типы переменных не известны (хотя может они где то и спрятались). Но! написать в левой части *perr - это нормально - это разыменования указателя. И эта звездочка не должна обманывать - это звездочка разыменования, а не объявления типа указателя. И квадратные скобки в этом случае лишены смысла. Но если бы там был индекс, то сразу ситуация улучшается.
В целом, си старается быть недалеко от ассемблера. Поэтому подобные конструкции в си и работают. С++ старается быть более строгим и проверяет детальнее.

Garbage collector: перемещение объекта из поколения в поколение

Когда у нас заполняется нулевое поколение кучи, происходит анализ этого поколения: удаляются "мёртвые" объекты и перемещаются "выжившие" в следующее поколение - 1. Вопрос: если в поколении 1 недостаточно места для приёма объектов из нулевой кучи, то что происходит? Очистка первого поколения?

UPDATE
Цитата (C# 5.0 in Nutshell, Albahari):
Среда CLR сохраняет раздел Gen() относительно небольшим (максимум 16 Мбайт в 32-битной версии для рабочей станции, с типичным размером от нескольких сотен Кбайт до нескольких Мбайт). Когда раздел Gen() заполняется, сборщик мусора GC инициирует сборку Gen() — что происходит относительно часто. Сборщик мусора применяет похожий порог памяти к разделу Gen1 (который действует как буфер для Gen2), поэтому сборки Gen1 являются тоже относительно быстрыми и частыми. Однако полные сборки мусора, включающие Gen2, занимают намного больше времени и, таким образом, происходят нечасто. Результат полной сборки мусора показан на рис. 12.2.


Ответ

Достижение поколением порогового размера — всего лишь триггер для начала сборки мусора. Когда общий размер объектов в Gen0 станет больше порога, запустится сборщик мусора.
Когда сборщик мусора запустится, он смотрит, не превышает ли суммарный размер объектов в Gen2 порог. Если да, запускается полная, медленная сборка мусора всех трёх поколений.
Если Gen2 в порядке, но суммарный размер объектов а Gen1 превышает порог для Gen1, запускается ускоренная сборка, которая рассматривает только Gen0 и Gen1.
Если же Gen1 тоже в порядке, то запускается ускоренная сборка только Gen0.
Если после сборки Gen0 переполнится Gen1 (то есть, суммарный размер Gen1 станет выше порога), ничего не произойдёт до следующего запуска сборщика мусора. А когда он таки запустится (по переполнению Gen0), он обнаружит переполнение поколения Gen1 и соберёт его тоже.
(Кстати, размеры порогов на текущий момент не фиксированы, и фреймворк динамически подгоняет их во время пробега программы.)

Литература: Jeffrey Richter. The Managed Heap and Garbage Collection in the CLR

Для чего используется Mock.Setup().Verifiable()?

Не могу разобраться для чего используется Mock.Verifiable(), если я правильно понимаю, такой код:
var mockContainer = new Mock(MockBehavior.Strict, StorageUri); mockContainer.Setup(c => c.GetBlockBlobReference(It.IsAny())) .Returns(mockBlobItem.Object); // ... mockContainer.Verify(c => c.GetBlockBlobReference(It.IsAny()), Times.AtLeastOnce);
Будет эквивалентен такому:
var mockContainer = new Mock(MockBehavior.Strict, StorageUri); mockContainer.Setup(c => c.GetBlockBlobReference(It.IsAny())) .Returns(mockBlobItem.Object) .Verifiable(); // ... mockContainer.Verify();
Есть ещё третий вариант:
var mockContainer = new Mock(MockBehavior.Strict, StorageUri); mockContainer.Setup(c => c.GetBlockBlobReference(It.IsAny())) .Returns(mockBlobItem.Object); // ... mockContainer.Verify();
Изучил множество примеров, так вот там используются, как правило, второй или третий варианты. А ещё есть .VerifyAll().
Как правильно и почему? Какие есть особенности и подводные камни? Как эти варианты зявисят от моделей поведения Strict и Loose?

Не смог найти документацию к Moq (кроме вот этой неполноценной), она вообще есть?


Ответ

Да Вы всё верно поняли.
Насколько можно судить из статьи этот метод может быть использован для проверки вызова ранее вызова метода определённого в Setup.
var thing = new Thing() { Id = 1 }; var mockMapper = new Mock(); mockMapper.Setup(p => p.Save(thing)).Verifiable();
// do stuff
mockMapper.Verify();
Кроме того согласно англоязычного ответа желательно не использовать этот подход т.к. он явно противоречит паттерну AAA. Противоречие заключается в том, что подготовка данных для тестирования (Arrange) и описание того, что должно быть проверено (Assert) происходит в методе Setup
Сами же мейнтейнеры проекта озвучивают ещё рад случаев почему не стоит продолжать развивать такое АПИ
Тем не менее этот подход может быть оправдан к примеру необходимостью избежать дублитрования кода.
Единственный случай, когда такой подход нельзя будет использовать это при необходимости проверить количество вызовов. В этом случае Вы можете использовать только метод Verify с полным описание ожидаемого вызова:
mock.Verify(c => c.Method(It.Is(x => x == "x")), Times.Once);
По поводу использования Verify без параметров. Он будет проверять только методы которые Вы в сетапе отметили при помощи метода Verifiable
var mockContainer = new Mock(MockBehavior.Strict, StorageUri); mockContainer.Setup(c => c.GetBlockBlobReference(It.IsAny())) .Returns(mockBlobItem.Object) .Verifiable(); // ... mockContainer.Verify();
Если же вы хотите проверить был ли вызван метод который не был отмечем как Verifiable, можно использовать метод VerifyAll
var mockContainer = new Mock(MockBehavior.Strict, StorageUri); mockContainer.Setup(c => c.GetBlockBlobReference(It.IsAny())) .Returns(mockBlobItem.Object); // ... // Verify - не будет проверять в этом случае // т.к. Вы не получите ошибку даже если метод не был вызван ни разу // для такого случая можно сделать так mockContainer.VerifyAll();
Но лично я бы не использовал VerifyAll хотя-бы потому, что он ну уж совсем не очевиден.

Разработка ведётся на гитхабе и кроме детальной документации на которую вы сослались есть быстрый старт и примеры использования.

C# вызов методов предка

Чисто вопрос интереса ради. Возможно ли вызвать метод старее чем предок из потомка? Чтонибудь типа
(КлассПраПраДедушка)base.МетодКласса()
или
base.base.МетодКласса()


Ответ

Конечно.
Например, так:
КлассПраПраДедушка grandpa = this; grandpa.МетодКласса();
Ну или просто ((КлассПраПраДедушка)this).МетодКласса();
Если МетодКласса не перекрыт при помощи new, то можно, разумеется, просто МетодКласса();
Синтаксиса, подобного base, для спуска дальше вниз по иерархии, нету. То есть, вам нужно указать точный тип предка.

Как правильно подсказывает @AntonShchyrov, для случая виртуального переопределённого метода, вызвать метод метод предка дальше, чем base, средствами языка невозможно.
Можно сделать грубый хак через рефлексию:
class Grandpa { public virtual void Do() => Console.WriteLine("Grandpa.Do"); }
class Father : Grandpa { public override void Do() => Console.WriteLine("Father.Do"); }
class Child : Father { public void CallGrandpa() { ((Action)Activator.CreateInstance( typeof(Action), this, typeof(Grandpa).GetMethod("Do").MethodHandle.GetFunctionPointer())).Invoke(); } }
Никогда не делайте так. О причинах, почему плохо вызывать что попало, говорит Эрик Липперт здесь

Прямой вызов через рефлексию не работает, и вызывает в реальности переопределённый метод. Хитрость с MethodHandle.GetFunctionPointer() позаимствована отсюда

Почему к одним и тем же командам существует по несколько мануалов?

Например: http://manpages.ubuntu.com/cgi-bin/search.py?q=ls&op=&cx=003883529982892832976%3A5zl6o8w6f0s&cof=FORID%3A9&ie=UTF-8&siteurl=manpages.ubuntu.com%2F&ref=&ss=2351j954255j9
Причём все действующие насколько я понимаю.


Ответ

Как написано на самих страницах, эти программы различаются. Например, в случае с ls, одна страница для стандартного ls, другая - для ls, удовлетворяющего стандарту POSIX (может понадобиться, например, для тестирования скриптов, которые должны быть переносимы), третья - из пакета, обеспечивающего совместимость с ОС Plan 9 From Bell Labs.

Сделал Reset Head hard но забыл закомитить

После изменений решил откатиться и сделал Reset Head hard. И откатился далеко назад. Остался только apk. Можно ли восстановить проект по apk?


Ответ

Желательно: перед тем, как начинать работать с репозиторием -- сделайте резервную копию всего каталога, чтобы можно было предварительно попрактиковаться на копии или вернуть старое состояние.
Если ваши изменения были закоммичены (достаточно даже только локально, без отправки в удалённый репозиторий), то вполне можно к ним вернуться, даже после того, как откатитесь далеко назад. (При условии, что не были запущены операции очистки репозитория от ненужных/устаревших ссылок -- они обычно хранятся 30 дней).
Всё, что нужно для этого -- это запомнить две простые команды:
git reflog
и
git reset --hard HEAD@{123}
Возможно, пригодится такая статья, я по ней изучал когда-то возможности возврата: git reset: повернуть время вспять

JS: существует таблица неявного приведения типов?

Привет!
Существует таблица неявного приведения типов или где правильные ответы смотреть?
Пример:
[1] + [2] - [3] = 9
или:
{} + {} = "[object Object][object Object]"


Ответ

Правильные ответы есть в спецификации
В примерах в вопросе нужно смотреть операции сложения и вычитания

Как видно из алгоритма, в случае сложения сначала операнды приводятся к примитивному типу, с помощью вызова внутренней функции ToPrimitive (алгоритм ToPrimivite можно также увидеть в ответе на вопрос В чем разница между valueOf и toString)
Далее, если хотя бы один из операндов строка - производится сложение строк. В противном случае, операнды приводятся к числу и выполняется сложение чисел.

В случае с вычитанием - операнды сразу приводятся к числу.
Рассмотрим первый пример из вопроса: [1] + [2] - [3]
Происходит вычисление [1] + [2].
операнды приводятся к примитивному типу, для массивов - это равносильно вызову ToString, следовательно: [1]+[2] -> "1"+"2" складываются строки: "1"+"2" = "12" Происходит вычисление "12" - [3].
Операнды приводятся к числам: "12" -> 12, [3] -> "3" -> 3 вычитание: 12 - 3 = 9

Google Play Console. Сбой при загрузке Не удалось сохранить изменения. Повторите попытку. ЗАГРУЗИТЬ ДРУГОЙ ФАЙЛ APK


СЛУЧИЛОСЬ СТРАШНОЕ!!!
Историю, куки и все такое чистил. Пробовал в Chrome, Yandex, Opera. Режим Инкогнито пробовал. Ранее, в течение года ничего подобного не было...


Ответ

Решение. Вышел из Google Play Console... И опять зашел (введя имя, пароль)...
И все заработало!!!
При этом, банально, произошло обновление сессии (не только у клиента (чистка куки, кэша, истории и т.п.), но и на сервере все обновилось... И все заработало... )
Т.е. "чистка" только у себя далеко не всегда помогает!!!

Развернуть backup на резервном сервере Oracle

Как развернуть backup, сделанный с помощью RMAN на резервном сервере? Так же интересует, не важно ли для переноса, какая ОС системы? На работающем сервере БД был запущен Rman и выполненны следующие команды:
connect target; shutdown immediate; startup mount; backup database; alter database open;
Затем файлы бекапа были скопированны на ПК где планируется развернуть резервную БД путь к папке E:\backup. На резервном ПК был запущен Rman со следующими командами:
connect target; shutdown immediate; startup mount; catalog start with 'E:\backup\';
Затем соглашаюсь добавить данные бекапы написав yes. Затем получаю ошибку
File Name: путь и имя файла RMAN-07518: Reson: Foreign database file DBID: 4099333308 Database Name: ORCL
Затем где-то читал, что можно написать set DBID 4099333308 и повторить заново, но ничего не вышло. БД даже не поднялась, указывая на то, что неверный DBID. Поэтому DBID я вернул какой был. Как решить проблему?


Ответ

Возможно проблема из за того что вы не восстановили SPFILE и CONTROLFILE.
Стартуем БД без монтирования spfile:
startup nomount;
Восстанавливаем spfile:
restore spfile from ’путь к файлу в бекапе *.CTF’;
Останавливаем
shutdown immediate;
Стартуем в режиме nomount,и восстанавливаем контрольный файл:
restore controlfile from ’путь к файлу в бекапе *.CTF’;
Стартуем в режиме mount
startup mount.
catalog start with ‘полный путь к папке бекапа’; Соглашаемся: Y run { restore database; recover database; } После восстановления появится ошибка, SCN не сходится. Сбрасываем SCN и стартуем
alter database open resetlogs;
Если исходный сервер(Oracle) был 32-битный а новый 64 то необходимо выполнить в sqlplus:
startup upgrade @$Oracle_Home
dbms\admin\utlip.sql @$Oracle_Home
dbms\admin\catupgrd.sql @$Oracle_Home
dbms\admin\utlrp.sql shutdown immediate startup

Почему возникает ошибка format string is not a string literal?

Согласно стандарту функция printf имеет прототип: int printf(const char *restrict format, ...);
Собственно, сабж:
#include
int main (void) { const char *format = "hello world!"; printf(format);
return 0; }
Протест Clang
printf.c:7:12: error: format string is not a string literal (potentially insecure) [-Werror,-Wformat-security] printf(format); ^~~~~~ printf.c:7:12: note: treat the string as an argument to avoid this printf(format); ^ "%s", 1 error generated
Почему возникает такая ошибка? Ведь строка форматирования соответствует прототипу.


Ответ

Собственно, clang ругается на совсем другое. Первой ошибкой он говорит, что хорошо бы строку форматирования явно задать литералом, а не переменной, так как переменную может кто то случайно поменять или подменить. А явное - это всегда лучше. Подобная строка форматирования сколько раз была причиной багов и уязвимостей, что clang решает предупредить.
Второй строкой он говорит, что красивее эту конструкцию писать так
printf("%s", format);
Но иногда лучше сразу писать
puts(format);
Но на самом деле ошибка возникает из за -Werror, который заставляет warning трактовать как ошибки.

Как правильно добавить ClickOnce приложение в автозагрузку?

Необходимо либо получить путь к ярлыку приложения, установленному при помощи ClickOnce, который создаётся в каталоге Environment.GetFolderPath(Environment.SpecialFolder.Programs)\PublisherName либо его создать программно. Всё что я находил либо не работает, либо не устраивает.
UPD: В чем суть. При установке с помощью ClickOnce запускается ваше приложение, вы производите настройку, выходите из приложения, запускаете снова - всё ок, настройки есть. Программно получаете Application.StartupPath, этот путь закидываете в автозапуск в реестре или создаёте ярлык в Автозагрузке, но наступает фиаско, когда при включении ПК настроек нет, всё по дефолту и необходимо конфигурировать заново. И запустив приложение с ярлыка, в котором Application.StartupPath указан, мы можем получить настройки приложения отличные от тех, которые указывали запустив приложение с ярлыка созданного установщиком ClickOnce. Во как!


Ответ

Самая неудачная идея для приложения с развертыванием clickonce, да и большинства приложений в принципе, это хранить конфигурационные файлы рядом с исполняемым файлом. Это вполне допустимо, если необходимые настройки можно сделать на этапе сборки релиза и менять их только в случае крайней необходимости, но если пользователь может менять их сам когда ему вздумается, лучше вынести в отдельное фиксированное расположение, не зависимое от расположения исполняемых файлов.
Плюс к этому, механизм обновления clickonce построен таким образом, что ваши конфигурационные файлы могут быть перезаписаны во время обновления, если в обновленной версии они более новые, для текстовых файлов по дате последнего изменения. Причина такого поведения довольно проста, в конфигурации обновленного приложения могут быть дополнительные параметры, без которых оно не сможет нормально работать, следовательно самый простой путь - перезаписать старую конфигурацию новой.
Самое грустное, что стандартные средства вроде app.config или Settings, которые можно настроить в свойствах проекта или добавить явно, предполагают хранение файла с настройками по-умолчанию рядом с исполняемым файлом. Разумеется, можно дописать недостающее в сгенерированый класс и он будет работать так как вы захотите, но по-умолчанию реализация минимальная из возможных, описание на MSDN довольно скудное, хотя при большом желании можно разобраться что и куда прописать в параметры объекта Settins, чтобы он начал себя вести хоть чуточку осмысленно (к тому же, MS сами в итоге отказались от этой идеи и по-умолчанию предлагают более легковесный и понятный app.config).
Итого, нужно сделать так, чтобы ваше приложение один раз настроенное, не теряло настройки при обновлениях. переустановках и т.д. Штатные средства этого не позволяют, значит придется писать собственный менеджер (ну или допиливать заготовку Settings от MS). Зато вы можете сами выбрать удобный для вас формат хранения настроек, хоть шифрованный бинарник, если вас или заказчика мучает паранойя.
В качестве возможных мест хранения конфигурации можно рассмотреть два: Реестр Windows (куст CurrentUser, чтобы не требовать права администратора) и папка %APPDATA%. В обоих случаях логика работы примерно одинакова, с поправкой на различие методов чтения/записи значений настроек:
Проверяем наличие папки %APPDATA%\\ или нужного раздела реестра. Проверяете наличие нужных файлов конфигурации в папке, ключей в разделе реестра. (Опционально) Проверяем версию конфигурации. Если нужные файлы/ключи реестра обнаружены и версия подходит, загружаем настройки и работаем как обычно. Если не подходит версия, дочитываем необходимое из настроек по-умолчанию, при необходимости просим пользователя уточнить параметры. Если файлы/ключи реестра не обнаружены, создаем папку и файлы, запускаем конфигуратор для пользователя или просто стартуем с настройками по-умолчанию.
Как видите, в данной схеме отсутствует упоминание "первого" и "последующих" запусков. В этом просто нет необходимости. Подобный подход не дает потерять настройки даже в результате случайного удаления и/или принудительной переустановки приложения по какой-то иной причине (при должном упорстве можно получить устойчивость и к переустановке ОС, но это уже отдельная тема).
Еще один плюс данного подхода заключается в том, что данная папка, как и конечная папка размещения приложения clickonce, находятся в профиле пользователя, а это означает, что приложение и настройки будут доступны пользователю на любой машине, если у вас есть домен, машина в домене и в домене настроены перемещаемые профили пользователей.
Как именно читать и сохранять настройки зависит от формата, который вы выберете. В простейшем случае можно просто скопировать *.config файлы с настройками по-умолчанию из папки с исполняемыми файлами в новое расположение и уже там их менять.
Для получения дополнительных сведений о текущей установке приложения clickonce воспользуйтесь классом ApplicationDeployment. Вообще стоит повнимательнее почитать про его возможности, если решили использовать clickonce.
Cсылку на приложение Environment.GetFolderPath(Environment.SpecialFolder.Programs)\PublisherName\AppName\AppName.appref-ms добавить в автозапуск любым удобным способом. При обозначенном выше способе хранения настроек, описанной вами проблемы не будет, так как они больше не привязаны к точке запуска приложения.

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

Как обратиться к элементу XAML с помощью C# в WPF приложении?

Для примера есть 2 кнопки с разным контентом

Отличаются в кнопках только Path.
Как можно реализовать программу так, чтобы не нужно было прописывать для каждого Path своё имя, но можно было изменять Path.
Для примера через имя кнопки ToggleButton.Path.Fill = ...


Ответ

Когда вы помещаете что-то внутрь тега Button - на самом деле вы устанавливаете этой кнопке свойство Content, соответственно через Content и можно попробовать добраться до нужного элемента. Это будет выглядеть примерно так:
((Path)((Grid)Button.Content).Children[0]).Fill = ...
Но я вам не рекомендую так делать, ведь это, во-первых, не удобно и громоздко, во-вторых, не надежно, т.к. фактически дерево элементов может отличаться от того, что вы видите в разметке

PasswordBox C# WPF

Здрастувуйте! Как сделать чтобы при выборе CheckBox пароль скрывался и наоборот, все никак не могу понять.


Ответ

Как вам уже сказали, такой функциональности нет у PasswordBox. Но я предложу решение-костыль, которое как-то реализовал. У нас есть TextBox, PasswordBox, CheckBox и Button.

Алгоритм проверки столкновения двух движущихся окружностей

Нужен оптимальный алгоритм определения столкновения двух движущихся окружностей. Окружности задаются координатами центров и радиусами. Движение задается углом и длинной вектора. При этом считается что обе окружности переместятся из начальной точки в конечную за одно и то-же время, т.е. скорости их движения зависят от длинны вектора.
Алгоритм "в лоб" который я сейчас использую:
Определяю количество итераций пути из расчета N = MAX(size1/r1, size2/r2) * 2 Разбиваю движение каждой окружности на N частей В цикле от 0 до N вычисляю положение каждой окружности и проверяю пересечение.
Алгоритм хорош всем кроме одного - это производительность. Может кто-то сталкивался с подобной задачей? Наверняка есть математическое описание этой модели.


Ответ

Представим ваши углы и длины по другому, а именно в координаты начальных и конечных точек. Окружности будут двигаться так:
(x11; y11) -> (x12; y12) (x21; y21) -> (x22; y22)
Введем параметр t (время), который изменяется от 0 до 1. При t=0 окружности находятся в исходных точках, при t=1 - в конечных. Тогда координаты центров окружностей во время движения будут:
x1 = x11 + (x12 - x11) * t y1 = y11 + (y12 - y11) * t
x2 = x21 + (x22 - x21) * t y2 = y21 + (y22 - y21) * t
В момент соприкосновения расстояние между центрами окружностей равно сумме радиусов. Получаем:
(r1 + r2)^2 = (x1 - x2)^2 + (y1 - y2)^2
Если подставить координаты точек в уравнение соприкосновения, получим огромное квадратное уравнение относительно t. Его коэффициенты такие:
a = x11 * x11 + x12 * x12 + y11 * y11 + y12 * y12 + x21 * x21 + x22 * x22 + y21 * y21 + y22 * y22 + 2 * (- x11 * x12 - x21 * x22 - y11 * y12 - y21 * y22 - x11 * x21 - y11 * y21 + x11 * x22 + y11 * y22 + x12 * x21 + y12 * y21 - x12 * x22 - y12 * y22); b = 2 * ( - x11 * x11 - x21 * x21 - y11 * y11 - y21 * y21 + x11 * x12 + y11 * y12 + x21 * x22 + y21 * y22 - x11 * x22 - y11 * y22 - x12 * x21 - y12 * y21 + 2 * x11 * x21 + 2 * y11 * y21) c = x11 * x11 - 2 * x11 * x21 + x21 * x21 + y11 * y11 - 2 * y11 * y21 + y21 * y21 - (r1 + r2) * (r1 + r2);
Как и любое квадратное уравнение, оно может иметь 0 решений (окружности не пересекаются), бесконечность решений (окружности скользят по параллельных отрезках), 2 решения (окружности соприкасаются, пересекаются, и расходятся), 1 решение (окружности касаются только один раз).
Плюс к этому нужно проверить, входит ли t в промежуток 0..1
Пример:
(-5; -10) -> (3; 10) [r1 = 1] (-10; -1) -> (10; -10) [r2 = 1]
Решения:
t1 = 0.274411137729595 t2 = 0.377365512016598
Координаты окружностей в момент пересечения:
(-2.805; -4.512) (-4.512; -3.470)

Автоматическое заполнение сетки ячеек

Есть поле пикселей и код для выбора пикселя, который меняет цвет:
$(".pixel").click(function() { $(this).toggleClass("white"); $(this).toggleClass("black"); }) var delta; var isCall = false; if (!isCall) { var zoom = 1; isCall = true; } #art { width: 101px; height: 101px; display: table; border-spacing: 1px; background-color: #d8d8d8; } .row { display: table-row; } .pixel { display: table-cell; } .black { background-color: black; } .white { background-color: white; }


Но возникла необходимость автоматически заполнять все поле, допустим я нажимаю на какую-нибудь клеточку и с небольшими задержками заполняются рандомные соседние клеточки(как домино падает во все стороны) и так пока не будет заполнено все поле. Такое возможно вообще реализовать? Мне намекнули, что похожий алгоритм в игре KAMI, но я пока не придумал, как такое можно сделать, поэтому надеюсь на ваши советы.


Ответ

var size = 20; for (var i = 0; i < size; i++) { var row = $('

'); $("#art").append(row); for (var j = 0; j < size; j++) { row.append('
'); } } var timerFind = null; var convert = []; $(".pixel").click(function() { $(this).removeClass("white"); $(this).addClass("black"); if (timerFind) return; function FindPixels() { var matrix = []; $(".row").each(function(iRow, row){ matrix[iRow] = []; $(row).find(".pixel").each(function(iPix, pix){ matrix[iRow].push($(pix)); }); }); var blacks = []; for (var iRow = 0; iRow < matrix.length; iRow++) { for (var iPix = 0; iPix < matrix[iRow].length; iPix++) { if (matrix[iRow][iPix].hasClass("black")) blacks.push({ row: iRow, col: iPix }); } } for (var iB = 0; iB < blacks.length; iB++) { for (var i = Math.max(0, blacks[iB].row-1); i <= Math.min(matrix.length-1, blacks[iB].row+1); i++) { for (var j = Math.max(0, blacks[iB].col-1); j <= Math.min(matrix[0].length-1, blacks[iB].col+1); j++) { if ((i == blacks[iB].row || j == blacks[iB].col) && matrix[i][j].hasClass("white") && convert.indexOf(matrix[i][j]) == -1) { convert.push(matrix[i][j]); $("#convert").text(convert.length); } } } } if (convert.length > 0) { var index = Math.floor(Math.random() * convert.length) convert[index].removeClass("white"); convert[index].addClass("black"); convert = []; $("#convert").text(convert.length); } if ($(".pixel.white").length == 0) { console.log("done"); } else { timerFind = setTimeout(FindPixels, 100); } } // FindPixels timerFind = setTimeout(FindPixels, 100); }); $(".row").last().find(".pixel").last().click(); #art { width: 181px; height: 181px; display: table; border-spacing: 1px; background-color: #d8d8d8; } .row { display: table-row; } .pixel { display: table-cell; } .black { background-color: black; } .white { background-color: white; } 0

При преобразовании String с дробными числами теряется информация

Столбец excel содержит числа в диапазоне от 1 до 0.0001. Когда оператор в ручную делает суммирование стобца примерно из 10-30 строк получается число 15,028
Я делаю автоматизацию. Мне в программу приходят данные из БД ОРАКЛ. Информация приходит в виде строк. Я преобразую строки в тип Double и суммирую. Сумма тех же строк дает у меня 13,9
Может ли Double округлять значения из-за чего информация теряется и как с этим бороться?
for (String[] rowx : СписокмассивовстрокИзОракл) { String key = "комбинация данных по логике автоматизации"; try { if (mapMass.containsKey(key)) { try { double src = 0.0; try { src = Double.valueOf(rowx[timeFakt]); //косяк, данные хранящиеся в ячейке timeFakt могут быть типа 0,0028 или 0,0000034. и они округляются. } catch (Exception e) { e.printStackTrace(); } total = Double.valueOf(mapMassTwo.get(key)) + src; String tf = String.valueOf(total); mapMassTwo.put(key, tf); total = 0.0; } catch (Exception e) { e.printStackTrace(); } } else { String tf = rowx[timeFakt]; mapMass.put(key, tf ); } } catch (Exception e) { e.printStackTrace(); } }


Ответ

Да, вполне. Операции с числами с плавающей точкой могут приводить к потерям. Вы можете использовать BigDecimal
BigDecimal sum = new BigDecimal(0);
while (thereIsNumbers()) { BigDecimal number = new BigDecimal(getNextNumberAsStringFromExcel()); sum = sum.add(number); }
System.out.println(sum);
При создании BigDecimal важно передавать в конструктор именно строку. Если вы передадите туда представление вашей строки уже в виде double, то могут быть погрешности.
Немного про погрешности: https://habrahabr.ru/post/219595/

Выбор кандидатов при вызове функций

Почему в следующем коде std::swap не рассматривается в качестве кандидата при вызове swap и приходится писать его полностью с пространством имён? Я ожидал, что обе функции (std::swap и smth::swap) попадут в кандидаты, а дальше выбор сделается на основе пареметров (как при перегрузке функций).
https://ideone.com/JGcZDR
#include
using namespace std;
struct smth { int x;
void swap(smth &s) { ////// error: no matching function for call to ‘smth::swap(int&, int&)’ ////// note: candidate: void smth::swap(smth&) ////// note: candidate expects 1 argument, 2 provided ////swap(x, s.x);
std::swap(x, s.x); } };
int main() { return 0; }


Ответ

Поиск неквалифицированных имен (unqualified name lookup) при вызове функции состоит из двух частей: обычного поиска и ADL-поиска.
Обычный поиск выполняется "изнутри наружу": из внутренней области видимости во все более и более охватывающие области видимости, пока хотя бы одно имя не найдено. Когда хотя бы одно имя найдено, обычный поиск немедленно прекращается
Какие области видимости просматриваются зависит от контекста. В вашем случае - это поим имени swap, использованного в определении функции-члена класса. Для такого контекста поиск выполняется в следующих областях видимости: локальная, класс smth, пространство имен ::. В процессе просмотра имя swap найдется в классе smth - это имя вашей же функции. Т.е. до поиска в глобальном пространстве имен дело не доходит вообще. ADL-поиск выполняется в пространствах имен, ассоциированных с типами аргументов вызываемой функции. Но в случае фундаментального типа int ADL не выполняется - у типа int нет ассоциированных пространств имен.
Более интересным был бы пример с
struct smth { std::string x;
void swap(smth &s) { swap(x, s.x); } };
В такой ситуации у типа std::string есть ассоциированное с ним пространство имен std. И ADL-поиск мог бы выполнить поиск в пространстве имен std (даже ваш using namespace std; не нужен) и найти там правильный std::swap. Однако особое правило unqualified name lookup говорит, что если обычный поиск нашел именно функцию-член класса, то ADL не выполняется вообще. Поэтому и здесь будет та же самая ошибка.

Авторские права на GitHub?

Не пойму какое реальное практическое применение имеет сервис github и как обстоят дела с авторскими правами?
В чем логика выкладывать свой код на всеобщее обозрение, чтобы его скопировали и потом продавали? Или там реальные вещи, которые несут материальную ценность не выкладываются? Или там что-то типа: о посмотрите, я написал новый супер-аудиоплеер, качайте на здоровье и пользуйтесь. Или сервис наполовину коммерческий, типа вот ограниченные версии кода, можете пользоваться, а если хотите что-то нормальное - покупайте лицензию? И что понимается под авторскими правами на GitHub-e, да и вообще впринципе. Верстка сайта (сами блоки, расположение), если скопировать (кроме дизайна) - это считается нарушением авторских прав? С дизайном понятно, если макет один в один - это вроде как нарушение авторских прав. И кстати, сам дизайн макет по сути налеплен из разных фоток, зачастую с лицами людей - сами-то дизайнеры откуда берут это все, тупо качают из интернета чужие фотки? Если взять код с функционалом типа CMS - это тоже нарушение авторских прав? Может я что-то не понимаю, но принцип CMS же примерно одинаковый, генерить статичные страницы, каталог и прочее взаимодействие? Взять тот же Bitrix, это что-то супер-уникальное чего нет в открытом доступе? Неужели за столько лет развития интернета в сети не появилось бесплатного качественного аналога платной CMS?


Ответ

В чем логика выкладывать свой код на всеобщее обозрение, чтобы его скопировали и потом продавали?
Есть такое понятие, как свободное ПО. Это когда вы выкладываете свой код под свободной лицензией, а в ответ получаете сообщество (по сути, бесплатных программистов, тестировщиков, авторов документации и многопрофильную службу поддержки на добровольных началах, мотивированных исключительно интересом к вашему продукту). Этот подход, кстати, применим и в бизнесе. В этом случае разработчик зарабатывает за счёт продажи не самого продукта (платформы), а своего рода премиум-услуг к нему (дополнительные модули, расширенная поддержка, помощь в интеграции и т. д.). В этом случае копирование кода не принесёт какого-либо вреда — всё равно дохода непосредственно от него ноль. Также компании могут выкладывать свои старые разработки, которые потеряли коммерческую ценность.
Или там реальные вещи, которые несут материальную ценность не выкладываются?
Вот вам пара примеров продуктов, живущих и здравствующих с такой бизнес-моделью:
NGINX (некоммерческая версия: https://nginx.ru/ru/ и коммерческая версия: https://www.nginx.com/), Qt (https://www.qt.io/).
Эти вещи реальны и приносят доход своим компаниям-владельцам.
Насчёт web-фреймворков сказать ничего не могу — не моя область.
Или сервис наполовину коммерческий, типа вот ограниченные версии кода, можете пользоваться, а если хотите что-то нормальное — покупайте лицензию?
Исходные коды продукта выложены в репозиторий, поэтому ни о какой пробной версии речи идти не может.
И что понимается под авторскими правами на GitHub-e, да и вообще в принципе.
То, что прописано в местных законах об авторском праве. Процитирую свой старый ответ на смежную тему:
... если планируете распространять программу в странах, принявших Бернскую конвенцию (среди которых есть РФ и США). Упоминание авторства — это реализация права на авторство, относящегося к неисключительным правам. Упоминание лицензии — указание на условия, по которым вам была передана копия библиотеки. Дело в том, что ничто не мешает автору раздавать одну и ту же библиотеку под различными лицензиями различным людям и предприятиям. Соответственно, при дальнейшем распространении (если лицензия это разрешает) вы мало того что тоже должны предоставить пользователям условия и разрешения, так ещё и указать, что это самое распространение вообще законно.

Верстка сайта (сами блоки, расположение), если скопировать (кроме дизайна) — это считается нарушением авторских прав? С дизайном понятно, если макет один в один — это вроде как нарушение авторских прав.
Тут весьма тонкая грань — надо обращаться к юристу.
И кстати, сам дизайн макет по сути налеплен из разных фоток, зачастую с лицами людей — сами-то дизайнеры откуда берут это все, тупо качают из интернета чужие фотки?
Кстати да, покупая макет, вы имеете право запросить копии всех лицензионных соглашений дизайнера этого макета с авторами фотографий или фотобанками.
Если взять код с функционалом типа CMS — это тоже нарушение авторских прав?
Зависит от лицензии (лицензионного соглашения), под которой этот код распространялся. Если она это разрешает, то нет, не является.
Может я что-то не понимаю, но принцип CMS же примерно одинаковый, генерить статичные страницы, каталог и прочее взаимодействие? Взять тот же Bitrix, это что-то супер-уникальное чего нет в открытом доступе? Неужели за столько лет развития интернета в сети не появилось бесплатного качественного аналога платной CMS?
С одной стороны, эту генерацию можно производить по разному. Но, с другой стороны, имеется нехороший прецедент судебной тяжбы между Oracle и Google из-за девяти строк кода. Так что с этим, опять же, только к юристу.

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

Есть точка в пространстве описанная 3мя числами: x,y,z
Есть угол поворота описанный кватернионом W,X,Y,Z
Нужно повернуть точку вокруг центра координат (0,0,0) и получить ее новые координаты.
Каким образом это вообще можно делать?
например, если точка имеет положение 0,10,0 , а кватернион описывает поворот вокруг Z оси на 180 градусов, на выходе должно получится 0,-10,0


Ответ

Попробовал матрицу поворота из комментария:

получилось вот что:
function rotate_direction_by_q(a,b){
var w=b[3]; var x=b[0]; var y=b[1]; var z=b[2]; var out=[];
out[0] = a[0] * (1 - 2*y*y - 2*z*z) + a[1] * (2*x*y - 2*z*w) + a[2] * (2*x*z + 2*y*w) ; out[1] = a[0] * (2*x*y + 2*z*w) + a[1] * (1 - 2*x*x - 2*z*z) + a[2] * (2*y*z - 2*x*w) ; out[2] = a[0] * (2*x*z - 2*y*w) + a[1] * (2*y*z + 2*x*w) + a[2] * (1 - 2*x*x - 2*y*y) ;
return out; }
Кватернион я беру из движка Blend4web. Там почему-то W идет в конце, поэтому w=b[3] a не w=b[0]
Тестируем поворот на 90 градусов:
кватернион (с неправильным w): [0, 0, 0.7071099877357483, 0.7071099877357483] координаты: [0,10,0] результат: [-10.000090695113002, -0.00009069511300197064, 0]
Работает!

Анимация указателя по часовой стрелке

чтобы доходило к пример до середины зеленой области. На js Или css лучше сделать? https://codepen.io/st-iv/pen/QaxEPM
.progress__bar { display: inline-block; background: url("https://image.ibb.co/dTVvGm/js_skill.png") no-repeat; background-size: contain; height: 128px; width: 100%; position: relative; } .arrow { position: absolute; height: 32px; bottom: 0; left: 20%; https://image.ibb.co/dp9pbm/Untitled_1.png }



Ответ

В css анимации есть свойство transform-origin которое задает точку анимации. В нашем случае это будет точка по которой будет вращаться картинка.
Просто надо определить точку анимации и вращать картинку по нему.
.progress__bar { display: inline-block; background: url("https://image.ibb.co/dTVvGm/js_skill.png") no-repeat; background-size: contain; height: 128px; width: 100%; position: relative; } .arrow { position: absolute; transform: rotateZ(-33deg); height: 32px; bottom: -5px; left: 85px; animation: example 5s linear 2s infinite alternate; transform-origin: 40px 26px; } span{ position: absolute; top: 139px; left: 138px; width: 1px; height: 1px; background: green; } @keyframes example { from { transform: rotateZ(-33deg); } to { transform: rotateZ(148deg); } }


Вот второй вариант с конечной остановкой.
.progress__bar { display: inline-block; background: url("https://image.ibb.co/dTVvGm/js_skill.png") no-repeat; background-size: contain; height: 128px; width: 100%; position: relative; } .arrow { position: absolute; transform: rotateZ(-33deg); height: 32px; bottom: -5px; left: 85px; animation: example 5s linear 2s; animation-direction: normal; animation-fill-mode: forwards; transform-origin: 40px 26px; } span{ position: absolute; top: 139px; left: 138px; width: 1px; height: 1px; background: green; } @keyframes example { from { transform: rotateZ(-33deg); } to { transform: rotateZ(148deg); } }

Вот еще один вариант. Можно задать другой animation-timing-function. Например ease-out. И сейчас конечная часть анимации будет медленней чем начальная.
Так красиво.
.progress__bar { display: inline-block; background: url("https://image.ibb.co/dTVvGm/js_skill.png") no-repeat; background-size: contain; height: 128px; width: 100%; position: relative; } .arrow { position: absolute; transform: rotateZ(-33deg); height: 32px; bottom: -5px; left: 85px; -webkit-animation: in 3s linear 1s; animation-timing-function: ease-out; animation-direction: normal; animation-fill-mode: forwards; transform-origin: 40px 26px; } span{ position: absolute; top: 139px; left: 138px; width: 1px; height: 1px; background: green; } @keyframes in { from { transform: rotateZ(-33deg); } to { transform: rotateZ(148deg); } }

Как div может пропадать со страницы HTML после посещения ссылки?

Как сделать так, чтобы

пропадал со страницы HTML после посещения ссылки? То что display: none; это понятно, а какой должна быть полная конструкция в CSS?
Пример:


Ответ

Все когда-либо посещённые ссылки (которые окрашиваются по умолчанию в фиолетовый) подпадают под CSS-селектор :visited
.visit_once:visited { color: white } Если вы видите эту ссылку, значит вы не посещали её
Важное замечание: вы не сможете полноценно скрыть посещённую ссылку через display: none, так как возможности селектора visited сильно ограничены в целях безопасности. Подробнее об этом можно почитать в статье «Privacy-related changes coming to CSS :visited» блога «Mozilla Hacks».

Возможно ли подключить библиотеки .NET Framework в .NET Core 2.1.4?

Нужно подключить библиотеку в виде DLL, но у меня не получается. Возможно ли это?


Ответ

В общем случае нельзя. Например, потому, что .NET Core является подмножеством .NET Framework. Выход: перевести библиотеку на ту версию .NET Standard, которая поддерживает .NET Core.
Многие 3rd party библиотеки потихоньку обзаводятся соответствующии версиями.
Upd
Говорят еще, что если библиотека не содержит Windows-specific вызовов, то ее можно зареференсить прямо так. Но я не проверял. Какую библиотеку вы пытаетесь подключить и что именно у вас не получается?
P.S. Ну и заодно привяжу "обратный" вопрос: Использование Net.Core библиотек в Net.Framewok

Python: встроенная функция dir()

Почему вывод атрибутов класса при помощи встроенной функция dir() не содержит такие атрибуты класса, как class.__bases__ и class.__mro__?


Ответ

Из документации
If the object is a type or class object, the list contains the names of its attributes, and recursively of the attributes of its bases.
По-русски говоря, dir() рекурсивно отображает содержимое атрибута __dict__ самого класса и всех его суперклассов, но атрибуты __bases__ и __mro__ в них не входят, так как относятся не к классу, а к типу

Разный IL для инициализации свойств со значениями

Рассматриваю в Linqpad'е IL-код простенького итератора:
void Main() { var a = new A(); a.Skip(2).Take(5).Dump(); }
public class A : IEnumerable { public IEnumerator GetEnumerator() { return new B(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
public class B : IEnumerator { public int Current { get { return 123; } }
object IEnumerator.Current { get { return this.Current; } }
public void Dispose() {}
public bool MoveNext() { return true; }
public void Reset() {} }
Любопытно сравнение кода, если воспользоваться новой возможностью c# 6 Инициализация свойств со значениями и заменить:
public int Current { get { return 123; } }
на:
public int Current => 123;
Вот что будет в IL для первого случая:
B.get_Current: IL_0000: nop IL_0001: ldc.i4.s 7B IL_0003: stloc.0 IL_0004: br.s IL_0006 IL_0006: ldloc.0 IL_0007: ret
и второго:
B.get_Current: IL_0000: ldc.i4.s 7B IL_0002: ret
Обычно новые фичи языка утяжеляют конструкции, но тут обратный случай: код чище и быстрее.
Я не понимаю, что помешало комплятору в первом случае выкинуть явно лишние команды. В обоих случаях Current – свойство get-only, простая константа.
При этом если рассматривать классическую замену, то происходят абсолютно аналогичные вещи.
Для
void Main() { var abc = new Abc {}; }
public class Abc { private int _id = 123; // backing field public int Id { get { return _id; } set { _id = value; } } }
будет сгенерирован такой код:
IL_0000: nop IL_0001: newobj UserQuery+Abc..ctor IL_0006: stloc.0 // abc IL_0007: ret
Abc.get_Id: IL_0000: nop IL_0001: ldarg.0 IL_0002: ldfld UserQuery+Abc._id IL_0007: stloc.0 IL_0008: br.s IL_000A IL_000A: ldloc.0 IL_000B: ret
Abc.set_Id: IL_0000: nop IL_0001: ldarg.0 IL_0002: ldarg.1 IL_0003: stfld UserQuery+Abc._id IL_0008: ret
Abc..ctor: IL_0000: ldarg.0 IL_0001: ldc.i4.s 7B IL_0003: stfld UserQuery+Abc._id IL_0008: ldarg.0 IL_0009: call System.Object..ctor IL_000E: nop IL_000F: ret
А для
public int Id { get; set; } = 123;
оптимизированный:
IL_0000: nop IL_0001: newobj UserQuery+Abc..ctor IL_0006: stloc.0 // abc IL_0007: ret
Abc.get_Id: IL_0000: ldarg.0 IL_0001: ldfld UserQuery+Abc.k__BackingField IL_0006: ret
Abc.set_Id: IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: stfld UserQuery+Abc.k__BackingField IL_0007: ret
Abc..ctor: IL_0000: ldarg.0 IL_0001: ldc.i4.s 7B IL_0003: stfld UserQuery+Abc.k__BackingField IL_0008: ldarg.0 IL_0009: call System.Object..ctor IL_000E: nop IL_000F: ret
Вообще, что делает соптимизированный участок кода, какую роль он выполняет в старой версии кода?
Выигрыш в коде получается копеечный, но выходит что в целях микрооптимизаций (если вдруг дойдёт до них) предпочтительнее использовать новую конструкцию.


Ответ

Вообще вопрос сам по себе достаточно бессмысленный.
Вы сравниваете результат компиляции в IL, явно указываете что собираете с отключенной отптимизацией
я в подобных случаях проверяю, что оптимизации выключены, не забыл и сейчас. Отключено, отключено - можете сами проверить. Вон же отладочные nop'ы для брейков в коде видны.
но и при этом пытаетесь сравнить "оптимизированность" кода.
Т.е. вы явно запретили компилятору оптимизировать, и делаете из последствий вашего запрета вывод, что компилятор иногда выдает "неоптимизированный код" :)
Если хотите получить оптимизированный код - включите оптимизацию. Если хотите получить код с отладочными вставками - выключите оптимизацию.
Вот этот артефакт:
IL_0007: stloc.0 IL_0008: br.s IL_000A IL_000A: ldloc.0
позволяет вам поставить брекпойнт на закрывающую скобку в
get { return _id; }
В случае нескольких return в методе - вы, скорее всего, получите пачку безусловных переходов на одну и ту же метку:
get { if (some) { return _id; } else { return 42; } } // брекпойнт на этой строке срабатывает всегда!
IL:
IL_0000: nop IL_0001: ldarg.0 IL_0002: ldfld bool ConsoleApp1.Abc::some IL_0007: stloc.0 IL_0008: ldloc.0 IL_0009: brfalse.s IL_0015 IL_000b: nop IL_000c: ldarg.0 IL_000d: ldfld int32 ConsoleApp1.Abc::_id IL_0012: stloc.1 IL_0013: br.s IL_001b IL_0015: nop IL_0016: ldc.i4.s 42 IL_0018: stloc.1 IL_0019: br.s IL_001b IL_001b: ldloc.1 IL_001c: ret
При отключенной отптимизации компилятор старается сделать код удобным для отладки, и, кроме nop-ов, вставляет вот такие вот костыли с явным сохранением возвращаемого значения в локальную переменную.
Включите оптимизацию - и отладочные хаки из IL исчезнут.
enSO:
Why is the 'br.s' IL opcode used in this case? Why does this very simple C# method produce such illogical CIL code?

C# ThreadPool, почему не работает .ToArray()/

Добрый вечер, не хочет работать ToArray(), да и вообще ни как не могу использовать результаты выполнения функции, которую я выполняю в пуле потоков. В дебагере видно, что массив globalOrder содержит элементы, но он их не отдает, ни с помощью .ToArray(), ни перечислением всех объектов, итоговый массив orders просто остается пустым. В чем причина, может кто сталкивался?
p.s. до того, как я поместил её в ThreadPool все работало.
Фрагмент кода:
ProgressbarModal bar1 = new ProgressbarModal();
var timeStart = DateTime.Now; List globalOrder = new List();
if (obj == null) { ThreadPool.QueueUserWorkItem(test.GetOrders, globalOrder); } else if (obj is DateTime) { var param = new Tuple>((DateTime)obj, globalOrder); ThreadPool.QueueUserWorkItem(test.GetOrders1, param); } else if (obj is DateTime[]) { var param = new Tuple>((DateTime[])obj, globalOrder); ThreadPool.QueueUserWorkItem(test.GetOrders2, param); } else if(obj is Int32) { var param = new Tuple>((Int32)obj, globalOrder); ThreadPool.QueueUserWorkItem(test.GetOrders3, param); } else { return; }
bar1.ShowDialog(); // Вот тут проблема, на точке останова, я вижу, что globalOrder // содержит 3000+ объектов, но массив orders так и остается пустой Order[] orders = globalOrder.ToArray();
ProgressbarModal bar = new ProgressbarModal();
ThreadPool.QueueUserWorkItem(OrdersWorker.Insert, orders); bar.ShowDialog();


Ответ

ThreadPool.QueueUserWorkItem() говорит о том, что метод должен быть выполнен в потоке пула. После этого вызова программа продолжает выполняться дальше. Это значит, что когда вы обращаетесь к списку globalOrder, он еще не успел заполниться. Вам нужно переосмыслить то, что вы делаете, и, возможно, дожидаться окончания работы функций GetOrders
К тому же стоит использовать потокобезопасную коллекцию (например, ConcurrentBag), иначе при записи из одного потока и при чтении из другого потока возможны ошибки и/или получение неконсистентных данных. В этом не будет необходимости в случае, если вы будете дожидаться окончания работы потока.

Как заставить SVG фигуру кружиться вокруг середины блока?

Дамы и Господа, есть такое примитивный пример:

Хочу заставить треугольник крутиться вершиной вокруг середины блока SVG
Не прошу банального решения за меня, прошу объяснить, как работает система координат from="1 1 100 " to="100 100 100". Если я правильно понял это аналог @keyframes - CSS и если я прав, то правильной ли будет такая конструкция со средними значениями from="1 1 100 " 50%="50 50 50" to="100 100 100"
И вообще, правильном ли я направлении в реализации данной задачи?


Ответ

От нуля до 360 градусов вокруг точки (50, 50):

Чтение построчно out of memory

В данном коде при обработке файла в 200 мегабайт выскакивает ошибка: out of memory. Как исправить Данную ошибку в этом коде ?
var list:TStrings; i:integer; str:string;
begin list :=TStringList.Create; list.LoadFromFile(OpenDialog1.FileName);
for i :=list.count-1 downto 0 do begin str :=list.Strings[i];
while Pos(edit1.text, str) >0 do begin Delete(str, Pos(edit1.text, str), Length(edit1.text)) ; list.Strings[i] :=str; end; end;
list.SaveToFile('out.txt'); list.free; end;


Ответ

var txtIn, txtOut: TextFile; str: string; begin AssignFile(txtIn, OpenDialog1.FileName); AssignFile(txtOut, ExtractFilePath(OpenDialog1.FileName) + 'tmp.txt');
Reset(txtIn); Rewrite(txtOut);
while not EOF(txtIn) do begin ReadLn(txtIn, str); // ... WriteLn(txtOut, str); end;
CloseFile(txtOut); CloseFile(txtIn);
// move 'tmp.txt' to OpenDialog1.FileName end;