1c subskrypcja wydarzenia jest wyłącznie interaktywna. Korzystanie z subskrypcji wydarzeń w celu dostosowania przepływu dokumentów „z zewnątrz”. Instrukcja korzystania z programu Event Study

💖 Podoba Ci się? Udostępnij link swoim znajomym

Podczas tworzenia lub modyfikowania rozwiązań aplikacyjnych na platformie 1C:Enterprise 8.x bardzo często konieczne jest wykonanie standardowej akcji dla grupy obiektów konfiguracyjnych (na przykład katalogów). Aby nie opisywać akcji wykonywanych w module każdego obiektu, programista może skorzystać ze standardowego mechanizmu platformy – subskrypcji zdarzeń.

Subskrypcje zdarzeń umożliwiają przechwytywanie zdarzeń obiektów konfiguracyjnych, takich jak katalogi, dokumenty, plany charakterystycznych typów i inne. Dzisiaj w artykule rozważymy kwestię kolejności wykonywania procedur obsługi subskrypcji zdarzeń, a także przeanalizujemy zachowanie platformy z kilkoma subskrypcjami zdarzeń dla jednej akcji (na przykład podczas nagrywania).

Standardowe zachowanie

Niech nasz przykład użyje określonego katalogu „SimpleDirectory”. Zawiera subskrypcje zdarzeń utworzone dla każdego zdarzenia, w którym programista może interweniować. Procedury obsługi zdarzeń znajdują się w odpowiednim wspólnym module serwera.

Kolejność wywoływania procedur obsługi subskrypcji jest taka sama jak w standardowym zachowaniu platformy podczas pracy z tym obiektem. Ponieważ w naszym przykładzie rozważamy pracę z katalogiem, proponuję rozważyć schemat wywoływania procedur obsługi w zależności od akcji z obiektem (patrz następny zrzut ekranu).

Jak widzimy, na początkowym etapie wywoływane są procedury obsługi zdarzeń „ProcessingFill” (aby utworzyć nowy element) lub „On Copying” (aby utworzyć element na podstawie już istniejącego). W obu przypadkach po wywołaniu nazwanych handlerów wykonywana jest procedura „OnInstallNewCode”, w której programista może ustawić prefiks w kodzie lub przesłonić zachowanie platformy przy nadawaniu nowego kodu.

Podczas zapisywania elementu katalogu, czy to nowego, czy już istniejącego, wywoływane są trzy handlery: „ProcessingFillCheck” (na tym etapie handler może sprawdzić poprawność wprowadzonych danych i w przypadku błędów odmówić zapisu), „BeforeWrite” (do czasu zapisania obiektu do bazy, możesz dostosować wartości szczegółów i sprawdzić dodatkowe warunki) a następnie „OnRecord” (do bazy został wprowadzony zapis, ale transakcja nie jest zamknięta , deweloper może sprawdzić dane po zapisie i w razie potrzeby anulować transakcję).

Zdarzenie „BeforeDelete” występuje tylko wtedy, gdy obiekt zostanie bezpośrednio usunięty z bazy danych. Zazwyczaj żaden użytkownik nie ma uprawnień do bezpośredniego usuwania bez sprawdzenia integralności referencyjnej. Usuwanie należy zawsze przeprowadzać przy pomocy operacji „Usuwanie zaznaczonych obiektów”. W tym drugim przypadku wywoływana jest także procedura obsługi „BeforeDelete”.

Zatem jeśli utworzymy element katalogu i zapiszemy go w bazie danych, platforma wywoła następujące procedury obsługi zdarzeń w określonej kolejności:

W przypadku pozostałych obiektów konfiguracyjnych działanie mechanizmu subskrypcji zdarzeń będzie podobne, różnią się jedynie zdarzenia i ich kolejność. Więcej szczegółów znajdziesz w pomocniku składni.

Strona nieudokumentowana

Przyjrzyjmy się teraz interesującej sytuacji. Załóżmy, że dla naszego katalogu „SimpleDirectory” zdefiniowano trzy subskrypcje zdarzenia „BeforeRecord”:

Jak myślisz, w jakiej kolejności będą wywoływane procedury obsługi tych subskrypcji? Nie zgadujmy. Podam wynik nagrania elementu, w którym handler dla każdej subskrypcji wyświetla komunikat z nazwą wywoływanej subskrypcji (patrz poniższy zrzut ekranu).

