суббота, 24 июня 2017 г.

Ещё про функторы

PROCEDURE EnumWindowChildren
  nWnd IN aWindow
  FUNCTOR IN aLambda
 
 aWindow aLambda DO
 // - вызываем aLambda на aWindow
 aWindow .EnumChildren ( aLambda call.me )
 // - вызываем себя рекурсивно
; // EnumWindowChildren

FunctorToIterator Desktop EnumWindowChildren .for .Out
// - перебираем все окна от Desktop рекурсивно

А теперь с анонимной функцией:

FunctorToIterator Desktop (
  nWnd IN aWindow
  FUNCTOR IN aLambda
 
 aWindow aLambda DO
 // - вызываем aLambda на aWindow
 aWindow .EnumChildren ( aLambda call.me )
 // - вызываем себя рекурсивно
) .for .Out
// - перебираем все окна от Desktop рекурсивно

Про функторы и итераторы. Простой пример

PROCEDURE .To
  IN aLowBound
  IN aHighBound
  FUNCTOR IN aLambda
 if ( aLowBound <= aHighBound ) then
 // - граничное условие
 begin
  aLowBound aLambda DO // - вызываем aLambda на aLowBound 
  Inc aLowBound // - увеличиваем aLowBound 
  aLowBound aHighBound aLambda call.me
  // - вызываем себя рекурсивно  
 end // ( aLowBound <= aHighBound )
; // .To

FunctorToIterator ( 1 10 ) .To .for .Out 
// - печатает числа от 1 до 10

FunctorToIterator ( 1 10 ) .To 
.filter ( <> 2 ) 
.for .Out 
// - печатает числа от 1 до 10, исключая 2

FunctorToIterator ( 1 10 ) .To 
.filter ( <> 2 ) 
.map ( 1 + ) 
.for .Out 
// - печатает числа от 2 до 11, исключая 3

То же самое, но с параметром справа:
PROCEDURE To
  IN aLowBound
  FUNCTOR IN aLambda
  Right IN aHighBound
 if ( aLowBound <= aHighBound ) then
 // - граничное условие
 begin
  aLowBound aLambda DO // - вызываем aLambda на aLowBound 
  Inc aLowBound // - увеличиваем aLowBound 
  aLowBound aLambda call.me aHighBound
  // - вызываем себя рекурсивно  
 end // ( aLowBound <= aHighBound )
; // To

FunctorToIterator 1 To 10 .for .Out 
// - печатает числа от 1 до 10

FunctorToIterator 1 To 10
.filter ( <> 2 ) 
.for .Out 
// - печатает числа от 1 до 10, исключая 2

FunctorToIterator 1 To 10
.filter ( <> 2 ) 
.map ( 1 + ) 
.for .Out 
// - печатает числа от 2 до 11, исключая 3

Немножко косметики:

ARRAY FUNCTION To
  IN aLowBound
  Right IN aHighBound

 PROCEDURE InnerTo
   IN aLowBound
   FUNCTOR IN aLambda
   Right IN aHighBound
  if ( aLowBound <= aHighBound ) then
  // - граничное условие
  begin
   aLowBound aLambda DO // - вызываем aLambda на aLowBound 
   Inc aLowBound // - увеличиваем aLowBound 
   aLowBound aLambda call.me aHighBound
   // - вызываем себя рекурсивно  
  end // ( aLowBound <= aHighBound )
 ; // InnerTo

 FunctorToIterator aLowBound InnerTo aHighBound
 >>> Result
; // To 

1 To 10 .for .Out 
// - печатает числа от 1 до 10

1 To 10
.filter ( <> 2 ) 
.for .Out 
// - печатает числа от 1 до 10, исключая 2

1 To 10
.filter ( <> 2 ) 
.map ( 1 + ) 
.for .Out 
// - печатает числа от 2 до 11, исключая 3

Ещё косметики:
ARRAY FUNCTION To
  IN aLowBound
  Right IN aHighBound

 PROCEDURE InnerTo
   IN aLowBound
   FUNCTOR IN aLambda
   Right IN aHighBound
  if ( aLowBound <= aHighBound ) then
  // - граничное условие
  begin
   aLowBound aLambda DO // - вызываем aLambda на aLowBound 
   Inc aLowBound // - увеличиваем aLowBound 
   aLowBound aLambda call.me aHighBound
   // - вызываем себя рекурсивно  
  end // ( aLowBound <= aHighBound )
 ; // InnerTo

 FunctorToIterator aLowBound InnerTo aHighBound
 >>> Result
; // To 

PROCEDURE for
  ARRAY Right anArray
  FUNCTOR Right aLambda
 anArray .for> aLambda  
; // for

for ( 1 To 10 ) 
.Out 
// - печатает числа от 1 до 10

