Solutions for Cast Carbon Steel

Steel is harder to cast than iron. It can also be fairly wear-resistant. Pouring steel is significantly more difficult. Hot-rolled steels present a superior chance to cut both value and weight in the event the cost per unit strength could be decreased. Stainless steel is a special type of steel that does not corrode. Other alloy steels are appropriate for service in the low-temperature selection.

Aluminum is more frequently used due to its effectiveness and low price tag. Steel wears more readily than iron, but might still be able resistant to certain kinds of abrasion. Carbon steel is comparable to stainless steel with respect to its weight. In general, it has a higher amount of carbon. It is a popular material for a wide range of applications. Low Carbon Steel is the most typical kind of steel used today as a result of relatively low manufacturing price.

Steel isn’t as simple to cut with the exact same consistency, and it causes more tool wear, causing higher production expenses. Cast steel is a type of isotropic material and can be reached into the general structural strength steel castings, thereby improving the trustworthiness of the undertaking. Low-carbon steel can acquire gummy, which makes it tricky to work with. Most steels supply an excellent balance of strength and ductility, making them extremely tough. Specifications for Low-temperature Steels Since a selection of low-temperature steels are available, the engineer must think about the advantages each must offer in line with the application.

Because it’s relatively inexpensive, mild steel is helpful for most projects requiring huge sums of steel. Mild steel may also have other elements like manganese, silicon and trace quantities of phosphorous. It is the most widespread form of steel and is used in 85% of all steel products in the United States alone. It is a form of low Carbon Steel. It has a relatively low amount of carbon.

Globe valves are employed in applications where flow has to be finely tuned. By way of example, rising stem valves aren’t proper for underground operations. For instance, they are not reasonable for underground operations. Non rising stem valves are employed in such circumstances. Less torque is also required to take out the retainer. At long last, there are valves made from firearm metal that it is possible to acquire from assorted manufacturers. Ultimately, there are valves made from gun metal that it is possible to obtain from various manufacturers.

The Ultimate Cast Carbon Steel Trick

Frankly, in the event you already own tons of cast iron, I wouldn’t attempt to convince you that you also need to put money into carbon steel. Cast iron and cast steel are two kinds of iron-carbon alloys. It has a much thicker, denser body. Ductile irons, generally, have good effect resistance. Type A395 ductile iron is completely ferritic.

The cookware doesn’t come pre-seasoned. It’s best not to cook in Iron pans each and every day. For the reason, brand-new pans are usually coated in beeswax to defend the surface during shipping and marketing. Seasoning a carbon steel pan is simple to do. Take a look at our article on seasoning to make sure that you’re seasoning your carbon steel pan the most suitable way.

The capacity is sufficient to cook for family members and friends. Additional it has the capability to cook meal enough for the whole family along with guest and friends who opt to stop by. Even at the pricier end, you’re not likely to go over $100 for the bigger sizes, and can spend quite somewhat less than that. Pick your favourite dimensions and design as each one have all you will need to begin cooking up a storm. Carbon steel shapes are ideal for that.

Cast Carbon Steel: No Longer a Mystery

In case the composition of alloying elements isn’t correct, quick adjustments can be created in the furnace or ladle before casting. For those who have any inquiries regarding in which in addition to the best way to make use of castermetal.com, you can e mail us at the web page. Moreover, chemical composition also has to be inspected. The very first thing you ought to do is remove that coating. Instead, it is a protective coating made by burning oil on the pan. Naturally, you can even lay down some new layers of seasoning utilizing the heat-oil-heat process above whenever you desire. Additionally, it comprises various other elements in smaller quantities, based on the usage.

The procedure for corrosion resistance for stainless steel is distinctive and interesting. On the flip side, higher pressure applications use large valves with bolted bonnets. When designing cast goods, however, it’s worth considering long-term use and replacement expenses.

Some advantages are given below. Other advantages consist of great formability and most important, superb weldability. They Float and thermostatic traps are generally recommended for use on modulated steam systems because they drain better when there is no motive pressure other than the static head of condensate. Finally, the option between cast iron and cast steel will depend on the kind and application of the last installation. The choice of the appropriate mix of the trim materials is among the main decisions to specify valves correctly. Certain alloy additions can also boost the abrasion qualities of steel.

Недискримінація – це головний зміст відкритих джерел (open source)

Сьогодні я дізнався , що щось з назвою проект Lerna додав доповнення до його ліцензії MIT, забороняючи використовування його програмного забеспечення довгому спискові организацій, тому що цей проект не погоджується з політичним вибором цих організацій.

Говорячи, як один зі оригінальних спів-авторів Визначення Відкритих Джерел (Open Source Definition), я затверджую факт. Оскільки є змінення, ліцензія Lerna більш не відповідає визначенням та правилам OSD. Вона конкретно порушила дотримання правила 5 – “Ніякої Дискрімінації Проти Персон Або Груп” (“No Discrimination Against Persons or Groups”).

Відповідно, Lerna вийшла з суспільства відкритих джерел (open-source community) і кожен, хто цінує здоров’я цього суспільства, мусить уникати контактів з організацією Lerna. Я не вноситиму шось корисного до їх проекту, і закликатиму інших не робити цього до того моменту, поки це змінення не буде скасовано.

Ми написали Правило 5 у декларації OSD заради добрих цілей. Різноманітні винятки та вилучення , як, наприклад, доповнення від проекту Lerna, при збільшенні їх кількості можуть створити велику невизначеність етичного характеру і навіть поставлять під сумнів питання легальності пере-використовування коду (legality of code re-use). Припустимо, що я був повинний взяти якийсь фрагмент з коду Lerna і пере-використовував цей фрагмент у проекті, який (можливо, без мого відому) був розгорнутим однією з заборонених проектом Lerna організацій; як у цьому випадку я виглядатиму з юридичної та етичної точок зору?

Може бути ще поганіше. Припустимо, що я написав якийсь код, котрий випадково вийшов ідентичним або дуже схожим з якимсь кодом з проекту Lerna? Хтось міг би завести справу за фактом порушення їх ліцензії? Це є дуже небезпечним, якщо таке питання залежить від знань та намірів, які напевно не знає ніхто поза межами черепної коробки потенційного порушника.
Вибір проекту Lerna є, більш того, деструктивним для однієї з головних норм, які забеспечують функційність суспільства відкритих джерел (open-source community) – відділення політики від нашої праці. Якщо ми не підтримуватимемо цю норму, ми маємо ризик перетворитися у сукупність сварюючихся груп, які сперечаються заради частковостей і не можуть підтримувати реально великомасштабні проекті, де співпраця багатьох людей є головною умовою.

Я вважаю, що це не просто неприємно, але реально небезпечно для цівілізації, яка спирається на нас стосовно критично важливої частини її зростаючої інфраструктури. Відповідно, нам треба розвівати співпрацювання більше, а не менше.

Це, у свою чергу, означає, що, навіть коли ми можемо мати різні погляди та думки про проблеми, подібні списку заборонених організацій у проекті Lerna, наши відносини повинні бути більш, а не менш, нейтральними і недискримінаційними у поведінці нашого колективу.

Оновлення: менш ніж через 24 години після того, як я запостив цю статтю, змінення у ліцензії було відкликаним, а ініціатор цього змінення був виключеним з проекту. Ось як перемагає здоровий глузд – один бій за раз.

Згідно з приміткою російського перекладача: виключенній з Lerna скандальний розробник залишив ліцензію з винятками в своїх особистих проектах react-loadable і unstated.

Посилання на оригінал статті
Посилання на сторінку автора – Eric Raymond
Автор перекладу: Alvetari

wideNES – заглядаємо поза межі екрану ігор NES


У середині 1980-х років система Nintendo Entertainment System (NES) була домашньою консоллю з разряду повинно бути.
Маючі кращий звук, кращу графіку і кращі ігри за порівнянням з будь-якою іншою домашньою консоллю того часу, вона стала зразком того, якими повинні бути домашні ігри.
І до наших днів такі ігри, як Super Mario Bros., The Legend of Zelda та Metroid вважаються одними з найкращих ігор всіх часів.

Вже більше 30 років пройшло з тих часів, коли система NES вперше була опублікованою, і в той час, як ці класичні ігри залишаються “на плаву”, не можна сказати цього ж і про залізо, на якому вони працювали.
З дозвілом екрану всього 256×240, NES не давала іграм реального простору для повноцінного працювання.
Тим не менш, безстрашні ігрові розробники змогли втиснути чудові і ставші каноничними ігрові світи до апаратних можливостей NES: лабіринтоподібні підземелля з The Legend of Zelda,
розповзаючуся планету з Metroid або барвисті рівні з Super Mario Bros.. Але все ж, через обмежень апаратної частини NES,
гравці могли насолоджуватися цими іграми тільки у рамках дозвілу 256×240.

