Architektury Usług Internetowych. Laboratorium 5

Podobne dokumenty
Architektury usług internetowych. Laboratorium 5. JADE

Architektury Usług Internetowych. Laboratorium 3. Usługi w środowisku wielo-agentowym

Przetwarzanie Zespołowe

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Kurs WWW. Paweł Rajba.

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Klasy abstrakcyjne i interfejsy

PHP 5 język obiektowy

Enkapsulacja, dziedziczenie, polimorfizm

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Java Agent DEvelopment Framework Systemy Agentowe

Java Agent DEvelopment Framework Systemy Agentowe

Kurs programowania. Wykład 13. Wojciech Macyna. 14 czerwiec 2017

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Programowanie obiektowe

Programowanie obiektowe i zdarzeniowe

Proxy (pełnomocnik) Cel: Zastosowanie: Dostarczyć zamiennik pewnego obiektu, pozwalający kontrolować dostęp do niego.

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Systemy wieloagentowe (MAS) zasady tworzenia systemów wieloagentowych za pomocą technologii MASE i JADEczęść.

Aplikacje Internetowe. Najprostsza aplikacja. Komponenty Javy. Podstawy języka Java

WSNHiD, Programowanie 2 Lab. 2 Język Java struktura programu, dziedziczenie, abstrakcja, polimorfizm, interfejsy

Język JAVA podstawy. Wykład 4, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Java: interfejsy i klasy wewnętrzne

Programowanie w Javie wykład 8 Interfejsy

Instrukcja implementacji sterownika wirtualnego portu szeregowego dla systemu Android. Opracowanie: Elzab Soft sp. z o.o.

Klasy abstrakcyjne, interfejsy i polimorfizm

Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

Aplikacje RMI

Współbieżność w środowisku Java

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Programowanie obiektowe

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Kurs programowania. Wykład 8. Wojciech Macyna

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

Dziedziczenie. Tomasz Borzyszkowski

BEAN VALIDATION. Waldemar Korłub. Narzędzia i aplikacje Java EE KASK ETI Politechnika Gdańska

Programowanie obiektowe

Katalog książek cz. 3: Web Service

Wykład 7: Pakiety i Interfejsy

Systemy operacyjne na platformach mobilnych

JADE - Java Agent DEvelopment Framework

.NET Klasy, obiekty. ciąg dalszy

Programowanie obiektowe

Programowanie obiektowe

Polimorfizm. dr Jarosław Skaruz

Singleton. Cel: Przykład: Zastosowanie: Zapewnienie, że klasa ma tylko jedną instancję i dostarczenie globalnego dostępu do niej.

Dzisiejszy wykład. Wzorce projektowe. Visitor Client-Server Factory Singleton

0.1 Hierarchia klas Diagram Krótkie wyjaśnienie

Tworzenie i wykorzystanie usług

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

Podstawy Programowania Programowanie Obiektowe

Ćwiczenie 1. Kolejki IBM Message Queue (MQ)

Klasy i obiekty cz II

Aplikacje w środowisku Java

Systemy wieloagentowe (MAS) zasady tworzenia systemów wieloagentowych za pomocą technologii MASE i JADEczęść.

Dziedziczenie. dr Jarosław Skaruz

Aplikacje w środowisku Java

Multimedia JAVA. Historia

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Java podstawy jęyka. Wykład 2. Klasy abstrakcyjne, Interfejsy, Klasy wewnętrzne, Anonimowe klasy wewnętrzne.

Kurs programowania. Wykład 8. Wojciech Macyna. 10 maj 2017

akademia androida Service, BroadcastReceiver, ContentProvider część IV

Laboratorium z przedmiotu: Inżynieria Oprogramowania INEK Instrukcja 7

Wykład 6: Dziedziczenie

Programowanie obiektowe

Dokumentacja do API Javy.

Język JAVA podstawy. Wykład 4, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Builder (budowniczy) Cel: Przykład:

Generatory. Michał R. Przybyłek