for
( 1 To 10
.filter ( <> 2 ) 
)
.Out 
// - печатает числа от 1 до 10, исключая 2

for 
( 1 To 10
.filter ( <> 2 ) 
.map ( 1 + ) 
)
.Out 
// - печатает числа от 2 до 11, исключая 3


Ещё про скипты


Также это в некотором смысле - аналог json.

Можно написать:

Elem A
 Elem B
 ; // B
 Elem C
 ; // C
; // A

PROCEDURE .Print
  IN anElement
 anElement .Stereotype .Out // - печатаем стереотип элемента
 anElement .Name .Out // - печатаем имя элемента
 anElement .MembersIterator .for call.me
 // - итерируем вложенные элементы и вызываем себя рекурсивно
; // .Print

@ A .Print

Будет напечатано:

Elem
A
Elem
B
Elem
C

А можно написать так:

STRING VAR S
S :=
'
Elem A
 Elem B
 ;
 Elem C
 ;
;
' 
>>> S // - кладём "код в строку"
// Да - строки в кавычках могут содержать в себе и переводы строк тоже 

S
.CompileStringAndDo .Print
// - компилируем строку и вызываем для построенного кода функцию .Print

Результат будет тот же.

А можно написать так:

: .ToStack
  IN anElement
 anElement // - это кладём на стек
 anElement .MembersIterator .for call.me
 // - итерируем вложенные элементы и вызываем себя рекурсивно
; // .ToStack

STRING VAR S
S :=
'
Elem A
 Elem B
 ;
 Elem C
 ;
;
' 
>>> S // - кладём "код в строку"
// Да - строки в кавычках могут содержать в себе и переводы строк тоже 

ARRAY VAR A
[ // - открываем массив
S .CompileStringAndDo .ToStack
] // - закрываем массив
>>> A // - кладём массив в переменную A

A .for .Out // - печатаем массив полностью
A .filter ( .Name <> 'B' ) .for .Out // - печатаем из массива элементы имя которых НЕ РАВНО B

Ну и всякие подобные штучки.

А можно без копирования:

PROCEDURE .Unfold
  IN anElement
  FUNCTOR IN aLambda
 anElement aLambda DO // - вызываем функтор aLambda на элементе anElement
 anElement .MembersIterator .for ( aLambda call.me )
 // - итерируем вложенные элементы и вызываем себя рекурсивно
; // .Unfold

STRING VAR S
S :=
'
Elem A
 Elem B
 ;
 Elem C
 ;
;
' 
>>> S // - кладём "код в строку"
// Да - строки в кавычках могут содержать в себе и переводы строк тоже 

VAR A
S .CompileStringAndDo ( >>> A ) // - компилируем код из строки S и кладём результат в переменную A

FunctorToIterator 
// - преобразование функтора в итератор
A 
// - параметр функтора
.Unfold 
// - сам функтор
.for .Out // - печатаем массив полностью

FunctorToIterator A .Unfold .filter ( .Name <> 'B' ) .for .Out // - печатаем из массива элементы имя которых НЕ РАВНО B

четверг, 22 июня 2017 г.

ToDo

Try..finally..end заменить на:

Try_finally ( a ) ( b )
Try_except ( a ) ( b )

И пихать begin в поток токенов.

Чтобы try a finally b end разворачивалось в:

Try_finally begin a end begin b end

Ну и try a except b end соответственно:

Try_except begin a end begin b end

Убрать FirstHalf и DualCompilingWord.

ToDo

Для слов сделать экземпляры, а не классы.

С event'ами.

среда, 21 июня 2017 г.

ToDo

Сделать Bind. С проверкой типов:

A pop:Word:Name
- типы не проверяются

A .Bind pop:Word:Name
- типы проверяются

И алиас ¦-> с подстановкой "pop:":

A ¦-> pop:Word:Name
- типы проверяются

A ¦-> Word:Name
- типы проверяются (производится постановка)

И "выбор типа":

A ¦¦-> Name
- типы проверяются (и производится выбор типа).

Для этого сделать на ValueTypes метод SelfName.

пятница, 16 июня 2017 г.

Написали...

"Привет! Есть вопрос один рядом с программированием. Я поддерживаю прогу одну, ранее участвовал в ее разработке. Обычно запускали ее на полноценных ноутах и разницы с настольным компом не видели. А вот сейчас запустили ее на мини-ноуте и работает в два раза медленнее. На мини ноуте проц стоит Atom x5-z8350? памяти 4Гб. графика не знаю какая, система 10-ка домашняя 64разряда. Обычно мы работали на Core i5 4570 или старше, оперативки 16Гб, система 7-ка профессиональная. Программа использует .net  При запуске программы на мини ноуте проц нагружается процентов на 10, память - суммарно со всеми службами - процентов на 50. Собственно вопрос - как выяснить, где узкое место? Проц/память/графика/система/платформа/все вместе? Никогда просто этим не занимался - и попал в тупик."