До теперешнього часу.

Представляємо: wideNES.
Новий шлях реалізації можливостей класичних ігор NES.

wideNES – це передове технічне вирішення, як автоматично і інтерактивно планувати хід ігор NES у режимі реального часу.

У той час, як гравці рухуються всередині рівня, wideNES записує екран, поступово будуючи мапу всього, що було досліджено.
На наступних проходженнях рівня, wideNES синхронізує дії на екрані зі згенерованою мапою,
ефективно дозволяючі гравцям бачити більше простору рівня, “заглядаючи” за край екрану NES!
І що є найкраще усього, підхід wideNES до генерації мап є повністю узагальненим,
що надає можливість працювати з wideNES для всіх ігор NES прямо з коробки!

Але як він працює?


Якщо Ви бажаєте спробувати додаток wideNES перед тим, як прочитати, як він працює – немає проблем!
ANESE це емулятор NES, який я написав сам,
і у даний час це єдиний емулятор, котрий може імплементувати додаток wideNES.
Хоча заради справедливості скажу, що
ANESE не є кращим емулятором NES як стосовно UI, так і стосовно якості працювання.
Більша частина опцій (включаючи активацію wideNES) є доступною тільки через командний рядок,
і, хоча багато популярних ігор працює добре, деякі з них можуть не працювати так, як очікувалося би.


Як працює wideNES

Перед тим, як закопатися у деталі, важливо коротко обговорити, як система NES візуалізує графіку.

Натиснення пікселів з PPU

У серці NES знаходиться поважний процесор MOS 6502. В кінці 70 – х і початку 80-х років процесор 6502 був всюди,
працюючи на таких легендарних машинах, як Commodore 64, Apple II і на багатьох інших. Він був дешевим, легким для завдань програмування і достатньо потужним, щоб бути пожеженебезпечним для машини.

Процесор 6502 доповнявся потужним графічним спів-процесором, званим Блок Процесування Зображень (PPU, Picture Processing Unit).
За порівнянням з базовими відеоспівпроцесорами у більш стародавних, заснованих на процесорі 6502, системах, PPU був широким кроком у гору.
Наприклад, за півдесятиліття до першого релізу NES, конфігурація Atari 2600 використовувала процесор 6502 для делегування графічних команд для кожноо рядку розгортки її спів-процесора,
залишаючи дуже мало часу для виконування головним процесором власне ігрової логіки. А PPU, з власного боку, вимагає тільки пару команд на один кадр,
залишаючи масу часу для того, щоб 6502 забезпечував цікавий геймплей.

PPU це чарівний чіп, обробляючий графіку так, як жоден сучасний GPU,
і було би потрібно написати цілу серію статтей, щоб дати повне роз’яснення,
як він працює.
Оскільки wideNES вимагає тільки невеличку підмножину функцій PPU, буде достатньо цього короткого огляду:

  • Дозвіл: 256x240px @60Hz
  • Запускається незалежно від CPU
    • Пов’язується з CPU, використовуючи Відображення Вводу/Виводу У Пам’ять(Memory Mapped I/O) (діапазон адрес 0x2000 – 0x2007)
  • 2 Шари Візуалізації: Шар Духів (Рухомих Об’єктів,Спрайтів), і Фоновий Шар
    • Шар Духів
      • Духи можуть бути розміщено у будь-якому місці екрану
      • Відмінно підходить для рухомих об’єктів: персонаж гравця, вороги, снаряди
      • До 64 духів розміром 8x8px
    • Фоновий Шар
      • Замкнутий на сітці
      • Відмінно підходить для статичних елементів: платформ, великих перешкод, декорацій
      • Достатньо пам’яті VRAM для зберігання 64×30 плиток розміром 8x8px
        • Ефективний внутрішній дозвіл 512×240, з портом огляду 256×240
        • Підтримує апаратне прокручування (hardware scrolling, апаратний скролінг)) для змінення порту огляду 256×240
          • Регістр PPUSCROLL (адреса 0x2005) контролює переміщення порту огляду за осю X/Y

З цим неймовірно коротким переглядом графічного процесору, давайте перейдемо до головного питання: як працює wideNES?

Базова Ідея

У кінці кожного кадру CPU оновляє змінені дані PPU. Це оновлення містить у себе нові позіції духів, дані нового рівня, і —найголовніше для wideNES— нові переміщення порту огляду.
Оскільки wideNES працює у емуляторі, реально легко відсліджувати значення, які записано у регістрі PPUSCROLL,
що означає неймовірну легкість розрахування розміру частини екрану, яка прокручується між двома будь-якими кадрами!

Хмм, що може відбутися, якщо замість малювання кожного нового кадру прямо понад старим кадром,
нові кадри малюватимуться перекриваючи попередний кадр, але при цьому переміщаючись у процесі поточного прокручування екрану?
Тоді з часом все більша і більша частина рівня залишатиметься на екрані, поступово вибудовуючи повну картину всього рівня!

Щоб перевірити, чи є в ідеї якась гідність, я схопився прямо і зробів першу реалізацію.

Компіляція…
Запуск…
Завантажуємо Super Mario Bros.

Вуаля!

Це працює!

Схоже на те…


Tangent: Чому не відобути рівні прямо з оперативної пам’яті?

Навіть без вдавання у деталі імплементації wideNES, треба розуміти, що ця техніка має одне важливе обмеження:
Повна мапа можлива лише у тому випадку, якщо гравець мануально досліджує усю гру повністю.

Що, якщо існує засіб витягнути рівні з необробленої оперативної пам’яті?!
Може така техніка існувати??

Ні, напевно ні.

Якщо взяти 2 гри зі системи NES, є тільки одна річ, яка є спільною для обох: ці ігри обидві працюють на NES.
Other than that, all bets are off! Ця невідповідність є реальна біль,
оскільки є, за суттю, безмежні шляхи зберігання даних рівня для ігор NES!

Деякі люди витягнули повні рівні методами реверс-інженерії засобів зберігання рівневих даних (іноді створюючи повноцінні редактори рівней!),
зробити це далеко не просто, це вимагає багато жорсткої праці, цілеспрямованості і розумного мислення.

Спроба витягнути рівневі дані з оперативної пам’яті NES могла би бути еквівалентним визначенню, які секції ROM є код (а не дані),
що є важким завданням, оскільки
пошук і знаходження всього коду у бінарному файлі
дорівнює проблемі зупину!
!

wideNES надає набагато більш легкий шлях: замість гадання, як ігри пакують рівневі дані у оперативної пам’яті, wideNES запускає гру і відстежує вивідні дані!


Прокручування (скролінг) за межами 255

NES є 8-бітною системою, що означає, що регістр PPUSCROLL приймає тільки 8-бітні значення.
Це обмежує максимальне зміщення при прокручуванні тільки 255-ма пікселами,то є найбільшим 8-бітним числом.
Це не випадково, що дозвіл екрану NES є 240×256 пікселів,
і зміщення розміром у 255px є як-раз-достатньо для прокручування всього екрану.

Але що відбувається, якщо ми прокручуватимемо поза межами 255 пікселів?

По-перше, ігри онулятимуть значення регістру PPUSCROLL. Це роз’ясняє, чому SMB відкидається назад до старту, коли Маріо переміщається занадто далеко управо.

Наступне – для компенсування 8-бітних обмежень PPUSCROLL ігри оновляють інший регістр PPU: PPUCTRL (адреса 0x2000).
Нижні 2 біта PPUCTRL визначають “початкову точку” поточної сцени з кроком повного кадру. Наприклад: написання значення 1 зміщає порт огляду вправо на 256px,
значення 2 зміщає порт огляду вниз на 240px. Це зміщення PPUCTRL відкладається до регістру PPUSCROLL, дозволяючи прокручувати екран на 512px зліва-вправо,
або на 480px згори-вниз.

Але затримайтеся на секунду, чи достатньо VRAM тільки для 2 екранів рівня? Що відбувається, коли порт огляду прокручується занадто далеко і “прострілює” VRAM?
Для обробки цього випадку, PPU імплементує тактику згортання, так що будь-які розділи вікна перегляду за межами призначеної відеопам’яті будуть просто переноситься на її протилежний кінець.

