
ααααΆααΈαααΌαα½ααααα»αα
ααααααααΆααΈαααΌαα
αα
α»αααααααααα»ααααααΆααααΆαααααΎααααΆααα§ααααααα·ααΆα PVS-Studio ααΊααΆααα½ααααα
αΌαααααααΆααΆαα½ααααααααα CI α α αΎααααααΈααΆααΆααα·ααΆααααααααα PVS-Studio ααΈαααααααααα½ααααα
αΌαααΆαααααααααΆααααααΎαααααΆααα’ααα’αΆα
ααααΌαααΆααααααΎααα
ααΆααΆααααααααΆαα½αα
ααα½αααααα ααααΎαααααααααΎα±ααααααΎαααΆααααααΆααααααΆααααα½αα α₯α‘αΌαααα PVS-Studio ααΆαααΆαααΆαααααααααΆααααΆααααααααααααααα’ααααα·ααΆααα
ααΆαααααααααααΆαα TeamCity - TeamCity Inspections Typeα αααααΎααααααααααΆααααΎαααΆαα
ααααααΆαα’αααΈαααααα·ααΈαααααΆαααααΎ
β α§ααααααα·ααΆααα·αα·αααααααααΆααααΌα C, C++, C# αα·α Java αααααααΌαααΆααα ααΆα‘αΎαααΎααααΈααααα½αααααα·α αα ααΆαααααααα αα·ααα½ααα»αααα α»αααααααααααααα α§ααααααα·ααΆαα’αΆα ααααΌαααΆαααααΎαα αααα»α Windows, Linux ΠΈ macOSαα αααα»αα’αααααααα ααΎαααΉαααααΎααααΆαααααΆαααααααα·αααααΉαααα§ααααααα·ααΆααααα½αα―αααα»ααααααα ααα»αααααααααΆααα§αααααααααΎααααΆαααα½αα ααα½αααΈααΆαα ααα αΆαααααααΆαααααα
β ααΊβααΆβαααΆαααΈαβααβαααα½αβαα·αα·αααβαααβαααα½αβαα·αα·αααβααΆαβααΎαβααααΎαβααΆαβα αααααα ααΆααααΌαααααααΎαααΆαααααΆαααα»ααααα αΆααααααΎααααααΎαααααααααααα’αααα αα αααα»ααααα snooping, server ααΉαααΆααΆααααααΎαααΆααα compilers αααααΆααααααΆααα’ααα αα½αααααααααΆααααΆα§αααααααααΎααααΆαααααα’αΆα ααααΎααΎααααΈαα·ααΆααααααα C/C++ ααα»αααααα
- α§αααααααααΎααααΆαααααααΆααααααααααααΆαααΆαααα’ααααα·ααΆααα ααΆααααααααααααα
ααααααΆαα’αααΈααααααααααααα»ααα·ααααΆ
αααααΆααααααα»αααΆαααααα ααΎα§ααΆα αααααΆααααααα - ααααα·ααΆααααααα OpenRCT2 α
- ααΆαα’αα»ααααααΎαα αα ααα αααα RollerCoaster Tycoon 2 (RCT2) ααααααααΈαααΆααΆαα½αααΉααα»αααΆαααααΈ αα·ααα½ααα»αααα α»αα ααΆααααα αααααα·ααα»ααα·αααΆαααΆαααα αα·αααΆααααααααΆαα½ααααααΆααααααααΆααααααααα·α α αΆα αα·ααααααΆααααα·ααααΆαααααααα α’ααααααααααΌαααααααΆααΆαααααααΆααα αααα αα·ααααααΆαααααα·ααααααααα’ααααα§ααααΆα αααααααααααααΎα±ααααααααααααΆαα α·αααα OpenRCT2 α’αα»ααααΆαα±ααα’ααααααααΆαααααα»αααααΆααΈαααΌ αα·ααααα’ααααααΆα αα ααααΆααΈαααΌαααααΌαα±ααα’ααααααααααααα·α αα ααΆαααΆααααΆαααα½ααααα»αααααααααααα ααααααααα Sandbox α’αα»ααααΆαα±ααα’αααααααααααΎααα½ααααααΆααααααα’αΆα ααααααααΆαααααα·αααΆαααΆαααΉααααααΉα α¬α α·ααααααααα»ααΆαα½αα‘αΎαα
ααΆααααααααΌα
ααΎααααΈααααααααααααΆ αααα»ααααα ααααΉαααααααααΎαααΆαααα‘αΎα α αΎαα αΆααααααΎαααΈαααααααααα»αααΆααααΆαααΈααα TeamCity ααααΎαααΆαααΎαα»αααααΌααααααααααα»αα ααΎαααααΌαα αΌααα ααΆααα localhost:{port αααααΆααααααΆαααααα»αα’αα‘α»ααααααααΎαααΆαααα‘αΎα} (αααα»αααααΈαααααααα»α localhost:9090) α αΎααααα αΌααα·ααααααααΆαα’αα»ααααΆαα αααααΆααααΈα αΌαααΎαααΉαααααΆαααααααα