Алгоритм маляра - одна из ПЕРВЫХ причин:
http://russian.joelonsoftware.com/Articles/BacktoBasics.html

По моему скромному мнению - в алгоритме маляра" наблюдается 80% проблем.

Вторая проблема - фрагментированность памяти. "Давить аллокации" - как писал мой друг Максим Лапшин.

Третья проблема - неудачная сортировка в контейнерах. Возможно надо использовать дихотомию (бинарную сортировку) вместо сортировки "пузырьком" (на контейнерах больше 1000 элементов, если верить Кнуту). Ну или использовать "мапы" вместо "векторов".

Ну и как советут Степанов - "сначала набираем данные, потом их фильтруем, , потом трансформируем, потом опять фильтруем, потом сортируем, потом ищем".

Add, Reduce, Map, Reduce, Sort, Find.

Array
.join> [ 1 2 3 "a" ]
.join> [ 3 2 1 "b" ]
.removeDuplicates>
.filter> .ItemIsInteger
.map> .ToString
.filter> .ItemNot "1"
.sort> .AsText
.find> "2"

Четвёртая проблема - работа с файлами, вместо работы с файлами. Кеширование - наше всё.

Пятая проблема связана со второй. "Множество мелких и короткоживущих объектов". Которые часто распределяются. Тут нам поможет шаблон LightWeight:
https://ru.m.wikipedia.org/wiki/Приспособленец_(шаблон_проектирования)

Ну и с этим же связана проблема выделения Mutable и Immutable объектов.

Ну и всяческие "фабрики" и "кеши".

Кешируемые Immutable объекты - "это хорошо".

Опять же - "давить аллокации".

http://www.gamedev.ru/code/forum/?id=205093&page=2

Навскидку - всё.

Ну и профайлер надо конечно использовать.

Больше проблем на своём опыте - я не встречал.

среда, 14 июня 2017 г.

ToDo. Проверка типов

Сделать INTEGER Cast и INTEGER :(

Ссылка. TVirtualInterface

Не устаю публиковать ссылку - http://docwiki.embarcadero.com/CodeExamples/XE8/en/Rtti.TVirtualInterface_(Delphi)

Уж очень мне идея нравится.

Я тут прикручиваю это дело к вариантам. Позже - напишу как получилось.

Offtopic

Соловьёв опять разрабатывает кулаками. Критикует немецкого министра обороны. Которая сказала, что "С Россией надо говорить с позиции силы".

Орёт. Иронизирует. Мол "немцы забыли Кузькину мать". Мол "мы им покажем".

Идиот. Извините. Вояка хренов. Он в армии то служил?

"Покажет он"...

Из Итальянского имения...

А аудитория строит и убивает головами...

Идиоты. Извините...

Они будут показывать? Сомневаюсь...

Мне не нравятся люди, которые не были в армии и махают кулаками. Я сам в армии не был. Но не махаю. Ибо понимаю, что окопы копать, как минимум, придётся мне, а не им.

А что такое - на морозе долбить мёрзлую землю - я знаю.


Offtopic. О жизни. Наблюдения

#байка

Сейчас на аллее. Идут парень с девушкой. Ну парень - "хипстер". А девушка. Ну ничего так девушка. В платье. И всё такое. А не то что - "пацанка". С цветами.

Обрывок разговора. Он ей говорит - "а я беру и рублю системный процесс..."

Наверное девушке ОЧЕНЬ интересно ;)

Она смеётся.

Update. Обратно идут - он ей - "ты понимаешь, что в нашей индустрии надо быть на голову выше остальных".

Она опять смеётся. ;)

четверг, 8 июня 2017 г.

Offtopic. Отвечаю на комментарий

"Я "из того Гаранта". Но в doom я не играю. Я вообще в игры не играю. Меня работа больше захватывает. Нет вру... в "цивилизацию" немножко играл... но с тех пор как появился UML - играю в основном в него. Это гораздо захватывающе. А игроки в doom у нас конечно же тоже были."

http://18delphi.blogspot.ru/2013/04/uml_21.html?m=1

Offtopic. Зарисовка из жизни.

#байка

Вхожу в подъезд.

Навстречу два пацана "хипстерского" вида.

Ну других сейчас уже почти не бывает.

Один со скейтом, а другой - самокатом и необъятным вейпом и "бородой".

Тот, что со скейтом и без бороды другому и говорит - "ты меня научил собирать компьютеры, давай я научу тебя правильно сгибать и разгибать колени".

Видимо речь о каком-то спорте идёт...

Эх... когда я последний раз "собирал компьютеры".