Automaty do zadań specjalnych. Olga Maciaszek-Sharma, Artur Kotow Wersja 1,

Podstawy programowania III

PHP: bloki kodu, tablice, obiekty i formularze

JADE Java Agent Development Framework. MiASI2, TWO2,

Aplikacje RMI Lab4

Template method (metoda szablonowa)

Programowanie obiektowe

Klasy. dr Anna Łazińska, WMiI UŁ Podstawy języka Java 1 / 13

Laboratorium z przedmiotu: Inżynieria Oprogramowania INEK Instrukcja 6

Programowanie obiektowe

Programowanie obiektowe

TEMAT : KLASY DZIEDZICZENIE

Wykład 2 Wybrane konstrukcje obiektowych języków programowania (1)

Logger. Następnie w klasie Bootstrapper muimy zarejestrować nasz nowy logger:

10. Programowanie obiektowe w PHP5

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Wielowątkowość. Programowanie w środowisku rozproszonym. Wykład 1.

Diagram stanów Laboratorium 9

public - może być używana w kodzie poza klasą, jedna klasa ModyfikatorKlasy może być kombinacją wyrażeń:

Zaawansowane aplikacje WWW - laboratorium

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Obiektowe programowanie rozproszone Java RMI. Krzysztof Banaś Systemy rozproszone 1

SWING c.d. przydatne narzędzia: JFileChooser, JOptionPane. drag'n drop, menu kontekstowe.

Java Zadanie 1. Aby poprawnie uruchomić aplikację desktopową, należy zaimplementować główną metodę zapewniającą punkt wejścia do programu.

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

Język JAVA podstawy. wykład 2, część 2. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

UML a kod. C++, Java i C#

Dawid Gierszewski Adam Hanasko

Zadanie polega na stworzeniu bazy danych w pamięci zapewniającej efektywny dostęp do danych baza osób.

Przykład -

Transkrypt:

Architektury Usług Internetowych Laboratorium 5 Celem zadania jest zapoznanie się mechanizmem definiowania, rejestrowania, wyszukiwania i wywoływania usług w środowisku wieloagentowym. Przy realizacji zadania należy posłużyć się przykładem (Alchemists) zaprezentowanym na wykładzie. Zawartość przykładu Zawartość projektu Alchemists: pl.gda.pg.eti.kask.sa.alchemists.agents paczka zawierający agenty: Alchemist.java agent sprzedający mikstury, Herbalist.java agent sprzedający zioła, Mage.java agent kupujący produkty, BaseAgent.java bazowa klasa dla agentów w projekcie; pl.gda.pg.eti.kask.sa.alchemists.behaviours zachowania agentów: ActionBehaviour.java wykonanie akcji żądanej przez innego agenta i odesłanie wyniku, FindServiceBehaviour.java wyszukanie agentów udostępniających określoną usługę, ReceiveResultBehaviour.java oczekiwanie na wynik akcji żądanej od innego agenta, RegisterServiceBehaviour.java zarejestrowanie usługi w katalogu, RequestActionBehaviour.java żądanie od innego agenta wykonania określonej akcji, WaitingBehaviour.java oczekiwanie na wiadomości nie związanej z żadną aktywną konwersacją, alchemist zachowania alchemika: AlchemistBehaviour.java implementacja WaitingBehaviour, SellPotionBehaviour.java implementacja ActionBehaviour, sprzedaż mikstury; herbalist zachowania zielarza: 2014 Michał Wójcik 1