Ze zrzutu ekranu nietrudno się domyślić, że kolejność wywoływania procedur obsługi subskrypcji zdarzeń odpowiada kolejności obiektów metadanych w gałęzi „Subskrypcje zdarzeń”. Ta funkcja nie jest opisana w żadnej literaturze referencyjnej na platformie 1C:Enterprise, dlatego należy zachować ostrożność podczas używania jej w konfiguracji, ponieważ nieudokumentowane funkcje mogą zmieniać się z wersji na wersję 1C:Enterprise i jednocześnie być nieobecne w lista zmian w programie.

Wycofać się

Możesz zapytać: „Po co tworzyć wiele subskrypcji dla jednego zdarzenia obiektu konfiguracyjnego?” Odpowiedź jest prosta. Jeśli w rozwój zaangażowanych jest kilka osób, to wzajemna ingerencja w stworzone przez siebie mechanizmy może doprowadzić do nieprawidłowego działania programu. W takich przypadkach najbardziej logicznym rozwiązaniem byłoby utworzenie oddzielnych subskrypcji wydarzeń dla każdego programisty, zgodnie z bieżącym zadaniem. Oczywiście możliwe jest, że w przyszłości zostaną one połączone w jedną procedurę obsługi.

Ten artykuł jest zapowiedzią nowej funkcjonalności.
Nie zaleca się wykorzystywania treści tego artykułu do poznawania nowych funkcjonalności.
Pełny opis nowej funkcjonalności zostanie podany w dokumentacji odpowiedniej wersji.
Pełna lista zmian w nowej wersji znajduje się w pliku v8Update.htm.

Zaimplementowano w wersji EDT 1.7.0.567.

W 1C:Enterprise Development Tools (EDT) wdrożyliśmy prototyp nowego narzędzia. Robocza nazwa tego narzędzia to edytor Wszystkie subskrypcje wydarzeń. Pomoże Ci to w wygodny sposób analizować subskrypcje wszystkich wydarzeń istniejących w rozwiązaniu aplikacyjnym.

Subskrypcje wydarzeń

Platforma 1C:Enterprise umożliwia tworzenie subskrypcji zdarzeń obiektów konfiguracyjnych w rozwiązaniu aplikacyjnym. Subskrypcja to procedura, która zostanie wykonana po wykonaniu oryginalnej procedury obsługi zdarzenia. Wygoda subskrypcji polega na tym, że jedną procedurę można „zasubskrybować” na zdarzenie należące do różnych obiektów konfiguracyjnych. Zatem jeśli istnieje algorytm, który trzeba wykonać zarówno podczas rejestracji organizacji, jak i działu, można go umieścić w abonamencie i wtedy nie będzie trzeba nawet zmieniać obsługi tego zdarzenia w samych obiektach.

Okazuje się, że subskrypcja to wygodny i uniwersalny mechanizm. Jednak w dużych rozwiązaniach aplikacyjnych liczba subskrypcji wydarzeń może sięgać kilkuset. Niewygodne staje się analizowanie ich w drzewie konfiguracyjnym, na liście liniowej. Na przykład w rozwiązaniu aplikacyjnym 1C:Zarządzanie przedsiębiorstwem (ERP) ponad 340 subskrypcji wydarzeń.

EDT nieco ułatwia pracę z subskrypcjami, pokazując je w panelu Schemat, gdy zostanie otwarty moduł obiektu aplikacji.


Takie wyświetlanie subskrypcji jest wygodne przy szeregu zadań związanych z edycją modułu. Ale nadal nie jest to odpowiednie, gdy trzeba szybko znaleźć i przeanalizować wszystkie algorytmy, które są wykonywane w subskrypcjach, gdy wystąpi określone zdarzenie.

Wszystkie subskrypcje wydarzeń

Aby pozbyć się powyższych niedogodności, wdrożyliśmy uniwersalny sposób reprezentacji subskrypcji, zdarzeń, obiektów konfiguracyjnych i procedur, w których implementowane są algorytmy subskrypcji.


W rezultacie możesz zadzwonić do redaktora Wszystkie subskrypcje wydarzeń dla całej konfiguracji, czy tylko dla jednego obiektu - różnica będzie jedynie w składzie danych, w jakiś sposób przefiltrowanych.