Ця тактика згортання, у з’єднанні з розумним маніпулюванням регістрами PPUSCROLL та PPUCTRL, дозволяє іграм NES надавати илюзію безмежно довгих/широких світів!
Ліниво завантажуючи більше рівньового простору попереду порту огляду і поступово прокручуючи його, гравці ніколи не розуміють, що вони насправді “бігають по колу” всередині VRAM!

Ця чудова илюстрація з nesdev wiki показує, як Super Mario Bros. використовує ці властивості для илюзії бачимості рівней більш довгих, ніж 2 екрани:

Повернемося до нашого головного питання: як wideNES оброблює прокручування поза межами 256 пікселів?

Чесно кажучи, wideNES повністю ігнорує регістр PPUCTRL, і просто відстежує різницю у значеннях регістру PPUSCROLL між кадрами!

Якщо PPUSCROLL неочіковано стрібає до ~256, це типово показує, що персонаж гравця перемістився вліво/вгору екрану, тоді як неочіковане переміщення значення регістру PPUSCROLL вниз до ~0
означає переміщення персонажа гравця вправо/вниз екрану.

Хоча евристика може виглядати простою — а вона і є простою — вона надійно працює!

Після імплементації евристики ігри Super Mario Bros., Metroid і багато інших ігор розпочали працювати майже ідеально!

Я був повний ентузіазму, і цьому я пішов уперед і завантажив ще одну класичну гру NES classic – Super Mario Bros. 3….

Хмм… Це не добре.

Ігнорування Статичних Елементів Екрану

Багато ігор мають елементи статичного UI на краях екрану. У випадку з SMB3, на екрані є синя колона ліворуч і рядок стану унизу.

За стандартом, wideNES семплює (записуває) 16-пікселевий відступ від країв екрану, що означає семплювання будь-яких статичних елементів поряд з краями екрану! Не добре!

Щоб вирішити цю проблему, wideNES імплементує декілька правил і евристичних методів, які призначені автоматично виявляти і маскувати статичні елементи екрану.

Взагалі є 3 різних типи статичних елементів екрану, використованих у іграх NES: HUD-и, Маски і Рядки Стану.

HUD-и – не проблема

Якщо гра накладає HUD поверх рівня, швидше за все, HUD складається з декількох Духів. Приклад: HUD у грі Metroid.

На щастя, ці HUD-и не є проблемою, так як wideNES просто ігнорує Шар Духів на даний момент. Здорово!

Маски – Простіше Простого

PPU має властивість, яка дозволяє іграм маскувати найлівіші 8 пікселів Фонового Шару. Вона активується надаванням 2-го біту регістру PPUMASK (адреса 0x2001).
Хоча ця властивість використовується багатьома іграми, роз’яснення, чому вони роблять так, виходить поза межи цієї статті.

Виявлення активованого стану маски є неймовірно простим: wideNES відстежує значення PPUMASK, і ігнорує найлівіші 8 пікселів у випадку надавання 2-го біту у цьому регістрі!

Схоже на те, що імплементація цього простого правила усунула помилку у SMB3:

…або майже усунула.

Рядки Стану – складна річ

Відповідно обмеженням PPU, тільки 64 Духи можуть бути присутні на екрані у поточному часу, і більше цього,
тільки 8 Духи мужть бути у окремому рядку розгортки у один й той же час.
Це обмеження не дозволяє іграм створювати складні HUD-и з Духів і змушує ігри використовувати сегменти Фонового Шару для відображення інформації.

За винятком масок, PPU насправді не надає простий спосіб розділити Фоновий Шар між зонами Гри і Стану. За суттю, розробники ігор стали більше творчими,
винаходячи безліч незвичайних шляхів створення Рядків Стану…

wideNES імплементує декілька різних евристичних методів виявлення типів Рядків Стану, але стосовно поточної теми, я оглядатиму один з найцікавіших:
Відстеження Запитів Переривання В Середині Кадру (Mid-Frame Interrupt ReQuest Tracking, Mid-Frame IRQ Tracking).

Відстеження Запитів Переривання В Середині Кадру

На відміну від сучасних GPU, які мають великі внутрішні відеобуфери (framebuffers), PPU не має відеобуфреу взагалі! Для зменшення використованого простору,
PPU зберігає сцени як сітку з 64×32 плиток розміром 8×8 пікселів. Замість передчасного обчислення пікселевих даних
плитки зберігаються, як вказівники на символьну память CHR Memory (Character Memory), яка містить збережені піксельні дані.

Оскільки система NES була розробленою у 80-х роках, PPU не мав сучасних технологій обробки візуальної інформації. Замість відображення повного кадру за один раз,
PPU виводить відео у форматі NTSC, який був спроектованим для ЕЛТ-екранів (CRT) і відображає відео піксель за пікселем, рядок розгортки за рядком розгортки, згори вниз, зліва вправо.

Чому це важливе?

Раз вже PPU обробляє кадри згори-униз і рядок-за-рядком,
є можливим посилати до PPU інструкції в середині екрану для створення відеоефектів, у інших ситуаціях неможливих!
Ці ефекти можуть бути такими ж простими, як зміна палітри, або настільки ж складними, як (Ви здогадалися) створення рядка стану!

Щоб роз’яснити, як записи PPU в середині кадру можуть згенерувати Рядки Стану,
я витягнув необроблений дамп шматку VRAM (відеопам’яті) і CHR Memory (символьної памяті) процесору PPU у окремому кадри гри SMB3:

Все виглядає нормально, нічого особливого … крім Рядка Стану! Він повністю спотворений!

Тепер, подивіться на той же необроблений дамп, але витягнутий після розгорткового рядку 196…

Так, рівень виглядає жахливо, але Рядок Стану повністю цілий!

Що відбувається??

SMB3 встановлює таймер для запуску Запиту Переривання (IRQ) у точності після обробки розгорткового рядку 195. Вона поміщає до обробнику Запитів Переривання (IRQ handler)
наступні інструкції:

  • Привласнити регістру PPUSCROLL значення (0,0) (забезпечення фіксованого Рядку Стану)
  • Замінити мапу плиток (swap the tilemap) у символьної памяті CHR Memory (виправлення графіки Рядку Стану)

Оскільки інша частина рівня є вже обрендереною, PPU не буде “ретроактивно” оновляти кадр. Замість цього, він продовжуватиме обробку зображення з цими новими параметрами,
виводячи красивий, неспотворений Рядок Стану!

Повертаючися до wideNES, відстежуючи Запити Перевивань в середині кадру (mid-frame IRQs) і примічаючи розгортковий рядок, у якому вони виникають,
wideNES може ігнорувати будь-які наступні розгорткові рядки у запису!
Навпаки, якщо IRQ виникає у розгортковому рядку менш ніж 240 / 2, всі попередні розгорткові рядки ігноруються,
тому що ранний запит на переривання розгорткового рядку (scanline IRQ) припускає, що Рядок Стану повинен бути у верху екрану.

З того часу, коли цей евристичний метод використовується, Super Mario Bros. 3 працює ідеально!


Я коротко розглянув бібліотеку Комп’ютерного Бачення OpenCV, щоб виявити рядки стану (і також інші статичні регіони екрану),
але у підсумку вирішив, що вона не є потрібною. Використовування величезної, складної і непрозорої бібліотеки Комп’ютерного Бачення
протистояло би духу додатку wideNES, який намагається спиратися на малі, прості та прозорі правила і евристичні методи досягнення результатів.


Виявлення “Сцен”

Крім декількох примітних прикладів (як Metroid), ігри NES мають тенденцію не розміщатися всередині одного великого та безперервного рівня.
Замість цього, більшість ігор NES є розділеною на менші за розміром окремі “сценки” з дверима або екранами/порталами переходу для переміщення між ними.

Оскільки wideNES не має концепту “сценок”, відбуваються погані речі, коли сцена змінюється…

Наприклад, ось перший перехід сцени у грі Castlevania, де Сімон Бельмонт входить до замку Дракули:

Уффф, це не добре! WideNES повністю переписав останній біт поточного рівня з першим бітом нового рівня!

Зрозуміле, що для wideNES було треба як-небудь виявити, де змінюється сцена. Але як?

Перцептуальне Хешування!

На відміну від криптографічних хеш-функцій, які шукають розкидати введені дані випадковим чином по виходному простору,
перцептуальні хеш-функції прагнуть тримати подібні вхідні сигнали “close” один до іншого у виходному просторі.
Це робить перцептуальні хеши ідеальними для виявлення взаємо подібних образів!