Кажется, что уже и "никогда"...

Предпочитаю, чтобы каждую работу делали профессионалы...

А ведь было дело... И собирал...

Побрюзжу. TStrings

Если в коде реализации встречается TStrings (не для поддержки "унаследованного кода"), то этот код (по моему мнению) - "дурно пахнет".

TStrings (имхо) - не самая лучшая придумка Borland/Embarcadero.

Offtopic. "О жизни". #3

Не знаю. "Зацепила" что-то "критика". Скажу за себя. Я когда начинал заниматься айкидо - я "видел в этом практическое применение". И пока первые два экзамена сдал - "тоже видел". Мне казалось - "вот оно откровение". Но потом я понял, что "не всё так просто". Попробовав с разными людьми. А потом оказалось - "совсем не просто". Ну и я ещё переосмыслил. Борьба которой я до этого занимался - тоже "в практическом плане" - не очень актуальна. И это всё видится мне теперь как "геометрия для тела" и "алгебра для ума". Опять же - за СЕБЯ ЛИЧНО говорю. Возможно - я что-то не понимаю. Так что я занимаюсь этим во-первых потому, что "это красиво", а во-вторых - потому, что "полезно". Для души и тела. Если кого-то волнует "реальный бой", то альтернативы лому или бите - НЕ СУЩЕСТВУЕТ. А уж пулемёту и подавно. Что касается "танцев". Не стоит так уничижительно. Мне знаю что сложнее - "танцы" или "айкидо". Для меня лично - "танцы" - наверное сложнее.

Ну а красоту и полезность - и в становой тяге можно найти.

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

Ещё я вспоминаю как к нам дзюдоисты приходили заниматься. Они всё пытались делать "на силу". Недолго они отзанимались.

Я сам многое делал "на силу". Тоже опыт борьбы сказывается. Пока партнёр слабее или неопытнее - "на силу" - получается. Иначе - не получается. Иначе - надо мозги включать. Оказывается.

Сейчас стал - "старый и больной". Всё совершенно по-другому видится. Мозги надо включать. Оказывается. А не пытаться "на силу". Откровение! Блин.

Опять же - "за себя лично" всё говорю. Возможно - опять же - многого не понимаю.

Ну и что касается опять же "реального боя". Я когда занимался борьбой - чувствовал себя достаточно уверенно. Ещё некоторая ударная практика была. Но когда меня били "всё те же десантники" в тамбуре поезда. Там двух ударов сапогом ниже пояса хватило, чтобы уверенность пропала раз и навсегда.

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

Что касается ножа (тоже было затронуто) - если достал нож - будь готов действовать до конца. Если не готов - лучше не доставай. Тебя же им и прирежут.

Про себя знаю - не готов.

Ну и "подводя итог". Ещё одна немаловажная вещь - это "готовность убивать" или мягче говоря "настроенность на победу". Бъёшь - бей. Честно и без раздумий. Бросаешь - бросай. Так чтобы у противника рёбра сложились. Достал нож - действуй. Орудуешь ледорубом - дай ему по голове. Ввязываешься в драку - готовься убивать. А не просто "порешать дела".

Кому-то дано, кому-то - нет.

Мне лично - не дано.

А для "реального боя" - это главное. Всё остальное - частности.

Или не ввязывайся.

Почему "условные чеченцы" выигрывают бой? Да потому, что у них мальчик "берёт нож и идёт резать барана" (сам видел). А мы - "думаем".

Вот и всё.

Ну а "критикам" надо ответить на вопрос - "они сами глаза не закрывают?"

Offtopic. "О жизни". #2

#байка

Раньше "бывало"... сходишь в горы... вернёшься в "город".. к "своему программированию"... окинешь взглядом код.. и думаешь - " это разве проблемы ?!"... вот у меня "на том перевале" - ДЕЙСТВИТЕЛЬНО проблемы были... на "третьей верёвке", когда крюк не бился.. и "на четвёртой", когда проушина не делалась... и "на пятой", когда она не сдёргивалась... а "это" - НУ РАЗВЕ ПРОБЛЕМЫ? Поправил "пару строк" и ВСЁ!

Offtopic. "О жизни"

#байка