Po lewej stronie edytor pokazuje wszystkie wydarzenia, a w każdym zdarzeniu wszystkie jego subskrypcje. Gdy wybierzesz konkretną subskrypcję, w prawym górnym rogu wyświetlona zostanie lista obiektów konfiguracyjnych, na których zdarzenia subskrypcja jest „subskrybowana”. Natomiast moduł i procedura, w której znajduje się algorytm subskrypcji, pokazano w prawym dolnym rogu. Klikając dwukrotnie procedurę, można ją otworzyć we wbudowanym edytorze języków.

Będąc w edytorze możesz analizować nie tylko pojedyncze subskrypcje, ale także wszystkie subskrypcje powiązane z jednym wydarzeniem. Jeśli wybierzesz zdarzenie, edytor pokaże wszystkie moduły i wszystkie procedury podpisane w celu przetworzenia tego zdarzenia.


Jeśli wywołasz edytor obiektu konfiguracyjnego, zostaną pokazane tylko zdarzenia i subskrypcje tego obiektu, a sam obiekt będzie zawsze podświetlony na czerwono na liście źródłowej. W ten sposób możesz szybko sprawdzić np. czy wybrana subskrypcja działa dla wszystkich obiektów konfiguracyjnych, dla których jest potrzebna.


Wywołanie edytora za pomocą polecenia kontekstowego (na obiekcie konfiguracyjnym) pozwala na natychmiastowe zmniejszenie liczby subskrypcji wyświetlanych w edytorze. Przykładowo możesz przeglądać subskrypcje tylko dla tych zdarzeń, które są przetwarzane w module obiektowym lub w module menadżerskim.


Ponadto edytor zawiera uniwersalny filtr, dzięki któremu możesz w dowolny sposób dostosować skład obiektów, zdarzeń i procedur.


Pamiętaj, że za pomocą tego filtra możesz zaznaczyć nie tylko konkretne obiekty będące źródłem zdarzeń, ale także zestawy typów np Obiekt katalogu, Obiekt dokumentu i inni. Takie zestawy typów obejmują wszystkie katalogi lub wszystkie dokumenty znajdujące się w konfiguracji.

Wyszukując po ciągu, szybko znajdziesz tylko te subskrypcje, które dotyczą interesującego Cię mechanizmu.


W każdej chwili możesz szybko przefiltrować treść po pokazanym w edytorze wydarzeniu lub źródle. Na przykład znalazłeś subskrypcję Sprawdź wzór obliczeniowy. Jego źródłem jest plan typów obliczeń Trzyma.


Używając polecenia kontekstowego w planie typów obliczeń, możesz szybko zobaczyć tylko te subskrypcje, które są powiązane z jego zdarzeniami.


Automatyczne dodawanie punktów przerwania

Jednym z typowych sposobów analizowania subskrypcji zdarzeń jest sekwencyjne przeglądanie wszystkich wywoływanych procedur w debugerze w kolejności, w jakiej zostały wykonane. W tym celu edytor udostępnia wygodne narzędzie do automatycznego dodawania punktów przerwania do procedur obsługi.

Przede wszystkim możesz wywołać to narzędzie bezpośrednio w edytorze.


Możesz znaleźć i wybrać interesujący Cię obiekt, wybrać jedno z jego zdarzeń oraz zaznaczyć np. wszystkie procedury obsługi. Po kliknięciu OK punkty przerwania zostaną dodane do pierwszej linii wykonywalnej każdego sprawdzanego modułu obsługi, a wszystkie te punkty przerwania pojawią się w panelu Punkty przerwania w perspektywie Debugowanie.


Inny sposób dodania punktów przerwania jest wygodny, gdy już znalazłeś w edytorze interesujący Cię obiekt lub wydarzenie. W takim przypadku możesz wywołać odpowiednie polecenie z menu kontekstowego.


I wreszcie trzeci sposób, którego możesz użyć, to automatyczne dodawanie punktów przerwania podczas debugowania. W tym przypadku nie trzeba otwierać edytora, ponieważ polecenie dodawania znajduje się bezpośrednio w panelu Punkty przerwania.


A więc redaktor Wszystkie subskrypcje wydarzeń to uniwersalne narzędzie, które pozwala na wykorzystanie różnorodnych scenariuszy analiz. Przyda się nie tylko programistom, którzy dobrze znają rozwiązanie aplikacyjne, ale także specjalistom wdrożeniowym czy specjalistom IT, którzy muszą zrozumieć nieznaną funkcjonalność.