Перцептуальні хеш-функції можуть бути неймовірно складними, а деякі можуть навіть виявити взаємоподібні образи, якщо один з них був
повернутим, зміненим у розмірі, розтягнутим або зі зміненим квітом.
На щастя, додатку wideNES не потрібно комплексну хеш-функцію, оскільки кожний кадр має гарантовано незмінений розмір.
Таким чином, wideNES використовує, ймовірно, самий простий перцептуальний хеш: підсумовування кожного пікселя на екрані!

Це просто, але працює досить добре!

Наприклад, подивіться, наскільки виділяються переходи сцени при побудуванні графіку змінення перцептуального хешу зі зміненням часу у грі The Legend of Zelda:

У даний час, wideNES використовує фіксований-поріг між значеннями перцептуального хешу для викликання переходу між сценами, але це знаходиться далеко від ідеалу.
Різні ігри можуть використовувати різні палітри, і існує багато випадків, коли wideNES вважає, що десь є перехід між сценами, а там його немає. У ідеалі,
wideNES є повинним використовувати динамічний поріг, але у цей момент використовується тільки статичний фіксований поріг.

З цим новим евристичним методом wideNES ефективно визначає вхід Сімону до замку у Castlevania і відповідно перемикається на свіжий інтер’єр.

І з цим кроком фінальний великий шмат пазлу за ім’ям wideNES знайшов собі місце.

Після імплементування деякої простої серіалізації я нарешті зміг запустити гру NES, повністю пройти декілька рівней,
і автоматично згенерувати мапи рівней!

Що тепер відбуватиметься з wideNES?

wideNES складається з двох окремих частин: Ядро wideNES , яке є набором правил/евристичних методів, закладених у підставу технології працювання додатку,
і конкретної імплементації wideNES всередині емулятору ANESE.

Поліпшення ядра wideNES

По-перше, wideNES має тенденцію занадто агресивно виявляти переходи сцен. Кількість брехливо-позитівних виявлень може бути мінімізованою
через використання більш кращого перцептуально-хешуючого алгоритму або через перемикання на динамічно-порогові значення між перцептуальними хешами.

Виявлення статичних екранних елементів також вимагає більше праці. Наприклад,
Megaman IV має запит переривання в середині кадру (mid-frame IRQ), але в його немає рядку стану,
що веде wideNES до помилкового ігнорування значної частини ігрового поля.
У той час, як цей окрема проблема може бути усунутою через деяке мануальне налагодження,
було б краще використовувати більш інтелектуальну евристику.

Декілька ігор NES прокручуває екран “унікальними” чинами. Яскравий приклад цього це The Legend of Zelda,
яка використовує PPUSCROLL для горизонтального прокручування, але вертікаьно прокручує екран з допомогою зовсім іншого регістру – PPUADDR.
Zelda є дуже популярною назвою,
і цьому wideNES імплементую евритиску тільки для Zelda.
Також існують і інші ігри з подібними режимами “унікального” прокручування екрану, які також вимагають особливих евристичних методів.

Було б корисно мати який-небудь спосіб “зшивати” однакові сцени. Наприклад, якщо хтось проходить Рівень 1 грі Super Mario Bros.,
але вибірає трубу, щоб дойти до підземної схованки з монетами, wideNES створюватиме дві окремі сцени для Рівня 1:
Сцену А – частину рівня до точки, де Маріо входить до зони х монетами,
і сцену Б – частину рівня з точки, де Маріо виходить з труби до флагштоку.
Якщо гра в дальшнішему перезавантажується і Рівень 1 переігривається без входження до труби,
wideNES елементарно оновлятиме Сцену А, щоб отримати повністю пройдений рівень, але залишатиме Сцену Б у “завислому” стані

Нарешті, wideNES повинен відстежувати переходи між сценами і зберігати ці дані. З цими даними було б можливо побудувати графік переходов між сценами,
дозволяючи генерувати “світові мапи” для ігор, які не є складеними з єдиного, величезного світу.

Поліпшення імплементації wideNES у емуляторі ANESE

У даний час реалізація праці wideNES можлива тільки у середовищі ANESE, емуляторі системи NES, який я написав сам.
ANESE є дуже, дуже спартанським емулятором,
з більшостю опцій, схованих поза флагами CLI, і з тільки одним встановленим UI – простим оверлеєм вибору файлів (file-picker overlay)!
Він дуже далеко, далеко від рівня “production ready.”

Хоча, окрім UI, ANESE та wideNES могли б обидва поліпшити сумісність та ефективність.
ANESE був першим великим емулятором, який я написав, і це помітно!

Є досить багато проблем сумісності, з деякими іграми, які працюють неправильно/ не запускаються взагалі.
На щастя, це відбувається тому що ANESE не є дійсно добрим емулятором,
а не тому що wideNES є поганим додатком.
Принципи, на яких спирається wideNES, є перевіреними і надійними, і дозволяють легко імплементовати додаток у інших емуляторах!

Стосовно ефективності ANESE та wideNES є не самі найвеликіші, і навіть деякі відносно потужні ПК можуть іноді падати у продуктивності ніжче 60fps!
Є багато оптимізацій, які повинні бути імплементовані до ANESE та wideNES.
Окрім загальних поліпшень ядра ANESE,
потрбін поліпшення у тому, як wideNES записуває кадри, відображає (рендерінг) мапи, і семплює хеши.

Висновок

Незважаючи на те, що я обговорив тут головні аспекти працювання додатку wideNES, є багато менш значних технічних питань для обговорення.
Наприклад, wideNES зберігає мапу істинного хешу кожного кадру і значення його прокруток (скролінгу),
які використовуються для відтворення сцен “повторного входу”.
Ця особливість, і також багато інших, є детально прокоментованими на ресурсі для wideNES,
який є доступним на сторінці проекту wideNES.

Працювання над проектом wideNES було реально чудовим досвідом, але з урахуванням наступного семестру у универсітеті Ватерлоо, який вже очікує мене за кутом,
я сумніваюся, що у мене буде шанс попрацювати над wideNES ще деякий час.
wideNES знаходиться в точці розвою, де він в основному працює,
і я радий, що зміг написати цей пост, обговорюючи з Вами деякі з технологій, які стоять за ним!

Спробуйте wideNES самостійно, і скажіть мені, що Ви думаєте! Завантажіть ANESE,
запустіть Super Mario Bros., або The Legend of Zelda, або Metroid, і трохі розважіться!

Посилання на оригінал статті: wideNES – Peeking Past the Edge of NES Games
Автор статті: Daniel Prilik
Автор перекладу: Alvetari

Roadmap for Java beginners

[ecko_annotated header=”” annotation=””]In this article I’ll try to provide step by step tutorial for beginners. For those who know nothing about Java and required environment or even about software development in general.[/ecko_annotated]

So, let’s begin.
For now, Java is the most popular in the world. It means you made a good choice :). It could be a bit difficult to start studying Java alone without any help that’s why I decided to prepare this roadmap.

I’ll split my article in a few logical parts like basic knowledge, required tools, databases, etc

First steps

  1. What is JDK and why we need it?

    JDK stands for Java Development Kit. In few words jdk translates Java language commands (your program) to computer instructions.
    You can download the latest jdk here. Just download and install. Follow official instructions. Now you are ready to write and run simple Java app. Just don’t forget to check if your jdk works properly. Open command line and execute command

    java -version

    if everything fine you will see Java version in console. By good old tradition first app should be called HelloWorld. Don’t spend your time on it and download app here. Run command line in the same folder with HelloWorld app and execute following command

    javac HelloWorld.java

    .JDK will compile the app and create new file HelloWorld.class – computer language version of Java app. Now you are ready to run our example. Execute command

    java HelloWorld

    in console and you will see this response

    Hello, World

    Let’s postpone explanation how this app works just remember the following – you should compile each project and only then run it.

  2. Simplest Java app

    HelloWorld is the simplest Java app and it consists of one class. Class is a logical unit in Java. In real life project could contain thousands of classes.

    package com.devua.article;
    import java.util.Date;
    
    public class HelloWorld {
        public static void main(String[] args) {
            System.out.println("Hello, World");
        }
    }

    First line is declaration of package. Package is not mandatory but it’s good practice. One important thing is if you add package declaration you should put file in corresponding folder structure. In our case it should be something like  MyTestProject/com/devua/article/HelloWorld.java. For test purpose you could skip package declaration. Otherwise when you compile you should go to MyTestProject folder, open command line and execute

    javac com/devua/article/HelloWorld.java

    and then execute

    java com.devua.article.HelloWorld

    Then we declare – import – the whole path to each other class which we need for our app. If we don’t need other classes we don’t import anything (We don’t use Date class here, so this import actually is not needed). Then we declare class itself. Hence, Java app is set of classes from one to infinity. ‘Cause apps have ability to grow all the time we group classes in packages from the start. I will not explain you how to write the code inside the classes, it takes a long time to do this and there are many good books on that subject. In Ukraine we usually recommend this one: Bruce Eckel – Thinking in Java but you can take any other book for beginners. Also I would recommend these two books: Jeanne Boyarsky and Scott Selikoff – OCA / OCP Java SE 8 Programmer Certification Kit. It’s shorter and cleaner so you will learn faster, especially if you have some elementary level in programming. Also, if you start with “Thinking In Java” you can skip GUI chapter without any harm. Even I would recommend you to stop reading before chapter about I/O then take few weeks to practice and only after that read the rest of the book.

 