Ну "а если серьёзно". Я какое-то время занимался айкидо. И как "неофита" - меня это прям сначала "пёрло". Прям "откровение". Больших успехов правда не достиг. Потом бросил. В силу разных причин. И потом масса "отговорок" находилась. То "времени нет". То "здоровья не хватает". Ну и "неудобно" было вернуться. В какой-то момент. Но мне часто снилось, что я прихожу в зал и занимаюсь. Просто "для себя". Без всяких раздумий о "реальном бое". Сейчас - вернулся. Когда "здоровье уже совсем кончилось". Когда уже "НАДО было". Занимаюсь. Такой кайф ощущаю. Чувствую, что ко мне вернулось "что-то важное". Что сложно выразить словами. И опять же - какой-то "коллектив единомышленников". Люди "разные", но "тут" занимаются одним ОБЩИМ делом.
Это как горы. Они мне тоже снятся. Как я иду по ледники. Троплю. Вешаю верёвки. Закрываю глаза, а передо мною - хребты, вершины, ледники, снега. Всё такое "в розовой дымке заката или рассвета". И "люди разные". Но все занимаются ОДНИМ ОБЩИМ делом. И нет "путиных", "Украины", "навальных" и "если ты такой умный, то почему такой бедный". Сублимация. Всё "просто и понятно". Это опять же - сложно словами выразить. Возможно и в горы я тоже ещё вернусь.

P.S. В "программировании" СООБЩЕСТВО ЕДИНОМЫШЛЕННИКОВ встречается почему-то всё реже и реже. Возможно из-за "узкой специализации" и возросшего количества "степеней свободы". Можно "сидеть с человеком в одной комнате и не найти точек соприкосновения". Ну или это я просто такой.

Брюзжу

Мне нравятся "советчики". Типа я "сейчас научу тебя жить".

И ведь не в курсе -- "чему же учить".

"а, скриптовую машину/движок пишем?

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

-------
я вообще делал через:
function Compile(const Source:string; var Output:TStrings):Boolean;

Result = true только тогда, когда успешно скомпилилось.
Output - полный всегда, вот там и ловить исключения.

а полный он потому, что там вперемежку идут ещё и Warning типа "declared but never used" и пр."

TStrings... хочу я посмотреть как оно гигабайт скриптов переварит...

Снобизм у программистов - в крови...

Не разобрались в вопросе и давай комментировать.

вторник, 6 июня 2017 г.

Offtopic. Побрюзжу

Ну "а если серьёзно". Я какое-то время занимался айкидо. И как "неофита" - меня это прям сначала "пёрло". Прям "откровение". Больших успехов правда не достиг. Потом бросил. В силу разных причин. И потом масса "отговорок" находилась. То "времени нет". То "здоровья не хватает". Ну и "неудобно" было вернуться. В какой-то момент. Но мне часто снилось, что я прихожу в зал и занимаюсь. Просто "для себя". Без всяких раздумий о "реальном бое". Сейчас - вернулся. Когда "здоровье уже совсем кончилось". Когда уже "НАДО было". Занимаюсь. Такой кайф ощущаю. Чувствую, что ко мне вернулось "что-то важное". Что сложно выразить словами. И опять же - какой-то "коллектив единомышленников". Люди "разные", но "тут" занимаются одним ОБЩИМ делом.
Это как горы. Они мне тоже снятся. Как я иду по ледники. Троплю. Вешаю верёвки. Закрываю глаза, а передо мною - хребты, вершины, ледники, снега. Всё такое "в розовой дымке заката или рассвета". И "люди разные". Но все занимаются ОДНИМ ОБЩИМ делом. И нет "путиных", "Украины", "навальных" и "если ты такой умный, то почему такой бедный". Сублимация. Всё "просто и понятно". Это опять же - сложно словами выразить. Возможно и в горы я тоже ещё вернусь.

P.S. В "программировании" СООБЩЕСТВО ЕДИНОМЫШЛЕННИКОВ встречается почему-то всё реже и реже. Возможно из-за "узкой специализации" и возросшего количества "степеней свободы". Можно "сидеть с человеком в одной комнате и не найти точек соприкосновения".

четверг, 1 июня 2017 г.

А ещё хочется написать

По мотивам:

http://programmingmindstream.blogspot.ru/2017/05/blog-post_31.html?m=1

А ещё хочется написать про то как код на Delphi "плавно" заменяется на код скриптовой машины. Со всякими map/reduce и прочими "функциональными штучками".

И насколько он лаконичнее и производительней.

Ссылка. Unit тесты

https://habrahabr.ru/company/jugru/blog/329372/

Толково. Но я лично для себя нового ничего не открыл.

Offtopic. Тоже про горы. Не моё

http://www.mountain.ru/article/article_display1.php?article_id=4507

Интересно себя со стороны наблюдать. Хотя мы все там и не в самом радужном ракурсе.

Ни о чём #2

Я обычно "обычным людям" стараюсь не рассказывать про работу.

Ну знаете. Из той серии как герой Бодрова. Даже если спрашивают - говорю "работаю писарем", мол занимаюсь обработкой текстов.

Чтобы не смотрели как на "чудака".

Но тут шли мы как-то компанией после тренировки.

Ну и завязался разговор туда-сюда.

Кто-то пару историй "про работу" рассказал

Все поржали.