W trakcie rozwiązywania różnych problemów użytkowników czasami konieczne staje się poddanie już wygenerowanych ruchów dokumentów (czyli pewnych zestawów rejestrów) pewnego rodzaju dostosowaniu.

Do tych celów doskonale nadaje się obiekt „Subskrypcja zdarzeń”, który pozwala na wykonanie pewnych działań w przypadku wystąpienia określonego zdarzenia dla dużej liczby obiektów (na przykład podczas rejestrowania dokumentów płatniczych lub podczas ustawiania nowego numeru dla katalogów związanych z podatkami) księgowość).

Również subskrypcja wydarzenia jest wygodna, ponieważ pozwala na wykonanie różnych akcji bez zmiany standardowych mechanizmów opisanych w poszczególnych modułach.

Na przykład powstało zadanie - konieczne jest zapisanie pewnych danych (informacji o działalności firmy) w dokumentach płatniczych po utworzeniu głównych ruchów dokumentu (wygenerowanych w zdarzeniu „Przetwarzanie Przetwarzanie”). Zadanie zrealizujemy z wykorzystaniem konfiguracji „Manufacturing Enterprise Management”, wyd. 1.3.

Przyjrzyjmy się rozwiązaniu bardziej szczegółowo:

Utwórzmy nową subskrypcję na wydarzenie „Zapisz wskazówki do płatności”. Subskrypcja ma wiele właściwości, które determinują jej zachowanie:

Źródło- jest to obiekt (np. dokument lub lista dokumentów), dla którego zostaną wywołane akcje. W naszym przypadku wybierzemy Zlecenie płatnicze wychodzące i Zlecenie płatnicze przychodzące

Wydarzenia- sama akcja, po której nasz kod zostanie wykonany. Zgodnie z warunkami problemu, wybieramy PrzetwarzaniePrzewodnictwo

Treser- wskazanie trybu, w jakim będzie odbywać się przetwarzanie. Wybierzmy do tych celów moduł ogólny Ogólny cel.

Po spełnieniu powyższych celów tworzona jest procedura, w której konieczne jest umieszczenie kodu w celu uzupełnienia danych kierunkowych (zakładając, że taka informacja jest już zawarta w płatnościach).

Spójrzmy na jego parametry:

Źródło- ten obiekt typu DirectoryObject lub DocumentObject, dla którego następuje akcja.

Odmowa- parametr pozwalający pod pewnymi warunkami anulować zaksięgowanie dokumentu.

Tryb- opcje implementacji (operacyjne lub nieoperacyjne), umożliwiające budowanie algorytmów przetwarzania na różne sposoby.

Skupmy się na parametrze Źródło. Dla naszego zadania typem tego parametru będzie - Obiekt dokumentu. Dla tego typu dostępna jest kolekcja Ruchy, który zawiera wszystkie zbiory zapisów rejestrowych, dla których dokument ten jest rejestratorem.

Zbiór ten zawiera zestaw rekordów Rozliczenia z Kontrahentami, co nas interesuje. Załóżmy, że w rejestrze został utworzony wymiar Kierunek, który musimy wypełnić z dokumentu.

Napiszmy następujący kod:

Zestawy = źródło. ruchy; Obliczenia = zestawy. Rozliczenia z kontrahentami; Dla każdej strony cyklu obliczeń. Kierunek = Źródło. Kierunek; KoniecJeśli ;

Jak widać, implementacja jest dość prosta; po przetworzeniu nie ma potrzeby podejmowania dodatkowych działań w celu zapisania zestawu - subskrypcja zdarzenia odbywa się w ramach transakcji zdarzenia ProcessingProcessing, po jej zakończeniu zestaw zostanie zapisany automatycznie .

Zalety tego podejścia: przetwarzanie danych poza standardowymi algorytmami, zmniejszenie nakładu pracy związanej z wyszukiwaniem i przenoszeniem zmian przy aktualizacji, większa widoczność – cały kod w jednej procedurze.

Wada tego podejścia: zwiększenie czasu poświęconego na prowadzenie dokumentów i ewidencjonowanie elementów spisów.