Above I explained really basic things. I recommend you now to spend few weeks on reading some book for beginners and coding each practice tasks from that book.

Now when you got some information about language itself and how to run simple app I’ll describe more specific stuff.

Tools

  1. IDE

    It’s quite usual for Java app to consist of many classes so it would be difficult to manage the whole project in a file manager. Also, if you write code in plain text editor it’s quite easy to make mistakes: any kind of typo, misusing Java language command, lost parenthesis, etc. So, for real work everybody uses IDE (integrated development environment) – application which assists you during development process. The most popular IDEs in Java world are Eclipse, Intellij IDEA and NetBeans. I prefer Eclipse, but you can try all of them. Just download, install, create new project, create new class with name HelloWorld, copy content from file above and finally run. It will allow you to decide which one suits you the best. IDE will not do your job but at least save you from stupid mistakes.

  2. Build tools

    As I mentioned above Java project could contain many classes also it could contain dozens third party libraries and hundreds configuration files. It is possible to manage everything manually but it’s much easier to use specific tools called – build tools. The oldest one is Ant, the most popular – Maven and the newest is Gradle. All these tools allow you to control and manage middle size and big projects. You don’t need them for oneclass practice tasks but if you would like to develop some pet project or just successfully pass job interview it’s better to spend some time on reading docs about them and creating test project with Maven and Gradle.

  3. Version control systems (VCS)

    When you start to develop more complex projects you would like to check history of changes from time to time, perhaps rollback some changes and revert files to previous state. If you are not alone on the project it is quite nice to save project on shared folder and trace changes of each other. For such purpose we use version control systems. Nowadays the most popular VCS are GIT and SVN. There is no need to setup these stuff on local server, you can find a lot of free services online like github, bitbucket, assembla, etc. Again, it’s not mandatory to use VCS for test or pet projects but it’s good practice and such experience would be a big plus on a job interview.

Career path

Now You read really short list of required knowledge and standard tools but you should understand it’s quite far from real tasks in Java development.
There are different types of Java apps and developers in those areas have slightly different set of skills.You can start working as:

  1. Android developer

    Honestly, I would say it’s not even Java developer but you will need knowledge of Java there. Just to feel a spirit of android development you could setup Android Studio, run emulators, download and run some “hello world” for android. I would say it’s quite different “world” comparing to plain Java app..

  2. Embedded developer

    Low-level development for different kind of devices. Strong knowledge of core Java is must have. You will  work a lot with device specifications. It would be useful to know how hardware and communication protocols works.

  3. Desktop Java

    You should know core Java especially concurrency and you will have to learn Swing or SWT for user interface development. Actually it’s not so popular but still there are some market behind.

  4. Enterprise software developer

    Pay attention – enterprise software not always means enterprise Java. It’s most widespread direction in Java. Enterprise software is a computer software used to satisfy the needs of an organization.

Enterprise software

Most probably you will start working on enterprise project. There are two different approaches to build enterprise software with Java:

  1. based on Java standard technologies i.e. JSF, EJB, etc.
  2. based on Spring (or any other lightweight framework) and separated UI.

Nowadays the second way is more popular. Typical structure of such project is
frontend -> backend -> DB

As usual frontend is written in some modern JS framework and quite often Java developers who are working mostly on backend do nothing there. Communication between frontend and backend could be implemented in different ways for example REST services. REST service is exposed URL, when frontend calls this URL backend executes some action or returns some data. Such approach allows to separate frontend and backend. Let assume you as Java developer will work only on backend. I explained above how to compile and run plain Java app. In case enterprise software it works in a bit different way. After compilation you should build deployment package (file with extension .war) and run it on web server like Tomcat, Jetty, etc.
More details how to create webproject and deploy on Tomcat you can find here or here

Databases

Most applications store results to DB so that you should have at least general knowledge about communication with DB. Core of DB operation in Java is JDBC API. The JDBC API is a Java API that can access any kind of tabular data, especially data stored in a Relational Database. JDBC overview.
There are few different approaches were implemented over JDBC: jpa, jdo or something like jooq, where you can work with DB without using JDBC API directly but in fact it’s really recommended to try working with JDBC API at the beginning.
One more interesting thing you should know about DB is nosql solutions which are quite popular today so don’t forget to read about it and learn difference between sql and nosql solutions.

Not The End

It’s quite difficult to cover all stuff which are required in daily job of Java developer so I tried just to show you right direction. Some time in article I simplified things so don’t hesitate to double-check and read more. Studying things one by one in logical order allows you to develop skills properly. Don’t jump immediately on omnipresent frameworks like Spring. I would rather recommend you to read something about software design principles like DRY, KISS, YAGNI, SOLID. Pay attention to naming and code convention in general. Don’t be greedy – use full and clear names for variables and methods, put parenthesis everywhere, avoid ternary and unary operators if you can, do not write long classes and methods. Any newcomer should understand your code without comments and docs. Be clear and consistent in your code.
I’m pretty sure if you read a bit about everything I wrote and run few test projects it will give you good chance to obtain Java trainee/junior position.

 

If you found mistake or just have some idea for improvement – let me know by mail [email protected]

Git mastering

We just migrated our source code to Git (GitLab) so that we decided to develop some git convention. I share our internal kitchen ’cause it could be useful for others as well. The main idea keeping master as only source for releases and all development should be done on branch called dev. Also we keep in reserve branch stage in case we will have to provide separate branch for qa purpose. For now we do not have dedicated QA on the given project so we directly merge from dev to master but if you have QA on project use following merge scheme dev -> stage -> master. Also on GitLab we have configured CI. For each push to remote repository CI builds project and show warning on MergeRequest in case project build/test fails.

Precondition

  1. We will use branch master only for releases!!!
  2. All changes should be merged to branch called dev and only then moved to master
  3. All changes from dev should be moved to master with GitLab Merge Requests. Do not run any actions manually through console!
  4. All development should be done on private branch created for each new task
  5. All changes from private branches should be moved to dev with GitLab Merge Requests
  6. Private branch should be deleted after approval of Merge Request

How to create dev branch

  1. Switch to master
    git checkout master
  2. Pull latest changes from origin master with discarding any local changes
    git pull --rebase origin master
  3. Create new branch dev on local env
    git checkout -b dev
  4. Push  local branch dev with command
    git push -u origin dev

How to create new private branch for development and then create Merge Request

  1. Sync local environment with git repository structure. Execute command once to let your local structure know about dev branch
    git fetch
  2. Switch to branch dev
    git checkout dev
  3. Get latest changes from dev
    git pull --rebase origin dev
  4. Create and switch to private branch
    git checkout -b  <my_private_branch_name>
  5. Development itself
  6. Commit your changes to local repository
    git commit -am "commit description"
  7. Push changes to remote repository
    git push -u origin <my_private_branch_name>

    Pay attention on key -u.  You can find good explanation on StackOverflow

  8. Create Merge Request with GitLab user interface. I recommend to select option “Remove source branch” and if you have enterprise version of GitLab also select option “Squash commits”
  9. Review Merge Request!
  10. Resolve conflicts if required
  11. Switch to branch dev again
    git checkout dev
  12. If you would like to remove local branches which are already removed on remote execute
    git fetch --prune