Ну и я - не выдержал и "рассказал" (то что там написано - http://programmingmindstream.blogspot.ru/2017/05/blog-post_24.html?m=1).

Гробовая тишина...

А потом - "Шура, это ты с нами разговаривал или думал вслух" ;)

В общем. Смеяться после слова "лопата"... ;)

А так хочется "живого человеческого общения", а я кроме как над "сервантами октетов" и поржать не могу. ;)

Шучу. Брюзжу помаленьку...

среда, 31 мая 2017 г.

Offtopic. Казбек. Трубка

Почему-то ещё вспомнилось. Мы как-то ходили на Казбек. Со стороны Майли и Колки.

Весной. В тот год когда потом лавина сошла и Бодров погиб. И многие другие.

Погода была жуткая.

Так вот почему-то - БЕСЦЕННЫМ удовольствием показалось, что мои коллеги по восхождения дали мне время спокойно на вершине сесть и выкурить трубку ароматного табака. Несмотря на все превратности погоды.

Незабываемое ощущение.

А потом нас накрыла непогода и на спуске мы не смогли дойти до лагеря и словили холодную сидячую ночёвку. Рыли в снегу ямы и ночевали в них. Укрываясь плащами.

А на следующий день опять была непогода.

И мы рыли снежную пещеру в наддуве.

Но это - другая история.

Возможно это всё - "цена выкуреной трубки". ;)

Но после таких "встрясок" - почему-то жизнь сразу начинает играть новыми яркими красками.

Ни о чём

Продолжим "вечер брюзжания".

Многое хочется в блоге написать про программирование.

Прям вот реально чувствую, что в последнее время - "пересматриваю свои ошибки молодости".

И вроде вижу пути - "как их не делать".

Хочется вот прям взять и "рубануть правду-матку" и покритиковать себя "молодого".

Никак только с духом не соберусь.

Себя кстати критиковать - гораздо интереснее, чем других.

Это - реально "вкусно". Разнести себя в пух и прах. Зная всю подноготную.

И поизмываться вволю. Над другими так не поиздеваешься.

Я правда как-то уже пытался.

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

Ну попробую найти "изюминку".

#1356. Как я делаю бекапы. СУБД FireBird

14010197737483.png
Беда пришла откуда не ждали…
У клиента завис процесс “Касса”, так что не смог снять процесс через Диспетчер задач.
Рабочее место “Касса” - одновременно сервер всей системы.

Клиент принял решение ресетнуть через кнопку.

В итоге умерла DB. FireBird 2.5

Backup’ы настроены не были, так что последняя версия БД, которая случайно лежала у меня на винте, была минус 8 дней. Подняли по-быстрому с неё. Но суть дальше.

Как делать бекапы для FireBird.
  • Я написал скрипт, который, когда его запускают, делает резервное копирование базы данных с именем БазаДаннах_30_05_2017_23_07_51.fbk

@echo off
set "currentTime=%Time: =0%"
set now=%date:~-4%_%date:~3,2%_%date:~0,2%_%currentTime:~0,2%_%currentTime:~3,2%_%currentTime:~6,2%
  
set user=SYSDBA
set password=masterkey
set database_name=PARKDB.FDB
set backup_name=Backup\PARKDB
set ext=.fbk

set backup_filename=%backup_name%_%now%%ext%
echo %backup_filename%

nbackup -U %user% -P %password% -B 0 %database_name% %backup_filename%

%date:~3,2%

Это означает взять из результата date(Это системная функция Windows), 2 символа, начиная с 3 позиции в строке
Обычный %date%  = 31.05.2017

set "currentTime=%Time: =0%"

Означает брать время, учитывая 0, когда часы меньше 10, то есть без этой команды, мы при выполнении команд:

set now=%date:~-4%_%date:~3,2%_%date:~0,2%_%currentTime:~0,2%_%currentTime:~3,2%_%currentTime:~6,2%

получили бы, что now=2017_05_31_ 0_44_33 ,

а имя файла выглядело бы так: Backup\PARKDB_2017_05_31_ 0_44_33.fbk

Пробел не сильно виден, но он неприемлем в названии файла для nbackup

  • дата и время берутся из текущего времени системы

Это вроде рассказал :).

  • далее, чтобы скрипт выполнялся постоянно,
  • я добавил задачу в планировщик задач виндовс,
  • он каждые 4 часа запускает мой скрипт
  • и создается новая БД,
  • далее я научился создавать задачи в планировщике задач через командную строку

@echo off
set script_name=e:\SoftBuild\Parking\DB\DB_Backup.bat
set task_name=LotParkingBackup
SCHTASKS /Create /SC DAILY /TN %task_name% /TR %script_name% /HRESULT /F /RI 240 /DU 24:00 /v1