α
α»α
ααΎαααΌαα»ααααααΎαααααααα αααααΆααααααααΎαααΎαααααα α αΎαααααααααα»αααΆαα

αααααΆααααΈα
α»α
αααΌαα»α αααααΎαααΎαααααΌαααΆαααααΆααααααααααα’α½α
αααααΆαααΆααααααα

αααα
α»α
αααααΎαααΆαααααααα
ααΆαααααααα.

αααααααΆαα αΎαα
α»α
αααααΎα. ααΎαααΎααααα’α½α
αα½ααααααααΎα±ααα’αααααααΎαααΎααααααααααααα½ααα·αα·αααααααα αααααΆααααααααΆαααΈααΆαααα½α
α αΎα ααΌαα
α»α
αααα.

ααΆα
α»αααααα ααΎααααααα
ααΆααααααααααααα

αααβααααααβααα αΆαβααα‘αΎαβααΎααααΈβααααΎβααΆαβα
α»α
βαααα ααα αΆαααΆαααα -> ααααααααα αΆαααΆαααα.

αα
ααΈαααααΎαααααΎαααΎαα
- ααααααα’αααααα -> αααααΆααααΆααααααααΆ
- ααα -> ααααααΈαααααΆαααααα½α
αααααΆαααΎαααΉαααααΎααΆααα·ααΆαααα‘α»ααααα ααααααααααα ααΆααα½αααααα»αααααΆ αα·αααΆααα·ααΆααα½αααααΆααα αΆααα½α ααΌα ααααααΌαααααααααα»αααΆα ααααααΈαααααΆαααααα½α:

ααΎαααΉααα·αα·αααααΎαααα αΆαααΈαα½αααα
ααααααααα ααΆααΆααΆαααααΆααααΆαααααααΆααααα»αα§ααααααα·ααΆα ααΆααααα»ααααααα ααΆααα·ααΆαααΆ αααααααααΆαααΆααα αα·αααΆαααααΎαααααααααΆα ααΆααααΌαα
αααΆααααααααΉαααααααα½ααα½αααααΌαα
ααΏαα α»αααααααααααΎαααααΌαααααΎααΊαααααα’αααααα·ααααΆα ααααααα»αααΆααααααΆααα’αααΈαα·ααΈαα½αα ααα½αααΎααααΈαααααα’ααααααΆαα’αΆααααααα½αααα ααΎααααΈααααΎααΌα αααααΌαααααα αααΆαααΆαααααα -> αααααααααΆαααΆααααααααααΈα α αΎαααααααα’αααααΈα