How to resolve Merge Request conflicts

  1. Switch to local version of dev
    git checkout dev
  2. Pull latest changes from origin dev with discarding any local changes
    git pull --rebase origin dev
  3. Switch back to private branch
    git checkout <my_private_branch_name>
  4. Rebase private branch on top of dev latest changes (reapply your work on top of the incoming changes)
    git rebase dev
  5. Resolve conflicts manually in conflicted files with IDE
  6. Commit changes
    git commit -m "commit description"
  7. Push changes with force key
    git push -f origin <my_private_branch_name>
  8. On this step Merge Request could be approved by reviewer

P.S.

In case you need to remove local branches which already deleted on remote repo, call

git remote prune origin

List all local branches with command

git branch

If you found mistake or just have some idea for improvement – let me know by mail [email protected]

Выделение области карты на GoogleMap

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

image


В общем в нашем MainActivity нам нужно будет подключить карту, и после этого отследить onTouch событие когда пользователь будет рисовать на карте, а потом что бы после того как будет нарисован какой-то круг, вся область за этим кругом была затемнена, а сам круг был обычного цвета карты, что бы был акцент именно на этой области. В общем как на скриншоте. По этому давайте подключим все библиотеки, у нас это ButterKnife и maps api.

app/build.gradle

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'

    implementation 'com.google.android.gms:play-services-location:9.6.1'
    implementation 'com.google.android.gms:play-services-maps:9.6.1'

    compile 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

ButterKnife используем для удобства подключения вьюх и остальных ресурсов в проект. Карты очевидно используем для отображения карт 🙂

Дальше нам нужно нарисовать нашу разметку, в ней у нас будет карта и фрейм леяут поверх нее.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <fragment
        android:id="@+id/map"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        class="com.google.android.gms.maps.SupportMapFragment" />

    <FrameLayout
        android:id="@+id/fram_map"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <Button
            android:id="@+id/drawBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onDrawClick"
            android:text="Free Draw" />
    </FrameLayout>

</FrameLayout>

Как я и говорил, у нас будет карта, она будет у нас основным объектом на экране, поверх у нас FrameLayout в котором кнопка по нажатию на которую мы будем чистить карту и потом рисован на ней.

MainActivity.java

import android.graphics.Point;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.maps.model.PolylineOptions;

import java.util.ArrayList;
import java.util.List;