Детали параметров можете посмотреть в хелпе. SCHTASKS /Create /?

  • потом добавил в инсталлятор создание скрипта, который делает то, что я описал только что, и запуск из инсталлятора

function NextButtonClick(CurPageID: Integer): Boolean;
var
  ServerHost, ServerPort, DBFileName, FBDirPath: string;
  ResultCode, ErrorCode: Integer;
  UDFFrom, UDFTo, ReaderPort: string;
  RegistryTaskFile, DBDirPath, BackupScriptPath, RegistryFileName: string;
begin
  if CurPageID = SettingsPage.ID then
  begin
    ServerHost := SettingsPage.Values[0];
    ServerPort := SettingsPage.Values[1];
    DBFileName := SettingsPage.Values[2];

    if IsComponentSelected(cDB) then
    begin
      DBDirPath := Copy(DBFileName, 1, Pos('PARKDB.FDB', DBFileName) - 1);
      BackupScriptPath := DBDirPath + 'DB_Backup.bat'
      RegistryTaskFile := '@echo off' + #13#10 + 
                          'set script_name=' + BackupScriptPath + #13#10 + 
                          'set task_name=LotParkingBackup' + #13#10 + 
                          'SCHTASKS /Create /SC DAILY /TN %task_name% /TR %script_name% /HRESULT /F /RI 240 /DU 24:00 /v1' + #13#10;
      
      RegistryFileName := DBDirPath + 'DB_RegistryBackup.bat';
      SaveStringToFile(RegistryFileName, RegistryTaskFile, False);
      
      Exec(ExpandConstant(RegistryFileName), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
    end;    
  end;
end;
  • теперь у меня есть скрипт, который делает резервную копию,
  • и скрипт, который регистрирует задачу,
  • далее я научился удалять задачу из планировщика,
  • опять же из командной строки

@echo off
set task_name=LotParkingBackup
SCHTASKS /DELETE /TN %task_name% /F

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

[UninstallRun]
Filename: "{app}\DB\DB_DeleteTask.bat"; WorkingDir: "{app}\DB\"; Flags: runhidden waituntilterminated; Components: DB

В итоге у нас каждые 4 часа есть бекап, и если мы делаем UnInstall, то всё чисто :)



#1355. Получаем AV при создании интерфейсов

type
 ISomeInterface = interface
  function Ptr: Pointer;
 end;//ISomeInterface 

 TSomeInterface = class(TInterfacedObject, ISomeInterface)
  f_Ptr: Pointer;
  function Ptr: Pointer;
  constructor Create(aPtr: Pointer; aSize: Integer);
  destructor Destroy; override;
 end;//TSomeInterface 

  function TSomeInterface.Ptr: Pointer;
  begin
   Result := f_Ptr;
  end;

  constructor TSomeInterface.Create(aPtr: Pointer; aSize: Integer);
  begin
   inherited Create;
   GetMem(f_Ptr, aSize);
   Move(f_Ptr^, aPtr^, aSize);
  end;

  destructor TSomeInterface.Destroy;
  begin
   FreeMem(f_Ptr);
   f_Ptr := nil;
   inherited;
  end;

const
 C : array [0..2] of Char = 'ABC';

var
 A : ISomeInterface;
 P : Pointer;

A := TSomeInterface.Create(@C, SizeOf(C));
P := A.Ptr;
A := TSomeInterface.Create(@C, SizeOf(C));
A := TSomeInterface.Create(P, SizeOf(C)); // - AV !!! Потому, что предыдущий A уже освобождён


четверг, 25 мая 2017 г.

Размышления

Сегодня понял одну банальную и в то же время совсем неочевидную вещь.

Если функционал хорошо покрыт тестами, то главное это, чтобы все тесты проходили. Пусть код "костылен" и неидеален.

Если тесты проходят, то это придаёт "уверенность в завтрашнем дне".

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

Но постепенно. А не "сразу".

среда, 24 мая 2017 г.

Offtopic. Любителям истории

http://periskop.livejournal.com/766659.html

"С фотоаппаратом по линии Зигфрида".

У меня есть скан этого номера Техники Молодёжи.

Люди упорно ищут

Люди упорно ищут контекст - "тест-кейс для проверки калькулятора".

И приходят ко мне в блог.

Что же реально они хотят найти?

Не понимаю 2...

Или написать DoFoo и потом комментарий - "этот метод делает то-то и то-то".

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

Не понимаю...

Написать UpdateSomeState(2).

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

// 2 - это "такая то константа", она делает то-то и то-то

Const или Enum уже отменили?

И ведь так - ПОВСЕМЕСТНО.

вторник, 23 мая 2017 г.

Смешно. "Смешит" и Embarcadero и Штефан Глинке