α’αααΈαααα’αααααααΌαααααΎααΊα
α»α
αααΌαα»α Run αα
αααα»αααΆαααααΆαααΆαααΎα ααααααααααααααααααα»αααααΌαααΆααααααΌααααα»α αα·ααα·ααΆα αααα»αααΉαααααΆααα’αααα’αααΈααααααΈαα
ααααααΈααααααααΆαα
ααααΌαααΎαααααΌαααΆαααααΆαα ααα αΆα PVS-Studio α α»αααααααααα’ααα αααααΆαααααα αΆαααααΎαααααΎαααααα·ααΈααααααααααααα αα Chocolatey α αααααΆααα’ααααααα ααααΉαααααααα’αααΈααΏααααααΆααααααααΌαααααΆα :
choco install pvs-studio -yαααααΆαααα ααΌαααΎαααααΎαααΆαα§αααααααΆαααΆαααΆααααΆααααααα CLMonitor α
%CLmon% monitor β-attachαααααΆααααααΎαααΉαααΆααααααααααααΆα’αααααα·ααααΆα α’αααααΈαααΈ ααΊααΆααααΌααα ααΆαααααα MSBuild ααααααα»αααααΌαααΆαααα
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortableααααααα αΌααααααΌαα αΌα αα·αα’αΆααααΆααααααααααΆαα PVS-Studioα
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%αααααΆααααΈααΆαααΆααααααΆααααα αα ααΌαααααΎαααΆα CLMonitor αααααααααΎααααΈαααααΎαα―αααΆααααααΆαααααΎαααΆααα»α αα·αααΆααα·ααΆααα·αα·ααααα
%CLmon% analyze -l "c:ptest.plog"αααααΆααααααΎαααΉαααααΎααααΆααα§αααααααααΎααααΆαααα½αααααααααααΈααΆαα ααα αΆαααααααΎαα PlogConverter ααααααααααΆαααΆαααααΈαααααααααααααΆααα ααΆααααααααΆααααΆαααααα TeamCity α ααΌαα’ααα»αα ααααααΆαααα ααΎαααΉαα’αΆα ααΎαααΆαααααααΆαααα αααα»ααααα’α½α ααΆααααα
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"ααα αΆαα α»ααααααααΊααααΌααααα αΆααααΆαααΆααααααααΆαααααΎαααααααααΆααα αααα»α stdoutαααααΆαααααααααααΆααΉαααααΌαααΆαααααΎαααΎααααα’αααααα TeamCity α
type "C:tempptest.plog_TeamCity.txt"ααΌαααααααΈααααα
choco install pvs-studio -y
%CLmon% monitor --attach
set platform=x64
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
%CLmon% analyze -l "c:ptest.plog"
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
type "C:tempptest.plog_TeamCity.txt"αααα»αααααααααΆααα½αααααα»αααααΆαα·αααΆααα·ααΆαααααααααααααΌαααΆααααα αααααααααααααΎαα’αΆα α αΌααα ααΆααααααΆαα αααααα α αΎαααααΌαααααΆααααΆααΆα

α₯α‘αΌααααααΌαα
α»α
ααΎ ααΆααααα½ααα·αα·αααααα»ααα
ααΎααααΆαααΆαααα’ααααα·ααΆαα