import butterknife.BindColor;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, View.OnTouchListener {

    private GoogleMap googleMap;

    private int source = 0;
    private int destination = 1;

    private boolean isMapMoveable = false;
    private boolean screenLeave = false;

    private ArrayList<LatLng> latLngArrayList = new ArrayList<>();

    @BindView(R.id.fram_map)
    FrameLayout framMap;
    @BindView(R.id.drawBtn)
    Button drawBtn;
    @BindColor(R.color.colorPrimary)
    int colorPrimary;
    @BindColor(R.color.transparentGray)
    int transparentGray;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        SupportMapFragment customMapFragment = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
        customMapFragment.getMapAsync(this);
    }

    @OnClick(R.id.drawBtn)
    public void onDrawClick() {
        isMapMoveable = true;
        drawBtn.setVisibility(View.GONE);
        latLngArrayList.removeAll(latLngArrayList);
        googleMap.clear();
    }

    public void drawMap() {
        if (latLngArrayList.size() > 1) {
            googleMap.addPolyline(new PolylineOptions().add(
                    latLngArrayList.get(source),
                    latLngArrayList.get(destination))
                    .width(20)
                    .color(colorPrimary)
            );
            source++;
            destination++;
        }
    }

    private List<LatLng> createOuterBounds() {
        final float delta = 0.01f;

        return new ArrayList<LatLng>() {{
            add(new LatLng(90 - delta, -180 + delta));
            add(new LatLng(0, -180 + delta));
            add(new LatLng(-90 + delta, -180 + delta));
            add(new LatLng(-90 + delta, 0));
            add(new LatLng(-90 + delta, 180 - delta));
            add(new LatLng(0, 180 - delta));
            add(new LatLng(90 - delta, 180 - delta));
            add(new LatLng(90 - delta, 0));
            add(new LatLng(90 - delta, -180 + delta));
        }};
    }


    private void drawFinalPolygon() {
        latLngArrayList.add(latLngArrayList.get(0));

        PolygonOptions polygonOptions = new PolygonOptions();
        polygonOptions.fillColor(transparentGray);
        polygonOptions.addAll(createOuterBounds());
        polygonOptions.strokeColor(colorPrimary);
        polygonOptions.strokeWidth(20);
        polygonOptions.addHole(latLngArrayList);

        Polygon polygon = googleMap.addPolygon(polygonOptions);

        for(LatLng latLng : polygon.getPoints()) {
            Log.e("latitude", "" + latLng.latitude);
            Log.e("longitude", "" + latLng.longitude);
        }
    }

    @Override
    public void onMapReady(final GoogleMap googleMap) {
        this.googleMap = googleMap;
        framMap.setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
        if (isMapMoveable) {
            Point point = new Point(Math.round(event.getX()), Math.round(event.getY()));
            LatLng latLng = googleMap.getProjection().fromScreenLocation(point);
            double latitude = latLng.latitude;
            double longitude = latLng.longitude;

            int eventaction = event.getAction();
            switch (eventaction) {
                case MotionEvent.ACTION_DOWN:
                    screenLeave = false;
                case MotionEvent.ACTION_MOVE:
                    latLngArrayList.add(new LatLng(latitude, longitude));
                    screenLeave = false;
                    drawMap();
                case MotionEvent.ACTION_UP:
                    if (!screenLeave) {
                        screenLeave = true;
                    } else {
                        isMapMoveable = false;
                        source = 0;
                        destination = 1;
                        drawBtn.setVisibility(View.VISIBLE);
                        drawFinalPolygon();
                    }
                    break;
                default:
                    break;
            }

            if (isMapMoveable) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
}

Рассмотрим все по порядку. В самом верху класса мы определили все переменные и ресурсы типа карты, GoogleMap и ArrayList в который мы будем сохранять наши координаты.
Дальше в методе onCreate() мы подключили SupportMapFragment и ButterKnife.
Метод onDrawClick() обрабатывает клик по кнопке, чистит карту делает карту рисовабельной и удаляет все из списка.
drawMap() — метод который добавляет полигоны на карту по ходу дела рисования пальцем на карте.
createOuterBounds() — метод который зарисовывает всю область вокруг нарисованного круга.
drawFinalPolygon() — очевидно рисует финальную версию полигона на карте по координатам которые мы сохранили в ArrayList и заканчивает круг в начальную точку с которой он начинался. Ну и дальше по желанию распечатывает в лог координаты которые были использованы на карте.
onMapReady() — метод класса GoogleMap, он вызывается когда карта готова к использованию.
onTouch() — метод в котором происходит вся магия, в начале мы проверяем если карта готова к началу рисования, то есть проверяется isMapMoveable, если да, тогда мы начинаем отслеживать нажатие на экран и отслеживать координаты на карте. По окончанию когда мы отпускаем карту по событию MotionEvent.ACTION_UP мы делаем isMapMoveable = false для того что бы мы снова могли двигать картой. И делаем кнопку снова видимой для очистки экрана и новой возможности для рисования.

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

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="project.dajver.com.drawgesturesmap">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google.maps.api.key"/>

    </application>

</manifest>

Исходники:
GitHub && Мой блог

Java Code Quality Tools

Few days back we decided that we need some code quality tool on our project and the search has begun.
The most comprehensive post on this topic we found here, but it’s been 6 years since the post was published and a lot of the tools are already outdated, so I decided to update it a bit. I sorted the list of tools by their update time, from newly updated to already dead tools(some update dates can be not that accurate, cause sometimes it was difficult to find the year of the last update).

The most used seem to be PMDCoberturaCheckstyleFindBugs and Sonar, which has many tools integrated inside it(e.g. FindBugs, PMD, Checkstyle, JDepend), and that’s why we decided to try it out.
Also, I found a new one – Codacy, functionally pretty similar to Sonar, but it works directly with repositories. If you know an efficient tool not listed below, feel free to mention it in the comments.

  • Qulice (last update: 2017)
    Is a static analysis quality control instrument for Java projects. It combines all the best static analysis instruments and pre-configure them. There are many tools that control the quality of Java code, including Checkstyle, PMD, FindBugs, Cobertura, etc. All of them are usually used to analyze the quality and build some fancy reports. It aggregates a few quality checkers, configures them to a maximum strict mode, and breaks your build if any of them fail.
  • Codacy(last update: 2017)
    Codacy is a complex customizable multilanguage quality control tool. It directly integrates with Github Enterprise, Bitbucket Server (Stash) and Gitlab and doesn’t require a change of workflow. With Codacy you get static analysis, code coverage, duplication and complexity changes in every commit and pull request.
  • Sonar(last update: 2017)
    Sonar is a continuous quality control tool for Java applications. Its basic purpose in life is to join your existing continuous integration tools to place all your development projects under quality control.
  • PMD(last update: 2017)
    It scans Java source code and looks for potential problems: Possible bugs, Dead code, Suboptimalulode, Overcomplicated expressions and Duplicate code.
  • Cobertura(last update: 2017)
    It’s a free Java tool that calculates the percentage of code accessed by tests. It can be used to identify which parts of your Java program are lacking test coverage. It is based on jcoverage.
  • Checkstyle(last update: 2017)
    It is a development tool to help programmers write Java code that adheres to a coding standard.
  • UCDetector(last update: 2017)
    UCDetector (Unecessary Code Detector) is a Open Source eclipse PlugIn Tool to find unecessary (dead) java code. It also tries to make code final, protected or private. UCDetector also finds cyclic dependencies between classes.
  • Cloc(last update: 2017)
    Cloc counts blank lines, comment lines, and physical lines of source code in many programming languages.
  • SourceMonitor(last update: 2017)
    The freeware program SourceMonitor lets you see inside your software source code to find out how much code you have and to identify the relative complexity of your modules. For example, you can use SourceMonitor to identify the code that is most likely to contain defects and thus warrants formal review.
  • Spoon(last update: 2017)
    Spoon provides a complete and fine-grained Java metamodel where any program element (classes, methods, fields, statements, expressions…) can be accessed both for reading and modification. Spoon can be used on validation purpose, to ensure that your programs respect some programming conventions or guidelines, or for program transformation, by using a pure-Java template engine.
  • PathFinder(last update: 2017)
    Java PathFinder (JPF) is a system to verify executable Java bytecode programs. In its basic form, it is a Java Virtual Machine (JVM) that is used as an explicit state software model checker, systematically exploring all potential execution paths of a program to find violations of properties like deadlocks or unhandled exceptions. Unlike traditional debuggers, JPF reports the entire execution path that leads to a defect. JPF is especially well-suited to finding hard-to-test concurrency defects in multithreaded program
  • Soot(last update: 2017)
    Soot can be used as a stand alone tool to optimize or inspect class files, as well as a framework to develop optimizations or transformations on Java bytecode.
  • FindBugs(last update: 2015)
    It looks for bugs in Java programs. It can detect a variety of common coding mistakes, including thread synchronization problems, misuse of API methods, etc.
  • JDepend(last update: 2015)
    JDepend traverses Java class file directories and generates design quality metrics for each Java package. JDepend allows you to automatically measure the quality of a design in terms of its extensibility, reusability, and maintainability to effectively manage and control package dependencies.
  • Classycle(last update: 2014)
    Classycle’s Analyser analyses the static class and package dependencies in Java applications or libraries. It is especially helpful for finding cyclic dependencies between classes or packages. Classycle is similar to JDepend which does also a dependency analysis but only on the package level.
  • CODERU(last update: 2014)
    CODERU is a java code quality tool to enforce good design in respect to package dependencies. The CODERU-rules rely on reserved package names and the allowed dependency rules between them expressed in a general way.
  • DoctorJ(last update: 2013)
    DoctorJ analyzes Java code, in the following functional areas: documentation verification, statistics generation and syntax analysis.
  • JarAnalyzer(last update: 2013)
    JarAnalyzer is a dependency management tool for .jar files. JarAnalyzer will analyze all .jar in a given directory and identify the dependencies between each. Output formats include xml, with a stylesheet included to transform it to html, and GraphViz DOT, allowing you to produce a visual component diagram showing the relationships between .jar files. The xml output includes important design metrics such as Afferent and Efferent coupling, Abstractness, Instability, and Distance. There is also an Ant task available that allows you to include JarAnalyzer as part of your build script.
  • Jalopy(last update: 2012)
    Jalopy is an easily configurable source code formatter that can detect, and fix, a number of code convention flaws that might appear in Java code. Jalopy is more of a code fixer than a code checker. Jalopy plug-ins are present for most IDEs and, in most cases, they gel quite seamlessly with the IDE.
  • JBoss Tattletale(last update: 2012)
    JBoss Tattletale is a tool that can help you get an overview of the project you are working on or a product that you depend on. The tool will recursive scan a directory for JAR files and generate linked and formatted HTML reports.
  • JLint(last update: 2011)
    It checks your Java code and finds bugs, inconsistencies and synchronization problems by doing data flow analysis and building the lock graph.
  • Squale(last update: 2011)
    Squale is a qualimetry platform that allows to analyze multi-language software applications in order to give a sharp and comprehensive picture of their quality: High level factors for top-managers and Practical indicators for development teams.
  • Hammurapi(last update: 2010)
    Hammurapi is an open source code inspection tool. Its release comes with more than 100 inspectors which inspect different aspects of code: Compliance with EJB specification, threading issues, coding standards, and much more.
  • Dependency Finder(last update: 2010)
    Extracts dependencies and OO metrics from Java class files produced by most Java compilers.
  • XRadar(last update: 2009)
    The XRadar is an open extensible code report tool that produces HTML/SVG reports of the systems current state and the development over time. Uses DependencyFinder, JDepend, PMD, PMD-CPD, JavaNCSS, Cobertura, Checkstyle, XSource, JUnit, Java2HTML, ant and maven.
  • JavaNCSS(last update: 2009)
    JavaNCSS is a simple command line utility which measures two standard source code metrics for the Java programming language. The metrics are collected globally, for each class and/or for each function.
  • Jameleon(last update: 2008)
    Jameleon is an automated testing framework that can be easily used by technical and non-technical users alike. One of the main concepts behind Jameleon is to create a group of keywords or tags that represent different screens of an application. All of the logic required to automate each particular screen can be defined in Java and mapped to these keywords. The keywords can then be organized with different data sets to form test scripts without requiring an in-depth knowledge of how the application works. The test scripts are then used to automate testing and to generate manual test case documentation.
  • Coqua(last update: 2008)
    Coqua measures 5 distinct Java code quality metrics, providing an overview and history for the management, and down-to-the-code, detailed views for the developer. Metrics can be defined per team. Ideal for mid- to large-sized and/or offshore projects.
  • Crap4j(last update: 2008)
    Crap4j is a Java implementation of the CRAP (Change Risk Analysis and Predictions) software metric – a mildly offensive metric name to help protect you from truly offensive code.
  • ESC/Java2(last update: 2008)
    The Extended Static Checker for Java version 2 (ESC/Java2) is a programming tool that attempts to find common run-time errors in JML-annotated Java programs by static analysis of the program code and its formal annotations. Users can control the amount and kinds of checking that ESC/Java2 performs by annotating their programs with specially formatted comments called pragmas.
  • Dependometer(last update: 2007)
    Dependometer performs a static analysis of physical dependencies within a software system. Dependometer validates dependencies against the logical architecture structuring the system into classes, packages, subsystems, vertical slices and layers and detects cycles between these structural elements. Furthermore, it calculates a number of quality metrics on the different abstraction layers and reports any violations against the configured thresholds.
  • JDiff(last update: 2007)
    JDiff is a Javadoc doclet which generates an HTML report of all the packages, classes, constructors, methods, and fields which have been removed, added or changed in any way, including their documentation, when two APIs are compared. This is very useful for describing exactly what has changed between two releases of a product. Only the API (Application Programming Interface) of each version is compared. It does not compare what the source code does when executed.
  • Panopticon(last update: 2007)
    The Panopticode project provides a set of open source tools for gathering, correlating, and displaying code metrics.
  • Lint4j(last update: 2007)
    Lint4j (“Lint for Java”) is a static Java source and byte code analyzer that detects locking and threading issues, performance and scalability problems, and checks complex contracts such as Java serialization by performing type, data flow, and lock graph analysis.
  • QALab(last update: 2006)
    QALab consolidates data from Checkstyle, PMD, FindBugs and Simian and displays it in one consolidated view. QALab keeps a track of the changes over time, thereby allowing you to see trends over time. You can tell weather the number of violations has increased or decreased – on a per file basis, or for the entire project. It also plots charts of this data. QALab plugs in to maven or ant.
  • Emma(last update: 2005)
    It is a fast Java code coverage tool based on bytecode instrumentation. It differs from the existing tools by enabling coverage profiling on large scale enterprise software projects with simultaneous emphasis on fast individual development.
  • Clirr(last update: 2005)
    Clirr is a tool that checks Java libraries for binary and source compatibility with older releases. Basically you give it two sets of jar files and Clirr dumps out a list of changes in the public api. The Clirr Ant task can be configured to break the build if it detects incompatible api changes. In a continuous integration process Clirr can automatically prevent accidental introduction of binary or source compatibility problems.
  • ckjm(last update: 2005)
    The program ckjm calculates Chidamber and Kemerer object-oriented metrics by processing the bytecode of compiled Java files. The program calculates for each class the following six metrics proposed by Chidamber and Kemerer.
  • Eclipse Metrics plugin(last update: 2005)
    Provide metrics calculation and dependency analyzer plugin for the Eclipse platform. Measure various metrics with average and standard deviation and detect cycles in package and type dependencies and graph them.
  • QJ-Pro(last update: 2005)
    QJ-Pro is a comprehensive software inspection tool targeted towards the software developer. Developers can automatically inspect their Java source code and improve their Java programming skills as they write their programs. QJ-Pro provides descriptive Java patterns explaining error prone code constructs and providing solutions for it.
  • Macker(last update: 2003)
    Macker is a build-time architectural rule checking utility for Java developers. It’s meant to model the architectural ideals programmers always dream up for their projects, and then break — it helps keep code clean and consistent. You can tailor a rules file to suit a specific project’s structure, or write some general “good practice” rules for your code. Macker doesn’t try to shove anybody else’s rules down your throat; it’s flexible, and writing a rules file is part of the development process for each unique project.
  • JCSC(last update: 2003)
    JCSC is a powerful tool to check source code against a highly definable coding standard and potential bad code. The standard covers naming conventions for class, interfaces, fields, parameter, … . Also the structural layout of the type (class/interface) can be defined. Like where to place fields, either before or after the methods and in which order. The order can be defined through the visibility or by type (instance, class, constant). The same is applicable for methods. Each of those rules is highly customizable. Readability is enhanced by defining where to put white spaces in the code and when to use braces. The existence of correct JavaDoc can be enforced and various levels. Apart from that, it finds weaknesses in the the code — potential bugs — like empty catch/finally block, switch without default, throwing of type ‘Exception’, slow code.
  • Condenser(last update: 2002)
    Condenser is a tool for finding and removing duplicated Java code. Unlike tools that only locate duplicated code, the aim of Condenser is to also automatically remove duplicated code where it is safe to do so.
  • CodePro Analytix(dead)
    It’s a great tool (Eclipse plugin) for improving software quality. It has the next key features: Code Analysis, JUnit Test Generation, JUnit Test Editor, Similar Code Analysis, Metrics, Code Coverage and Dependency Analysis.
  • DCD(dead)
    DCD finds dead code in your Java applications.
  • Byecycle(dead)
    Byecycle is an auto-arranging dependency analysis plugin for Eclipse. Its goal is to make you feel sick when you see bad code and to make you feel happy when you see a good code.
  • Relief(dead)
    Relief provides a new look on Java projects. Relying on our ability to deal with real objects by examining their shape, size or relative place in space it gives a “physical” view on java packages, types and fields and their relationships, making them easier to handle. Lets discuss quickly how we interprete physical properties and how it can help us to grasp project characteristics.

Віртуальний GUI на Scala

Розглянемо створення застосунку з графічним інтерфейсом, який би працював на робочому столі , в браузері та під Android без зміни коду.
Звичайно нам знадобляться бібліотеки- фасади, які інкапсулюють різницю між бібліотеками контролів цих систем (JavaFX, Android, DOM)

Для створення таких фасадів прекрасно підходять implicit класи. Наприклад:

implicit class TextFieldExt(txt: Text) {
  def text=txt.getText
  def text_=(a: Any) = txt.setText(a.toString)
}

Так ми зможемо зробити GUI не тільки на методах, але і на властивостях: btHello.text=”Hello”

Але ні в DOM ні в Android немає готового контрола Table. Доопрацювання тих віджетів що там є на implicit класах уже не можливе, потрібно зберігати стан.

Тому Table – це звичайний клас. Крім того в Android для табличних даних потрібенще клас адаптера. Серед стандартних адаптерів немає такого,що вміє працювати з Array, ArrayList ,ArrayBuffer в яких зберігаються класи даних. Прийшлось написати свій ItemAdapter.
Для обробки структур даних в яких віджет це поле і в якому можуть бути різні класи віджетів:
val card=Array(new Card{id=txtName, prop=TEXT,….},new Card{id=cbCat, prop=INDEX…},….)
нас виручить потужний механізм зіставлення з взірцем :

for(c<-card)
  c.id match {
  case text :Text =>text.text=...
  case combo: Combo => combo.index=...
 ….....
  }
 }