Mam nadzieję, że informacje te przydadzą się zarówno początkującym programistom, jak i ich bardziej doświadczonym kolegom, jako sposób na poszerzenie swoich horyzontów.

Gdy użytkownik wykonuje jakiekolwiek czynności, platforma 1C generuje zdarzenia programowe. Z reguły nie jest generowane jedno zdarzenie, ale cały łańcuch zdarzeń. Zadaniem programisty jest prawidłowe umieszczenie kodu programu w zdarzeniach, tak aby uzyskać oczekiwane zachowanie programu. Jednak dla początkującego programisty 1C nie będzie to łatwe z powodów wymienionych poniżej.

Zdarzenia mogą być generowane w kontrolowanej formie: On ReadingOnServer, OnCreatingOnServer, OnOpening itp.

Zdarzenia w kontrolowanej formie generowane są na kliencie i na serwerze: BeforeRecord, BeforeRecordOnServer.

Zdarzenia wywoływane są w różnych modułach: ElementForm, ObjectModule, ManagerModule.

Niektóre zdarzenia można wywoływać wielokrotnie, jeśli na liście znajduje się kilka elementów katalogu, na przykład: ReceivingViewProcessing.

Zarządzany formularz może zostać otwarty w wyniku różnych działań użytkownika, a łańcuchy wywołań zdarzeń będą się różnić. Każda z poniższych akcji użytkownika na katalogu spowoduje otwarcie kontrolowanego formularza: utworzenie nowego elementu, skopiowanie elementu, zmiana istniejącego elementu katalogu.

Zdarzenia generowane są także przez elementy formularza: podczas dodawania wiersza do części tabelarycznej, podczas edycji wiersza w części tabelarycznej, podczas aktywacji wiersza lub pola, podczas wybierania elementu przeglądania w polu wejściowym itp.

Aby lepiej zrozumieć logikę i sekwencję wyzwalanych zdarzeń, możesz skorzystać z opracowania „Studium zdarzeń” dołączonego do tego artykułu. Znając kontekst wywołania zdarzenia, sekwencję zdarzeń i akcje, które wykona użytkownik, łatwiej będzie zrozumieć, w którym procedurze obsługi zdarzeń najlepiej umieścić swój kod programu.

Instrukcja korzystania z programu Event Study

Program badania zdarzeń pokazuje zdarzenia generowane przez platformę 1C podczas interaktywnych działań użytkownika. Zasada działania jest następująca: użytkownik otwiera katalog, program pokazuje ciąg zdarzeń. Użytkownik zaznacza element katalogu do usunięcia, a program wyświetla sekwencję zachodzących zdarzeń. Zdarzenia domyślnie wyświetlane są z niewielkim opóźnieniem wynoszącym 3 sekundy, jest to konieczne, aby oddzielić jeden łańcuch zdarzeń od drugiego. Dlatego musisz wykonywać interaktywne działania „na luzie”.

Wszystkie wydarzenia wyświetlane są w specjalnym oknie „Najnowsze wydarzenia”. Tutaj możesz włączyć lub wyłączyć nagrywanie zdarzeń. Domyślnie nagrywanie zdarzeń jest włączone przy pierwszym otwarciu. Polecam przypiąć okno „Najnowsze wydarzenia” na dole ekranu od razu po uruchomieniu programu, aby ułatwić przeglądanie wydarzeń.

Sam program nie jest w stanie określić, jakie działanie spowodowało ciąg zdarzeń; radzę wpisać w polu „Przyczyna działania” nazwy ostatnich działań, na przykład „Formularz listy katalogów jest otwarty”, „Element w katalogu”. lista jest oznaczona do usunięcia” itp. Ułatwi to wówczas analizę działań i zdarzeń.

Zdarzenia są rejestrowane i wyświetlane dla obiektów umieszczonych w sekcji Śledzenie zdarzeń, jeśli w formularzu Ostatnie zdarzenia włączono rejestrację zdarzeń.

Wszystkie zarejestrowane zdarzenia można przeglądać poprzez „Raport zdarzeń”, który znajduje się w sekcji „Serwis”.

Aby szybko wyczyścić wszystkie zapisane akcje i zdarzenia, w sekcji „Serwis” wybierz „Wyczyść zdarzenia i akcje”.