ααΆααααααΆαααααΌαααΆαααΆααααΆαααα»ααααααααααα½αααααα·αα·α
ααααα ααΎααααΈαα»αααααΆααααααΌα α’αααααααΌαα
α»α
ααΎααααααααΆαααααααΆααααααΆαααααΆαα ααΆαα
α»α
ααΎαααααΆαα½ααα
αααα»αααΆαααααΆαααΆαααΎααΉαααΎαααααΆααααααΈαα½αααΆαα½αα―αααΆαα α’αααααα’αΆα
αα»αααααΆααααααΌααααα
α»α
ααΎααααααααΆααααΆαα½αααΉαααΆααααααΆαα’ααααα·ααΆαα ααΆααα»αααααΈαα»αααααΌαααααΈα
ααααΆαααΊα’αΆα
ααααΎαα
ααΆααα
αααααααΎ αααααTreeRoot αααααΆαααααΆααα ααααΆααααΆαααααα
αΆααα’αΆααααααααΎααααααααα·ααααα·ααΆαααααα’ααααα·ααΆααααα’αΆα
ααααΆαααααα½αα―αααΆαα½αααΉαααααααααααααΌαααααΆα .
ααΆαααΎαααααααααααα’ααααα·ααΆα
α₯α‘αΌαααα ααΎαααΆααααα ααααΆαααΆαααααααΆα αα·αααααααα ααΆαααααααααααααα αΎα ααΌααα·αα·αααααΎαααΆααααααΆααα½αα±ααα αΆααα’αΆαααααααα½αα ααα½ααααααΆαααααΎααα αααα»ααααααααααααΎααααα»αααΎαα
ααΆααααααΆα N1
[CWE-401] ααααΈααΎααααααααΌαααΆααααα ααααααα·ααααα ααααααα·α 'αααααα' α ααΆαααα ααααΆαα’αααα αα αΆαααΊα’αΆα ααααΎαα ααΆαα libopenrct2 ObjectFactory.cpp α€α€α£
Object* CreateObjectFromJson(....)
{
Object* result = nullptr;
....
result = CreateObject(entry);
....
if (readContext.WasError())
{
throw std::runtime_error("Object has errors");
}
....
}
Object* CreateObject(const rct_object_entry& entry)
{
Object* result;
switch (entry.GetType())
{
case OBJECT_TYPE_RIDE:
result = new RideObject(entry);
break;
case OBJECT_TYPE_SMALL_SCENERY:
result = new SmallSceneryObject(entry);
break;
case OBJECT_TYPE_LARGE_SCENERY:
result = new LargeSceneryObject(entry);
break;
....
default:
throw std::runtime_error("Invalid object type");
}
return result;
}α’ααααα·ααΆαααΆαααααααααΆααααΎαααα α»αααααααααΆααααΈαααα ααα’αααα αα αΆααααααΆααααα αααααΎαααααα»αα αααααααΈααΎααααααΎαα‘αΎα α’αααα αα αΆααα·αααααΌαααΆααααα’αΆααα α αΎαααΆαααα ααααΆαα’αααα αα αΆαααΎαα‘αΎαα
ααΆααααααΆα N2
ααΆαααααααααααΌα ααααΆααααα·α '(1ULL << WIDX_MONTH_BOX)' αα ααΆαααααα αα·ααα ααΆαααααΆααα '|' ααααα·ααααα·ααα libopenrct2ui Cheats.cpp α€α¨α§
static uint64_t window_cheats_page_enabled_widgets[] =
{
MAIN_CHEAT_ENABLED_WIDGETS |
(1ULL << WIDX_NO_MONEY) |
(1ULL << WIDX_ADD_SET_MONEY_GROUP) |
(1ULL << WIDX_MONEY_SPINNER) |
(1ULL << WIDX_MONEY_SPINNER_INCREMENT) |
(1ULL << WIDX_MONEY_SPINNER_DECREMENT) |
(1ULL << WIDX_ADD_MONEY) |
(1ULL << WIDX_SET_MONEY) |
(1ULL << WIDX_CLEAR_LOAN) |
(1ULL << WIDX_DATE_SET) |
(1ULL << WIDX_MONTH_BOX) | // <=
(1ULL << WIDX_MONTH_UP) |
(1ULL << WIDX_MONTH_DOWN) |
(1ULL << WIDX_YEAR_BOX) |
(1ULL << WIDX_YEAR_UP) |
(1ULL << WIDX_YEAR_DOWN) |
(1ULL << WIDX_DAY_BOX) |
(1ULL << WIDX_DAY_UP) |
(1ULL << WIDX_DAY_DOWN) |
(1ULL << WIDX_MONTH_BOX) | // <=
(1ULL << WIDX_DATE_GROUP) |
(1ULL << WIDX_DATE_RESET),
....
};ααΆαααα»ααααα·α ααΆααααααααα ααΈα’ααααα·ααΆααα·αα·ααααα’αΆα ααααααΆααααΆαααΆαααααααΆαααα α·ααααα»αααΆαααααα α§ααΆα αααααααΆαα αααααα·αααααΆαααααααΊααα’αααααΆααα ααα»ααααααααΆαααΆααααΆααα
ααΆααααααΆα N3
ααΆααΆααΏαα ααααααααααΆα 'ααα' αα αααα»αααααΆαααααααΆαααααΈ 'RCT12BannerElement' αααααααΆααααΎααΆααα αααα»αααααΆααααΌαααααΆα 'RCT12TileElementBase' α αα·αα·ααααααααΆααα RCT12.h:570, RCT12.h:259α libopenrct2 RCT12.h 570
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};ααΆβααΆαβαα·αβααΆαα ααΆαβααααΎβα’αααβαααβααΆαβαααααβααΌα βααααΆβαα βαααα»αβααααΆααβααΌαααααΆα αα·αβαααα»αβααααΆααβααααβαα·αβαααβαααααβααΆαβααα α»αβαααβααα αααααΆαααΆαααΆααααα αα αα αααα·ααααΆααααααααααα½αααΆααααααααΆααααααα·αααααΆααα’ααααααααΆααααααΊααΆαααααααΆααα αααα»αααααΆααααΌαα ααΆααααααΆααααααΆαααΆααααααΆααααααααΌα ααααΆαα αααα»αα’αααααα½ααααα ααΎααααααΎαααΆααααααα ααα‘αα
ααΆααααααΆα N4
ααΆααΆααΏαα ααααααααααααααααααα ααααΈαααααααΆααα 'imageDirection / 8' ααΊααΆααααααα½αααααααααααα αααα ααααΆααα ααααΈαααααααΆαααααααα½αααααααΌαααΆαααααααααααΆαα½αα’αααΈααααααααα libopenrct2 ObservationTower.cpp α£α¨
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}α αΌαααΎααα·αα·αααααΎαα±ααααΆααααα αααΆααα αααααα ααΌαααΆααα·ααα / α¨ ααΉααα·ααα·αααααα·αααΎ αα·ααα ααΌαααΆα αααα·ααα α αααααααΈ -7 ααα 7 α αααααααΈααΈαα (ααΌαααΆααα·ααα / α¨) != α£ αα·αα·ααα αα·ααα ααΌαααΆα αααααΆαααα ααΆααααα αα½α: ααΈ -31 αα -24 αα·αααΈ 24 αα 31 αααααααΆα ααΆα αΆααααΌα ααΆα αααααααΆαααααααΆαααααα»ααααα»αααΆααα·αα·αααααΎαααααααααΆααααΆαααΆαααααα αΌααααα»ααα½αααΆααααΆαααα½ααα αααα»ααα·ααΈααα α αΎααααααΈααΆαα·αααΆαααα α»ααα αααα»ααααααααααΌααααααααα αααα»αααΌαααααΆαα±αααααααααααααααααΆαααααα‘αΎααα·αααΎααααΈα±ααααΆααααα αααΆααααΆααα αααααΉαααααΎα±ααααΈαα·αααΆααααααΆααααα½ααααααΆααα’ααααααααΉαα’αΆα αα·ααααααΆααΌααααα
ααΆααααααΆα N5
ααααΆααααααααα·α αα ααΆααααααααααα A = B; B = A; αα·αα·ααααααααΆααα 1115, 1118. libopenrct2ui MouseInput.cpp 1118
void process_mouse_over(....)
{
....
switch (window->widgets[widgetId].type)
{
case WWT_VIEWPORT:
ebx = 0;
edi = cursorId; // <=
// Window event WE_UNKNOWN_0E was called here,
// but no windows actually implemented a handler and
// it's not known what it was for
cursorId = edi; // <=
if ((ebx & 0xFF) != 0)
{
set_cursor(cursorId);
return;
}
break;
....
}
....
}αααααααΌααααααααααΆααα½αααΆααααααΆααααααα αααααΆαααα ααααα·αα·α αααααααααα·αααααααααα ααα αααααααααΌααα·αααααΎαααΆαααααΌαααΆαααα ααα ααααααΆαααΆααααααα ααααΆαααααα·ααααα·ααΆαααΈαααΈααααα ααα ααααααααΆααααααααααααα·α αααβααβαα·αβααΆαβαααβα αααΎαβαααα
ααΆααααααΆα N6
[CWE-476] ααααα·α 'α’αααααα' ααααΌαααΆαααααΎαααααααΆααα»ααααα·ααΆα αααααΆααααΈααΆααααΌαααΆααααααααααΆαααααααΆααααΉα nullptr α αα·αα·ααααααααΆααα 2085, 2094. libopenrct2 Network.cpp 2094
void Network::ProcessPlayerList()
{
....
auto* player = GetPlayerByID(pendingPlayer.Id);
if (player == nullptr)
{
// Add new player.
player = AddPlayer("", "");
if (player) // <=
{
*player = pendingPlayer;
if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
{
_serverConnection->Player = player;
}
}
newPlayers.push_back(player->Id); // <=
}
....
}αααααΌααααααΆααααα½ααα α’αααααααΆααααααααΌααα·αα·αααααΆααΆααΎαααΈααΈ ααΈα‘αΆαα αα βααααα·α βααα α¬βααααααβααΆβαα βαα½βααβααα ααααΈβαααααααΆαααβααΆαβααααααααα αααα»αααΌαααααΆααααααΎαααΈααΈαα
void Network::ProcessPlayerList()
{
....
auto* player = GetPlayerByID(pendingPlayer.Id);
if (player == nullptr)
{
// Add new player.
player = AddPlayer("", "");
if (player)
{
*player = pendingPlayer;
if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
{
_serverConnection->Player = player;
}
newPlayers.push_back(player->Id);
}
}
....
}ααΆααααααΆα N7
[CWE-570] αααααα 'name == nullptr' ααααααα·ααα·αα libopenrct2 ServerList.cpp 102
std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
auto name = json_object_get(server, "name");
.....
if (name == nullptr || version == nullptr)
{
....
}
else
{
....
entry.name = (name == nullptr ? "" : json_string_value(name));
....
}
....
}α’αααβα’αΆα βαααα αΆααβαααααΆααβααΌαβαααβαα·ααΆαβα’αΆαβαααα»αβαααβαααα½α α αΎαβαααααααΆαβαααα αΆβαααβαα·αα·αααβααΎα nullptr. αααα»αααααΎα±ααααααΆααααααΌααααααΌαααΌα ααΆααααααα
std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
auto name = json_object_get(server, "name");
.....
if (name == nullptr || version == nullptr)
{
name = ""
....
}
else
{
....
entry.name = json_string_value(name);
....
}
....
}ααΆααααααΆα N8
[CWE-1164] α’ααα 'ColumnHeaderPressedCurrentState' ααααΌαααΆαααααααααααααΌα ααααΆα libopenrct2ui CustomListView.cpp 510
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}ααΌαααΎααα α αααααααΆααα ααΆα αΆααααΌα ααΆαααα»αααΆααΆαααΆαααΆααα»ααα αααα»ααααααααα α¬αα ααααααααα’αααα‘αΎααα·α ColumnHeaderPressedCurrentState ααααα αα·ααα·α.
ααα ααααΈααααα·ααααΆα
ααΌα αααααΎαα’αΆα ααΎαααΎα ααΆααα½ααααα αΌαα§ααααααα·ααΆααα·αα·αααα PVS-Studio αα αααα»ααααααα TeamCity ααααα’αααααΊααΆααααααΆααα ααΎααααΈααααΎααΌα αααααΆαααααααααΆααα αΎααααα»αααΆααααααα―αααΆαααααααα ααΆααααααααααΌα αα½αα ααΆααα·αα·αααααΎααααααΌαααΉαα’αα»ααααΆαα±ααα’αααααααααααα αΆααααΆαααααααΆααααΈααΆααα½αααααα»αααααΆαααααΉααα½ααα»αααααΆααααΆαα ααααααααΆααααα»αααααΆααα·ααααααααααΆαααααΆααααααΌααα ααααΆαααααα·αααΆαα
ααααα·αααΎα’αααα
ααα
αααααααα’ααααααααααΆαα½ααααααα·αααααααα·ααΆαααΆααΆα’ααααααα ααΌαααααΎαααααααααα Vladislav Stolyarov α .
ααααα: www.habr.com