Ще однією проблемою є те, що в кожній із трьох систем свій механізм ініціалізації графічного інтерфейсу. Можливо стабілізація API макросів і мій вільний час вирішать цю проблему в майбутньому. А поки що так))

Код для Android:
 class MorgFx extends AppCompatActivity {

  override def onCreate(savedInstanceState: Bundle)={
    super.onCreate(savedInstanceState)
    setContentView(R.layout.hello_app)
    val context:Context = this
    val root=this
    val btHello = root.elem(R.layout.btHello).asInstanceOf[Button]
    val cbHello = root.elem(R.layout.cbHello).asInstanceOf[Combo]
    val txtHello = root.elem(R.layout.txtHello).asInstanceOf[Text]
    cbHello.fill(Array("man","woman"), context)
    btHello.onSelect(btSelect)

    def btSelect(sender:Any){
      context.showMessage(txtHello.text)
      }
  }
 }

Код для браузера:

object HelloApp extends JSApp {
  def main(): Unit = {
    val context=startGUI("divHello")
    val root=context
    val btHello = root.elem("#btHello").asInstanceOf[Button]
    val cbHello = root.elem("#cbHello").asInstanceOf[Combo]
    val txtHello = root.elem("#txtHello").asInstanceOf[Text]
    cbHello.fill(Array("man","woman"), context)
    btHello.onSelect(btSelect);

     def btSelect(sender:Any){
      context.showMessage(txtHello.text)
    }
  }
 }

Код для робочого столу:

object HelloApp {
  def main(args: Array[String]): Unit ={
    Application.launch(classOf[HelloApp], args: _*)
  }
}

class HelloApp extends Application {
  type Combo = ComboBox[String]
  override def start(stage: Stage): Unit = {
    val context = stage
    val root = context.startGUI("divHello")
    val btHello =root.elem("#btHello").asInstanceOf[Button]
    val cbHello = root.elem("#cbHello").asInstanceOf[Combo]
    val txtHello = root.elem("#txtHello").asInstanceOf[Text]
    btHello.onSelect(btSelect);

    def btSelect(sender:Any){
      context.showMessage(txtHello.text)
    }
  }
 }

Посилання на  GitHub  https://github.com/anatoly62/scala-gui

Брак SQL функцій в H2 DB – вирішення проблеми

В мене виникла проблема з H2 DB під час розробки фукнціональних тестів для аплікейшна, в якого MySQL (MariaDB) в проді – а H2 DB, відповідно, в функціональних тестах.

В H2 DB, як виявляється, немає більшості функцій для конверсії дат, наявних в MySQL – а саме мені забракло такої примітивної речі як UNIX_TIMESTAMP (яка в MySQL конвертує дати в, ясне діло, unix timestamp).

В результаті код то працює, але фукнціональний тест не написати, бо SQL запит, який чудово працюе сам по собі, в тестах валиться через відсутність UNIX_TIMESTAMP.

Фікс виявився дуже простим – в H2 DB в якості функції реєструється джавішний static метод через виклик CREATE ALIAS. Т.я. classpath в тестах спільний з classpath-ом H2 DB, працюючий код тесту виглядає приблизно так (JUnit4+Spring):

package my.package;

class MyTestClass {
    public static long unixTimestamp(java.sql.Timestamp datetime) {
        return datetime.getTime() / 1000;
    }

    @Autowired
    DataSource dataSource;

    @Before
    public void beforeTestInit() {
        try (Connection conn = dataSource.getConnection()) {
            conn.createStatement().execute("CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR \"my.package.MyTestClass.unixTimestamp\"");
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
   }
    @Test
    public void doYourStuff() throws Exception {
        // Ваш тест тут
    }
}

От і все. Boom, done.

Сподіваюсь комусь цей приклад стане на пригоді.