HerbalistBehaviour.java implementacja WaitingBehaviour, SellHerbBehaviour.java implementacja ActionBehaviour, sprzedaż zioła; mage zachowania maga: MageBehaviour.java oczekiwanie na zakończenie innego zachowania, ReceiveHerbBehaviour.java implementacja ReceiveResultBehaviour, odebranie zioła, ReceivePotionBehaviour.java implementacja ReceiveResultBehaviour, odebranie mikstury, RequestHerbBehaviour.java implementacja RequestActionBehaviour, żądanie zioła, RequestPotionBehaviour.java implementacja RequestActionBehaviour, żądanie mikstury; pl.gda.pg.eti.kask.sa.alchemists.ontology ontologia: AlchemyOntology.java klasa definiująca ontologię, Herb.java koncept opisujący zioło, Potion.java koncept opisujący miksturę, SellHerb.java akcja sprzedaży zioła, SellPotion.java akcja sprzedaży mikstury. Ontologia Ontologia jest zbiorem słownictwa wykorzystywanego w komunikacji pomiędzy agentami. Najprostszym sposobem definiowania ontologii jest dziedziczenie po klasie jade.concept.onto.beanontology a następnie zarejestrowanie wszystkich jej elementów w konstruktorze. @Log public class AlchemyOntology extends BeanOntology { public static final String NAME = "alchemy ontology"; @Getter private static final AlchemyOntology instance = new AlchemyOntology(NAME); private AlchemyOntology(String name) { super(name); add(herb.class); add(potion.class); 2014 Michał Wójcik 2

add(sellherb.class); add(sellpotion.class); catch (BeanOntologyException ex) { log.log(level.severe, null, ex); Na ontologię składają się trzy elementy: koncept opis pewnego bytu, predykat opisuje cechę konceptu, akcja opisuje akcję wykonywaną przez agenta. Wykorzystywany przykład składa się z dwóch konceptów opisujących miksturę i zioło oraz dwóch akcji opisujących sprzedaż bytów opisanych przez te koncepty. Elementy ontologii definiuje się poprzez definicję klas i implementacją odpowiednich interfejsów: Concept, Predicate i AgentAction. Przykład konceptu: @Getter @Setter @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode @ToString public class Herb implements Concept { private String name; Przykład akcji: @Getter @Setter @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode @ToString public class SellHerb implements AgentAction { private Herb herb; 2014 Michał Wójcik 3

Należy pamiętać że każdy z elementów ontologii musi mieć publiczny konstruktor bez parametrów oraz prywatne pola dostępne przez publiczne metody get i set. Bazowe klasy Bazową klasą dla wszystkich agentów w przykładzie jest BaseAgent, zawierający jedynie listę aktywnych konwersacji oraz rejestrację języka SL i odpowiedniej ontologii w metodzie setup. public class BaseAgent extends Agent { @Getter protected final List<String> activeconversationids = new ArrayList<>(); public BaseAgent() { protected void setup() { super.setup(); getcontentmanager().registerlanguage(new SLCodec()); getcontentmanager().registerontology( AlchemyOntology.getInstance()); Globalna lista aktywnych konwersacji ma na celu zapewnienie, że zachowania odbierające wszystkie wiadomości przychodzące do agenta nie odbierą tych będących częścią już wcześniej rozpoczętej konwersacji. Na wiadomości których identyfikator konwersacji znajduje się na liście czekają inne zachowania. Klasa WaitingBehaviour jest abstrakcyjną klasą służącą odbieraniu wiadomości inicjujących konwersację. public void action() { MessageTemplate mt = MessageTemplate.MatchAll(); for (String id : myagent.getactiveconversationids()) { mt = MessageTemplate.and( mt, MessageTemplate.not( MessageTemplate.MatchConversationId(id))); ACLMessage message = myagent.receive(mt); if (message!= null) { ContentElement ce = myagent.getcontentmanager().extractcontent(message); 2014 Michał Wójcik 4

if (ce instanceof Action) { action((action) ce, message.getconversationid(), message.getsender()); catch (Codec.CodecException OntologyException ex) { log.log(level.severe, null, ex); protected abstract void action(action action, String conversationid, AID participant); Powyżej przedstawiono metodę action zachowania, która kolejno: tworzy filtr przyjmujący wszystkie wiadomości, dodaje do filtru ignorowanie wszystkich aktywnych konwersacji, odbiera wiadomość z kolejki, jeśli przyszła jakaś wiadomość to jej zawartość jest rozpakowywana, jeśli zawartością wiadomości był obiekt typu Action to jest on wraz z identyfikatorem konwersacji i identyfikatorem nadawcy przekazywany do abstrakcyjnej metody action. Abstrakcyjna metoda action jest nadpisywana w konkretnych zachowaniach przygotowanych już pod konkretnego agenta. Klasa RequestActionBehaviour jest abstrakcyjną klasą służącą wysłania żądania wykonania jakiejś akcji do agenta. public RequestActionBehaviour(E agent, AID participant, T action) { this.participant = participant; this.action = action; this.myagent = agent; public void action() { Action action = new Action(participant, this.action); String conversationid = UUID.randomUUID().toString(); ACLMessage request = new ACLMessage(ACLMessage.REQUEST); request.setlanguage(new SLCodec().getName()); request.setontology(alchemyontology.getinstance().getname()); request.addreceiver(participant); request.setconversationid(conversationid); myagent.getcontentmanager().fillcontent(request, action); myagent.getactiveconversationids().add(conversationid); myagent.send(request); ReceiveResultBehaviour resultbehaviour = 2014 Michał Wójcik 5

createresultbehaviour(conversationid); if (getparent()!= null && getparent() instanceof SequentialBehaviour) { ((SequentialBehaviour)getParent()).addSubBehaviour( resultbehaviour); else { myagent.addbehaviour(resultbehaviour); catch (Codec.CodecException OntologyException ex) { log.log(level.warning, ex.getmessage(), ex); protected abstract ReceiveResultBehaviour createresultbehaviour( String conversationid); Powyżej przedstawiono metodę action zachowania, która kolejno: tworzy żądanie wykonania akcji zawierające agenta, który ma ją wykonać i opis akcji, generuje identyfikator konwersacji, tworzy wiadomość typu żądanie i ustawia wszystkie wymagane własności, wypełnia wiadomość i dodaje identyfikator konwersacji do globalnej list aktywnych konwersacji, wysyła wiadomość, za pomocą abstrakcyjnej metody createresultbehaviour tworzy zachowanie służące odebraniu wyniku żądanej akcji, zależnie od tego czy aktualne zachowanie wykonuje się jako element jakiegoś złożonego zachowania czy bezpośrednio z poziomu agenta nowe zachowanie jest dodawane albo do rodzica albo bezpośrednio do agenta. Abstrakcyjna metoda createresultbehaviour jest nadpisywana w konkretnych zachowaniach przygotowanych już pod konkretnego agenta. Klasa ReceiveResultBehaviour jest abstrakcyjną klasą służącą odebraniu wyniku żądanej akcji. public ReceiveResultBehaviour(E agent, String conversationid) { super(agent); this.myagent = agent; this.conversationid = conversationid; public void onstart() { super.onstart(); mt = MessageTemplate.MatchConversationId(conversationId); 2014 Michał Wójcik 6

public void action() { ACLMessage msg = myagent.receive(mt); if (msg!= null) { done = true; ContentElement ce = myagent.getcontentmanager().extractcontent(msg); handleresult((predicate) ce, msg.getsender()); catch (Codec.CodecException OntologyException ex) { log.log(level.severe, null, ex); public boolean done() { return done; protected abstract void handleresult(predicate predicate, AID participant); Powyżej przedstawiono metodę action zachowania, która kolejno: odbiera wiadomość należącą do tej konkretnej konwersacji, jeśli przyszła wiadomość to ustawia flagę zakończenia na true, wypakowuje wiadomość i przekazuje jej wynik do abstrakcyjnej metody handleresult. Abstrakcyjna metoda handleresult jest nadpisywana w konkretnych zachowaniach przygotowanych już pod konkretnego agenta. Klasa ActionBehaviour jest abstrakcyjną klasą służącą wykonaniu żądanej akcji przez agenta. public ActionBehaviour(E agent, T action, String conversationid, AID participant) { super(agent); this.myagent = agent; this.action = action; this.conversationid = conversationid; this.participant = participant; public void action() { Predicate result = performaction(); ACLMessage msg; if (result!= null) { msg = new ACLMessage(ACLMessage.INFORM); 2014 Michał Wójcik 7

else { msg = new ACLMessage(ACLMessage.REFUSE); msg.setlanguage(new SLCodec().getName()); msg.setontology(alchemyontology.getinstance().getname()); msg.setconversationid(conversationid); msg.addreceiver(participant); if (result!= null) { myagent.getcontentmanager().fillcontent(msg, result); myagent.send(msg); catch (Codec.CodecException OntologyException ex) { log.log(level.severe, null, ex); protected abstract Predicate performaction(); Powyżej przedstawiono metodę action zachowania, która kolejno: wywołuje abstrakcyjną metodę performaction zwracającą predykat zawierający wynik wykonanej akcji, jeśli nie ma wyniku akcji to tworzy wiadomość odmowy wykonania, w innym przypadku wiadomość informująca o wyniku, ustawia wszystkie wymagane własności wiadomości i wypełnia ją zawartością, wysyła wiadomość. Abstrakcyjna metoda performaction jest nadpisywana w konkretnych zachowaniach przygotowanych już pod konkretnego agenta i pod konkretną akcję. Usługi Zarządzanie katalogiem usług na platformie JADE odbywa się za pośrednictwem agenta DF, który podobnie jak agent AMS jest uruchamiany na głównym kontenerze wraz ze startem platformy. Klasa RegisterServiceBehaviour realizuje pojedyncze zachowanie rejestrujące usługę. public RegisterServiceBehaviour(Agent agent, String servicetype) { super(agent); this.servicetype = servicetype; public void action() { DFAgentDescription dfad = new DFAgentDescription(); 2014 Michał Wójcik 8

dfad.setname(myagent.getaid()); ServiceDescription sd = new ServiceDescription(); sd.settype(servicetype); sd.setname(myagent.getname() + " " + servicetype); dfad.addservices(sd); DFService.register(myAgent, dfad); catch (FIPAException ex) { log.log(level.severe, null, ex); Powyżej przedstawiono metodę action zachowania, która kolejno: tworzy opis agenta, tworzy opis usługi, dodaje opis usługi do opisu agenta, rejestruje opis agenta. Klasa FindServiceBehaviour realizuje pojedyncze zachowanie wyszukujące usługę. public FindServiceBehaviour(Agent agent, String servicetype) { super(agent); this.servicetype = servicetype; public void action() { DFAgentDescription dfad = new DFAgentDescription(); ServiceDescription sd = new ServiceDescription(); sd.settype(servicetype); dfad.addservices(sd); DFAgentDescription[] services = DFService.search( myagent, dfad); onresult(services); catch (FIPAException ex) { log.log(level.severe, null, ex); protected abstract void onresult(dfagentdescription[] services); Powyżej przedstawiono metodę action zachowania, która kolejno: tworzy pusty opis agenta, tworzy opis usługi, dodaje opis usługi do opisu agenta, wyszukuje agentów udostępniających usługę, 2014 Michał Wójcik 9

wywołuje abstrakcyjną metodę onresult. Abstrakcyjna metoda onresult jest nadpisywana w konkretnych zachowaniach przygotowanych już pod konkretnego agenta i pod konkretną usługę. Konkretne zachowania Implementacje zarówno klas agentów jak i klas zachowań dla alchemika i zielarza (Alchemist/Hebalist) są zrobione analogicznie i różnią się jedynie kontekstem (mikstury, zioła). Każdy z nich dziedziczy bo bazowej klasie BaseAgent i zawiera globalną listę rzeczy, które może sprzedawać. public class Alchemist extends BaseAgent { @Getter private final List<Potion> potions = new ArrayList<>(); public Alchemist() { protected void setup() { super.setup(); potions.add(new Potion("Shrouding Potion")); potions.add(new Potion("Heroic Potion")); addbehaviour(new RegisterServiceBehaviour(this, "alchemist")); addbehaviour(new AlchemistBehaviour(this)); Agent po uruchomieniu wypełnia swoją listę, rejestruje swoją usługę sprzedaży oraz uruchamia zachowanie odbierające wiadomości inicjujące konwersacje. Zachowania AlchemistBehaviour i HerbalistBehaviour dziedziczą po WaitingBehaviour i implementują jedynie metodę action odpowiedzialną za wykonanie żądanej akcji. public class AlchemistBehaviour extends WaitingBehaviour<Alchemist>{ public AlchemistBehaviour(Alchemist agent) { super(agent); protected void action(action action, String conversationid, AID participant) { if (action.getaction() instanceof SellPotion) { myagent.addbehaviour(new SellPotionBehaviour(myAgent, (SellPotion) action.getaction(), 2014 Michał Wójcik 10

conversationid, participant)); Zarówno alchemik jak i zielarz obsługują jedynie akcję sprzedaży (SellPotion/SellHerb). W przypadku gdy wiadomość inicjująca zawiera obsługiwane żądanie do agenta dodawane jest zachowania realizacji akcji (SellPotionBehaviour/SellHerbBehaviour). Klasy SellPotionBehaviour i SellHerbBehaviour dziedziczą po klasie bazowej ActionBehaviour i implementują jedynie metodę performaction. public class SellHerbBehaviour extends ActionBehaviour<SellHerb, Herbalist> { public SellHerbBehaviour(Herbalist agent, SellHerb action, String conversationid, AID participant) { super(agent, action, conversationid, participant); protected Predicate performaction() { if (myagent.getherbs().contains(action.getherb())) { return new Result(action, action.getherb()); else { return null; Ostatnim agentem jest mag (Mage) szukający odpowiednich ziół i mikstur. public class Mage extends BaseAgent { public Mage() { protected void setup() { super.setup(); SequentialBehaviour behaviour = new SequentialBehaviour(this); behaviour.addsubbehaviour(...); behaviour.addsubbehaviour(...); addbehaviour(behaviour); addbehaviour(new MageBehaviour(behaviour, this)); 2014 Michał Wójcik 11

Podczas uruchomienia agent tworzy dwa zachowania. Pierwszym jest zachowanie sekwencyjne, które będzie miało na celu znalezienie i kupienie wszystkich wymaganych elementów. Drugim jest zachowanie sprawdzające czy poprzednie zostało już wykonane. Na początku sekwencyjne zachowanie składa się z dwóch pod zachowań szukających usługi alchemika i zielarza. behaviour.addsubbehaviour( new FindServiceBehaviour(this, "alchemist") { protected void onresult(dfagentdescription[] services) { if (services!= null && services.length > 0) { AID alchemist = services[0].getname(); SellPotion action = new SellPotion(new Potion("Heroic Potion")); RequestPotionBehaviour request = new RequestPotionBehaviour(Mage.this, alchemist, action); ((SequentialBehaviour) getparent()).addsubbehaviour(request); ); Wyszukiwanie zostało dodane jako klasa anonimowa z nadpisaną metodą onresult, która jeśli zostanie znaleziona usługa dodaje zachowanie wysłania żądania wykonania akcji sprzedaży. Zadania Zadania do wykonania: uruchomienie przykładu, modyfikacja kodu alchemika i zielarza tak aby lista mikstur/ziół które posiada były przekazywane jako argumenty startowe agenta a nie na sztywno ustawione w kodzie, modyfikacja kodu maga tak aby mógł szukać listy różnych ziół i mikstur podawanych jako argumenty startowe agenta, stworzenie nowego sprzedawcy (odpowiednie elementy ontologii, zachowanie sprzedaży, zachowanie odbierania wiadomości, agent) podanego przez prowadzącego, dodanie zachowań pozwalających kupowanie magowi od nowego sprzedawcy. 2014 Michał Wójcik 12

Uwagi Kod może być pomocny w realizacji dalszych zadań laboratoryjnych. 2014 Michał Wójcik 13