Podczas pracy z bazą informacji 1C często konieczne staje się powiązanie nowego algorytmu ze zdarzeniem związanym ze zmianą obiektu. W wersji 7 programu, aby uruchomić handler konieczne było przepisanie kodu źródłowego programu, co powodowało problemy przy aktualizacji konfiguracji.

Po przeanalizowaniu opinii użytkowników ośmiu programistów wdrożyło nowy obiekt o nazwie „Subskrypcja zdarzeń”. W tym artykule postaramy się ujawnić:

  • Konfigurowanie subskrypcji;
  • Kreacja;
  • Cechy funkcjonowania.

Utwórz nową subskrypcję

Jak każdy inny obiekt metadanych, z konfiguratora dodawana jest subskrypcja wydarzenia w 1C.

Elementy te znajdują się w gałęzi drzewa „Ogólne” (rys. 1).

Aby dodać nowego handlera musisz:


Ryc.3

Aby uniknąć problemów z aktualizacją, do własnych rozbudów najlepiej jest stworzyć własny wspólny moduł, który będzie zawierał tylko Twoje procedury i funkcje.

Funkcje funkcjonowania subskrypcji

Jednym z głównych pytań, jakie pojawia się u użytkowników rozpoczynających pracę z obiektem „Subskrypcja zdarzeń”, jest kwestia kolejności wywoływania procedur. Często w tym miejscu leżą błędy, ponieważ procedura nie działa lub działa tylko od czasu do czasu.

Na przykładzie procedury AtWrite() dla dowolnego dokumentu można zobaczyć kolejność wywoływania procedur obsługi.

Jeśli więc w module obiektu dokumentu taka procedura istnieje i równolegle z nią następuje przetwarzanie wywołane z subskrypcji i przetwarzanie tego samego zdarzenia, to w pierwszej kolejności zostanie przetworzony moduł dokumentu. Jeśli podczas wykonywania AtRecord() w module dokumentu parametr Rejection z jakiegoś powodu przyjmie wartość True, subskrypcja nie będzie działać.

W przypadku, gdy istnieje kilka obiektów subskrypcji, które są takie same dla jednego źródła i jednego zdarzenia, bardzo trudno jest prześledzić kolejność realizacji. A jeśli podczas wykonywania co najmniej jednej procedury obsługi zostanie zgłoszony wyjątek, niektóre procedury pozostaną niezrealizowane.

Zatem kolejność przetwarzania można określić w następujący sposób:

  1. Przetwarzane są zdarzenia modułu obiektu;
  2. Przetwarzane są subskrypcje powiązane bezpośrednio z bieżącym typem danych;
  3. Kod powiązany z typem ogólnym jest przetwarzany.

Bardzo ważne jest, aby pamiętać, że w żadnym wypadku nie należy wstawiać do procedur wykonywanych podczas nagrywania kodu zmieniającego dane obiektu źródłowego, gdyż może to doprowadzić do niepotrzebnego zapętlenia. Lepiej jest użyć takiego kodu w procedurach BeforeWrite.

Otwórz formularz obsługi zdarzeń

Rosnąca popularność formularzy zarządzanych zastosowanych w wersji 8 programu, a także problemy związane z aktualizacją tych obiektów przy zapisywaniu własnych zmian, spowodowały, że począwszy od platformy 8.2.15 w programie pojawiło się zdarzenie FormReceivingProcessing. Tutaj możesz wstawić kod, który zmienia i zastępuje standardowe formularze.

Niektóre funkcje tego modułu obsługi:

  • Zdarzenie nie zostanie uruchomione, jeśli w konfiguracji ściśle określono standardowy formularz do otwarcia;
  • Zdarzenie można wdrożyć tylko w przypadku formularzy zarządzanych;
  • Moduł ogólny zawierający tę procedurę obsługi musi nie tylko posiadać atrybut „Serwer”, ale także zawierać zaznaczone pole wyboru w polu „Wywołaj serwer”.

Należy wziąć pod uwagę, że ta subskrypcja jest wywoływana nie dla konkretnego obiektu, ale dla jego menedżera, to znaczy pole źródłowe musi zawierać to słowo (ryc. 4)

Ryc.4

Podsumowując powyższe, chciałbym powiedzieć, że „Subskrypcja zdarzeń” jest niezwykle przydatnym i niezbędnym narzędziem dla programisty, które pozwala programiście osiągnąć własne cele i zadania bez większej ingerencji w konfigurację.

Powiedz przyjaciołom