https://plus.google.com/u/0/+StefanGlienke/posts/Ys1NnBKQQxU?cfem=1
It just occured to me that when I have such code:

type
TFooBar = class
s: string;
end;

procedure Main;
var
x, y: TFooBar;
begin
x := TFooBar.Create;
y := TFooBar.Create;

x.s := 'True';
y.s := 'True';

Assert(Pointer(x.s) = Pointer(y.s));
end;

begin
Main;
end.

The assertion will raise because whenever you assign a string literal to a string variable it checks if the string is a const (refcount = -1) and then calls _NewUnicodeString). I guess this has been discussed already somewhere else but I cannot find anything regarding my question:

I would guess that even if it is a const it could assign that reference to s and don't touch the refcount. This should work fine with the cow mechanics.

But as it is this would mean that if code runs through such const string assignments every time a new string gets allocated, no?
In my case I am using the const string 'True' for nullables in Spring to set the "HasValue" flag for them (otherwise the field is empty). However by using a const there it creates a new string every time. So if you have 10 nullable values you have 10 string instances with the content "True". The only solution I found so far was to make the const a variable (in this case it works because its private) and assign 'True' to it in the initialization section (or could also in the class ctor). That way there is only one string instance with content 'True' for the nullables around.

Any other solution I am missing?

Edit: I found this SO question:
https://stackoverflow.com/questions/12837129/string-const-why-different-implementation-for-local-and-result so I changed the original example to use objects and non global variables.

In my case I know that the module the literal is coming from will not be unloaded before anyone that is using it. That makes me think if we would need some kind of const string with start refcount = 1. Since its a const you could not modify it (which would modify the const because of refcount 1) but when assigning somewhere the same reference is being used and no new strings are being produced. I guess I am missing some cornercases why this is not possible -.- So I probably will use the hidden string variable to get the same result.

вторник, 16 мая 2017 г.

Offtopic. Сказка закончилась №2

ВТОРОЙ МОМЕНТ.

Про СКАЗКУ и КРАСОТУ.

Когда-то в аэропортах с парковкой и организацией движения была СКАЗКА и КРАСОТА. Почти ЕВРОПА.

Но и это всё изгавняли. Простите.

Вот тут был в Шереметьево на машине. Заплатил 700 руб за "парковку" в течении 22 мин.

В чём же дело?

А очень просто.

Я подъехал, чтобы забрать пассажира. Взял билет. Поехал к выходу. Над одним выходом написано "VIP. Международные линии".

Думаю - НЕ ТУДА.

Еду дальше. Дальше написано - "внутренние линии".

ВСЁ - БОЛЬШЕ НИКАКОЙ информации нет.

СПРОСИТЬ - не у кого.

Подъехал. Спросил какого-то мужика - он говорит "не это внутренние линии, где международные - не знаю".

Выехал. Поехал на второй круг.

Опять взял билет - поехал туда где написано - "VIP. Международные линии".

Долго ездил по "кишке" с поворотами. Упёрся в шлагбаум. На нём написано "приложите билет или вставьте карту". Билет прикладывать - НЕКУДА.

Матерясь выехал по "кишке задним ходом".

Подъехал обратно к "внутренним линиям". Поставил машину. Нашёл пассажира. Посадил.

Оказалось, что всех выпускают там где написано "внутренние линии". И с международных - ТОЖЕ.

По часам вроде - в 15 мин уложился.

Подъезжаю к шлагбауму. Вставляю билет. А мне пишут - "требуется оплата". Платить негде.

За мной выстроился хвост из 5 машин.

Я всех "растолкал" и выехал задом к паркоматам.

У паркоматов стоит человек десть и все пытаются оплатить. НИ У ОДНОГО не получается. Все засовывают тысячные купюры - всем их возвращают. Кто-то ругается по громкой связи с парковщиками.

Току - НОЛЬ.

Минут через пять дождался своей очереди.

У меня были мелкие купюры. ПО 100 руб.

О ЧУДО! У меня паркомат оплату ПРИНЯЛ.

И у следующих за мной - ТОЖЕ.

ПРОБЛЕМА БЫЛА в ОТСУТСТВИИ сдачи.

ПАРКОВЩИКИ об этом - НИ УХОМ НИ РЫЛОМ.

ПО чеку - я потратил 22 мин. Т.е. с учётом времени оплаты - я не уложился видимо где-то в 1 (ОДНУ) минуту.

Всё изгавняли.

РЫБЯТЫ!

Мне НЕ 700 руб ЖАЛКО! Мне "за ДЕРЖАВУ обидно"!

Была КРАСОТА, СКАЗКА и ЕВРОПА.

Стало...

Ну стало - "как обычно"...

ОЧЕНЬ ЖАЛЬ.

Ну и указатетели и знаки в Шереметьево - ГОВНО. Извините...