├── .gitignore ├── LICENSE ├── README.md ├── docs ├── Makefile ├── _static │ ├── UFC_logo.png │ ├── grei.png │ └── pade_logo.png ├── _templates │ ├── sidebarintro.html │ └── sidebarlogo.html ├── _themes │ ├── .gitignore │ ├── LICENSE │ ├── README.rst │ ├── flask_theme_support.py │ ├── kr │ │ ├── layout.html │ │ ├── relations.html │ │ ├── static │ │ │ └── flasky.css_t │ │ └── theme.conf │ └── kr_small │ │ ├── layout.html │ │ ├── static │ │ └── flasky.css_t │ │ └── theme.conf ├── api.rst ├── conf.py ├── flaskstyle.sty ├── img │ ├── InterfaceSniffer.png │ ├── contract_net │ │ ├── ACLMessage_795.png │ │ ├── ACLMessage_795.xcf │ │ ├── ACLMessage_796.png │ │ ├── ACLMessage_797.png │ │ ├── ACLMessage_todas.png │ │ └── InterfacedeGerenciamentodosAgentes_794.png │ ├── janela_agentes.png │ ├── janela_mensagem.png │ ├── pade_logo.svg │ ├── seq_diag_contract.diag │ ├── seq_diag_contract.png │ ├── seq_diag_request.diag │ ├── seq_diag_request.png │ ├── seq_diag_subscribe.diag │ └── seq_diag_subscribe.png ├── index.rst ├── logo.pdf └── user │ ├── agentes-temporais.rst │ ├── enviando-mensagens.rst │ ├── enviando-objetos.rst │ ├── hello-world.rst │ ├── index.html │ ├── instalacao.rst │ ├── interface-grafica.rst │ ├── meu-primeiro-agente.rst │ ├── protocolos.rst │ ├── recebendo-mensagens.rst │ ├── selecao-de-mensagens.rst │ └── um-momento.rst ├── examples ├── agente_teste_1.py ├── agente_teste_2.py ├── agente_teste_3.py ├── agente_teste_4.py ├── agente_teste_5.py ├── database.db └── start_ams.py ├── pade ├── __init__.py ├── acl │ ├── __init__.py │ ├── aid.py │ ├── filters.py │ └── messages.py ├── behaviours │ ├── __init__.py │ └── protocols.py ├── core │ ├── __init__.py │ ├── agent.py │ ├── ams.py │ └── peer.py ├── database.db ├── db │ └── __init__.py ├── gui │ ├── __init__.py │ ├── img │ │ └── preferencias.png │ └── interface.py ├── images │ ├── interface.png │ └── pade_logo.png ├── misc │ ├── __init__.py │ ├── common.py │ └── utility.py ├── tests │ └── v1 │ │ ├── script_2.py │ │ ├── script_2_revisado.py │ │ ├── script_2_revisado_local.py │ │ ├── script_2_revisado_local_2.py │ │ ├── script_2_revisado_raspberry.py │ │ ├── script_3.py │ │ ├── script_4.py │ │ ├── script_5.py │ │ ├── server_client.py │ │ ├── test_agent.py │ │ ├── test_command_line.py │ │ └── teste.py └── web │ ├── __init__.py │ ├── data.sqlite │ ├── flask_server.py │ ├── static │ ├── __init__.py │ ├── raphael-min.js │ ├── sequence-diagram-min.js │ └── underscore-min.js │ └── templates │ ├── __init__.py │ ├── agentes.html │ ├── diagrams.html │ ├── footer.html │ ├── header.html │ ├── index.html │ ├── message.html │ └── messages.html └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository isn't more the PADE offcial repository. The new PADE repository has been changed to: [new PADE repository](https://github.com/grei-ufc/pade). 2 | ----- 3 | 4 | Python Agent DEvelopment framework (PADE) 5 | ====== 6 | 7 | [![Join the chat at https://gitter.im/lucassm/Pade](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/lucassm/Pade?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 8 | 9 | ![Logo padrão do projeto PADE] (https://raw.githubusercontent.com/lucassm/Pade/master/pade/images/pade_logo.png) 10 | 11 | PADE é um framework para desenvolvimento, execução e gerenciamento de sistemas multiagentes em ambientes de computação distribuída. PADE é escrito 100% em Python e utiliza as bibliotecas do projeto Twisted para implementar a comunicação entre os nós da rede. 12 | PADE é software livre, licenciado sob os termos da licença MIT, desenvolvido no ambito da Universidade Federal do Ceará pelo Grupo de Redes Elétricas Inteligentes (GREI) que pertence ao departamento de Engenharia Elétrica. 13 | Qualquer um que queira contribuir com o projeto é convidado a baixar, executar, testar e enviar feedback a respeito das impressões tiradas da plataforma. 14 | 15 | Dependências 16 | ----- 17 | 18 | PADE é desenvolvido com [Python 2.7](https://www.python.org/) no topo do framework [Twisted](https://twistedmatrix.com/trac/) que é sua principal dependência. 19 | 20 | Instalação 21 | ------ 22 | 23 | Para baixar e instalar o PADE, basta abrir uma seção do terminal de comandos Linux e digitar os seguintes comandos: 24 | 25 | $ git clone https://github.com/lucassm/PADE 26 | $ cd PADE 27 | $ sudo python setup.py install 28 | 29 | Pronto! Você já está pronto para utilizar o PADE! 30 | 31 | Exemplo 32 | ------ 33 | 34 | Um simples agente desenvolvido com as bibliotecas do PADE: 35 | 36 | ```python 37 | from pade.misc.utility import display_message 38 | from pade.misc.common import set_ams, start_loop 39 | from pade.core.agent import Agent 40 | from pade.acl.aid import AID 41 | 42 | 43 | class AgenteHelloWorld(Agent): 44 | def __init__(self, aid): 45 | super(AgenteHelloWorld, self).__init__(aid=aid, debug=False) 46 | display_message(self.aid.localname, 'Hello World!') 47 | 48 | if __name__ == '__main__': 49 | 50 | set_ams('localhost', 8000, debug=False) 51 | 52 | agents = list() 53 | 54 | agente_hello = AgenteHelloWorld(AID(name='agente_hello')) 55 | agente_hello.ams = {'name': 'localhost', 'port': 8000} 56 | agents.append(agente_hello) 57 | 58 | start_loop(agents, gui=True) 59 | ``` 60 | 61 | Funcionalidades 62 | ------ 63 | 64 | Pade possui as seguintes funcionalidades: 65 | 66 | * Bibliotecas para desenvolver agentes que se comunicam no Padrão FIPA-ACL; 67 | * Fácil de utilizar e com versatilizade do Python; 68 | * Ambiente de execução distribuído testado em hardware embarcados como Raspberry Pi e BeagleBone Black; 69 | * Desenvolvido inteiramente em Python! isso mesmo feito por quem ama Python para quem ama programar em Python; 70 | * Interface gráfica para monitoramento de agentes; 71 | * Projeto em pleno desenvolvimento; 72 | * É software livre. 73 | 74 | 75 | Interface de Desenvolvimento 76 | ------- 77 | 78 | ![Interface do Python](https://raw.githubusercontent.com/lucassm/Pade/master/pade/images/interface.png) 79 | 80 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Pade.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Pade.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Pade" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Pade" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/_static/UFC_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/_static/UFC_logo.png -------------------------------------------------------------------------------- /docs/_static/grei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/_static/grei.png -------------------------------------------------------------------------------- /docs/_static/pade_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/_static/pade_logo.png -------------------------------------------------------------------------------- /docs/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |

8 | PADE é um framework simples e elegante para desenvolvimento de sistemas multiagentes em Python. 9 |

10 | 11 | 12 |

Get Updates

13 |

Receive updates on new releases and upcoming projects.

14 | 15 |

Subscribe to Newsletter

16 | 17 |

Useful Links

18 | 25 | -------------------------------------------------------------------------------- /docs/_templates/sidebarlogo.html: -------------------------------------------------------------------------------- 1 | 6 | 7 |

8 | PADE é um framework simples e elegante para desenvolvimento de sistemas multiagentes em Python. 9 |

10 | 11 |

Get Updates

12 |

Receive updates on new releases and upcoming projects.

13 | 14 |

Subscribe to Newsletter

-------------------------------------------------------------------------------- /docs/_themes/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /docs/_themes/LICENSE: -------------------------------------------------------------------------------- 1 | Modifications: 2 | 3 | Copyright (c) 2011 Kenneth Reitz. 4 | 5 | 6 | Original Project: 7 | 8 | Copyright (c) 2010 by Armin Ronacher. 9 | 10 | 11 | Some rights reserved. 12 | 13 | Redistribution and use in source and binary forms of the theme, with or 14 | without modification, are permitted provided that the following conditions 15 | are met: 16 | 17 | * Redistributions of source code must retain the above copyright 18 | notice, this list of conditions and the following disclaimer. 19 | 20 | * Redistributions in binary form must reproduce the above 21 | copyright notice, this list of conditions and the following 22 | disclaimer in the documentation and/or other materials provided 23 | with the distribution. 24 | 25 | * The names of the contributors may not be used to endorse or 26 | promote products derived from this software without specific 27 | prior written permission. 28 | 29 | We kindly ask you to only use these themes in an unmodified manner just 30 | for Flask and Flask-related products, not for unrelated projects. If you 31 | like the visual style and want to use it for your own projects, please 32 | consider making some larger changes to the themes (such as changing 33 | font faces, sizes, colors or margins). 34 | 35 | THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 36 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 38 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 39 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 40 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 41 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 42 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 43 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 44 | ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE 45 | POSSIBILITY OF SUCH DAMAGE. 46 | -------------------------------------------------------------------------------- /docs/_themes/README.rst: -------------------------------------------------------------------------------- 1 | krTheme Sphinx Style 2 | ==================== 3 | 4 | This repository contains sphinx styles Kenneth Reitz uses in most of 5 | his projects. It is a derivative of Mitsuhiko's themes for Flask and Flask related 6 | projects. To use this style in your Sphinx documentation, follow 7 | this guide: 8 | 9 | 1. put this folder as _themes into your docs folder. Alternatively 10 | you can also use git submodules to check out the contents there. 11 | 12 | 2. add this to your conf.py: :: 13 | 14 | sys.path.append(os.path.abspath('_themes')) 15 | html_theme_path = ['_themes'] 16 | html_theme = 'flask' 17 | 18 | The following themes exist: 19 | 20 | **kr** 21 | the standard flask documentation theme for large projects 22 | 23 | **kr_small** 24 | small one-page theme. Intended to be used by very small addon libraries. 25 | 26 | -------------------------------------------------------------------------------- /docs/_themes/flask_theme_support.py: -------------------------------------------------------------------------------- 1 | # flasky extensions. flasky pygments style based on tango style 2 | from pygments.style import Style 3 | from pygments.token import Keyword, Name, Comment, String, Error, \ 4 | Number, Operator, Generic, Whitespace, Punctuation, Other, Literal 5 | 6 | 7 | class FlaskyStyle(Style): 8 | background_color = "#f8f8f8" 9 | default_style = "" 10 | 11 | styles = { 12 | # No corresponding class for the following: 13 | #Text: "", # class: '' 14 | Whitespace: "underline #f8f8f8", # class: 'w' 15 | Error: "#a40000 border:#ef2929", # class: 'err' 16 | Other: "#000000", # class 'x' 17 | 18 | Comment: "italic #8f5902", # class: 'c' 19 | Comment.Preproc: "noitalic", # class: 'cp' 20 | 21 | Keyword: "bold #004461", # class: 'k' 22 | Keyword.Constant: "bold #004461", # class: 'kc' 23 | Keyword.Declaration: "bold #004461", # class: 'kd' 24 | Keyword.Namespace: "bold #004461", # class: 'kn' 25 | Keyword.Pseudo: "bold #004461", # class: 'kp' 26 | Keyword.Reserved: "bold #004461", # class: 'kr' 27 | Keyword.Type: "bold #004461", # class: 'kt' 28 | 29 | Operator: "#582800", # class: 'o' 30 | Operator.Word: "bold #004461", # class: 'ow' - like keywords 31 | 32 | Punctuation: "bold #000000", # class: 'p' 33 | 34 | # because special names such as Name.Class, Name.Function, etc. 35 | # are not recognized as such later in the parsing, we choose them 36 | # to look the same as ordinary variables. 37 | Name: "#000000", # class: 'n' 38 | Name.Attribute: "#c4a000", # class: 'na' - to be revised 39 | Name.Builtin: "#004461", # class: 'nb' 40 | Name.Builtin.Pseudo: "#3465a4", # class: 'bp' 41 | Name.Class: "#000000", # class: 'nc' - to be revised 42 | Name.Constant: "#000000", # class: 'no' - to be revised 43 | Name.Decorator: "#888", # class: 'nd' - to be revised 44 | Name.Entity: "#ce5c00", # class: 'ni' 45 | Name.Exception: "bold #cc0000", # class: 'ne' 46 | Name.Function: "#000000", # class: 'nf' 47 | Name.Property: "#000000", # class: 'py' 48 | Name.Label: "#f57900", # class: 'nl' 49 | Name.Namespace: "#000000", # class: 'nn' - to be revised 50 | Name.Other: "#000000", # class: 'nx' 51 | Name.Tag: "bold #004461", # class: 'nt' - like a keyword 52 | Name.Variable: "#000000", # class: 'nv' - to be revised 53 | Name.Variable.Class: "#000000", # class: 'vc' - to be revised 54 | Name.Variable.Global: "#000000", # class: 'vg' - to be revised 55 | Name.Variable.Instance: "#000000", # class: 'vi' - to be revised 56 | 57 | Number: "#990000", # class: 'm' 58 | 59 | Literal: "#000000", # class: 'l' 60 | Literal.Date: "#000000", # class: 'ld' 61 | 62 | String: "#4e9a06", # class: 's' 63 | String.Backtick: "#4e9a06", # class: 'sb' 64 | String.Char: "#4e9a06", # class: 'sc' 65 | String.Doc: "italic #8f5902", # class: 'sd' - like a comment 66 | String.Double: "#4e9a06", # class: 's2' 67 | String.Escape: "#4e9a06", # class: 'se' 68 | String.Heredoc: "#4e9a06", # class: 'sh' 69 | String.Interpol: "#4e9a06", # class: 'si' 70 | String.Other: "#4e9a06", # class: 'sx' 71 | String.Regex: "#4e9a06", # class: 'sr' 72 | String.Single: "#4e9a06", # class: 's1' 73 | String.Symbol: "#4e9a06", # class: 'ss' 74 | 75 | Generic: "#000000", # class: 'g' 76 | Generic.Deleted: "#a40000", # class: 'gd' 77 | Generic.Emph: "italic #000000", # class: 'ge' 78 | Generic.Error: "#ef2929", # class: 'gr' 79 | Generic.Heading: "bold #000080", # class: 'gh' 80 | Generic.Inserted: "#00A000", # class: 'gi' 81 | Generic.Output: "#888", # class: 'go' 82 | Generic.Prompt: "#745334", # class: 'gp' 83 | Generic.Strong: "bold #000000", # class: 'gs' 84 | Generic.Subheading: "bold #800080", # class: 'gu' 85 | Generic.Traceback: "bold #a40000", # class: 'gt' 86 | } 87 | -------------------------------------------------------------------------------- /docs/_themes/kr/layout.html: -------------------------------------------------------------------------------- 1 | {%- extends "basic/layout.html" %} 2 | {%- block extrahead %} 3 | {{ super() }} 4 | {% if theme_touch_icon %} 5 | 6 | {% endif %} 7 | 8 | 9 | {% endblock %} 10 | {%- block relbar2 %}{% endblock %} 11 | {%- block footer %} 12 | 15 | 16 | Fork me on GitHub 17 | 18 | 19 | 20 | 21 | 32 | 38 | 39 | 42 | 43 | 44 | 59 | 60 | 73 | 74 | 83 | 84 | 85 | {%- endblock %} 86 | -------------------------------------------------------------------------------- /docs/_themes/kr/relations.html: -------------------------------------------------------------------------------- 1 |

Related Topics

2 | 20 | -------------------------------------------------------------------------------- /docs/_themes/kr/static/flasky.css_t: -------------------------------------------------------------------------------- 1 | /* 2 | * flasky.css_t 3 | * ~~~~~~~~~~~~ 4 | * 5 | * :copyright: Copyright 2010 by Armin Ronacher. Modifications by Kenneth Reitz. 6 | * :license: Flask Design License, see LICENSE for details. 7 | */ 8 | 9 | {% set page_width = '940px' %} 10 | {% set sidebar_width = '220px' %} 11 | 12 | @import url("basic.css"); 13 | 14 | /* -- page layout ----------------------------------------------------------- */ 15 | 16 | body { 17 | font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro'; 18 | font-size: 17px; 19 | background-color: white; 20 | color: #000; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | div.document { 26 | width: {{ page_width }}; 27 | margin: 30px auto 0 auto; 28 | } 29 | 30 | div.documentwrapper { 31 | float: left; 32 | width: 100%; 33 | } 34 | 35 | div.bodywrapper { 36 | margin: 0 0 0 {{ sidebar_width }}; 37 | } 38 | 39 | div.sphinxsidebar { 40 | width: {{ sidebar_width }}; 41 | } 42 | 43 | hr { 44 | border: 1px solid #B1B4B6; 45 | } 46 | 47 | div.body { 48 | background-color: #ffffff; 49 | color: #3E4349; 50 | padding: 0 30px 0 30px; 51 | } 52 | 53 | img.floatingflask { 54 | padding: 0 0 10px 10px; 55 | float: right; 56 | } 57 | 58 | div.footer { 59 | width: {{ page_width }}; 60 | margin: 20px auto 30px auto; 61 | font-size: 14px; 62 | color: #888; 63 | text-align: right; 64 | } 65 | 66 | div.footer a { 67 | color: #888; 68 | } 69 | 70 | div.related { 71 | display: none; 72 | } 73 | 74 | div.sphinxsidebar a { 75 | color: #444; 76 | text-decoration: none; 77 | border-bottom: 1px dotted #999; 78 | } 79 | 80 | div.sphinxsidebar a:hover { 81 | border-bottom: 1px solid #999; 82 | } 83 | 84 | div.sphinxsidebar { 85 | font-size: 14px; 86 | line-height: 1.5; 87 | } 88 | 89 | div.sphinxsidebarwrapper { 90 | padding: 18px 10px; 91 | } 92 | 93 | div.sphinxsidebarwrapper p.logo { 94 | padding: 0; 95 | margin: -10px 0 0 -20px; 96 | text-align: center; 97 | } 98 | 99 | div.sphinxsidebar h3, 100 | div.sphinxsidebar h4 { 101 | font-family: 'Garamond', 'Georgia', serif; 102 | color: #444; 103 | font-size: 24px; 104 | font-weight: normal; 105 | margin: 0 0 5px 0; 106 | padding: 0; 107 | } 108 | 109 | div.sphinxsidebar h4 { 110 | font-size: 20px; 111 | } 112 | 113 | div.sphinxsidebar h3 a { 114 | color: #444; 115 | } 116 | 117 | div.sphinxsidebar p.logo a, 118 | div.sphinxsidebar h3 a, 119 | div.sphinxsidebar p.logo a:hover, 120 | div.sphinxsidebar h3 a:hover { 121 | border: none; 122 | } 123 | 124 | div.sphinxsidebar p { 125 | color: #555; 126 | margin: 10px 0; 127 | } 128 | 129 | div.sphinxsidebar ul { 130 | margin: 10px 0; 131 | padding: 0; 132 | color: #000; 133 | } 134 | 135 | div.sphinxsidebar input { 136 | border: 1px solid #ccc; 137 | font-family: 'Georgia', serif; 138 | font-size: 1em; 139 | } 140 | 141 | /* -- body styles ----------------------------------------------------------- */ 142 | 143 | a { 144 | color: #004B6B; 145 | text-decoration: underline; 146 | } 147 | 148 | a:hover { 149 | color: #6D4100; 150 | text-decoration: underline; 151 | } 152 | 153 | div.body h1, 154 | div.body h2, 155 | div.body h3, 156 | div.body h4, 157 | div.body h5, 158 | div.body h6 { 159 | font-family: 'Garamond', 'Georgia', serif; 160 | font-weight: normal; 161 | margin: 30px 0px 10px 0px; 162 | padding: 0; 163 | } 164 | 165 | div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } 166 | div.body h2 { font-size: 180%; } 167 | div.body h3 { font-size: 150%; } 168 | div.body h4 { font-size: 130%; } 169 | div.body h5 { font-size: 100%; } 170 | div.body h6 { font-size: 100%; } 171 | 172 | a.headerlink { 173 | color: #ddd; 174 | padding: 0 4px; 175 | text-decoration: none; 176 | } 177 | 178 | a.headerlink:hover { 179 | color: #444; 180 | background: #eaeaea; 181 | } 182 | 183 | div.body p, div.body dd, div.body li { 184 | line-height: 1.4em; 185 | } 186 | 187 | div.admonition { 188 | background: #fafafa; 189 | margin: 20px -30px; 190 | padding: 10px 30px; 191 | border-top: 1px solid #ccc; 192 | border-bottom: 1px solid #ccc; 193 | } 194 | 195 | div.admonition tt.xref, div.admonition a tt { 196 | border-bottom: 1px solid #fafafa; 197 | } 198 | 199 | dd div.admonition { 200 | margin-left: -60px; 201 | padding-left: 60px; 202 | } 203 | 204 | div.admonition p.admonition-title { 205 | font-family: 'Garamond', 'Georgia', serif; 206 | font-weight: normal; 207 | font-size: 24px; 208 | margin: 0 0 10px 0; 209 | padding: 0; 210 | line-height: 1; 211 | } 212 | 213 | div.admonition p.last { 214 | margin-bottom: 0; 215 | } 216 | 217 | div.highlight { 218 | background-color: white; 219 | } 220 | 221 | dt:target, .highlight { 222 | background: #FAF3E8; 223 | } 224 | 225 | div.note { 226 | background-color: #eee; 227 | border: 1px solid #ccc; 228 | } 229 | 230 | div.seealso { 231 | background-color: #ffc; 232 | border: 1px solid #ff6; 233 | } 234 | 235 | div.topic { 236 | background-color: #eee; 237 | } 238 | 239 | p.admonition-title { 240 | display: inline; 241 | } 242 | 243 | p.admonition-title:after { 244 | content: ":"; 245 | } 246 | 247 | pre, tt { 248 | font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 249 | font-size: 0.9em; 250 | } 251 | 252 | img.screenshot { 253 | } 254 | 255 | tt.descname, tt.descclassname { 256 | font-size: 0.95em; 257 | } 258 | 259 | tt.descname { 260 | padding-right: 0.08em; 261 | } 262 | 263 | img.screenshot { 264 | -moz-box-shadow: 2px 2px 4px #eee; 265 | -webkit-box-shadow: 2px 2px 4px #eee; 266 | box-shadow: 2px 2px 4px #eee; 267 | } 268 | 269 | table.docutils { 270 | border: 1px solid #888; 271 | -moz-box-shadow: 2px 2px 4px #eee; 272 | -webkit-box-shadow: 2px 2px 4px #eee; 273 | box-shadow: 2px 2px 4px #eee; 274 | } 275 | 276 | table.docutils td, table.docutils th { 277 | border: 1px solid #888; 278 | padding: 0.25em 0.7em; 279 | } 280 | 281 | table.field-list, table.footnote { 282 | border: none; 283 | -moz-box-shadow: none; 284 | -webkit-box-shadow: none; 285 | box-shadow: none; 286 | } 287 | 288 | table.footnote { 289 | margin: 15px 0; 290 | width: 100%; 291 | border: 1px solid #eee; 292 | background: #fdfdfd; 293 | font-size: 0.9em; 294 | } 295 | 296 | table.footnote + table.footnote { 297 | margin-top: -15px; 298 | border-top: none; 299 | } 300 | 301 | table.field-list th { 302 | padding: 0 0.8em 0 0; 303 | } 304 | 305 | table.field-list td { 306 | padding: 0; 307 | } 308 | 309 | table.footnote td.label { 310 | width: 0px; 311 | padding: 0.3em 0 0.3em 0.5em; 312 | } 313 | 314 | table.footnote td { 315 | padding: 0.3em 0.5em; 316 | } 317 | 318 | dl { 319 | margin: 0; 320 | padding: 0; 321 | } 322 | 323 | dl dd { 324 | margin-left: 30px; 325 | } 326 | 327 | blockquote { 328 | margin: 0 0 0 30px; 329 | padding: 0; 330 | } 331 | 332 | ul, ol { 333 | margin: 10px 0 10px 30px; 334 | padding: 0; 335 | } 336 | 337 | pre { 338 | background: #eee; 339 | padding: 7px 30px; 340 | margin: 15px -30px; 341 | line-height: 1.3em; 342 | } 343 | 344 | dl pre, blockquote pre, li pre { 345 | margin-left: -60px; 346 | padding-left: 60px; 347 | } 348 | 349 | dl dl pre { 350 | margin-left: -90px; 351 | padding-left: 90px; 352 | } 353 | 354 | tt { 355 | background-color: #ecf0f3; 356 | color: #222; 357 | /* padding: 1px 2px; */ 358 | } 359 | 360 | tt.xref, a tt { 361 | background-color: #FBFBFB; 362 | border-bottom: 1px solid white; 363 | } 364 | 365 | a.reference { 366 | text-decoration: none; 367 | border-bottom: 1px dotted #004B6B; 368 | } 369 | 370 | a.reference:hover { 371 | border-bottom: 1px solid #6D4100; 372 | } 373 | 374 | a.footnote-reference { 375 | text-decoration: none; 376 | font-size: 0.7em; 377 | vertical-align: top; 378 | border-bottom: 1px dotted #004B6B; 379 | } 380 | 381 | a.footnote-reference:hover { 382 | border-bottom: 1px solid #6D4100; 383 | } 384 | 385 | a:hover tt { 386 | background: #EEE; 387 | } 388 | 389 | 390 | @media screen and (max-width: 870px) { 391 | 392 | div.sphinxsidebar { 393 | display: none; 394 | } 395 | 396 | div.document { 397 | width: 100%; 398 | 399 | } 400 | 401 | div.documentwrapper { 402 | margin-left: 0; 403 | margin-top: 0; 404 | margin-right: 0; 405 | margin-bottom: 0; 406 | } 407 | 408 | div.bodywrapper { 409 | margin-top: 0; 410 | margin-right: 0; 411 | margin-bottom: 0; 412 | margin-left: 0; 413 | } 414 | 415 | ul { 416 | margin-left: 0; 417 | } 418 | 419 | .document { 420 | width: auto; 421 | } 422 | 423 | .footer { 424 | width: auto; 425 | } 426 | 427 | .bodywrapper { 428 | margin: 0; 429 | } 430 | 431 | .footer { 432 | width: auto; 433 | } 434 | 435 | .github { 436 | display: none; 437 | } 438 | 439 | 440 | 441 | } 442 | 443 | 444 | 445 | @media screen and (max-width: 875px) { 446 | 447 | body { 448 | margin: 0; 449 | padding: 20px 30px; 450 | } 451 | 452 | div.documentwrapper { 453 | float: none; 454 | background: white; 455 | } 456 | 457 | div.sphinxsidebar { 458 | display: block; 459 | float: none; 460 | width: 102.5%; 461 | margin: 50px -30px -20px -30px; 462 | padding: 10px 20px; 463 | background: #333; 464 | color: white; 465 | } 466 | 467 | div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, 468 | div.sphinxsidebar h3 a { 469 | color: white; 470 | } 471 | 472 | div.sphinxsidebar a { 473 | color: #aaa; 474 | } 475 | 476 | div.sphinxsidebar p.logo { 477 | display: none; 478 | } 479 | 480 | div.document { 481 | width: 100%; 482 | margin: 0; 483 | } 484 | 485 | div.related { 486 | display: block; 487 | margin: 0; 488 | padding: 10px 0 20px 0; 489 | } 490 | 491 | div.related ul, 492 | div.related ul li { 493 | margin: 0; 494 | padding: 0; 495 | } 496 | 497 | div.footer { 498 | display: none; 499 | } 500 | 501 | div.bodywrapper { 502 | margin: 0; 503 | } 504 | 505 | div.body { 506 | min-height: 0; 507 | padding: 0; 508 | } 509 | 510 | .rtd_doc_footer { 511 | display: none; 512 | } 513 | 514 | .document { 515 | width: auto; 516 | } 517 | 518 | .footer { 519 | width: auto; 520 | } 521 | 522 | .footer { 523 | width: auto; 524 | } 525 | 526 | .github { 527 | display: none; 528 | } 529 | } 530 | 531 | 532 | /* misc. */ 533 | 534 | .revsys-inline { 535 | display: none!important; 536 | } -------------------------------------------------------------------------------- /docs/_themes/kr/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | pygments_style = flask_theme_support.FlaskyStyle 5 | 6 | [options] 7 | touch_icon = 8 | -------------------------------------------------------------------------------- /docs/_themes/kr_small/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "basic/layout.html" %} 2 | {% block header %} 3 | {{ super() }} 4 | {% if pagename == 'index' %} 5 |
6 | {% endif %} 7 | {% endblock %} 8 | {% block footer %} 9 | {% if pagename == 'index' %} 10 |
11 | {% endif %} 12 | {% endblock %} 13 | {# do not display relbars #} 14 | {% block relbar1 %}{% endblock %} 15 | {% block relbar2 %} 16 | {% if theme_github_fork %} 17 | Fork me on GitHub 19 | {% endif %} 20 | {% endblock %} 21 | {% block sidebar1 %}{% endblock %} 22 | {% block sidebar2 %}{% endblock %} 23 | -------------------------------------------------------------------------------- /docs/_themes/kr_small/static/flasky.css_t: -------------------------------------------------------------------------------- 1 | /* 2 | * flasky.css_t 3 | * ~~~~~~~~~~~~ 4 | * 5 | * Sphinx stylesheet -- flasky theme based on nature theme. 6 | * 7 | * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | @import url("basic.css"); 13 | 14 | /* -- page layout ----------------------------------------------------------- */ 15 | 16 | body { 17 | font-family: 'Georgia', serif; 18 | font-size: 17px; 19 | color: #000; 20 | background: white; 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | div.documentwrapper { 26 | float: left; 27 | width: 100%; 28 | } 29 | 30 | div.bodywrapper { 31 | margin: 40px auto 0 auto; 32 | width: 700px; 33 | } 34 | 35 | hr { 36 | border: 1px solid #B1B4B6; 37 | } 38 | 39 | div.body { 40 | background-color: #ffffff; 41 | color: #3E4349; 42 | padding: 0 30px 30px 30px; 43 | } 44 | 45 | img.floatingflask { 46 | padding: 0 0 10px 10px; 47 | float: right; 48 | } 49 | 50 | div.footer { 51 | text-align: right; 52 | color: #888; 53 | padding: 10px; 54 | font-size: 14px; 55 | width: 650px; 56 | margin: 0 auto 40px auto; 57 | } 58 | 59 | div.footer a { 60 | color: #888; 61 | text-decoration: underline; 62 | } 63 | 64 | div.related { 65 | line-height: 32px; 66 | color: #888; 67 | } 68 | 69 | div.related ul { 70 | padding: 0 0 0 10px; 71 | } 72 | 73 | div.related a { 74 | color: #444; 75 | } 76 | 77 | /* -- body styles ----------------------------------------------------------- */ 78 | 79 | a { 80 | color: #004B6B; 81 | text-decoration: underline; 82 | } 83 | 84 | a:hover { 85 | color: #6D4100; 86 | text-decoration: underline; 87 | } 88 | 89 | div.body { 90 | padding-bottom: 40px; /* saved for footer */ 91 | } 92 | 93 | div.body h1, 94 | div.body h2, 95 | div.body h3, 96 | div.body h4, 97 | div.body h5, 98 | div.body h6 { 99 | font-family: 'Garamond', 'Georgia', serif; 100 | font-weight: normal; 101 | margin: 30px 0px 10px 0px; 102 | padding: 0; 103 | } 104 | 105 | {% if theme_index_logo %} 106 | div.indexwrapper h1 { 107 | text-indent: -999999px; 108 | background: url({{ theme_index_logo }}) no-repeat center center; 109 | height: {{ theme_index_logo_height }}; 110 | } 111 | {% endif %} 112 | 113 | div.body h2 { font-size: 180%; } 114 | div.body h3 { font-size: 150%; } 115 | div.body h4 { font-size: 130%; } 116 | div.body h5 { font-size: 100%; } 117 | div.body h6 { font-size: 100%; } 118 | 119 | a.headerlink { 120 | color: white; 121 | padding: 0 4px; 122 | text-decoration: none; 123 | } 124 | 125 | a.headerlink:hover { 126 | color: #444; 127 | background: #eaeaea; 128 | } 129 | 130 | div.body p, div.body dd, div.body li { 131 | line-height: 1.4em; 132 | } 133 | 134 | div.admonition { 135 | background: #fafafa; 136 | margin: 20px -30px; 137 | padding: 10px 30px; 138 | border-top: 1px solid #ccc; 139 | border-bottom: 1px solid #ccc; 140 | } 141 | 142 | div.admonition p.admonition-title { 143 | font-family: 'Garamond', 'Georgia', serif; 144 | font-weight: normal; 145 | font-size: 24px; 146 | margin: 0 0 10px 0; 147 | padding: 0; 148 | line-height: 1; 149 | } 150 | 151 | div.admonition p.last { 152 | margin-bottom: 0; 153 | } 154 | 155 | div.highlight{ 156 | background-color: white; 157 | } 158 | 159 | dt:target, .highlight { 160 | background: #FAF3E8; 161 | } 162 | 163 | div.note { 164 | background-color: #eee; 165 | border: 1px solid #ccc; 166 | } 167 | 168 | div.seealso { 169 | background-color: #ffc; 170 | border: 1px solid #ff6; 171 | } 172 | 173 | div.topic { 174 | background-color: #eee; 175 | } 176 | 177 | div.warning { 178 | background-color: #ffe4e4; 179 | border: 1px solid #f66; 180 | } 181 | 182 | p.admonition-title { 183 | display: inline; 184 | } 185 | 186 | p.admonition-title:after { 187 | content: ":"; 188 | } 189 | 190 | pre, tt { 191 | font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 192 | font-size: 0.85em; 193 | } 194 | 195 | img.screenshot { 196 | } 197 | 198 | tt.descname, tt.descclassname { 199 | font-size: 0.95em; 200 | } 201 | 202 | tt.descname { 203 | padding-right: 0.08em; 204 | } 205 | 206 | img.screenshot { 207 | -moz-box-shadow: 2px 2px 4px #eee; 208 | -webkit-box-shadow: 2px 2px 4px #eee; 209 | box-shadow: 2px 2px 4px #eee; 210 | } 211 | 212 | table.docutils { 213 | border: 1px solid #888; 214 | -moz-box-shadow: 2px 2px 4px #eee; 215 | -webkit-box-shadow: 2px 2px 4px #eee; 216 | box-shadow: 2px 2px 4px #eee; 217 | } 218 | 219 | table.docutils td, table.docutils th { 220 | border: 1px solid #888; 221 | padding: 0.25em 0.7em; 222 | } 223 | 224 | table.field-list, table.footnote { 225 | border: none; 226 | -moz-box-shadow: none; 227 | -webkit-box-shadow: none; 228 | box-shadow: none; 229 | } 230 | 231 | table.footnote { 232 | margin: 15px 0; 233 | width: 100%; 234 | border: 1px solid #eee; 235 | } 236 | 237 | table.field-list th { 238 | padding: 0 0.8em 0 0; 239 | } 240 | 241 | table.field-list td { 242 | padding: 0; 243 | } 244 | 245 | table.footnote td { 246 | padding: 0.5em; 247 | } 248 | 249 | dl { 250 | margin: 0; 251 | padding: 0; 252 | } 253 | 254 | dl dd { 255 | margin-left: 30px; 256 | } 257 | 258 | pre { 259 | padding: 0; 260 | margin: 15px -30px; 261 | padding: 8px; 262 | line-height: 1.3em; 263 | padding: 7px 30px; 264 | background: #eee; 265 | border-radius: 2px; 266 | -moz-border-radius: 2px; 267 | -webkit-border-radius: 2px; 268 | } 269 | 270 | dl pre { 271 | margin-left: -60px; 272 | padding-left: 60px; 273 | } 274 | 275 | tt { 276 | background-color: #ecf0f3; 277 | color: #222; 278 | /* padding: 1px 2px; */ 279 | } 280 | 281 | tt.xref, a tt { 282 | background-color: #FBFBFB; 283 | } 284 | 285 | a:hover tt { 286 | background: #EEE; 287 | } 288 | -------------------------------------------------------------------------------- /docs/_themes/kr_small/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = flasky.css 4 | nosidebar = true 5 | pygments_style = flask_theme_support.FlaskyStyle 6 | 7 | [options] 8 | index_logo = '' 9 | index_logo_height = 120px 10 | github_fork = '' 11 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API PADE 2 | ======== 3 | 4 | Aqui estão todos os módulos que são de interesse para utilização do PADE, tais como o módulo que contém a classe Agent, módulo de construção de mensagens e de construção de comportamentos. 5 | 6 | .. automodule:: pade.core.agent 7 | :members: 8 | 9 | 10 | .. automodule:: pade.core.ams 11 | :members: 12 | 13 | 14 | .. automodule:: pade.core.sniffer 15 | :members: 16 | 17 | 18 | .. automodule:: pade.acl.messages 19 | :members: 20 | 21 | 22 | .. automodule:: pade.behaviours.protocols 23 | :members: -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Pade documentation build configuration file, created by 4 | # sphinx-quickstart on Sat Sep 12 19:30:28 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import sys 16 | import os 17 | 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | sys.path.insert(0, os.path.abspath('..')) 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | #needs_sphinx = '1.0' 28 | 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | extensions = ['sphinx.ext.autodoc', 33 | 'sphinx.ext.intersphinx', 34 | # 'IPython.sphinxext.ipython_console_highlighting', 35 | # 'IPython.sphinxext.ipython_directive'] 36 | ] 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # The suffix of source filenames. 41 | source_suffix = '.rst' 42 | 43 | # The encoding of source files. 44 | #source_encoding = 'utf-8-sig' 45 | 46 | # The master toctree document. 47 | master_doc = 'index' 48 | 49 | # General information about the project. 50 | project = u'Pade' 51 | copyright = u'2015, Lucas Melo' 52 | 53 | # The version info for the project you're documenting, acts as replacement for 54 | # |version| and |release|, also used in various other places throughout the 55 | # built documents. 56 | # 57 | # The short X.Y version. 58 | version = '1.0' 59 | # The full version, including alpha/beta/rc tags. 60 | release = '1.0' 61 | 62 | # The language for content autogenerated by Sphinx. Refer to documentation 63 | # for a list of supported languages. 64 | language = 'pt_BR' 65 | 66 | # There are two options for replacing |today|: either, you set today to some 67 | # non-false value, then it is used: 68 | #today = '' 69 | # Else, today_fmt is used as the format for a strftime call. 70 | #today_fmt = '%B %d, %Y' 71 | 72 | # List of patterns, relative to source directory, that match files and 73 | # directories to ignore when looking for source files. 74 | exclude_patterns = ['_build'] 75 | 76 | # The reST default role (used for this markup: `text`) to use for all 77 | # documents. 78 | #default_role = None 79 | 80 | # If true, '()' will be appended to :func: etc. cross-reference text. 81 | #add_function_parentheses = True 82 | 83 | # If true, the current module name will be prepended to all description 84 | # unit titles (such as .. function::). 85 | #add_module_names = True 86 | 87 | # If true, sectionauthor and moduleauthor directives will be shown in the 88 | # output. They are ignored by default. 89 | #show_authors = False 90 | 91 | # The name of the Pygments (syntax highlighting) style to use. 92 | # pygments_style = 'sphinx' 93 | pygments_style = 'flask_theme_support.FlaskyStyle' 94 | 95 | # A list of ignored prefixes for module index sorting. 96 | #modindex_common_prefix = [] 97 | 98 | # If true, keep warnings as "system message" paragraphs in the built documents. 99 | #keep_warnings = False 100 | 101 | 102 | # -- Options for HTML output ---------------------------------------------- 103 | 104 | # The theme to use for HTML and HTML Help pages. See the documentation for 105 | # a list of builtin themes. 106 | # html_theme = 'default' 107 | 108 | sys.path.append(os.path.abspath('_themes')) 109 | html_theme_path = ['_themes'] 110 | html_theme = 'kr' 111 | 112 | # Theme options are theme-specific and customize the look and feel of a theme 113 | # further. For a list of options available for each theme, see the 114 | # documentation. 115 | #html_theme_options = {} 116 | 117 | # Add any paths that contain custom themes here, relative to this directory. 118 | #html_theme_path = [] 119 | 120 | # The name for this set of Sphinx documents. If None, it defaults to 121 | # " v documentation". 122 | #html_title = None 123 | 124 | # A shorter title for the navigation bar. Default is the same as html_title. 125 | #html_short_title = None 126 | 127 | # The name of an image file (relative to this directory) to place at the top 128 | # of the sidebar. 129 | #html_logo = None 130 | 131 | # The name of an image file (within the static path) to use as favicon of the 132 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 133 | # pixels large. 134 | #html_favicon = None 135 | 136 | # Add any paths that contain custom static files (such as style sheets) here, 137 | # relative to this directory. They are copied after the builtin static files, 138 | # so a file named "default.css" will overwrite the builtin "default.css". 139 | html_static_path = ['_static'] 140 | 141 | # Add any extra paths that contain custom files (such as robots.txt or 142 | # .htaccess) here, relative to this directory. These files are copied 143 | # directly to the root of the documentation. 144 | #html_extra_path = [] 145 | 146 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 147 | # using the given strftime format. 148 | #html_last_updated_fmt = '%b %d, %Y' 149 | 150 | # If true, SmartyPants will be used to convert quotes and dashes to 151 | # typographically correct entities. 152 | #html_use_smartypants = True 153 | 154 | # Custom sidebar templates, maps document names to template names. 155 | #html_sidebars = {} 156 | 157 | html_sidebars = { 158 | 'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'], 159 | '**': ['sidebarlogo.html', 'localtoc.html', 'relations.html', 160 | 'sourcelink.html', 'searchbox.html'] 161 | } 162 | 163 | # Additional templates that should be rendered to pages, maps page names to 164 | # template names. 165 | #html_additional_pages = {} 166 | 167 | # If false, no module index is generated. 168 | #html_domain_indices = True 169 | 170 | # If false, no index is generated. 171 | #html_use_index = True 172 | 173 | # If true, the index is split into individual pages for each letter. 174 | #html_split_index = False 175 | 176 | # If true, links to the reST sources are added to the pages. 177 | #html_show_sourcelink = True 178 | 179 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 180 | #html_show_sphinx = True 181 | 182 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 183 | #html_show_copyright = True 184 | 185 | # If true, an OpenSearch description file will be output, and all pages will 186 | # contain a tag referring to it. The value of this option must be the 187 | # base URL from which the finished HTML is served. 188 | #html_use_opensearch = '' 189 | 190 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 191 | #html_file_suffix = None 192 | 193 | # Output file base name for HTML help builder. 194 | htmlhelp_basename = 'Padedoc' 195 | 196 | 197 | # -- Options for LaTeX output --------------------------------------------- 198 | 199 | latex_elements = { 200 | # The paper size ('letterpaper' or 'a4paper'). 201 | #'papersize': 'letterpaper', 202 | 203 | # The font size ('10pt', '11pt' or '12pt'). 204 | 'pointsize': '12pt', 205 | 206 | # Font Type 207 | 'fontpkg' : r'\usepackage{mathpazo}', 208 | 209 | # Additional stuff for the LaTeX preamble. 210 | 'preamble': r'\usepackage{flaskstyle}', 211 | } 212 | 213 | # Grouping the document tree into LaTeX files. List of tuples 214 | # (source start file, target name, title, 215 | # author, documentclass [howto, manual, or own class]). 216 | latex_documents = [ 217 | ('index', 'Pade.tex', u'Pade Documentation', 218 | u'Lucas Melo', 'manual'), 219 | ] 220 | 221 | # The name of an image file (relative to this directory) to place at the top of 222 | # the title page. 223 | #latex_logo = None 224 | 225 | # For "manual" documents, if this is true, then toplevel headings are parts, 226 | # not chapters. 227 | #latex_use_parts = False 228 | 229 | # If true, show page references after internal links. 230 | #latex_show_pagerefs = False 231 | 232 | # If true, show URL addresses after external links. 233 | #latex_show_urls = False 234 | 235 | # Documents to append as an appendix to all manuals. 236 | #latex_appendices = [] 237 | 238 | # If false, no module index is generated. 239 | #latex_domain_indices = True 240 | 241 | latex_additional_files = ['flaskstyle.sty', 'logo.pdf'] 242 | 243 | # -- Options for manual page output --------------------------------------- 244 | 245 | # One entry per manual page. List of tuples 246 | # (source start file, name, description, authors, manual section). 247 | man_pages = [ 248 | ('index', 'pade', u'Pade Documentation', 249 | [u'Lucas Melo'], 1) 250 | ] 251 | 252 | # If true, show URL addresses after external links. 253 | #man_show_urls = False 254 | 255 | 256 | # -- Options for Texinfo output ------------------------------------------- 257 | 258 | # Grouping the document tree into Texinfo files. List of tuples 259 | # (source start file, target name, title, author, 260 | # dir menu entry, description, category) 261 | texinfo_documents = [ 262 | ('index', 'Pade', u'Pade Documentation', 263 | u'Lucas Melo', 'Pade', 'One line description of project.', 264 | 'Miscellaneous'), 265 | ] 266 | 267 | # Documents to append as an appendix to all manuals. 268 | #texinfo_appendices = [] 269 | 270 | # If false, no module index is generated. 271 | #texinfo_domain_indices = True 272 | 273 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 274 | #texinfo_show_urls = 'footnote' 275 | 276 | # If true, do not generate a @detailmenu in the "Top" node's menu. 277 | #texinfo_no_detailmenu = False 278 | -------------------------------------------------------------------------------- /docs/flaskstyle.sty: -------------------------------------------------------------------------------- 1 | \definecolor{TitleColor}{rgb}{0,0,0} 2 | \definecolor{InnerLinkColor}{rgb}{0,0,0} 3 | 4 | \renewcommand{\maketitle}{% 5 | \begin{titlepage}% 6 | \let\footnotesize\small 7 | \let\footnoterule\relax 8 | \ifsphinxpdfoutput 9 | \begingroup 10 | % This \def is required to deal with multi-line authors; it 11 | % changes \\ to ', ' (comma-space), making it pass muster for 12 | % generating document info in the PDF file. 13 | \def\\{, } 14 | \pdfinfo{ 15 | /Author (\@author) 16 | /Title (\@title) 17 | } 18 | \endgroup 19 | \fi 20 | \begin{flushright}% 21 | %\sphinxlogo% 22 | {\center 23 | \vspace*{3cm} 24 | \includegraphics[width=3.0in]{logo.pdf} 25 | \vspace{1cm} 26 | \par 27 | {\rm\Huge \@title \par}% 28 | {\em\LARGE \py@release\releaseinfo \par} 29 | {\large 30 | \@date \par 31 | \py@authoraddress \par 32 | }}% 33 | \end{flushright}%\par 34 | \@thanks 35 | \end{titlepage}% 36 | \cleardoublepage% 37 | \setcounter{footnote}{0}% 38 | \let\thanks\relax\let\maketitle\relax 39 | %\gdef\@thanks{}\gdef\@author{}\gdef\@title{} 40 | } 41 | 42 | \fancypagestyle{normal}{ 43 | \fancyhf{} 44 | \fancyfoot[LE,RO]{{\thepage}} 45 | \fancyfoot[LO]{{\nouppercase{\rightmark}}} 46 | \fancyfoot[RE]{{\nouppercase{\leftmark}}} 47 | \fancyhead[LE,RO]{{ \@title, \py@release}} 48 | \renewcommand{\headrulewidth}{0.4pt} 49 | \renewcommand{\footrulewidth}{0.4pt} 50 | } 51 | 52 | \fancypagestyle{plain}{ 53 | \fancyhf{} 54 | \fancyfoot[LE,RO]{{\thepage}} 55 | \renewcommand{\headrulewidth}{0pt} 56 | \renewcommand{\footrulewidth}{0.4pt} 57 | } 58 | 59 | \titleformat{\section}{\Large}% 60 | {\py@TitleColor\thesection}{0.5em}{\py@TitleColor}{\py@NormalColor} 61 | \titleformat{\subsection}{\large}% 62 | {\py@TitleColor\thesubsection}{0.5em}{\py@TitleColor}{\py@NormalColor} 63 | \titleformat{\subsubsection}{}% 64 | {\py@TitleColor\thesubsubsection}{0.5em}{\py@TitleColor}{\py@NormalColor} 65 | \titleformat{\paragraph}{\large}% 66 | {\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor} 67 | 68 | \ChNameVar{\raggedleft\normalsize} 69 | \ChNumVar{\raggedleft \bfseries\Large} 70 | \ChTitleVar{\raggedleft \rm\Huge} 71 | 72 | \renewcommand\thepart{\@Roman\c@part} 73 | \renewcommand\part{% 74 | \pagestyle{plain} 75 | \if@noskipsec \leavevmode \fi 76 | \cleardoublepage 77 | \vspace*{6cm}% 78 | \@afterindentfalse 79 | \secdef\@part\@spart} 80 | 81 | \def\@part[#1]#2{% 82 | \ifnum \c@secnumdepth >\m@ne 83 | \refstepcounter{part}% 84 | \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}% 85 | \else 86 | \addcontentsline{toc}{part}{#1}% 87 | \fi 88 | {\parindent \z@ %\center 89 | \interlinepenalty \@M 90 | \normalfont 91 | \ifnum \c@secnumdepth >\m@ne 92 | \rm\Large \partname~\thepart 93 | \par\nobreak 94 | \fi 95 | \MakeUppercase{\rm\Huge #2}% 96 | \markboth{}{}\par}% 97 | \nobreak 98 | \vskip 8ex 99 | \@afterheading} 100 | \def\@spart#1{% 101 | {\parindent \z@ %\center 102 | \interlinepenalty \@M 103 | \normalfont 104 | \huge \bfseries #1\par}% 105 | \nobreak 106 | \vskip 3ex 107 | \@afterheading} 108 | 109 | % use inconsolata font 110 | \usepackage{inconsolata} 111 | 112 | % fix single quotes, for inconsolata. (does not work) 113 | %%\usepackage{textcomp} 114 | %%\begingroup 115 | %% \catcode`'=\active 116 | %% \g@addto@macro\@noligs{\let'\textsinglequote} 117 | %% \endgroup 118 | %%\endinput 119 | -------------------------------------------------------------------------------- /docs/img/InterfaceSniffer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/InterfaceSniffer.png -------------------------------------------------------------------------------- /docs/img/contract_net/ACLMessage_795.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/contract_net/ACLMessage_795.png -------------------------------------------------------------------------------- /docs/img/contract_net/ACLMessage_795.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/contract_net/ACLMessage_795.xcf -------------------------------------------------------------------------------- /docs/img/contract_net/ACLMessage_796.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/contract_net/ACLMessage_796.png -------------------------------------------------------------------------------- /docs/img/contract_net/ACLMessage_797.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/contract_net/ACLMessage_797.png -------------------------------------------------------------------------------- /docs/img/contract_net/ACLMessage_todas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/contract_net/ACLMessage_todas.png -------------------------------------------------------------------------------- /docs/img/contract_net/InterfacedeGerenciamentodosAgentes_794.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/contract_net/InterfacedeGerenciamentodosAgentes_794.png -------------------------------------------------------------------------------- /docs/img/janela_agentes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/janela_agentes.png -------------------------------------------------------------------------------- /docs/img/janela_mensagem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/janela_mensagem.png -------------------------------------------------------------------------------- /docs/img/pade_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 27 | 32 | 38 | 42 | 47 | 53 | 54 | 55 | 77 | 79 | 80 | 82 | image/svg+xml 83 | 85 | 86 | 87 | 88 | 89 | 94 | 99 | P 110 | A 120 | DE 130 | Python Agent DEvelopment framework 147 | 148 | 149 | -------------------------------------------------------------------------------- /docs/img/seq_diag_contract.diag: -------------------------------------------------------------------------------- 1 | seqdiag{ 2 | activation = none; 3 | 4 | agente_iniciante -> agente_participante_1 [label='CFP']; 5 | agente_iniciante -> agente_participante_2 [label='CFP']; 6 | agente_iniciante <- agente_participante_1 [label='PROPOSE']; 7 | agente_iniciante <- agente_participante_2 [label='PROPOSE']; 8 | agente_iniciante -> agente_participante_1 [label='ACCEPT-PROPOSE']; 9 | agente_iniciante -> agente_participante_2 [label='REJECT-PROPOSE']; 10 | agente_iniciante <- agente_participante_1 [label='INFORM']; 11 | } -------------------------------------------------------------------------------- /docs/img/seq_diag_contract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/seq_diag_contract.png -------------------------------------------------------------------------------- /docs/img/seq_diag_request.diag: -------------------------------------------------------------------------------- 1 | seqdiag{ 2 | activation = none; 3 | 4 | agente_iniciante -> agente_participante [label='REQUEST']; 5 | agente_iniciante <- agente_participante [label='INFORM']; 6 | } -------------------------------------------------------------------------------- /docs/img/seq_diag_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/seq_diag_request.png -------------------------------------------------------------------------------- /docs/img/seq_diag_subscribe.diag: -------------------------------------------------------------------------------- 1 | seqdiag{ 2 | activation = none; 3 | 4 | agente_assinante_1 -> agente_editor[label='SUBSCRIBE']; 5 | agente_assinante_1 <- agente_editor[label='AGREE']; 6 | agente_assinante_2 -> agente_editor[label='SUBSCRIBE']; 7 | agente_assinante_2 <- agente_editor[label='AGREE']; 8 | agente_assinante_3 -> agente_editor[label='SUBSCRIBE']; 9 | agente_assinante_3 <- agente_editor[label='REFUSE']; 10 | agente_assinante_1 <- agente_editor[label='INFORM']; 11 | agente_assinante_2 <- agente_editor[label='INFORM']; 12 | } -------------------------------------------------------------------------------- /docs/img/seq_diag_subscribe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/img/seq_diag_subscribe.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Pade documentation master file, created by 2 | sphinx-quickstart on Sat Sep 12 19:30:28 2015. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Python Agent DEvelopment framework 7 | ================================== 8 | 9 | Sistemas Multiagentes para Python! 10 | ---------------------------------- 11 | 12 | PADE é um framework para desenvolvimento, execução e gerenciamento de sistemas multiagentes em ambientes de computação distribuída. 13 | 14 | PADE é escrito 100% em Python e utiliza as bibliotecas do projeto `Twisted `_ para implementar a comunicação entre os nós da rede. 15 | 16 | PADE é software livre, licenciado sob os termos da licença MIT, desenvolvido no ambito da Universidade Federal do Ceará pelo Grupo de Redes Elétricas Inteligentes (GREI) que pertence ao departamento de Engenharia Elétrica. 17 | 18 | Qualquer um que queira contribuir com o projeto é convidado a baixar, executar, testar e enviar feedback a respeito das impressões tiradas da plataforma. 19 | 20 | PADE é simples! 21 | ~~~~~~~~~~~~~~~~~ 22 | 23 | :: 24 | 25 | # este e o arquivo start_ams.py 26 | from pade.misc.common import set_ams, start_loop 27 | 28 | if __name__ == '__main__': 29 | set_ams('localhost', 8000) 30 | start_loop(list(), gui=True) 31 | 32 | 33 | E fácil de instalar! 34 | ~~~~~~~~~~~~~~~~~~~~ 35 | 36 | Para instalar o PADE basta executar o seguinte comando em um terminal linux: 37 | 38 | :: 39 | 40 | $ pip install pade 41 | $ python start_ams.py 42 | 43 | Funcionalidades 44 | ~~~~~~~~~~~~~~~ 45 | 46 | O PADE foi desenvolvido tendo em vista os requisitos para sistema de automação. PADE oferece os seguintes recursos em sua biblioteca para desenvolvimento de sistemas multiagentes: 47 | 48 | 49 | **Orientação a Objetos** 50 | Abstração para construção de agentes e seus comportamentos utilizando conceitos de orientação a objetos; 51 | 52 | **Ambiente de execução** 53 | Módulo para inicialização do ambiente de execução de agentes, inteiramente em código Python; 54 | 55 | **Mensagens no padrão FIPA-ACL** 56 | Módulo para construção e tratamento de mensagens no padrão FIPA-ACL; 57 | 58 | **Filtragem de Mensagens** 59 | Módulo para filtragem de mensagens; 60 | 61 | **Protocolos FIPA** 62 | Módulo para a implementação dos protocolos definidos pela FIPA; 63 | 64 | **Comportamentos Cíclicos e Temporais** 65 | Módulo para implementação de comportamentos cíclicos e temporais; 66 | 67 | **Banco de Dados** 68 | Módulo para interação com banco de dados; 69 | 70 | **Envio de Objetos Serializados** 71 | Possibilidade de envio de objetos serializados como conteúdo das mensagens FIPA-ACL. 72 | 73 | 74 | Além dessas funcionalidades, o PADE é de fácil instalação e configuração, multiplataforma, podendo ser instalado e utilizado em hardwares embarcados que executam sistema operacional Linux, como Raspberry Pi e BeagleBone Black, bem como sistema operacional Windows. 75 | 76 | 77 | 78 | Guia do Usuário 79 | ---------------- 80 | 81 | .. toctree:: 82 | :maxdepth: 2 83 | 84 | user/instalacao.rst 85 | user/hello-world 86 | user/meu-primeiro-agente 87 | user/agentes-temporais 88 | user/enviando-mensagens 89 | user/recebendo-mensagens 90 | user/um-momento 91 | user/enviando-objetos 92 | user/selecao-de-mensagens 93 | user/interface-grafica 94 | user/protocolos 95 | 96 | 97 | 98 | Referência da API do PADE 99 | ------------------------- 100 | 101 | .. toctree:: 102 | :maxdepth: 2 103 | 104 | api 105 | 106 | 107 | -------------------------------------------------------------------------------- /docs/logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/docs/logo.pdf -------------------------------------------------------------------------------- /docs/user/agentes-temporais.rst: -------------------------------------------------------------------------------- 1 | Agentes Temporais 2 | ================= 3 | 4 | Em aplicações reais é comum que o comportamento do agente seja executado de tempos em tempos e não apenas uma vez, mas como fazer isso no PADE? :( 5 | 6 | Execução de um agente temporal 7 | ------------------------------ 8 | 9 | Este é um exemplo de um agente que executa indefinidamente um comportamento a cada 1,0 segundos: 10 | 11 | :: 12 | 13 | #!coding=utf-8 14 | # Hello world temporal in PADE! 15 | # 16 | # Criado por Lucas S Melo em 21 de julho de 2015 - Fortaleza, Ceará - Brasil 17 | 18 | from pade.behaviours.protocols import TimedBehaviour 19 | from pade.misc.utility import display_message 20 | from pade.misc.common import set_ams, start_loop 21 | from pade.core.agent import Agent 22 | from pade.acl.aid import AID 23 | 24 | 25 | class ComportTemporal(TimedBehaviour): 26 | def __init__(self, agent, time): 27 | super(ComportTemporal, self).__init__(agent, time) 28 | 29 | def on_time(self): 30 | super(ComportTemporal, self).on_time() 31 | display_message(self.agent.aid.localname, 'Hello World!') 32 | 33 | 34 | class AgenteHelloWorld(Agent): 35 | def __init__(self, aid): 36 | super(AgenteHelloWorld, self).__init__(aid=aid, debug=False) 37 | 38 | comp_temp = ComportTemporal(self, 1.0) 39 | 40 | self.behaviours.append(comp_temp) 41 | 42 | 43 | if __name__ == '__main__': 44 | 45 | set_ams('localhost', 8000, debug=False) 46 | 47 | agents = list() 48 | 49 | agente_1 = AgenteHelloWorld(AID(name='agente_1')) 50 | agente_1.ams = {'name': 'localhost', 'port': 8000} 51 | 52 | agents.append(agente_1) 53 | 54 | start_loop(agents, gui=True) 55 | 56 | Execução de dois agentes temporais 57 | ---------------------------------- 58 | 59 | Mas e se eu quiser dois agentes com o mesmo comportamento!? Não tem problema, basta instanciar um outro agente com a mesma classe! 60 | 61 | :: 62 | 63 | if __name__ == '__main__': 64 | 65 | set_ams('localhost', 8000, debug=False) 66 | 67 | agents = list() 68 | 69 | agente_1 = AgenteHelloWorld(AID(name='agente_1')) 70 | agente_1.ams = {'name': 'localhost', 'port': 8000} 71 | 72 | agente_2 = AgenteHelloWorld(AID(name='agente_2')) 73 | agente_2.ams = {'name': 'localhost', 'port': 8000} 74 | 75 | agents.append(agente_1) 76 | agents.append(agente_2) 77 | 78 | start_loop(agents, gui=True) 79 | 80 | -------------------------------------------------------------------------------- /docs/user/enviando-mensagens.rst: -------------------------------------------------------------------------------- 1 | Enviando Mensagens 2 | ================== 3 | 4 | Para enviar uma mensagem com o PADE é muito simples! As mensagens enviadas pelos agentes desenvolvidos com PADE seguem o padrão FIPA-ACL e têm os seguintes campos: 5 | 6 | * *conversation-id:* identidade única de uma conversa; 7 | * *performative:* rótulo da mensagem; 8 | * *sender:* remetente da mensagem; 9 | * *receivers:* destinatários da mensagem; 10 | * *content:* conteúdo da mensagem; 11 | * *protocol:* protocolo da mensagem; 12 | * *language:* linguagem utilizada; 13 | * *encoding:* codificação da mensagem; 14 | * *ontology:* ontologia utilizada; 15 | * *reply-with:* Expressão utilizada pelo agente de resposta a identificar a mensagem; 16 | * *reply-by:* A referência a uma ação anterior em que a mensagem é uma resposta; 17 | * *in-reply-to:* Data/hora indicando quando uma resposta deve ser recebida.. 18 | 19 | Mensagens FIPA-ACL no PADE 20 | -------------------------- 21 | 22 | Uma mensagem FIPA-ACL pode ser montada no pade da seguinte forma: 23 | 24 | :: 25 | 26 | from pade.acl.messages import ACLMessage, AID 27 | message = ACLMessage(ACLMessage.INFORM) 28 | message.set_protocol(ACLMessage.FIPA_REQUEST_PROTOCOL) 29 | message.add_receiver(AID('agente_destino')) 30 | message.set_content('Ola Agente') 31 | 32 | 33 | Enviando uma mensagem com PADE 34 | ------------------------------ 35 | 36 | Uma vez que se está dentro de uma instância da classe `Agent()` a mensagem pode ser enviada, simplesmente utilizando o comando: 37 | 38 | :: 39 | 40 | self.send(message) 41 | 42 | 43 | Mensagem no padrão FIPA-ACL 44 | --------------------------- 45 | 46 | Realizando o comando `print message` a mensagem no padão FIPA ACL será impressa na tela: 47 | 48 | :: 49 | 50 | (inform 51 | :conversationID b2e806b8-50a0-11e5-b3b6-e8b1fc5c3cdf 52 | :receiver 53 | (set 54 | (agent-identifier 55 | :name agente_destino@localhost:51645 56 | :addresses 57 | (sequence 58 | localhost:51645 59 | ) 60 | ) 61 | 62 | ) 63 | :content "Ola Agente" 64 | :protocol fipa-request protocol 65 | ) 66 | 67 | 68 | Mensagem no padrão XML 69 | ---------------------- 70 | 71 | Mas também é possível obter a mensagem no formato XML por meio do comando `print message.as_xml()` 72 | 73 | .. code-block:: xml 74 | 75 | 76 | 77 | inform 78 | 79 | 80 | agente_destino@localhost:51645 81 | 82 | 83 | Ola Agente 84 | 85 | 86 | 87 | fipa-request protocol 88 | b2e806b8-50a0-11e5-b3b6-e8b1fc5c3cdf 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/user/enviando-objetos.rst: -------------------------------------------------------------------------------- 1 | Enviando Objetos 2 | ================ 3 | 4 | Nem sempre o que é preciso enviar para outros agentes pode ser representado por texto simpes não é mesmo! 5 | 6 | Para enviar objetos encapsulados no content de mensagens FIPA-ACL com PADE basta utilizar o módulo nativo do Python *pickle*. 7 | 8 | Enviando objetos serializados com pickle 9 | ---------------------------------------- 10 | 11 | Para enviar um objeto serializado com piclke basta seguir os passos: 12 | 13 | :: 14 | 15 | import pickle 16 | 17 | *pickle* é uma biblioteca para serialização de objetos, assim, para serializar um objeto qualquer, utilize `pickle.dumps()`, veja: 18 | 19 | :: 20 | 21 | dados = {'nome' : 'agente_consumidor', 'porta' : 2004} 22 | dados_serial = pickle.dumps(dados) 23 | message.set_content(dados_serial) 24 | 25 | Pronto! O objeto já pode ser enviado no conteúdo da mensagem. 26 | 27 | Recebendo objetos serializados com pickle 28 | ---------------------------------------- 29 | 30 | Agora para receber o objeto, basta carregá-lo utilizando o comando: 31 | 32 | :: 33 | 34 | dados_serial = message.content 35 | dados = pickle.loads(dados_serial) 36 | 37 | Simples assim ;) -------------------------------------------------------------------------------- /docs/user/hello-world.rst: -------------------------------------------------------------------------------- 1 | Alô Mundo 2 | ========= 3 | 4 | PADE foi implementado com um objetivo central: simplicidade! 5 | 6 | Depois de ter o PADE instalado em seu computador fica bem simples começar a trabalhar. 7 | 8 | Em uma pasta crie um arquivo chamado start_ams.py com o seu editor de texto preferido, e copie e cole o seguinte trecho de código dentro dele: 9 | 10 | :: 11 | 12 | # este e o arquivo start_ams.py 13 | from pade.misc.common import set_ams, start_loop 14 | 15 | if __name__ == '__main__': 16 | set_ams('localhost', 8000) 17 | start_loop(list(), gui=True) 18 | 19 | A essa altura você já deve estar vendo a interface gráfica de monitoramento dos agentes em Python, assim como essa: 20 | 21 | .. figure:: ../img/InterfaceSniffer.png 22 | :align: center 23 | :width: 5.0in 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/user/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: Documentação 4 | description: Python Agent Development framework 5 | permalink: /docs/home/ 6 | --- 7 | 8 |

Bem vindo a documentacão do PADE!

9 | 10 |
    11 | {% for page in site.pages|sort(attribute='categories') %} 12 | {% if page.title %} 13 | {% if page.categories == "docs" %} 14 |
  • 15 | {{ page.title }} 16 |
  • 17 | {% endif %} 18 | {% endif %} 19 | {% endfor %} 20 |
-------------------------------------------------------------------------------- /docs/user/instalacao.rst: -------------------------------------------------------------------------------- 1 | Instalação 2 | ========== 3 | 4 | Instalar o PADE em seu computador, ou dispositivo embarcado é bem simples, basta que ele esteja conectado à internet! 5 | 6 | Instalação via PIP 7 | ------------------ 8 | 9 | Para instalar o PADE via PIP basta digitar em um terminal: 10 | 11 | .. code-block:: console 12 | 13 | $ pip install pade 14 | 15 | 16 | Pronto! O Pade está instalado! 17 | 18 | .. warning:: 19 | Atenção! O PADE é oficalmente testado no ambiente Ubuntu 14.04 LTS. Sendo necessário a instalação dos pacotes python-twisted-qt4reactor e pyside 20 | 21 | Instalação via GitHub 22 | --------------------- 23 | 24 | Se você quiser ter acesso ao fonte do PADE e instala-lo a partir do fonte, basta digitar as seguintes linhas no terminal: 25 | 26 | .. code-block:: console 27 | 28 | $ git clone https://github.com/lucassm/Pade 29 | $ cd Pade 30 | $ python setup.py install 31 | 32 | Pronto o PADE está pronto para ser utilizado, faça um teste no interpretador Python digitando: 33 | 34 | :: 35 | 36 | from pade.misc.utility import display_message 37 | 38 | Instalando o PADE em um ambiente virtual 39 | ---------------------------------------- 40 | 41 | Quando se trabalha com módulos Python é importante saber criar e manipular ambientes virtuais para gerenciar as dependências do projeto de uma maneira mais organizada. Aqui iremos mostrar como criar um ambiente virtual python, ativá-lo e utilizar o pip para instalar o PADE. Para uma visão mais detalhada sobre ambientes virtuais Python, acesse: `Python Guide `_. 42 | 43 | Primeiro você irá precisar ter o pacote virtualenv instalado em seu PC, instale-o digitando o comando: 44 | 45 | .. code-block:: console 46 | 47 | $ pip install virtualenv 48 | 49 | Após instalado o virtualenv é hora de criar um ambiente virtual, por meio do seguinte comando: 50 | 51 | .. code-block:: console 52 | 53 | $ cd my_project_folder 54 | $ virtualenv venv 55 | 56 | Para ativar o ambiente virtual criado, digite o comando: 57 | 58 | .. code-block:: console 59 | 60 | $ source venv/bin/activate 61 | 62 | Agora basta instalar o pade, por meio do pip: 63 | 64 | .. code-block:: console 65 | 66 | $ pip install pade 67 | 68 | 69 | Ativando a interface gráfica 70 | ---------------------------- 71 | 72 | Para que a interface gráfica do PADE funcione é necessário que o pacote PySide, um binding do Qt, esteja instalado. Como não existem binários do PySide disponíveis para Linux e o procedimento de compilação é bastante demorado, é necessário fazer o seguinte procedimento: 73 | 74 | 1. Instale o PySide via linha de comando: 75 | 76 | .. code-block:: console 77 | 78 | $ sudo apt-get install python-pyside 79 | 80 | 2. Copie a pasta com a instalação do PySide da pasta site-packages, onde fica a instalação padrão do Python em seu sistema operacional, e então coloque dentro da pasta onde ficam instalados os pacotes padrões do ambiente virtual, no nosso caso: venv/lib/python2.7/site-packages. 81 | 82 | Pronto a instalação do PySide no ambiente virtual está concluída, mas outro procedimento que deve ser realizado é a instalação do reactor que interage com o loop de eventos do PySide, para isso, digite: 83 | 84 | .. code-block:: console 85 | 86 | $ sudo apt-get install python-qt4reactor 87 | 88 | -------------------------------------------------------------------------------- /docs/user/interface-grafica.rst: -------------------------------------------------------------------------------- 1 | Interface Gráfica 2 | ================= 3 | 4 | Para ativar a funcionalidade de interface gráfica do PADE é bem simples, basta passar o parâmetro *gui=True* na função 5 | :: 6 | 7 | start_loop(agentes, gui=True) 8 | 9 | A interface gráfica do PADE ainda está bem simples e sem muitas funcionalidades, implementada com base no framework para desenvolvimento de GUI Qt/PySide, isso gera ulgumas complicações. Para a versão 2.0 será implementada uma interface web com base no framework `Flask `_, mais completa e funcional. -------------------------------------------------------------------------------- /docs/user/meu-primeiro-agente.rst: -------------------------------------------------------------------------------- 1 | Meu Primeiro Agente 2 | =================== 3 | 4 | 5 | Agora já está na hora de construir um agente de verdade! 6 | 7 | Construindo meu primeiro agente 8 | ------------------------------- 9 | 10 | Para implementar seu primeiro agente abra seu editor de textos preferido e digite o seguinte código: 11 | 12 | :: 13 | 14 | from pade.misc.utility import display_message 15 | from pade.misc.common import set_ams, start_loop 16 | from pade.core.agent import Agent 17 | from pade.acl.aid import AID 18 | 19 | 20 | class AgenteHelloWorld(Agent): 21 | def __init__(self, aid): 22 | super(AgenteHelloWorld, self).__init__(aid=aid, debug=False) 23 | display_message(self.aid.localname, 'Hello World!') 24 | 25 | if __name__ == '__main__': 26 | 27 | set_ams('localhost', 8000, debug=False) 28 | 29 | agents = list() 30 | 31 | agente_hello = AgenteHelloWorld(AID(name='agente_hello')) 32 | agente_hello.ams = {'name': 'localhost', 'port': 8000} 33 | agents.append(agente_hello) 34 | 35 | start_loop(agents, gui=True) 36 | 37 | 38 | Este já é um agente, mas não tem muita utilidade, não é mesmo! Executa apenas uma vez :( 39 | 40 | Então como construir um agente que tenha seu comportamento executado de tempos em tempos? 41 | -------------------------------------------------------------------------------- /docs/user/recebendo-mensagens.rst: -------------------------------------------------------------------------------- 1 | Recebendo Mensagens 2 | =================== 3 | 4 | No PADE para que um agente possa receber mensagens, basta que o método react() seja implementado, dentro da classe que herda da classe `Agent()`. 5 | 6 | Recebendo mensagens FIPA-ACL com PADE 7 | ------------------------------------- 8 | 9 | No exemplo a seguir são implementados dois agentes distintos, o primeiro é o agente ```remetente``` modelado pela classe `Remetente()`, que tem o papel de enviar uma mensagem ao agente `destinatario` modelado pela classe `Destinatario`, que irá receber a mensagem enviada pelo agente `remetente` e por isso tem o método `react()` implementado. 10 | 11 | :: 12 | 13 | from pade.misc.utility import display_message 14 | from pade.misc.common import set_ams, start_loop 15 | from pade.core.agent import Agent 16 | from pade.acl.aid import AID 17 | from pade.acl.messages import ACLMessage 18 | 19 | 20 | class Remetente(Agent): 21 | def __init__(self, aid): 22 | super(Remetente, self).__init__(aid=aid, debug=False) 23 | 24 | def on_start(self): 25 | display_message(self.aid.localname, 'Enviando Mensagem') 26 | message = ACLMessage(ACLMessage.INFORM) 27 | message.add_receiver(AID('destinatario')) 28 | message.set_content('Ola') 29 | self.send(message) 30 | 31 | def react(self, message): 32 | pass 33 | 34 | 35 | class Destinatario(Agent): 36 | def __init__(self, aid): 37 | super(Destinatario, self).__init__(aid=aid, debug=False) 38 | 39 | def react(self, message): 40 | display_message(self.aid.localname, 'Mensagem recebida') 41 | 42 | 43 | if __name__ == '__main__': 44 | 45 | set_ams('localhost', 8000, debug=False) 46 | 47 | agentes = list() 48 | 49 | destinatario = Destinatario(AID(name='destinatario')) 50 | destinatario.ams = {'name': 'localhost', 'port': 8000} 51 | agentes.append(destinatario) 52 | 53 | remetente = Remetente(AID(name='remetente')) 54 | remetente.ams = {'name': 'localhost', 'port': 8000} 55 | agentes.append(remetente) 56 | 57 | start_loop(agentes, gui=True) 58 | 59 | 60 | Visualização via Interface Gráfica 61 | ---------------------------------- 62 | 63 | A seguir é possível observar a interface gráfica do PADE que mostra os agentes cadastrados no AMS. 64 | 65 | .. figure:: ../img/janela_agentes.png 66 | :align: center 67 | :width: 4.5in 68 | 69 | Ao clicar na mensagem recebida pelo agente `destinatario` é possível observar todos os dados contidos na mensagem: 70 | 71 | .. figure:: ../img/janela_mensagem.png 72 | :align: center 73 | :width: 3.0in -------------------------------------------------------------------------------- /docs/user/selecao-de-mensagens.rst: -------------------------------------------------------------------------------- 1 | Seleção de Mensagens 2 | ==================== 3 | 4 | Com PADE é possível implementar filtros de mensagens de maneira simples e direta, por meio da classe Filtro: 5 | 6 | :: 7 | 8 | from pade.acl.filters import Filter 9 | 10 | Filtrando mensagens com o módulo filters 11 | ---------------------------------------- 12 | 13 | Por exemplo para a seguinte mensagem: 14 | 15 | :: 16 | 17 | from pade.acl.messages import ACLMessage 18 | from pade.acl.aid import AID 19 | 20 | message = ACLMessage(ACLMessage.INFORM) 21 | message.set_protocol(ACLMessage.FIPA_REQUEST_PROTOCOL) 22 | message.set_sender(AID('remetente')) 23 | message.add_receiver(AID('destinatario')) 24 | 25 | 26 | Podemos criar o seguinte filtro: 27 | 28 | :: 29 | 30 | from pade.acl.filters import Filter 31 | 32 | f.performative = ACLMessage.REQUEST 33 | 34 | 35 | Em uma sessão do interpretador Python é possível observar o efeito da aplicação do filtro sobre a mensagem: 36 | 37 | .. code-block:: python 38 | 39 | >> f.filter(message) 40 | False 41 | 42 | 43 | Ajustando agora o filtro para outra condição: 44 | 45 | .. code-block:: python 46 | 47 | f.performative = ACLMessage.INFORM 48 | 49 | E aplicando o filtro novamente sobre a mensagem, obtemos um novo resultado: 50 | 51 | .. code-block:: python 52 | 53 | >> f.filter(message) 54 | True 55 | 56 | -------------------------------------------------------------------------------- /docs/user/um-momento.rst: -------------------------------------------------------------------------------- 1 | Um momento Por Favor! 2 | ===================== 3 | 4 | Com PADE é possível adiar a execução de um determinado trecho de código de forma bem simples! É só utilizar o método *call_later()* disponível na classe *Agent()*. 5 | 6 | Como utilizar o método call_later() 7 | ----------------------------------- 8 | 9 | Para utilizar *call_later()*, os seguintes parâmetros devem ser especificados: tempo de atraso, metodo que deve ser chamado após este tempo e argumento do metodo utilizado, *call_later(tempo, metodo, *args)*. 10 | 11 | No código a seguir utiliza *call_later()* é utilizado na classe *Remetente()* no método *on_start()* para assegurar que todos os agentes já foram lançados na plataforma, chamando o método *send_message()* 4,0 segundos após a inicialização dos agentes: 12 | 13 | :: 14 | 15 | from pade.misc.utility import display_message 16 | from pade.misc.common import set_ams, start_loop 17 | from pade.core.agent import Agent 18 | from pade.acl.aid import AID 19 | from pade.acl.messages import ACLMessage 20 | 21 | 22 | class Remetente(Agent): 23 | def __init__(self, aid): 24 | super(Remetente, self).__init__(aid=aid, debug=False) 25 | 26 | def on_start(self): 27 | self.call_later(4.0, self.send_message) 28 | 29 | def send_message(self): 30 | display_message(self.aid.localname, 'Enviando Mensagem') 31 | message = ACLMessage(ACLMessage.INFORM) 32 | message.add_receiver(AID('destinatario')) 33 | message.set_content('Ola') 34 | self.send(message) 35 | 36 | def react(self, message): 37 | pass 38 | 39 | 40 | class Destinatario(Agent): 41 | def __init__(self, aid): 42 | super(Destinatario, self).__init__(aid=aid, debug=False) 43 | 44 | def react(self, message): 45 | display_message(self.aid.localname, 'Mensagem recebida') 46 | 47 | 48 | if __name__ == '__main__': 49 | 50 | set_ams('localhost', 8000, debug=False) 51 | 52 | agentes = list() 53 | 54 | destinatario = Destinatario(AID(name='destinatario')) 55 | destinatario.ams = {'name': 'localhost', 'port': 8000} 56 | agentes.append(destinatario) 57 | 58 | remetente = Remetente(AID(name='remetente')) 59 | remetente.ams = {'name': 'localhost', 'port': 8000} 60 | agentes.append(remetente) 61 | 62 | start_loop(agentes, gui=True) 63 | -------------------------------------------------------------------------------- /examples/agente_teste_1.py: -------------------------------------------------------------------------------- 1 | #!coding=utf-8 2 | # Hello world in PADE! 3 | # 4 | # Criado por Lucas S Melo em 21 de julho de 2015 - Fortaleza, Ceará - Brasil 5 | 6 | from pade.misc.utility import display_message 7 | from pade.misc.common import PSession, start_loop 8 | from pade.core.agent import Agent 9 | from pade.acl.aid import AID 10 | 11 | 12 | class AgenteHelloWorld(Agent): 13 | def __init__(self, aid): 14 | super(AgenteHelloWorld, self).__init__(aid=aid, debug=True) 15 | display_message(self.aid.localname, 'Hello World!') 16 | 17 | 18 | def config_agents(): 19 | 20 | agents = list() 21 | 22 | agente_hello = AgenteHelloWorld(AID(name='agente_hello')) 23 | agents.append(agente_hello) 24 | 25 | s = PSession() 26 | s.add_all_agents(agents) 27 | s.register_user(username='lucassm', email='lucas@gmail.com', password='12345') 28 | 29 | return s 30 | 31 | if __name__ == '__main__': 32 | 33 | start_loop(config_agents()) 34 | -------------------------------------------------------------------------------- /examples/agente_teste_2.py: -------------------------------------------------------------------------------- 1 | #!coding=utf-8 2 | # Hello world temporal in PADE! 3 | # 4 | # Criado por Lucas S Melo em 21 de julho de 2015 - Fortaleza, Ceará - Brasil 5 | 6 | from pade.behaviours.protocols import TimedBehaviour 7 | from pade.misc.utility import display_message 8 | from pade.misc.common import PSession, start_loop 9 | from pade.core.agent import Agent 10 | from pade.acl.aid import AID 11 | 12 | 13 | class ComportTemporal(TimedBehaviour): 14 | def __init__(self, agent, time): 15 | super(ComportTemporal, self).__init__(agent, time) 16 | 17 | def on_time(self): 18 | super(ComportTemporal, self).on_time() 19 | display_message(self.agent.aid.localname, 'Hello World!') 20 | 21 | 22 | class AgenteHelloWorld(Agent): 23 | def __init__(self, aid): 24 | super(AgenteHelloWorld, self).__init__(aid=aid, debug=False) 25 | 26 | comp_temp = ComportTemporal(self, 1.0) 27 | 28 | self.behaviours.append(comp_temp) 29 | 30 | 31 | def config_agents(): 32 | agents = list() 33 | 34 | agente_1 = AgenteHelloWorld(AID(name='agente_1')) 35 | agente_2 = AgenteHelloWorld(AID(name='agente_2')) 36 | 37 | agents.append(agente_1) 38 | agents.append(agente_2) 39 | 40 | s = PSession() 41 | s.add_all_agents(agents) 42 | s.register_user(username='lucassm', email='lucas@gmail.com', password='12345') 43 | 44 | return s 45 | 46 | if __name__ == '__main__': 47 | start_loop(config_agents()) 48 | -------------------------------------------------------------------------------- /examples/agente_teste_3.py: -------------------------------------------------------------------------------- 1 | from pade.misc.common import start_loop, set_ams 2 | from pade.misc.utility import display_message 3 | from pade.core.agent import Agent 4 | from pade.acl.messages import ACLMessage 5 | from pade.acl.aid import AID 6 | from pade.behaviours.protocols import FipaRequestProtocol 7 | from pade.behaviours.protocols import TimedBehaviour 8 | 9 | from datetime import datetime 10 | 11 | 12 | class CompRequest(FipaRequestProtocol): 13 | """Comportamento FIPA Request 14 | do agente Horario""" 15 | def __init__(self, agent): 16 | super(CompRequest, self).__init__(agent=agent, 17 | message=None, 18 | is_initiator=False) 19 | 20 | def handle_request(self, message): 21 | super(CompRequest, self).handle_request(message) 22 | display_message(self.agent.aid.localname, 'mensagem request recebida') 23 | now = datetime.now() 24 | reply = message.create_reply() 25 | reply.set_performative(ACLMessage.INFORM) 26 | reply.set_content(now.strftime('%d/%m/%Y - %H:%M:%S')) 27 | self.agent.send(reply) 28 | 29 | 30 | class CompRequest2(FipaRequestProtocol): 31 | """Comportamento FIPA Request 32 | do agente Relogio""" 33 | def __init__(self, agent, message): 34 | super(CompRequest2, self).__init__(agent=agent, 35 | message=message, 36 | is_initiator=True) 37 | 38 | def handle_inform(self, message): 39 | display_message(self.agent.aid.localname, message.content) 40 | 41 | 42 | class ComportTemporal(TimedBehaviour): 43 | """Comportamento FIPA Request 44 | do agente Relogio""" 45 | def __init__(self, agent, time, message): 46 | super(ComportTemporal, self).__init__(agent, time) 47 | self.message = message 48 | 49 | def on_time(self): 50 | super(ComportTemporal, self).on_time() 51 | self.agent.send(self.message) 52 | 53 | 54 | class AgenteHorario(Agent): 55 | """Classe que define o agente Horario""" 56 | def __init__(self, aid): 57 | super(AgenteHorario, self).__init__(aid=aid, debug=False) 58 | 59 | self.comport_request = CompRequest(self) 60 | 61 | self.behaviours.append(self.comport_request) 62 | 63 | 64 | class AgenteRelogio(Agent): 65 | """Classe que define o agente Relogio""" 66 | def __init__(self, aid): 67 | super(AgenteRelogio, self).__init__(aid=aid) 68 | 69 | # mensagem que requisita horario do horario 70 | message = ACLMessage(ACLMessage.REQUEST) 71 | message.set_protocol(ACLMessage.FIPA_REQUEST_PROTOCOL) 72 | message.add_receiver(AID(name='horario')) 73 | message.set_content('time') 74 | 75 | self.comport_request = CompRequest2(self, message) 76 | self.comport_temp = ComportTemporal(self, 1.0, message) 77 | 78 | self.behaviours.append(self.comport_request) 79 | self.behaviours.append(self.comport_temp) 80 | 81 | 82 | def main(): 83 | 84 | AMS = {'name' : 'localhost', 'port' : 8000} 85 | set_ams(AMS['name'], AMS['port']) 86 | 87 | agentes = list() 88 | 89 | a = AgenteHorario(AID(name='horario')) 90 | a.ams = AMS 91 | agentes.append(a) 92 | 93 | a = AgenteRelogio(AID(name='relogio')) 94 | a.ams = AMS 95 | agentes.append(a) 96 | 97 | start_loop(agentes) 98 | 99 | if __name__ == '__main__': 100 | main() 101 | -------------------------------------------------------------------------------- /examples/agente_teste_4.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from pade.misc.common import start_loop, set_ams 3 | from pade.misc.utility import display_message 4 | from pade.core.agent import Agent 5 | from pade.acl.messages import ACLMessage 6 | from pade.acl.aid import AID 7 | from pade.behaviours.protocols import FipaContractNetProtocol 8 | 9 | 10 | class CompContNet1(FipaContractNetProtocol): 11 | '''CompContNet1 12 | 13 | Comportamento FIPA-ContractNet Iniciante que envia mensagens 14 | CFP para outros agentes alimentadores solicitando propostas 15 | de restauração. Este comportamento também faz a analise das 16 | das propostas e analisa-as selecionando a que julga ser a 17 | melhor''' 18 | 19 | def __init__(self, agent, message): 20 | super(CompContNet1, self).__init__( 21 | agent=agent, message=message, is_initiator=True) 22 | self.cfp = message 23 | 24 | def handle_all_proposes(self, proposes): 25 | """ 26 | """ 27 | 28 | super(CompContNet1, self).handle_all_proposes(proposes) 29 | 30 | melhor_propositor = None 31 | maior_potencia = 0.0 32 | demais_propositores = list() 33 | display_message(self.agent.aid.name, 'Analisando propostas...') 34 | 35 | i = 1 36 | 37 | # lógica de seleção de propostas pela maior potência disponibilizada 38 | for message in proposes: 39 | content = message.content 40 | potencia = float(content) 41 | display_message(self.agent.aid.name, 42 | 'Analisando proposta {i}'.format(i=i)) 43 | display_message(self.agent.aid.name, 44 | 'Potencia Ofertada: {pot}'.format(pot=potencia)) 45 | i += 1 46 | if potencia > maior_potencia: 47 | if melhor_propositor is not None: 48 | demais_propositores.append(melhor_propositor) 49 | 50 | maior_potencia = potencia 51 | melhor_propositor = message.sender 52 | else: 53 | demais_propositores.append(message.sender) 54 | 55 | display_message(self.agent.aid.name, 56 | 'A melhor proposta foi de: {pot} VA'.format( 57 | pot=maior_potencia)) 58 | 59 | if demais_propositores != []: 60 | display_message(self.agent.aid.name, 61 | 'Enviando respostas de recusa...') 62 | resposta = ACLMessage(ACLMessage.REJECT_PROPOSAL) 63 | resposta.set_protocol(ACLMessage.FIPA_CONTRACT_NET_PROTOCOL) 64 | resposta.set_content('') 65 | for agente in demais_propositores: 66 | resposta.add_receiver(agente) 67 | 68 | self.agent.send(resposta) 69 | 70 | if melhor_propositor is not None: 71 | display_message(self.agent.aid.name, 72 | 'Enviando resposta de aceitacao...') 73 | 74 | resposta = ACLMessage(ACLMessage.ACCEPT_PROPOSAL) 75 | resposta.set_protocol(ACLMessage.FIPA_CONTRACT_NET_PROTOCOL) 76 | resposta.set_content('OK') 77 | resposta.add_receiver(melhor_propositor) 78 | self.agent.send(resposta) 79 | 80 | def handle_inform(self, message): 81 | """ 82 | """ 83 | super(CompContNet1, self).handle_inform(message) 84 | 85 | display_message(self.agent.aid.name, 'Mensagem INFORM recebida') 86 | 87 | def handle_refuse(self, message): 88 | """ 89 | """ 90 | super(CompContNet1, self).handle_refuse(message) 91 | 92 | display_message(self.agent.aid.name, 'Mensagem REFUSE recebida') 93 | 94 | def handle_propose(self, message): 95 | """ 96 | """ 97 | super(CompContNet1, self).handle_propose(message) 98 | 99 | display_message(self.agent.aid.name, 'Mensagem PROPOSE recebida') 100 | 101 | 102 | class CompContNet2(FipaContractNetProtocol): 103 | '''CompContNet2 104 | 105 | Comportamento FIPA-ContractNet Participante que é acionado 106 | quando um agente recebe uma mensagem do Tipo CFP enviando logo 107 | em seguida uma proposta e caso esta seja selecinada realiza as 108 | as análises de restrição para que seja possível a restauração''' 109 | 110 | def __init__(self, agent): 111 | super(CompContNet2, self).__init__(agent=agent, 112 | message=None, 113 | is_initiator=False) 114 | 115 | def handle_cfp(self, message): 116 | """ 117 | """ 118 | self.agent.call_later(1.0, self._handle_cfp, message) 119 | 120 | def _handle_cfp(self, message): 121 | """ 122 | """ 123 | super(CompContNet2, self).handle_cfp(message) 124 | self.message = message 125 | 126 | display_message(self.agent.aid.name, 'Mensagem CFP recebida') 127 | 128 | resposta = self.message.create_reply() 129 | resposta.set_performative(ACLMessage.PROPOSE) 130 | resposta.set_content(str(self.agent.pot_disp)) 131 | self.agent.send(resposta) 132 | 133 | def handle_reject_propose(self, message): 134 | """ 135 | """ 136 | super(CompContNet2, self).handle_reject_propose(message) 137 | 138 | display_message(self.agent.aid.name, 139 | 'Mensagem REJECT_PROPOSAL recebida') 140 | 141 | def handle_accept_propose(self, message): 142 | """ 143 | """ 144 | super(CompContNet2, self).handle_accept_propose(message) 145 | 146 | display_message(self.agent.aid.name, 147 | 'Mensagem ACCEPT_PROPOSE recebida') 148 | 149 | resposta = message.create_reply() 150 | resposta.set_performative(ACLMessage.INFORM) 151 | resposta.set_content('OK') 152 | self.agent.send(resposta) 153 | 154 | 155 | class AgenteIniciante(Agent): 156 | 157 | def __init__(self, aid): 158 | super(AgenteIniciante, self).__init__(aid=aid, debug=False) 159 | 160 | message = ACLMessage(ACLMessage.CFP) 161 | message.set_protocol(ACLMessage.FIPA_CONTRACT_NET_PROTOCOL) 162 | message.set_content('60.0') 163 | message.add_receiver(AID('AP1')) 164 | message.add_receiver(AID('AP2')) 165 | 166 | comp = CompContNet1(self, message) 167 | self.behaviours.append(comp) 168 | self.call_later(2.0, comp.on_start) 169 | 170 | 171 | class AgenteParticipante(Agent): 172 | 173 | def __init__(self, aid, pot_disp): 174 | super(AgenteParticipante, self).__init__(aid=aid, debug=False) 175 | 176 | self.pot_disp = pot_disp 177 | 178 | comp = CompContNet2(self) 179 | 180 | self.behaviours.append(comp) 181 | 182 | if __name__ == "__main__": 183 | 184 | AMS = {'name' : 'localhost', 'port' : 8000} 185 | set_ams(AMS['name'], AMS['port']) 186 | 187 | aa_1 = AgenteIniciante(AID(name='AI1')) 188 | aa_1.ams = AMS 189 | 190 | aa_2 = AgenteParticipante(AID(name='AP1'), 150.0) 191 | aa_2.ams = AMS 192 | 193 | aa_3 = AgenteParticipante(AID(name='AP2'), 100.0) 194 | aa_3.ams = AMS 195 | 196 | agents_list = list([aa_1, aa_2, aa_3]) 197 | 198 | start_loop(agents_list) 199 | -------------------------------------------------------------------------------- /examples/agente_teste_5.py: -------------------------------------------------------------------------------- 1 | from pade.misc.common import start_loop, set_ams 2 | from pade.misc.utility import display_message 3 | from pade.core.agent import Agent 4 | from pade.acl.aid import AID 5 | from pade.acl.messages import ACLMessage 6 | from pade.behaviours.protocols import FipaSubscribeProtocol, TimedBehaviour 7 | from numpy import sin 8 | 9 | 10 | class SubscribeInitiator(FipaSubscribeProtocol): 11 | 12 | def __init__(self, agent, message): 13 | super(SubscribeInitiator, self).__init__(agent, 14 | message, 15 | is_initiator=True) 16 | 17 | def handle_agree(self, message): 18 | display_message(self.agent.aid.name, message.content) 19 | 20 | def handle_inform(self, message): 21 | display_message(self.agent.aid.name, message.content) 22 | 23 | 24 | class SubscribeParticipant(FipaSubscribeProtocol): 25 | 26 | def __init__(self, agent): 27 | super(SubscribeParticipant, self).__init__(agent, 28 | message=None, 29 | is_initiator=False) 30 | 31 | def handle_subscribe(self, message): 32 | self.register(message.sender) 33 | display_message(self.agent.aid.name, message.content) 34 | 35 | resposta = message.create_reply() 36 | resposta.set_performative(ACLMessage.AGREE) 37 | resposta.set_content('Pedido de subscricao aceito') 38 | self.agent.send(resposta) 39 | 40 | def handle_cancel(self, message): 41 | self.deregister(self, message.sender) 42 | display_message(self.agent.aid.name, message.content) 43 | 44 | def notify(self, message): 45 | super(SubscribeParticipant, self).notify(message) 46 | 47 | 48 | class Time(TimedBehaviour): 49 | 50 | def __init__(self, agent, notify): 51 | super(Time, self).__init__(agent, 1) 52 | self.notify = notify 53 | self.inc = 0 54 | 55 | def on_time(self): 56 | super(Time, self).on_time() 57 | message = ACLMessage(ACLMessage.INFORM) 58 | message.set_protocol(ACLMessage.FIPA_SUBSCRIBE_PROTOCOL) 59 | message.set_content(str(sin(self.inc))) 60 | 61 | self.notify(message) 62 | self.inc += 0.1 63 | 64 | 65 | class AgenteInitiator(Agent): 66 | 67 | def __init__(self, aid, message): 68 | super(AgenteInitiator, self).__init__(aid) 69 | self.protocol = SubscribeInitiator(self, message) 70 | self.behaviours.append(self.protocol) 71 | 72 | 73 | class AgenteParticipante(Agent): 74 | 75 | def __init__(self, aid): 76 | super(AgenteParticipante, self).__init__(aid) 77 | 78 | self.protocol = SubscribeParticipant(self) 79 | self.timed = Time(self, self.protocol.notify) 80 | 81 | self.behaviours.append(self.protocol) 82 | self.behaviours.append(self.timed) 83 | 84 | if __name__ == '__main__': 85 | 86 | set_ams('localhost', 5000, debug=False) 87 | 88 | editor = AgenteParticipante(AID('editor')) 89 | editor.ams = {'name': 'localhost', 'port': 5000} 90 | 91 | msg = ACLMessage(ACLMessage.SUBSCRIBE) 92 | msg.set_protocol(ACLMessage.FIPA_SUBSCRIBE_PROTOCOL) 93 | msg.set_content('Pedido de subscricao') 94 | msg.add_receiver('editor') 95 | 96 | ass1 = AgenteInitiator(AID('assinante_1'), msg) 97 | ass1.ams = {'name': 'localhost', 'port': 5000} 98 | 99 | ass2 = AgenteInitiator(AID('assinante_2'), msg) 100 | ass2.ams = {'name': 'localhost', 'port': 5000} 101 | 102 | agentes = [editor, ass1, ass2] 103 | 104 | start_loop(agentes, gui=True) 105 | -------------------------------------------------------------------------------- /examples/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/examples/database.db -------------------------------------------------------------------------------- /examples/start_ams.py: -------------------------------------------------------------------------------- 1 | from pade.misc.common import set_ams, start_loop 2 | 3 | if __name__ == '__main__': 4 | set_ams('localhost', 8000) 5 | start_loop(list(), gui=True) 6 | -------------------------------------------------------------------------------- /pade/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from twisted.internet import reactor 3 | except: 4 | pass 5 | -------------------------------------------------------------------------------- /pade/acl/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/acl/__init__.py -------------------------------------------------------------------------------- /pade/acl/aid.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Framework para Desenvolvimento de Agentes Inteligentes PADE 5 | 6 | # The MIT License (MIT) 7 | 8 | # Copyright (c) 2015 Lucas S Melo 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | # THE SOFTWARE. 27 | 28 | 29 | import random 30 | 31 | class AID(object): 32 | def __init__(self, name=None, addresses=None, resolvers=None, userDefinedProperties=None): 33 | """ 34 | Agent Identifier Class 35 | Optional parameters: 36 | String name with the form: localname@myAdress:port 37 | String[] addresses 38 | String[] resolvers 39 | ContentObject co 40 | """ 41 | 42 | if name is not None: 43 | if '@' in name: 44 | self.name = name 45 | self.localname, adress = self.name.split('@') 46 | self.addresses = [adress] 47 | if ':' in adress: 48 | self.host, self.port = adress.split(':') 49 | self.port = int(self.port) 50 | else: 51 | self.host, self.port = None, None 52 | else: 53 | self.localname = name 54 | self.host = 'localhost' 55 | self.port = random.randint(1024, 64024) 56 | self.name = self.localname + '@' + self.host + ':' + str(self.port) 57 | self.addresses = [self.host + ':' + str(self.port)] 58 | else: 59 | self.name = None # string 60 | if resolvers is not None: 61 | self.resolvers = resolvers 62 | else: 63 | self.resolvers = list() # AID 64 | if userDefinedProperties is not None: 65 | self.userDefinedProperties = userDefinedProperties 66 | else: 67 | self.userDefinedProperties = list() # properties 68 | 69 | def getName(self): 70 | """ 71 | returns name of the agent (string) 72 | """ 73 | return self.name 74 | 75 | def getLocalName(self): 76 | ''' 77 | returns the localname of the agent 78 | ''' 79 | return self.localname 80 | 81 | def setLocalName(self, name): 82 | """ 83 | sets local name of the agent (string) 84 | """ 85 | self.localname = name 86 | self.name = self.localname + '@' + self.host + ':' + str(self.port) 87 | 88 | def getHost(self): 89 | """ 90 | gets host of the agent (string) 91 | """ 92 | return self.host 93 | 94 | def setHost(self, host): 95 | """ 96 | sets host of the agent (string) 97 | """ 98 | self.host = host 99 | self.name = self.localname + '@' + self.host + ':' + str(self.port) 100 | 101 | def getPort(self): 102 | """ 103 | gets port of the agent (string) 104 | """ 105 | return self.port 106 | 107 | def setPort(self, port): 108 | """ 109 | sets port of the agent (string) 110 | """ 111 | self.port = port 112 | self.name = self.localname + '@' + self.host + ':' + str(self.port) 113 | 114 | def getAddresses(self): 115 | """ 116 | returns a list of addreses 117 | """ 118 | return self.addresses 119 | 120 | def addAddress(self, addr): 121 | """ 122 | adds a new address to the addresses list 123 | """ 124 | self.addresses.append(addr) 125 | 126 | def getResolvers(self): 127 | """ 128 | returns a list of resolvers 129 | """ 130 | return self.resolvers 131 | 132 | def addResolvers(self, resolver): 133 | """ 134 | adds a new resolver to the resolvers list 135 | """ 136 | self.resolvers.append(resolver) 137 | 138 | def getProperties(self): 139 | return self.userDefinedProperties 140 | 141 | def addProperty(self, prop): 142 | self.userDefinedProperties.append(prop) 143 | 144 | def match(self, other): 145 | """ 146 | returns True if two AIDs are similar 147 | else returns False 148 | """ 149 | 150 | if other is None: 151 | return True 152 | 153 | if (self.getName() is not None and other.getName() is not None 154 | and not (other.getName() in self.getName())): 155 | return False 156 | if (len(self.getAddresses()) > 0 and len(other.getAddresses()) > 0): 157 | for oaddr in other.getAddresses(): 158 | found = False 159 | for saddr in self.getAddresses(): 160 | if (oaddr in saddr): 161 | found = True 162 | if not found: 163 | return False 164 | if (len(self.getResolvers()) > 0 and len(other.getResolvers()) > 0): 165 | for oaddr in other.getResolvers(): 166 | found = False 167 | for saddr in self.getResolvers(): 168 | if (oaddr in saddr): 169 | found = True 170 | if not found: 171 | return False 172 | if (len(self.getProperties()) > 0 and len(other.getProperties()) > 0): 173 | for oaddr in other.getProperties(): 174 | found = False 175 | for saddr in self.getProperties(): 176 | if (oaddr in saddr): 177 | found = True 178 | if not found: 179 | return False 180 | return True 181 | 182 | def __eq__(self, other): 183 | """ 184 | Comparision operator (==) 185 | returns True if two AIDs are equal 186 | else returns False 187 | """ 188 | if other is None: 189 | return False 190 | 191 | if (self.getName() is not None and other.getName() is not None 192 | and self.getName() != other.getName()): 193 | return False 194 | addr1 = self.getAddresses() 195 | addr2 = other.getAddresses() 196 | addr1.sort() 197 | addr2.sort() 198 | if addr1 != addr2: 199 | return False 200 | 201 | res1 = self.getResolvers() 202 | res2 = other.getResolvers() 203 | res1.sort() 204 | res2.sort() 205 | if res1 != res2: 206 | return False 207 | 208 | return True 209 | 210 | def __ne__(self, other): 211 | """ 212 | != operator 213 | returns False if two AIDs are equal 214 | else returns True 215 | """ 216 | 217 | return not (self == other) 218 | 219 | def __hash__(self): 220 | h = hash(self.name) 221 | for i in self.addresses: 222 | h = h + hash(i) 223 | for i in self.resolvers: 224 | h = h + hash(i) 225 | for i in self.userDefinedProperties: 226 | h = h + hash(i) 227 | return h 228 | 229 | def __str__(self): 230 | """ 231 | returns a printable version of an AID 232 | """ 233 | sb = "" 234 | if self.getName() is not None: 235 | sb = sb + ":name " + str(self.getName()) + "\n" 236 | if self.getAddresses() != []: 237 | sb = sb + ":addresses \n(sequence\n" 238 | for i in self.getAddresses(): 239 | sb = sb + str(i) + '\n' 240 | sb = sb + ")\n" 241 | if self.getResolvers() != []: 242 | sb = sb + ":resolvers \n(sequence\n" 243 | for i in self.getResolvers(): 244 | sb = sb + str(i) + '\n' 245 | sb = sb + ")\n" 246 | if sb != "": 247 | sb = "(agent-identifier\n" + sb + ")\n" 248 | else: 249 | sb = "None" 250 | 251 | return sb 252 | 253 | def as_xml(self): 254 | """ 255 | returns a printable version of an AID in XML 256 | """ 257 | sb = "\n\t" + self.encodeTag("name", self.getName()) + "\n" 258 | sb = sb + "\t\n" 259 | 260 | addresses = self.getAddresses() 261 | for addr in addresses: 262 | sb = sb + "\t\t" + self.encodeTag("url", addr) + "\n" 263 | 264 | sb = sb + "\t\n" 265 | 266 | sb = sb + "\n" 267 | 268 | return sb 269 | 270 | def encodeTag(self, tag, content): 271 | """ 272 | encodes a content between 2 XML tags using the tag parameter 273 | 274 | content 275 | 276 | return string 277 | """ 278 | sb = "<" + tag + ">" + content + "" 279 | 280 | return sb 281 | 282 | if __name__ == '__main__': 283 | 284 | agentname = AID('lucas') 285 | print agentname.getName() 286 | print agentname.getHost() 287 | print agentname.getPort() 288 | print agentname.as_xml() 289 | print agentname.__str__() -------------------------------------------------------------------------------- /pade/acl/filters.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Framework para Desenvolvimento de Agentes Inteligentes PADE 5 | 6 | # The MIT License (MIT) 7 | 8 | # Copyright (c) 2015 Lucas S Melo 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | # THE SOFTWARE. 27 | 28 | from pade.acl.aid import AID 29 | from pade.acl.messages import ACLMessage 30 | 31 | class Filter(): 32 | ''' 33 | Esta classe instacia um objeto filtro que tem como proposito 34 | selecionar mensagens com atributos pré-estabelecidos neste objeto 35 | ''' 36 | def __init__(self): 37 | self.conversationID = None 38 | self.sender = None 39 | self.performative = None 40 | self.protocol = None 41 | 42 | def set_sender(self, aid): 43 | self.sender = aid 44 | 45 | def set_performative(self, performative): 46 | self.performative = performative 47 | 48 | def setConversationID(self, conversationID): 49 | self.conversationID = conversationID 50 | 51 | def set_protocol(self, protocol): 52 | self.protocol = protocol 53 | 54 | def filter(self, message): 55 | state = True 56 | 57 | if self.conversationID != None and self.conversationID != message.conversationID: 58 | state = False 59 | 60 | if self.sender != None and self.sender != message.sender: 61 | state = False 62 | 63 | if self.performative != None and self.performative != message.performative: 64 | state = False 65 | 66 | if self.protocol != None and self.protocol != message.protocol: 67 | state = False 68 | 69 | return state 70 | 71 | if __name__ == '__main__': 72 | message = ACLMessage(ACLMessage.REQUEST) 73 | message.set_sender(AID('lucas')) 74 | message.add_receiver('allana') 75 | message.set_protocol(ACLMessage.FIPA_REQUEST_PROTOCOL) 76 | 77 | filtro = Filter() 78 | filtro.set_protocol(ACLMessage.FIPA_REQUEST_PROTOCOL) 79 | 80 | if filtro.filter(message): 81 | print message.as_xml() 82 | else: 83 | print 'A mensagem foi barrada pelo protocolo' 84 | -------------------------------------------------------------------------------- /pade/behaviours/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/behaviours/__init__.py -------------------------------------------------------------------------------- /pade/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/core/__init__.py -------------------------------------------------------------------------------- /pade/core/ams.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Framework para Desenvolvimento de Agentes Inteligentes PADE 4 | 5 | # The MIT License (MIT) 6 | 7 | # Copyright (c) 2015 Lucas S Melo 8 | 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | 16 | # The above copyright notice and this permission notice shall be included in 17 | # all copies or substantial portions of the Software. 18 | 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | # THE SOFTWARE. 26 | 27 | """ 28 | Módulo de Definição do AMS 29 | -------------------------- 30 | 31 | Neste módulo estão definidos os comportamentos do agente 32 | AMS. 33 | """ 34 | 35 | from twisted.internet import protocol, reactor 36 | from twisted.enterprise import adbapi 37 | 38 | from pickle import dumps, loads 39 | from uuid import uuid4 40 | import datetime 41 | 42 | from pade.core.peer import PeerProtocol 43 | from pade.acl.aid import AID 44 | from pade.acl.messages import ACLMessage 45 | from pade.misc.utility import display_message 46 | from pade.web.flask_server import db, Agent, Message 47 | 48 | 49 | class AgentManagementProtocol(PeerProtocol): 50 | 51 | """Esta classe implementa os comportamentos de um agente AMS 52 | 53 | A princiapal funcionalidade do AMS é registrar todos os agentes que 54 | estão conectados ao sistema e atualizar a tabela de agentes de cada 55 | um deles sempre que um novo agente se conectar. 56 | """ 57 | 58 | def __init__(self, fact): 59 | """ 60 | Este método Inicializa o objeto que implementa a classe AMS 61 | 62 | Parâmetros 63 | ---------- 64 | factory: factory do protocolo do AMS 65 | """ 66 | PeerProtocol.__init__(self, fact) 67 | 68 | def connectionMade(self): 69 | """Este método é executado sempre que uma conexão é realizada 70 | com o agente AMS 71 | """ 72 | # armazena as informações do agente conectado por meio do metodo 73 | # transport.getPeer() 74 | peer = self.transport.getPeer() 75 | 76 | # laço for percorre as mensagens armazenadas na variavel 77 | # fact.messages e caso alguma mensagem seja para o agente 78 | # conectado esta será enviada 79 | for message in self.fact.messages: 80 | if int(message[0].port) == int(peer.port): 81 | # envia a mensagem por meio do metodo sendLine() 82 | self.send_message(message[1].get_message()) 83 | # remove a mesagem enviada da variavel fact.messages 84 | self.fact.messages.remove(message) 85 | display_message( 86 | self.fact.aid.name, 87 | 'Mensagem enviada ao agente ' + message[0].name) 88 | break 89 | reactor.callLater(2.0, self.close_con) 90 | 91 | def close_con(self): 92 | self.transport.loseConnection() 93 | 94 | def connectionLost(self, reason): 95 | """Este método é executado sempre que uma conexão é perdida 96 | com o agente AMS. Isso geralmente acontece quando o 97 | recebimento de uma mensagem é encerrado 98 | """ 99 | if self.message is not None: 100 | message = PeerProtocol.connectionLost(self, reason) 101 | 102 | # carrega o conteudo da mensagem recebida 103 | content = loads(message.content) 104 | # se a mensagem for de identificação, lança o comportamento de 105 | # identificação 106 | if content['ref'] == 'IDENT': 107 | self.handle_identif(content['aid']) 108 | # se não, lança o comportamento de armazenamento de mensagens 109 | elif content['ref'] == 'MESSAGE': 110 | self.handle_store_messages(content['message'], message.sender) 111 | 112 | # reinicia a variável que armazena a mensagem recebida 113 | self.message = None 114 | 115 | def send_message(self, message): 116 | PeerProtocol.send_message(self, message) 117 | 118 | def lineReceived(self, line): 119 | """Quando uma mensagem é enviada ao AMS este método é executado. 120 | Quando em fase de identificação, o AMS registra o agente 121 | em sua tabela de agentes ativos 122 | """ 123 | 124 | # recebe uma parte da mensagem enviada 125 | PeerProtocol.lineReceived(self, line) 126 | 127 | def handle_identif(self, aid): 128 | """Este método é utilizado para cadastrar o agente que esta se identificando 129 | na tabela de agentes ativos. 130 | """ 131 | if aid.name in self.fact.table: 132 | display_message( 133 | 'AMS', 'Falha na Identificacao do agente ' + aid.name) 134 | 135 | # prepara mensagem de resposta 136 | message = ACLMessage(ACLMessage.REFUSE) 137 | message.set_sender(self.fact.aid) 138 | message.add_receiver(aid) 139 | message.set_content( 140 | 'Ja existe um agente com este identificador. Por favor, escolha outro.') 141 | # envia mensagem 142 | self.send_message(message.get_message()) 143 | return 144 | self.aid = aid 145 | self.fact.table[self.aid.name] = self.aid 146 | display_message( 147 | 'AMS', 'Agente ' + aid.name + ' identificado com sucesso') 148 | 149 | # prepara mensagem de resposta 150 | message = ACLMessage(ACLMessage.INFORM) 151 | message.set_sender(self.fact.aid) 152 | for receiver in self.fact.table.values(): 153 | message.add_receiver(receiver) 154 | 155 | message.set_content(dumps(self.fact.table)) 156 | self.fact.broadcast_message(message) 157 | 158 | def handle_store_messages(self, message, sender): 159 | m = Message(sender=message.sender.localname, 160 | date=datetime.datetime.now(), 161 | performative=message.performative, 162 | protocol=message.protocol, 163 | content=message.content, 164 | conversation_id=message.conversationID, 165 | message_id=message.messageID, 166 | ontology=message.ontology, 167 | language=message.language) 168 | 169 | receivers = list() 170 | for receiver in message.receivers: 171 | receivers.append(receiver.localname) 172 | m.receivers = receivers 173 | 174 | a = Agent.query.filter_by(name=sender.localname).all()[0] 175 | m.agent_id = a.id 176 | 177 | db.session.add(m) 178 | db.session.commit() 179 | 180 | display_message(self.fact.aid.name, 'Message stored') 181 | 182 | class AgentManagementFactory(protocol.ClientFactory): 183 | 184 | """Esta classe implementa as ações e atributos do protocolo AMS 185 | sua principal função é armazenar informações importantes ao protocolo de comunicação 186 | do agente AMS 187 | """ 188 | 189 | def __init__(self, port, debug): 190 | 191 | self.state = 'IDENT' 192 | self.debug = debug 193 | # dictionary que tem como keys o nome dos agentes e como valor o objeto aid que identifica o agente 194 | # indicado pela chave 195 | self.table = {} 196 | 197 | # lista que armazena as mensagens recebidas pelo AMS, devera ser utilizada posteriormente pelo 198 | # serviço de visualização de mensagens 199 | self.messages = [] 200 | 201 | # aid do agente AMS 202 | self.aid = AID(name='AMS' + '@' + 'localhost' + ':' + str(port)) 203 | 204 | display_message( 205 | 'AMS', 'AMS esta servindo na porta ' + str(self.aid.port)) 206 | 207 | # instancia o objeto que realizará a conexão com o banco de dados 208 | self.conn = adbapi.ConnectionPool( 209 | 'sqlite3', 'database.db', check_same_thread=False) 210 | self.d = self.createAgentsTable() 211 | self.d.addCallback(self.insert_agent) 212 | 213 | # Inicialização do comportamento de verificação das conexões 214 | reactor.callLater(5, self.connection_test_send) 215 | 216 | def buildProtocol(self, addr): 217 | # instancia do objeto que implementa o protocolo AMS 218 | return AgentManagementProtocol(self) 219 | 220 | def clientConnectionLost(self, connector, reason): 221 | pass 222 | 223 | def clientConnectionFailed(self, connector, reason): 224 | for name, aid in self.table.iteritems(): 225 | if aid.port == connector.port: 226 | display_message( 227 | self.aid.name, 'O agente ' + aid.name + ' esta desconectado.') 228 | print reason 229 | self.table.pop(name) 230 | message = ACLMessage(ACLMessage.INFORM) 231 | message.set_sender(self.aid) 232 | message.set_content(dumps(self.table)) 233 | self.broadcast_message(message) 234 | break 235 | 236 | def connection_test_send(self): 237 | """Este método é executado ciclicamente com o objetivo de 238 | verificar se os agentes estão conectados 239 | """ 240 | if self.debug: 241 | display_message(self.aid.name, 242 | 'Enviando mensagens de verificação da conexão...') 243 | for name, aid in self.table.iteritems(): 244 | if self.debug: 245 | display_message( 246 | self.aid.name, 247 | 'Tentando conexão com agente ' + name + '...') 248 | reactor.connectTCP(aid.host, int(aid.port), self) 249 | else: 250 | reactor.callLater(1, self.connection_test_send) 251 | 252 | # envia tabela de agentes atualizada a todos os agentes com conexao 253 | # ativa com o AMS 254 | def broadcast_message(self, message): 255 | """Este método é utilizado para o envio de mensagems de atualização da 256 | tabela de agentes ativos sempre que um novo agente é connectado. 257 | """ 258 | for name, aid in self.table.iteritems(): 259 | reactor.connectTCP( 260 | aid.host, int(aid.port), self) 261 | self.messages.append((aid, message)) 262 | 263 | # ======================================================================= 264 | # Estes métodos são utilizados para a comunicação do loop 265 | # twisted com o banco de dados 266 | # ======================================================================= 267 | def createAgentsTable(self): 268 | display_message( 269 | self.aid.name, 'Tabela de agentes criada no banco de dados.') 270 | return self.conn.runInteraction(self._cretateAgentsTable) 271 | 272 | def _cretateAgentsTable(self, transaction): 273 | display_message( 274 | self.aid.name, 'Tabela de agentes criada no banco de dados.') 275 | self.dbid = 'agents_' + str(uuid4().time) 276 | s = 'CREATE TABLE ' + self.dbid + '( id INTEGER PRIMARY KEY AUTOINCREMENT, ' +\ 277 | 'name VARCHAR(20), ' +\ 278 | 'port INTEGER);' 279 | transaction.execute(s) 280 | #transaction.execute('INSERT INTO ' + self.dbid + ' VALUES ' + '') 281 | 282 | def insert_agent(self): 283 | pass 284 | -------------------------------------------------------------------------------- /pade/core/peer.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Framework para Desenvolvimento de Agentes Inteligentes PADE 5 | 6 | # The MIT License (MIT) 7 | 8 | # Copyright (c) 2015 Lucas S Melo 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | # THE SOFTWARE. 27 | 28 | 29 | from twisted.protocols.basic import LineReceiver 30 | from pade.acl.messages import ACLMessage 31 | 32 | 33 | class PeerProtocol(LineReceiver): 34 | """docstring for PeerProtocol""" 35 | 36 | message = None 37 | 38 | def __init__(self, fact): 39 | self.fact = fact 40 | 41 | def connectionMade(self): 42 | peer = self.transport.getPeer() 43 | 44 | sended_message = None 45 | 46 | for message in self.fact.messages: 47 | if int(message[0].port) == int(peer.port): 48 | if str(message[0].host) == 'localhost' and str(peer.host) == '127.0.0.1' or \ 49 | str(message[0].host) == str(peer.host): 50 | self.send_message(message[1].get_message()) 51 | sended_message = message 52 | break 53 | if sended_message is not None: 54 | self.fact.messages.remove(sended_message) 55 | 56 | def connectionLost(self, reason): 57 | if self.message is not None: 58 | message = ACLMessage() 59 | message.set_message(self.message) 60 | return message 61 | 62 | def lineReceived(self, line): 63 | # recebe uma parte da mensagem enviada 64 | if self.message is not None: 65 | self.message += line 66 | else: 67 | self.message = line 68 | 69 | def send_message(self, message): 70 | l = len(message) 71 | if l > 14384: 72 | 73 | while len(message) > 0: 74 | message, m = message[14384:], message[:14384] 75 | self.sendLine(m) 76 | else: 77 | self.sendLine(message) 78 | 79 | self.transport.loseConnection() 80 | -------------------------------------------------------------------------------- /pade/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/database.db -------------------------------------------------------------------------------- /pade/db/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/db/__init__.py -------------------------------------------------------------------------------- /pade/gui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/gui/__init__.py -------------------------------------------------------------------------------- /pade/gui/img/preferencias.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/gui/img/preferencias.png -------------------------------------------------------------------------------- /pade/images/interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/images/interface.png -------------------------------------------------------------------------------- /pade/images/pade_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/images/pade_logo.png -------------------------------------------------------------------------------- /pade/misc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/misc/__init__.py -------------------------------------------------------------------------------- /pade/misc/common.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Framework para Desenvolvimento de Agentes Inteligentes PADE 5 | 6 | # The MIT License (MIT) 7 | 8 | # Copyright (c) 2015 Lucas S Melo 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | # THE SOFTWARE. 27 | 28 | """ 29 | Módulo de Utilidades 30 | -------------------- 31 | 32 | Este módulo Python disponibiliza métodos de configuração 33 | do loop twisted onde os agentes serão executados e caso se utilize 34 | interface gráfica, é neste módulo que o loop Qt4 é integrado ao 35 | loop Twisted, além de disponibilizar métodos para lançamento do AMS 36 | e Sniffer por linha de comando e para exibição de informações no 37 | terminal 38 | 39 | @author: lucas 40 | """ 41 | 42 | import twisted.internet 43 | from pade.acl.aid import AID 44 | from pade.core.ams import AgentManagementFactory 45 | from pade.core.sniffer import SnifferFactory 46 | 47 | from pade.web.flask_server import run_server, db 48 | from pade.web.flask_server import Session, Agent, User 49 | 50 | import optparse 51 | import multiprocessing 52 | import uuid 53 | import datetime 54 | 55 | 56 | class FlaskServerProcess(multiprocessing.Process): 57 | """ 58 | Esta classe implementa a thread que executa 59 | o servidor web com o aplicativo Flask 60 | """ 61 | def __init__(self): 62 | multiprocessing.Process.__init__(self) 63 | 64 | def run(self): 65 | run_server() 66 | 67 | class PSession(object): 68 | 69 | agents = list() 70 | users = list() 71 | 72 | def __init__(self, name=None, ams=None): 73 | if name is not None: 74 | self.name = name 75 | else: 76 | self.name = str(uuid.uuid1())[:13] 77 | 78 | if ams is not None: 79 | self.ams = ams 80 | else: 81 | self.ams = {'name': 'localhost', 'port': 8000} 82 | 83 | def add_agent(self, agent): 84 | agent.ams = self.ams 85 | self.agents.append(agent) 86 | 87 | 88 | def add_all_agents(self, agents): 89 | for agent in agents: 90 | agent.ams = self.ams 91 | self.agents = self.agents + agents 92 | 93 | def register_user(self, username, email, password): 94 | self.users.append({'username' : username, 'email' : email, 'password' : password}) 95 | 96 | def start_loop(session, debug=False): 97 | """ 98 | Lança o loop do twisted integrado com o loop do Qt se a opção GUI for 99 | verdadeira, se não lança o loop do Twisted 100 | """ 101 | 102 | # instancia o factory do agente AMS e chama o metodo listenTCP 103 | # do Twisted para o agente AMS 104 | amsFactory = AgentManagementFactory(session.ams['port'], debug) 105 | twisted.internet.reactor.listenTCP(session.ams['port'], amsFactory) 106 | 107 | # instancia a classe que lança o processo 108 | # com o servidor web com o aplicativo Flask 109 | p1 = FlaskServerProcess() 110 | p1.daemon = True 111 | 112 | p1.start() 113 | 114 | db.drop_all() 115 | db.create_all() 116 | 117 | # registra uma nova sessão no banco de dados 118 | s = Session(name=session.name, 119 | date=datetime.datetime.now(), 120 | state = 'Ativo') 121 | db.session.add(s) 122 | db.session.commit() 123 | 124 | # registra os agentes no banco de dados 125 | i = 1 126 | agents_db = list() 127 | for agent in session.agents: 128 | twisted.internet.reactor.callLater(i, listen_agent, agent) 129 | a = Agent(name=agent.aid.localname, 130 | session_id=s.id, 131 | date=datetime.datetime.now(), 132 | state = 'Ativo') 133 | agents_db.append(a) 134 | i += 0.2 135 | 136 | db.session.add_all(agents_db) 137 | db.session.commit() 138 | 139 | # registra os usuarios no banco de dados 140 | users_db = list() 141 | for user in session.users: 142 | u = User(username=user['username'], 143 | email=user['email'], 144 | password=user['password'], 145 | session_id=s.id) 146 | users_db.append(u) 147 | 148 | db.session.add_all(users_db) 149 | db.session.commit() 150 | 151 | # lança o loop do Twisted 152 | twisted.internet.reactor.run() 153 | 154 | 155 | def listen_agent(agent): 156 | # Conecta o agente ao AMS 157 | twisted.internet.reactor.connectTCP( 158 | agent.ams['name'], agent.ams['port'], agent.agentInstance) 159 | # Conecta o agente à porta que será utilizada para comunicação 160 | twisted.internet.reactor.listenTCP(agent.aid.port, agent.agentInstance) 161 | -------------------------------------------------------------------------------- /pade/misc/utility.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Framework para Desenvolvimento de Agentes Inteligentes PADE 5 | 6 | # The MIT License (MIT) 7 | 8 | # Copyright (c) 2015 Lucas S Melo 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | # THE SOFTWARE. 27 | 28 | from datetime import datetime 29 | 30 | def display_message(name, data): 31 | """ 32 | Metodo utilizado para exibicao de mensagens no console de comandos 33 | """ 34 | date = datetime.now() 35 | date = date.strftime('%d/%m/%Y %H:%M:%S --> ') 36 | print '[' + name + '] ' + date + str(data) 37 | -------------------------------------------------------------------------------- /pade/tests/v1/script_2.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from utils import set_ams, config_loop, start_loop, display_message 5 | config_loop(gui=True) 6 | 7 | from agent import Agent 8 | from messages import ACLMessage 9 | from aid import AID 10 | from pickle import dumps, loads 11 | from time import sleep 12 | 13 | class Consumer(Agent): 14 | 15 | def __init__(self, aid, bookStores): 16 | Agent.__init__(self, aid) 17 | 18 | self.bookStores = bookStores 19 | self.bestPropose = None 20 | self.bestBookStore = None 21 | self.proposes = [] 22 | self.messages = [] 23 | self.sends = 0 24 | self.receives = 0 25 | 26 | def consult(self, pedido): 27 | message = ACLMessage(ACLMessage.CALL_FOR_PROPOSAL) 28 | for i in self.bookStores: 29 | message.add_receiver(i) 30 | message.set_content(dumps(pedido)) 31 | self.sends = len(self.bookStores) 32 | self.send(message) 33 | 34 | def buy(self, proposta): 35 | message = ACLMessage(ACLMessage.REQUEST) 36 | message.add_receiver(proposta['book store']) 37 | message.addContent(dumps(proposta)) 38 | self.send(message) 39 | 40 | def analisys(self): 41 | self.bestPropose = self.messages[0] 42 | for message in self.messages: 43 | propose = loads(message.content) 44 | if propose['how much is'] < loads(self.messages[0].content)['how much is']: 45 | self.bestPropose = message 46 | 47 | return self.bestPropose 48 | 49 | def on_start 50 | on_start(self): 51 | Agent.on_start 52 | on_start(self) 53 | sleep(1) 54 | pedido = {'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 5} 55 | self.consult(pedido) 56 | 57 | def react(self, message): 58 | 59 | if message.performative == ACLMessage.PROPOSE or message.performative == ACLMessage.REJECT_PROPOSAL: 60 | self.receives += 1 61 | self.messages.append(message) 62 | display_message(self.aid.name, 'Received Propose') 63 | print str(loads(message.content)) 64 | 65 | if self.receives == self.sends: 66 | message = self.analisys() 67 | display_message(self.aid.name, 'Best Propose Selected:') 68 | propose = loads(message.content) 69 | print str(propose) 70 | 71 | class BookStore(Agent): 72 | def __init__(self, aid, booksList): 73 | Agent.__init__(self, aid) 74 | 75 | self.booksList = booksList 76 | 77 | def on_start 78 | on_start(self): 79 | pass 80 | 81 | def react(self, message): 82 | display_message(self.aid.name, 'Received Purchase Order') 83 | self.message = message 84 | if message.performative == ACLMessage.CALL_FOR_PROPOSAL: 85 | self.pedido = loads(message.content) 86 | self.analisys(self.pedido) 87 | 88 | def analisys(self, pedido): 89 | for book in self.booksList: 90 | if book['title'] == pedido['title'] and book['author'] == pedido['author']: 91 | if book['qtd'] >= pedido['qtd']: 92 | message = ACLMessage(ACLMessage.PROPOSE) 93 | message.add_receiver(self.message.sender) 94 | book['book store'] = self.aid.name 95 | message.set_content(dumps(book)) 96 | self.send(message) 97 | else: 98 | message = ACLMessage(ACLMessage.REJECT_PROPOSAL) 99 | message.add_receiver(self.message.sender) 100 | message.set_content('Request Refused') 101 | self.send(message) 102 | 103 | if __name__ == '__main__': 104 | 105 | 106 | booksList_Saraiva = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 53.50}, 107 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 33.70}, 108 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10,'how much is' : 23.80} 109 | ] 110 | 111 | bookslist_Cultura = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 43.50}, 112 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 31.70}, 113 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10, 'how much is' : 53.80} 114 | ] 115 | 116 | bookslist_Nobel = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 63.50}, 117 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 35.70}, 118 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10, 'how much is' : 33.80} 119 | ] 120 | 121 | bookStoresInfo = [(AID(name='Saraiva'), booksList_Saraiva), 122 | (AID(name='Cultura'), bookslist_Cultura), 123 | (AID(name='Nobel'), bookslist_Nobel)] 124 | 125 | set_ams('localhost', 8000) 126 | 127 | for bookStore in bookStoresInfo: 128 | agent = BookStore(bookStore[0], bookStore[1]) 129 | agent.set_ams('localhost', 8000) 130 | agent.start() 131 | 132 | consumidor = Consumer(AID('Lucas'), ['Saraiva', 'Cultura', 'Nobel']) 133 | consumidor.set_ams('localhost', 8000) 134 | consumidor.start() 135 | 136 | start_loop() -------------------------------------------------------------------------------- /pade/tests/v1/script_2_revisado.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from utils import display_message, set_ams, start_loop, config_loop 4 | config_loop(gui=True) 5 | from agent import Agent 6 | from messages import ACLMessage 7 | from aid import AID 8 | from protocols import FipaContractNetProtocol 9 | from filters import Filter 10 | from pickle import loads, dumps 11 | from time import sleep 12 | 13 | #=============================================================================== 14 | # Note, o que é necessário para criar um agente com comportamentos padronizados 15 | # em protocolos? 16 | # Primeiro, é preciso definir a classe protocolo 17 | # Segundo é preciso associar esta classe protocolo como um comportamento do 18 | # agente 19 | #=============================================================================== 20 | 21 | 22 | class ComportamentoAgenteConsumidor(FipaContractNetProtocol): 23 | def __init__(self, agent, message): 24 | super(ComportamentoAgenteConsumidor, self).__init__(agent, message, is_initiator=True) 25 | self.bestPropose = None 26 | self.bestBookStore = None 27 | 28 | def handle_propose(self, message): 29 | FipaContractNetProtocol.handle_propose(self, message) 30 | display_message(self.agent.aid.name, 'Proposta Recebida') 31 | 32 | def handle_all_proposes(self, proposes): 33 | FipaContractNetProtocol.handle_all_proposes(self, proposes) 34 | 35 | try: 36 | 37 | self.bestPropose = proposes[0] 38 | 39 | for propose in proposes: 40 | content = loads(propose.content) 41 | if content['how much is'] < loads(self.bestPropose.content)['how much is']: 42 | self.bestPropose = propose 43 | 44 | response = self.bestPropose.create_reply() 45 | response.set_performative(ACLMessage.ACCEPT_PROPOSAL) 46 | response.set_content('Proposta Aceita') 47 | self.agent.send(response) 48 | 49 | for propose in proposes: 50 | if propose != self.bestPropose: 51 | response = propose.create_reply() 52 | response.set_performative(ACLMessage.REJECT_PROPOSAL) 53 | response.set_content('Proposta Recusada') 54 | self.agent.send(response) 55 | except: 56 | display_message(self.agent.aid.name, 'O Processamento não foi possivel porque nenhuma mensagem foi retornada.') 57 | 58 | def handle_inform(self, message): 59 | FipaContractNetProtocol.handle_inform(self, message) 60 | display_message(self.agent.aid.name, 'Compra Autorizada') 61 | 62 | class ComportamentoAgenteLivraria(FipaContractNetProtocol): 63 | def __init__(self, agent): 64 | super(ComportamentoAgenteLivraria, self).__init__(agent, is_initiator=False) 65 | 66 | def handle_cfp(self, message): 67 | FipaContractNetProtocol.handle_cfp(self, message) 68 | display_message(self.agent.aid.name, 'Solicitação Recebida') 69 | 70 | pedido = loads(message.content) 71 | 72 | for book in self.agent.booksList: 73 | if book['title'] == pedido['title'] and book['author'] == pedido['author']: 74 | if book['qtd'] >= pedido['qtd']: 75 | response = message.create_reply() 76 | response.set_performative(ACLMessage.PROPOSE) 77 | book['book store'] = self.agent.aid.name 78 | response.set_content(dumps(book)) 79 | self.agent.send(response) 80 | else: 81 | response = message.create_reply() 82 | response.set_performative(ACLMessage.REJECT_PROPOSAL) 83 | response.set_content('Requisição Recusada') 84 | self.agent.send(response) 85 | 86 | def handle_accept_propose(self, message): 87 | FipaContractNetProtocol.handle_accept_propose(self, message) 88 | 89 | display_message(self.agent.aid.name, 'Proposta Aceita') 90 | 91 | response = message.create_reply() 92 | response.set_performative(ACLMessage.INFORM) 93 | response.set_content('Compra Autorizada') 94 | self.agent.send(response) 95 | 96 | 97 | def handle_reject_proposes(self, message): 98 | FipaContractNetProtocol.handle_reject_proposes(self, message) 99 | 100 | display_message(self.agent.aid.name, 'Proposta Recusada') 101 | 102 | class AgenteConsumidor(Agent): 103 | 104 | def __init__(self, aid, bookStores, pedido): 105 | Agent.__init__(self, aid) 106 | 107 | self.bookStores = bookStores 108 | self.pedido = pedido 109 | 110 | cfp_message = ACLMessage(ACLMessage.CFP) 111 | cfp_message.set_protocol(ACLMessage.FIPA_CONTRACT_NET_PROTOCOL) 112 | for i in self.bookStores: 113 | cfp_message.add_receiver(i) 114 | cfp_message.set_content(dumps(self.pedido)) 115 | 116 | comportamento = ComportamentoAgenteConsumidor(self, cfp_message) 117 | self.behaviours.append(comportamento) 118 | 119 | class AgenteLivraria(Agent): 120 | 121 | def __init__(self, aid, booksList): 122 | Agent.__init__(self, aid) 123 | 124 | self.booksList = booksList 125 | 126 | comportamento = ComportamentoAgenteLivraria(self) 127 | self.behaviours.append(comportamento) 128 | 129 | if __name__ == '__main__': 130 | booksList_Saraiva = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 53.50}, 131 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 33.70}, 132 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10,'how much is' : 23.80} 133 | ] 134 | 135 | bookslist_Cultura = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 43.50}, 136 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 31.70}, 137 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10, 'how much is' : 53.80} 138 | ] 139 | 140 | bookslist_Nobel = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 63.50}, 141 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 35.70}, 142 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10, 'how much is' : 33.80} 143 | ] 144 | 145 | bookStoresInfo = [(AID(name='Cultura'), bookslist_Cultura), 146 | (AID(name='Saraiva'), booksList_Saraiva), 147 | (AID(name='Nobel'), bookslist_Nobel)] 148 | 149 | pedido = {'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 5} 150 | 151 | set_ams('localhost', 8000) 152 | 153 | agents = [] 154 | saraiva = AgenteLivraria(AID(name='Saraiva'), booksList_Saraiva) 155 | agents.append(saraiva) 156 | 157 | cultura = AgenteLivraria(AID(name='Cultura'), bookslist_Cultura) 158 | agents.append(cultura) 159 | 160 | nobel = AgenteLivraria(AID(name='Nobel'), bookslist_Nobel) 161 | # agents.append(nobel) 162 | 163 | consumidor = AgenteConsumidor(AID('Lucas'), ['Saraiva', 'Cultura', 'Nobel'], pedido) 164 | agents.append(consumidor) 165 | 166 | start_loop(agents) -------------------------------------------------------------------------------- /pade/tests/v1/script_2_revisado_local.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from utils import display_message, set_ams, start_loop, config_loop 4 | #config_loop(gui=True) 5 | from agent import Agent 6 | from messages import ACLMessage 7 | from aid import AID 8 | from protocols import FipaContractNetProtocol 9 | from filters import Filter 10 | from pickle import loads, dumps 11 | from time import sleep 12 | 13 | #=============================================================================== 14 | # Note, o que é necessário para criar um agente com comportamentos padronizados 15 | # em protocolos? 16 | # Primeiro, é preciso definir a classe protocolo 17 | # Segundo é preciso associar esta classe protocolo como um comportamento do 18 | # agente 19 | #=============================================================================== 20 | 21 | class ComportamentoAgenteLivraria(FipaContractNetProtocol): 22 | def __init__(self, agent): 23 | super(ComportamentoAgenteLivraria, self).__init__(agent, is_initiator=False) 24 | 25 | def handle_cfp(self, message): 26 | FipaContractNetProtocol.handle_cfp(self, message) 27 | display_message(self.agent.aid.name, 'Solicitação Recebida') 28 | 29 | pedido = loads(message.content) 30 | 31 | for book in self.agent.booksList: 32 | if book['title'] == pedido['title'] and book['author'] == pedido['author']: 33 | if book['qtd'] >= pedido['qtd']: 34 | response = message.create_reply() 35 | response.set_performative(ACLMessage.PROPOSE) 36 | book['book store'] = self.agent.aid.name 37 | response.set_content(dumps(book)) 38 | self.agent.send(response) 39 | else: 40 | response = message.create_reply() 41 | response.set_performative(ACLMessage.REJECT_PROPOSAL) 42 | response.set_content('Requisição Recusada') 43 | self.agent.send(response) 44 | 45 | def handle_accept_propose(self, message): 46 | FipaContractNetProtocol.handle_accept_propose(self, message) 47 | 48 | display_message(self.agent.aid.name, 'Proposta Aceita') 49 | 50 | response = message.create_reply() 51 | response.set_performative(ACLMessage.INFORM) 52 | response.set_content('Compra Autorizada') 53 | self.agent.send(response) 54 | 55 | 56 | def handle_reject_proposes(self, message): 57 | FipaContractNetProtocol.handle_reject_proposes(self, message) 58 | 59 | display_message(self.agent.aid.name, 'Proposta Recusada') 60 | 61 | class AgenteLivraria(Agent): 62 | 63 | def __init__(self, aid, booksList): 64 | Agent.__init__(self, aid) 65 | 66 | self.booksList = booksList 67 | 68 | comportamento = ComportamentoAgenteLivraria(self) 69 | self.addBehaviour(comportamento) 70 | 71 | if __name__ == '__main__': 72 | booksList_Saraiva = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 53.50}, 73 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 33.70}, 74 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10,'how much is' : 23.80} 75 | ] 76 | 77 | bookslist_Cultura = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 43.50}, 78 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 31.70}, 79 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10, 'how much is' : 53.80} 80 | ] 81 | 82 | bookStoresInfo = [(AID(name='Cultura'), bookslist_Cultura), 83 | (AID(name='Saraiva'), booksList_Saraiva)] 84 | 85 | pedido = {'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 5} 86 | 87 | #set_ams('localhost', 8000) 88 | 89 | agents = [] 90 | #saraiva = AgenteLivraria(AID(name='Saraiva@192.168.0.100:2002'), booksList_Saraiva) 91 | saraiva = AgenteLivraria(AID(name='Saraiva'), booksList_Saraiva) 92 | saraiva.set_ams() 93 | agents.append(saraiva) 94 | 95 | #cultura = AgenteLivraria(AID(name='Cultura@192.168.0.100:2003'), bookslist_Cultura) 96 | cultura = AgenteLivraria(AID(name='Cultura'), bookslist_Cultura) 97 | cultura.set_ams() 98 | agents.append(cultura) 99 | 100 | start_loop(agents) -------------------------------------------------------------------------------- /pade/tests/v1/script_2_revisado_local_2.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from utils import display_message, set_ams, start_loop, config_loop 4 | config_loop() 5 | from agent import Agent 6 | from messages import ACLMessage 7 | from aid import AID 8 | from protocols import FipaContractNetProtocol 9 | from filters import Filter 10 | from pickle import loads, dumps 11 | from time import sleep 12 | 13 | #=============================================================================== 14 | # Note, o que é necessário para criar um agente com comportamentos padronizados 15 | # em protocolos? 16 | # Primeiro, é preciso definir a classe protocolo 17 | # Segundo é preciso associar esta classe protocolo como um comportamento do 18 | # agente 19 | #=============================================================================== 20 | 21 | 22 | class ComportamentoAgenteConsumidor(FipaContractNetProtocol): 23 | def __init__(self, agent, message): 24 | super(ComportamentoAgenteConsumidor, self).__init__(agent, message, is_initiator=True) 25 | self.bestPropose = None 26 | self.bestBookStore = None 27 | 28 | def handle_propose(self, message): 29 | FipaContractNetProtocol.handle_propose(self, message) 30 | display_message(self.agent.aid.name, 'Proposta Recebida') 31 | 32 | def handle_all_proposes(self, proposes): 33 | FipaContractNetProtocol.handle_all_proposes(self, proposes) 34 | 35 | try: 36 | 37 | self.bestPropose = proposes[0] 38 | 39 | for propose in proposes: 40 | content = loads(propose.content) 41 | if content['how much is'] < loads(self.bestPropose.content)['how much is']: 42 | self.bestPropose = propose 43 | 44 | response = self.bestPropose.create_reply() 45 | response.set_performative(ACLMessage.ACCEPT_PROPOSAL) 46 | response.set_content('Proposta Aceita') 47 | self.agent.send(response) 48 | 49 | for propose in proposes: 50 | if propose != self.bestPropose: 51 | response = propose.create_reply() 52 | response.set_performative(ACLMessage.REJECT_PROPOSAL) 53 | response.set_content('Proposta Recusada') 54 | self.agent.send(response) 55 | except: 56 | display_message(self.agent.aid.name, 'O Processamento não foi possivel porque nenhuma mensagem foi retornada.') 57 | 58 | def handle_inform(self, message): 59 | FipaContractNetProtocol.handle_inform(self, message) 60 | display_message(self.agent.aid.name, 'Compra Autorizada') 61 | 62 | class AgenteConsumidor(Agent): 63 | 64 | def __init__(self, aid, bookStores, pedido): 65 | Agent.__init__(self, aid) 66 | 67 | self.bookStores = bookStores 68 | self.pedido = pedido 69 | 70 | cfp_message = ACLMessage(ACLMessage.CFP) 71 | cfp_message.set_protocol(ACLMessage.FIPA_CONTRACT_NET_PROTOCOL) 72 | for i in self.bookStores: 73 | cfp_message.add_receiver(i) 74 | cfp_message.set_content(dumps(self.pedido)) 75 | 76 | comportamento = ComportamentoAgenteConsumidor(self, cfp_message) 77 | self.addBehaviour(comportamento) 78 | 79 | if __name__ == '__main__': 80 | 81 | agents = [] 82 | pedido = {'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 5} 83 | 84 | #consumidor = AgenteConsumidor(AID('Lucas@192.168.0.100:2004'), ['Saraiva', 'Cultura', 'Nobel'], pedido) 85 | consumidor = AgenteConsumidor(AID('Lucas'), ['Saraiva', 'Cultura', 'Nobel'], pedido) 86 | 87 | consumidor.set_ams() 88 | agents.append(consumidor) 89 | 90 | start_loop(agents) -------------------------------------------------------------------------------- /pade/tests/v1/script_2_revisado_raspberry.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | from utils import display_message, set_ams, start_loop, config_loop 4 | config_loop() 5 | from agent import Agent 6 | from messages import ACLMessage 7 | from aid import AID 8 | from protocols import FipaContractNetProtocol 9 | from filters import Filter 10 | from pickle import loads, dumps 11 | from time import sleep 12 | 13 | #=============================================================================== 14 | # Note, o que é necessário para criar um agente com comportamentos padronizados 15 | # em protocolos? 16 | # Primeiro, é preciso definir a classe protocolo 17 | # Segundo é preciso associar esta classe protocolo como um comportamento do 18 | # agente 19 | #=============================================================================== 20 | 21 | class ComportamentoAgenteLivraria(FipaContractNetProtocol): 22 | def __init__(self, agent): 23 | super(ComportamentoAgenteLivraria, self).__init__(agent, is_initiator=False) 24 | 25 | def handle_cfp(self, message): 26 | FipaContractNetProtocol.handle_cfp(self, message) 27 | display_message(self.agent.aid.name, 'Solicitação Recebida') 28 | 29 | pedido = loads(message.content) 30 | 31 | for book in self.agent.booksList: 32 | if book['title'] == pedido['title'] and book['author'] == pedido['author']: 33 | if book['qtd'] >= pedido['qtd']: 34 | response = message.create_reply() 35 | response.set_performative(ACLMessage.PROPOSE) 36 | book['book store'] = self.agent.aid.name 37 | response.set_content(dumps(book)) 38 | self.agent.send(response) 39 | else: 40 | response = message.create_reply() 41 | response.set_performative(ACLMessage.REJECT_PROPOSAL) 42 | response.set_content('Requisição Recusada') 43 | self.agent.send(response) 44 | 45 | def handle_accept_propose(self, message): 46 | FipaContractNetProtocol.handle_accept_propose(self, message) 47 | 48 | display_message(self.agent.aid.name, 'Proposta Aceita') 49 | 50 | response = message.create_reply() 51 | response.set_performative(ACLMessage.INFORM) 52 | response.set_content('Compra Autorizada') 53 | self.agent.send(response) 54 | 55 | 56 | def handle_reject_proposes(self, message): 57 | FipaContractNetProtocol.handle_reject_proposes(self, message) 58 | 59 | display_message(self.agent.aid.name, 'Proposta Recusada') 60 | 61 | class AgenteLivraria(Agent): 62 | 63 | def __init__(self, aid, booksList): 64 | Agent.__init__(self, aid) 65 | 66 | self.booksList = booksList 67 | 68 | comportamento = ComportamentoAgenteLivraria(self) 69 | self.addBehaviour(comportamento) 70 | 71 | if __name__ == '__main__': 72 | 73 | bookslist_Nobel = [{'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 10, 'how much is' : 63.50}, 74 | {'title' : 'Harry Potter', 'author' : 'J. K. Roling', 'qtd' : 10, 'how much is' : 35.70}, 75 | {'title' : 'Game of Thrones', 'author' : 'A. M. M. Martin', 'qtd' : 10, 'how much is' : 33.80} 76 | ] 77 | 78 | bookStoresInfo = [(AID(name='Nobel@192.168.0.101:2001'), bookslist_Nobel)] 79 | 80 | pedido = {'title' : 'The Lord of the Rings', 'author' : 'J. R. R. Tolkien', 'qtd' : 5} 81 | 82 | agents = [] 83 | 84 | nobel = AgenteLivraria(AID(name='Nobel'), bookslist_Nobel) 85 | nobel.set_ams('192.168.0.101', 8000) 86 | agents.append(nobel) 87 | 88 | start_loop(agents) -------------------------------------------------------------------------------- /pade/tests/v1/script_3.py: -------------------------------------------------------------------------------- 1 | from protocols import FipaRequestProtocol 2 | from agent import Agent 3 | from utils import display_message, set_ams, start_loop 4 | from messages import ACLMessage 5 | from aid import AID 6 | 7 | class RequestIniciante(FipaRequestProtocol): 8 | 9 | def __init__(self, agent, message): 10 | super(RequestIniciante, self).__init__(agent, message, is_initiator=True) 11 | 12 | def handle_agree(self, message): 13 | display_message(self.agent.aid.name, message.content) 14 | 15 | def handle_inform(self, message): 16 | display_message(self.agent.aid.name, message.content) 17 | 18 | class RequestParticipante(FipaRequestProtocol): 19 | 20 | def __init__(self, agent): 21 | super(RequestParticipante, self).__init__(agent, message=None, is_initiator=False) 22 | 23 | def handle_request(self, message): 24 | display_message(self.agent.aid.name, message.content) 25 | 26 | response = message.create_reply() 27 | response.set_performative(ACLMessage.AGREE) 28 | response.set_content('AGREE') 29 | self.agent.send(response) 30 | 31 | response_2 = message.create_reply() 32 | response_2.set_performative(ACLMessage.INFORM) 33 | response_2.set_content('INFORM') 34 | self.agent.send(response_2) 35 | 36 | class Agent_Initiator(Agent): 37 | def __init__(self, aid): 38 | Agent.__init__(self, aid) 39 | 40 | message = ACLMessage(ACLMessage.REQUEST) 41 | message.set_protocol(ACLMessage.FIPA_REQUEST_PROTOCOL) 42 | message.set_content('REQUEST') 43 | message.add_receiver('agent_participant_1') 44 | comportamento_1 = RequestIniciante(self, message) 45 | self.addBehaviour(comportamento_1) 46 | 47 | def on_start 48 | on_start(self): 49 | Agent.on_start 50 | on_start(self) 51 | 52 | class Agent_Participant(Agent): 53 | def __init__(self, aid): 54 | Agent.__init__(self, aid) 55 | comportamento_1 = RequestParticipante(self) 56 | self.addBehaviour(comportamento_1) 57 | 58 | def on_start 59 | on_start(self): 60 | Agent.on_start 61 | on_start(self) 62 | 63 | if __name__ == '__main__': 64 | 65 | set_ams(8000) 66 | 67 | agent_participant_1 = Agent_Participant(AID('agent_participant_1')) 68 | agent_participant_1.set_ams('localhost', 8000) 69 | agent_participant_1.start() 70 | 71 | agent_initiator = Agent_Initiator(AID('agent_initiator')) 72 | agent_initiator.set_ams('localhost', 8000) 73 | agent_initiator.start() 74 | 75 | start_loop() -------------------------------------------------------------------------------- /pade/tests/v1/script_4.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from utils import set_ams, config_loop, start_loop, display_message 5 | config_loop(gui=True) 6 | 7 | from agent import Agent 8 | from messages import ACLMessage 9 | from protocols import FipaContractNetProtocol 10 | from aid import AID 11 | from pickle import dumps, loads 12 | 13 | class InitiatorProtocol(FipaContractNetProtocol): 14 | 15 | def __init__(self, agent, message): 16 | super(InitiatorProtocol, self).__init__(agent, message, is_initiator=True) 17 | 18 | 19 | def handle_propose(self, message): 20 | FipaContractNetProtocol.handle_propose(self, message) 21 | display_message(self.agent.aid.name, loads(message.content)) 22 | 23 | def handle_refuse(self, message): 24 | FipaContractNetProtocol.handle_refuse(self, message) 25 | display_message(self.agent.aid.name, loads(message.content)) 26 | 27 | def handle_all_proposes(self, proposes): 28 | FipaContractNetProtocol.handle_all_proposes(self, proposes) 29 | 30 | display_message(self.agent.aid.name, 'Analisando Propostas...') 31 | better_propose = loads(proposes[0].content) 32 | better_propositor = proposes[0] 33 | for propose in proposes: 34 | power_value = loads(propose.content) 35 | if power_value['value'] > better_propose['value']: 36 | better_propose = power_value 37 | better_propositor = propose 38 | 39 | response_1 = better_propositor.create_reply() 40 | response_1.set_performative(ACLMessage.ACCEPT_PROPOSAL) 41 | response_1.set_content('Proposta ACEITA') 42 | self.agent.send(response_1) 43 | 44 | for propose in proposes: 45 | if propose != better_propositor: 46 | response = propose.create_reply() 47 | response.set_performative(ACLMessage.REJECT_PROPOSAL) 48 | response.set_content('Proposta RECUSADA') 49 | self.agent.send(response) 50 | 51 | 52 | def handle_inform(self, message): 53 | FipaContractNetProtocol.handle_inform(self, message) 54 | display_message(self.agent.aid.name, message.content) 55 | 56 | class ParticipantProtocol(FipaContractNetProtocol): 57 | 58 | def __init__(self, agent, power_values): 59 | super(ParticipantProtocol,self).__init__(agent, is_initiator=False) 60 | self.power_values = power_values 61 | 62 | def handle_cfp(self, message): 63 | FipaContractNetProtocol.handle_cfp(self, message) 64 | 65 | display_message(self.agent.aid.name, loads(message.content)) 66 | response = message.create_reply() 67 | response.set_performative(ACLMessage.PROPOSE) 68 | response.set_content(dumps(self.power_values)) 69 | self.agent.send(response) 70 | 71 | def handle_accept_propose(self, message): 72 | FipaContractNetProtocol.handle_accept_propose(self, message) 73 | response = message.create_reply() 74 | response.set_performative(ACLMessage.INFORM) 75 | response.set_content('RECOMPOSICAO AUTORIZADA') 76 | self.agent.send(response) 77 | display_message(self.agent.aid.name, message.content) 78 | 79 | def handle_reject_proposes(self, message): 80 | FipaContractNetProtocol.handle_reject_proposes(self, message) 81 | display_message(self.agent.aid.name, message.content) 82 | 83 | class InitiatorAgent(Agent): 84 | 85 | def __init__(self, aid): 86 | Agent.__init__(self, aid) 87 | 88 | pedido = {'tipo' : 'pedido', 'qtd' : 100.0} 89 | message = ACLMessage(ACLMessage.CFP) 90 | message.set_protocol(ACLMessage.FIPA_CONTRACT_NET_PROTOCOL) 91 | message.set_content(dumps(pedido)) 92 | message.add_receiver('participant_agent_1') 93 | message.add_receiver('participant_agent_2') 94 | behaviour = InitiatorProtocol(self, message) 95 | self.addBehaviour(behaviour) 96 | 97 | class ParticipantAgent(Agent): 98 | 99 | def __init__(self, aid, power_values): 100 | Agent.__init__(self, aid) 101 | behaviour = ParticipantProtocol(self, power_values) 102 | self.addBehaviour(behaviour) 103 | 104 | if __name__ == '__main__': 105 | 106 | set_ams('localhost', 8000) 107 | 108 | agent_participant_1 = ParticipantAgent(AID('participant_agent_1'), {'value' : 100.0}) 109 | agent_participant_1.set_ams('localhost', 8000) 110 | agent_participant_1.start() 111 | 112 | agent_participant_2 = ParticipantAgent(AID('participant_agent_2'), {'value' : 200.0}) 113 | agent_participant_2.set_ams('localhost', 8000) 114 | agent_participant_2.start() 115 | 116 | agent_initiator = InitiatorAgent(AID('initiator_agent')) 117 | agent_initiator.set_ams('localhost', 8000) 118 | agent_initiator.start() 119 | 120 | start_loop() -------------------------------------------------------------------------------- /pade/tests/v1/script_5.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/ python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from utils import set_ams, config_loop, start_loop, display_message 5 | config_loop(gui=True) 6 | 7 | from agent import Agent 8 | from messages import ACLMessage 9 | from aid import AID 10 | from pickle import dumps, loads 11 | from time import sleep 12 | 13 | 14 | 15 | class Teste(Agent): 16 | def __init__(self, aid): 17 | Agent.__init__(self, aid) 18 | 19 | def on_start 20 | on_start(self): 21 | Agent.on_start 22 | on_start(self) 23 | display_message(self.aid.name, "Hello World") 24 | if 'Bob' in self.aid.name: 25 | message = ACLMessage(ACLMessage.INFORM) 26 | message.add_receiver(AID('Alice')) 27 | message.set_content('Ola Alice!') 28 | self.send(message) 29 | 30 | def react(self, message): 31 | Agent.react(self, message) 32 | display_message(self.aid.name, message.get_message()) 33 | 34 | if __name__ == '__main__': 35 | set_ams('localhost', 8000) 36 | 37 | agente = Teste(AID('Alice')) 38 | agente.set_ams('localhost', 8000) 39 | agente.start() 40 | 41 | agente = Teste(AID('Bob')) 42 | agente.set_ams('localhost', 8000) 43 | agente.start() 44 | 45 | start_loop() -------------------------------------------------------------------------------- /pade/tests/v1/server_client.py: -------------------------------------------------------------------------------- 1 | from twisted.internet import protocol, reactor 2 | 3 | class Sniffer(protocol.Protocol): 4 | 5 | def __init__(self, factory): 6 | self.factory = factory 7 | 8 | def connectionMade(self): 9 | if self.factory.isClient: 10 | self.transport.write('Connection is made with ' + str(self.transport.getPeer())) 11 | else: 12 | self.transport.write('Voce e um cliente e esta conectado!') 13 | 14 | def dataReceived(self, data): 15 | if 'quit' in data: 16 | self.transport.loseConnection() 17 | else: 18 | if self.factory.isClient: 19 | print 'Mensagem recebida: ', data 20 | else: 21 | print 'Tentando conectar' 22 | reactor.connectTCP('localhost', 1234, SnifferFactory(isClient=True)) 23 | 24 | class SnifferFactory(protocol.ClientFactory): 25 | 26 | def __init__(self, isClient): 27 | self.isClient = isClient 28 | 29 | def buildProtocol(self, addr): 30 | return Sniffer(self) 31 | 32 | reactor.listenTCP(1235, SnifferFactory(isClient=False)) 33 | reactor.run() -------------------------------------------------------------------------------- /pade/tests/v1/test_agent.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/ python 2 | # -*- encoding: utf-8 -*- 3 | 4 | from utils import config_loop, start_loop, set_ams, display_message 5 | config_loop(gui=True) 6 | 7 | from agent import Agent 8 | from messages import ACLMessage 9 | from aid import AID 10 | 11 | 12 | class Teste(Agent): 13 | 14 | def __init__(self, aid): 15 | Agent.__init__(self, aid) 16 | 17 | def on_start(self): 18 | Agent.on_start(self) 19 | display_message(self.aid.name, "Hello World") 20 | 21 | if 'agente_teste_iniciante' in self.aid.name: 22 | message = ACLMessage(ACLMessage.INFORM) 23 | message.add_receiver('agente_teste_participante') 24 | message.set_content('Ola Agente!') 25 | self.send(message) 26 | display_message(self.aid.name, 'Enviando mensagem...') 27 | 28 | def react(self, message): 29 | Agent.react(self, message) 30 | display_message(self.aid.name, 'Uma mensagem recebida') 31 | 32 | if 'agente_teste_participante' in self.aid.name: 33 | resposta = message.create_reply() 34 | resposta.set_content('Ola tambem agente!') 35 | self.send(resposta) 36 | 37 | if __name__ == '__main__': 38 | 39 | set_ams('localhost', 8000) 40 | 41 | agente_teste_iniciante = Teste(AID('agente_teste_iniciante')) 42 | 43 | agente_teste_participante = Teste(AID('agente_teste_participante')) 44 | 45 | agentes = list() 46 | 47 | print id(agente_teste_iniciante) 48 | print id(agente_teste_participante) 49 | 50 | agentes.append(agente_teste_participante) 51 | agentes.append(agente_teste_iniciante) 52 | 53 | start_loop(agentes) -------------------------------------------------------------------------------- /pade/tests/v1/test_command_line.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import optparse 4 | 5 | def main(): 6 | p = optparse.OptionParser() 7 | p.add_option('--person', '-p', default='person') 8 | options, arguments = p.parse_args() 9 | print 'Hello World, %s' % options.person 10 | 11 | if __name__ == '__main__': 12 | main() 13 | 14 | -------------------------------------------------------------------------------- /pade/tests/v1/teste.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from twisted.internet import protocol, reactor 4 | 5 | class Echo(protocol.Protocol): 6 | def connectionMade(self): 7 | self.transport.write('Hello Server!') 8 | print 'Conacxão realizada!' 9 | 10 | def dataReceived(self, data): 11 | print data 12 | 13 | class EchoFactory(protocol.ClientFactory): 14 | def buildProtocol(self, addr): 15 | return Echo() 16 | 17 | def clientConnectionFailed(self, connector, reason): 18 | print 'Conexão falhou!' 19 | print reason.getErrorMessage() 20 | reactor.stop() 21 | 22 | if __name__ == '__main__': 23 | print 'Conectando...' 24 | reactor.connectTCP('192.168.0.32', 1234, EchoFactory()) 25 | reactor.run() -------------------------------------------------------------------------------- /pade/web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/web/__init__.py -------------------------------------------------------------------------------- /pade/web/data.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/web/data.sqlite -------------------------------------------------------------------------------- /pade/web/flask_server.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask import request, render_template, flash, redirect, url_for 4 | from flask.ext.bootstrap import Bootstrap 5 | from flask.ext.login import LoginManager, login_required, login_user, logout_user 6 | from flask.ext.wtf import Form 7 | from wtforms import StringField, PasswordField, BooleanField, SubmitField 8 | from wtforms.validators import Required, Email, Length 9 | 10 | from flask.ext.sqlalchemy import SQLAlchemy 11 | from flask.ext.login import UserMixin 12 | from werkzeug import generate_password_hash, check_password_hash 13 | 14 | 15 | basedir = os.path.abspath(os.path.dirname(__file__)) 16 | 17 | app = Flask(__name__) 18 | 19 | # Configuracoes do banco de dados 20 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + \ 21 | os.path.join(basedir, 'data.sqlite') 22 | app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 23 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True 24 | 25 | # configiracao para utilizacao de chave de seguranca 26 | # em formularios submetidos pelo metodo POST 27 | app.config['SECRET_KEY'] = 'h5xzTxz2ksytu8GJjei37KHI8t0unJKN7EQ8KOPU3Khkjhkjguv' 28 | 29 | # configuracao para utilizacao offline do Bootstrap 30 | app.config['BOOTSTRAP_SERVE_LOCAL'] = True 31 | 32 | # configuracao do sistema de login 33 | login_manager = LoginManager() 34 | login_manager.init_app(app) 35 | login_manager.session_protection = 'strong' 36 | login_manager.login_view = 'login' 37 | 38 | db = SQLAlchemy(app) 39 | 40 | bootstrap = Bootstrap(app) 41 | 42 | class Session(db.Model): 43 | __tablename__ = 'sessions' 44 | id = db.Column(db.Integer, primary_key=True) 45 | name = db.Column(db.String(64), unique=True) 46 | date = db.Column(db.DateTime) 47 | state = db.Column(db.String(64)) 48 | agents = db.relationship('Agent', backref='session') 49 | users = db.relationship('User', backref='session') 50 | 51 | def __repr__(self): 52 | return "Session %s" % self.name 53 | 54 | 55 | class User(UserMixin, db.Model): 56 | __tablename__ = 'users' 57 | id = db.Column(db.Integer, primary_key=True) 58 | session_id = db.Column(db.Integer, db.ForeignKey('sessions.id')) 59 | username = db.Column(db.String(64), unique=True) 60 | email = db.Column(db.String(64), unique=True) 61 | password_hash = db.Column(db.String(128)) 62 | 63 | @property 64 | def password(self): 65 | raise AttributeError('password is not a readable attribute!') 66 | 67 | @password.setter 68 | def password(self, password): 69 | self.password_hash = generate_password_hash(password) 70 | 71 | def verify_password(self, password): 72 | return check_password_hash(self.password_hash, password) 73 | 74 | def __repr__(self): 75 | return 'Username: %s' % self.username 76 | 77 | 78 | class Agent(db.Model): 79 | 80 | __tablename__ = 'agents' 81 | id = db.Column(db.Integer, primary_key=True) 82 | session_id = db.Column(db.Integer, db.ForeignKey('sessions.id')) 83 | name = db.Column(db.String(64), unique=True) 84 | date = db.Column(db.DateTime) 85 | state = db.Column(db.String(64)) 86 | messages = db.relationship('Message', backref='agent') 87 | def __repr__(self): 88 | return 'Agent %s' % self.name 89 | 90 | 91 | class Message(db.Model): 92 | __tablename__ = 'messages' 93 | id = db.Column(db.Integer, primary_key=True) 94 | agent_id = db.Column(db.Integer, db.ForeignKey('agents.id')) 95 | conversation_id = db.Column(db.String(64)) 96 | message_id = db.Column(db.String(64)) 97 | date = db.Column(db.DateTime) 98 | performative = db.Column(db.String(64)) 99 | protocol = db.Column(db.String(64)) 100 | sender = db.Column(db.String(64)) 101 | receivers = db.Column(db.PickleType) 102 | content = db.Column(db.String) 103 | ontology = db.Column(db.String) 104 | language = db.Column(db.String) 105 | 106 | def __repr__(self): 107 | return 'Message %s' % self.id 108 | 109 | class LoginForm(Form): 110 | email = StringField('Email', validators=[Required(), Length(1, 64), 111 | Email()]) 112 | password = PasswordField('Password', validators=[Required()]) 113 | remember_me = BooleanField('Keep me logged in') 114 | submit = SubmitField('Log In') 115 | 116 | 117 | @app.before_first_request 118 | def create_database(): 119 | db.create_all() 120 | print '[flask-server] >>> Database created.' 121 | 122 | @login_manager.user_loader 123 | def load_user(user_id): 124 | return User.query.get(int(user_id)) 125 | 126 | @app.route('/login', methods=['GET', 'POST']) 127 | def login(): 128 | form = LoginForm() 129 | if form.validate_on_submit(): 130 | user = User.query.filter_by(email=form.email.data).first() 131 | if user is not None and user.verify_password(form.password.data): 132 | login_user(user, form.remember_me.data) 133 | return redirect(url_for('index')) 134 | flash('Invalid username or password.') 135 | else: 136 | user = request.args.get('email', type=str) 137 | password = request.args.get('password', type=str) 138 | remember = request.args.get('remember', type=bool) 139 | user = User.query.filter_by(email=user).first() 140 | if user is not None and user.verify_password(password): 141 | login_user(user, remember) 142 | return redirect(url_for('index')) 143 | else: 144 | return render_template('login.html', form=form) 145 | 146 | @app.route('/logout', methods=['GET', 'POST']) 147 | def logout(): 148 | logout_user() 149 | flash('You have been logged out') 150 | return redirect(url_for('login')) 151 | 152 | @app.route('/') 153 | @login_required 154 | def index(): 155 | sessions = Session.query.all() 156 | return render_template('index.html', sessions=sessions) 157 | 158 | @app.route('/session/') 159 | @login_required 160 | def session_page(session_id): 161 | session = Session.query.filter_by(id=session_id).all()[0] 162 | agents = session.agents 163 | return render_template('agentes.html', session=session.name, agents=agents) 164 | 165 | @app.route('/session/agent/') 166 | @login_required 167 | def agent_page(agent_id): 168 | agent = Agent.query.filter_by(id=agent_id).all()[0] 169 | messages = agent.messages 170 | return render_template('messages.html', messages=messages) 171 | 172 | @app.route('/session/agent/message/') 173 | @login_required 174 | def message_page(message_id): 175 | message = Message.query.filter_by(id=message_id).all()[0] 176 | return render_template('message.html', message=message) 177 | 178 | @app.route('/diagrams') 179 | @login_required 180 | def diagrams(): 181 | messages = Message.query.order_by(Message.date).all() 182 | _messages = list() 183 | msgs_id = list() 184 | 185 | for msg in messages: 186 | if msg.message_id in msgs_id: 187 | messages.remove(msg) 188 | continue 189 | msgs_id.append(msg.message_id) 190 | 191 | return render_template('diagrams.html', messages=messages) 192 | 193 | @app.route('/post', methods=['POST', 'GET']) 194 | def my_post(): 195 | if request.method == 'GET': 196 | return basedir 197 | else: 198 | return 'Hello ' + str(request.form['name']) 199 | 200 | def run_server(): 201 | app.run(host='0.0.0.0', port=5000, debug=None) 202 | 203 | if __name__ == '__main__': 204 | run_server() 205 | -------------------------------------------------------------------------------- /pade/web/static/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/web/static/__init__.py -------------------------------------------------------------------------------- /pade/web/static/underscore-min.js: -------------------------------------------------------------------------------- 1 | (function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.indexi;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};M.unescape=w.invert(M.escape);var S={escape:RegExp("["+w.keys(M.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(M.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,q={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},B=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return"\\"+q[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); -------------------------------------------------------------------------------- /pade/web/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucassm/Pade/3dc6216a9c302b3361a22ff049fabd3d27a1ccca/pade/web/templates/__init__.py -------------------------------------------------------------------------------- /pade/web/templates/agentes.html: -------------------------------------------------------------------------------- 1 | {% include 'header.html' %} 2 | 3 | 4 | 5 | {% block content %} 6 | 7 | 23 | 24 | {% endblock %} 25 | 26 | 44 | 45 | 46 | {% include 'footer.html' %} 47 | -------------------------------------------------------------------------------- /pade/web/templates/diagrams.html: -------------------------------------------------------------------------------- 1 | {% include 'header.html' %} 2 | 3 | 4 | 5 | {% block content %} 6 | 7 |
8 | 11 |
12 | 13 |
14 |
15 |
16 | 17 | {% endblock %} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 36 | -------------------------------------------------------------------------------- /pade/web/templates/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /pade/web/templates/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Python Agent DEvelopment framework 7 | 8 | 9 | {% extends "bootstrap/base.html" %} 10 | 11 | {% block title %} PADE {% endblock %} 12 | 13 | {% block navbar %} 14 | 41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /pade/web/templates/index.html: -------------------------------------------------------------------------------- 1 | {% include 'header.html' %} 2 | 3 | 4 | 5 | {% block content %} 6 |
7 | 10 |
11 | 12 | 28 | {% endblock %} 29 | 30 | 48 | 49 | 50 | {% include 'footer.html' %} 51 | -------------------------------------------------------------------------------- /pade/web/templates/message.html: -------------------------------------------------------------------------------- 1 | {% include 'header.html' %} 2 | 3 | 4 | 5 | 6 | {% block content %} 7 | 8 |
9 | 12 |
13 | 14 |
15 |
16 |
17 | 18 |
19 |
20 |
21 |
22 | 23 |
24 |

{{ message.date.hour }}:{{ message.date.minute }}:{{ message.date.second }} - {{ message.date.day }}/{{ message.date.month }}/{{ message.date.year }}

25 |
26 |
27 |
28 | 29 |
30 |

{{ message.conversation_id }}

31 |
32 |
33 |
34 | 35 |
36 |

{{ message.sender }}

37 |
38 |
39 |
40 | 41 |
42 | {% for receiver in message.receivers %} 43 |

{{ receiver }}

44 | {% endfor %} 45 |
46 |
47 |
48 | 49 |
50 |

{{ message.performative }}

51 |
52 |
53 |
54 | 55 |
56 |

{{ message.protocol }}

57 |
58 |
59 |
60 | 61 |
62 |

{{ message.content }}

63 |
64 |
65 |
66 | 67 |
68 |

{{ message.ontology }}

69 |
70 |
71 |
72 | 73 |
74 |

{{ message.language }}

75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | {% endblock %} 84 | 85 | 103 | 104 | 105 | {% include 'footer.html' %} 106 | -------------------------------------------------------------------------------- /pade/web/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% include 'header.html' %} 2 | 3 | 4 | 5 | {% block content %} 6 | 7 | 24 | {% endblock %} 25 | 26 | 44 | 45 | 46 | {% include 'footer.html' %} 47 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Framework para Desenvolvimento de Agentes Inteligentes PADE 5 | 6 | # The MIT License (MIT) 7 | 8 | # Copyright (c) 2015 Lucas S Melo 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in 18 | # all copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | # THE SOFTWARE. 27 | 28 | from setuptools import setup, find_packages 29 | 30 | setup(name='pade', 31 | version='1.6', 32 | description='Framework para desenvolvimento de \ 33 | sistemas multiagentes em Python', 34 | author='Lucas S Melo', 35 | author_email='lucassmelo@dee.ufc.br', 36 | package_data={'': ['*.html', '*.js', '*.css', '*.sqlite']}, 37 | include_package_data=True, 38 | install_requires=['twisted'], 39 | license='MIT', 40 | keywords='multiagents distributed systems', 41 | url='http://pade.readthedocs.org', 42 | packages=find_packages()) 43 | --------------------------------------------------------------------------------